| Index: content/browser/time_zone_monitor_linux.cc
|
| diff --git a/content/browser/time_zone_monitor_linux.cc b/content/browser/time_zone_monitor_linux.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..96117fb3c550bcaa1db13be907bf3067b51293ae
|
| --- /dev/null
|
| +++ b/content/browser/time_zone_monitor_linux.cc
|
| @@ -0,0 +1,165 @@
|
| +// 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) {
|
| + 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
|
|
|