diff options
Diffstat (limited to 'chromium/content/browser/time_zone_monitor_linux.cc')
-rw-r--r-- | chromium/content/browser/time_zone_monitor_linux.cc | 166 |
1 files changed, 166 insertions, 0 deletions
diff --git a/chromium/content/browser/time_zone_monitor_linux.cc b/chromium/content/browser/time_zone_monitor_linux.cc new file mode 100644 index 00000000000..f8cae0e2430 --- /dev/null +++ b/chromium/content/browser/time_zone_monitor_linux.cc @@ -0,0 +1,166 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/browser/time_zone_monitor.h" + +#include <stdlib.h> + +#include <vector> + +#include "base/basictypes.h" +#include "base/bind.h" +#include "base/files/file_path.h" +#include "base/files/file_path_watcher.h" +#include "base/memory/ref_counted.h" +#include "base/stl_util.h" +#include "content/public/browser/browser_thread.h" + +#if !defined(OS_CHROMEOS) + +namespace content { + +namespace { +class TimeZoneMonitorLinuxImpl; +} // namespace + +class TimeZoneMonitorLinux : public TimeZoneMonitor { + public: + TimeZoneMonitorLinux(); + virtual ~TimeZoneMonitorLinux(); + + void NotifyRenderersFromImpl() { + NotifyRenderers(); + } + + private: + scoped_refptr<TimeZoneMonitorLinuxImpl> impl_; + + DISALLOW_COPY_AND_ASSIGN(TimeZoneMonitorLinux); +}; + +namespace { + +// FilePathWatcher needs to run on the FILE thread, but TimeZoneMonitor runs +// on the UI thread. TimeZoneMonitorLinuxImpl is the bridge between these +// threads. +class TimeZoneMonitorLinuxImpl + : public base::RefCountedThreadSafe<TimeZoneMonitorLinuxImpl> { + public: + explicit TimeZoneMonitorLinuxImpl(TimeZoneMonitorLinux* owner) + : base::RefCountedThreadSafe<TimeZoneMonitorLinuxImpl>(), + file_path_watchers_(), + owner_(owner) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + BrowserThread::PostTask( + BrowserThread::FILE, + FROM_HERE, + base::Bind(&TimeZoneMonitorLinuxImpl::StartWatchingOnFileThread, this)); + } + + void StopWatching() { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + owner_ = NULL; + BrowserThread::PostTask( + BrowserThread::FILE, + FROM_HERE, + base::Bind(&TimeZoneMonitorLinuxImpl::StopWatchingOnFileThread, this)); + } + + private: + friend class base::RefCountedThreadSafe<TimeZoneMonitorLinuxImpl>; + + ~TimeZoneMonitorLinuxImpl() { + DCHECK(!owner_); + STLDeleteElements(&file_path_watchers_); + } + + void StartWatchingOnFileThread() { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); + + // There is no true standard for where time zone information is actually + // stored. glibc uses /etc/localtime, uClibc uses /etc/TZ, and some older + // systems store the name of the time zone file within /usr/share/zoneinfo + // in /etc/timezone. Different libraries and custom builds may mean that + // still more paths are used. Just watch all three of these paths, because + // false positives are harmless, assuming the false positive rate is + // reasonable. + const char* kFilesToWatch[] = { + "/etc/localtime", + "/etc/timezone", + "/etc/TZ", + }; + + for (size_t index = 0; index < arraysize(kFilesToWatch); ++index) { + file_path_watchers_.push_back(new base::FilePathWatcher()); + file_path_watchers_.back()->Watch( + base::FilePath(kFilesToWatch[index]), + false, + base::Bind(&TimeZoneMonitorLinuxImpl::OnTimeZoneFileChanged, this)); + } + } + + void StopWatchingOnFileThread() { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); + STLDeleteElements(&file_path_watchers_); + } + + void OnTimeZoneFileChanged(const base::FilePath& path, bool error) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); + BrowserThread::PostTask( + BrowserThread::UI, + FROM_HERE, + base::Bind(&TimeZoneMonitorLinuxImpl::OnTimeZoneFileChangedOnUIThread, + this)); + } + + void OnTimeZoneFileChangedOnUIThread() { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + if (owner_) { + owner_->NotifyRenderersFromImpl(); + } + } + + std::vector<base::FilePathWatcher*> file_path_watchers_; + TimeZoneMonitorLinux* owner_; + + DISALLOW_COPY_AND_ASSIGN(TimeZoneMonitorLinuxImpl); +}; + +} // namespace + +TimeZoneMonitorLinux::TimeZoneMonitorLinux() + : TimeZoneMonitor(), + impl_() { + // If the TZ environment variable is set, its value specifies the time zone + // specification, and it's pointless to monitor any files in /etc for + // changes because such changes would have no effect on the TZ environment + // variable and thus the interpretation of the local time zone in the + // or renderer processes. + // + // The system-specific format for the TZ environment variable beginning with + // a colon is implemented by glibc as the path to a time zone data file, and + // it would be possible to monitor this file for changes if a TZ variable of + // this format was encountered, but this is not necessary: when loading a + // time zone specification in this way, glibc does not reload the file when + // it changes, so it's pointless to respond to a notification that it has + // changed. + if (!getenv("TZ")) { + impl_ = new TimeZoneMonitorLinuxImpl(this); + } +} + +TimeZoneMonitorLinux::~TimeZoneMonitorLinux() { + if (impl_) { + impl_->StopWatching(); + } +} + +// static +scoped_ptr<TimeZoneMonitor> TimeZoneMonitor::Create() { + return scoped_ptr<TimeZoneMonitor>(new TimeZoneMonitorLinux()); +} + +} // namespace content + +#endif // !OS_CHROMEOS |