summaryrefslogtreecommitdiffstats
path: root/chromium/content/browser/time_zone_monitor_linux.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/content/browser/time_zone_monitor_linux.cc')
-rw-r--r--chromium/content/browser/time_zone_monitor_linux.cc166
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