summaryrefslogtreecommitdiffstats
path: root/content/browser
diff options
context:
space:
mode:
Diffstat (limited to 'content/browser')
-rw-r--r--content/browser/android/browser_jni_registrar.cc11
-rw-r--r--content/browser/browser_main_loop.cc48
-rw-r--r--content/browser/browser_main_loop.h5
-rw-r--r--content/browser/time_zone_monitor.cc31
-rw-r--r--content/browser/time_zone_monitor.h51
-rw-r--r--content/browser/time_zone_monitor_android.cc38
-rw-r--r--content/browser/time_zone_monitor_android.h37
-rw-r--r--content/browser/time_zone_monitor_chromeos.cc37
-rw-r--r--content/browser/time_zone_monitor_linux.cc166
-rw-r--r--content/browser/time_zone_monitor_mac.mm40
-rw-r--r--content/browser/time_zone_monitor_win.cc46
11 files changed, 485 insertions, 25 deletions
diff --git a/content/browser/android/browser_jni_registrar.cc b/content/browser/android/browser_jni_registrar.cc
index fca55a9..60221e9 100644
--- a/content/browser/android/browser_jni_registrar.cc
+++ b/content/browser/android/browser_jni_registrar.cc
@@ -35,6 +35,7 @@
#include "content/browser/renderer_host/java/java_bound_object.h"
#include "content/browser/screen_orientation/screen_orientation_provider_android.h"
#include "content/browser/speech/speech_recognizer_impl_android.h"
+#include "content/browser/time_zone_monitor_android.h"
#include "content/browser/vibration/vibration_provider_android.h"
#include "content/browser/web_contents/web_contents_android.h"
@@ -44,15 +45,17 @@ namespace {
base::android::RegistrationMethod kContentRegisteredMethods[] = {
{"AndroidLocationApiAdapter",
content::AndroidLocationApiAdapter::RegisterGeolocationService},
+ {"BatteryStatusManagerAndroid",
+ content::BatteryStatusManagerAndroid::Register},
{"BrowserAccessibilityManager",
content::RegisterBrowserAccessibilityManager},
{"BrowserStartupController", content::RegisterBrowserStartupController},
{"ChildProcessLauncher", content::RegisterChildProcessLauncher},
{"ContentSettings", content::ContentSettings::RegisterContentSettings},
- {"ContentViewRenderView",
- content::ContentViewRenderView::RegisterContentViewRenderView},
{"ContentVideoView", content::ContentVideoView::RegisterContentVideoView},
{"ContentViewCore", content::RegisterContentViewCore},
+ {"ContentViewRenderView",
+ content::ContentViewRenderView::RegisterContentViewRenderView},
{"DateTimePickerAndroid", content::RegisterDateTimeChooserAndroid},
{"DownloadControllerAndroidImpl",
content::DownloadControllerAndroidImpl::RegisterDownloadController},
@@ -75,6 +78,7 @@ base::android::RegistrationMethod kContentRegisteredMethods[] = {
{"SensorManagerAndroid", content::SensorManagerAndroid::Register},
{"SpeechRecognizerImplAndroid",
content::SpeechRecognizerImplAndroid::RegisterSpeechRecognizer},
+ {"TimeZoneMonitorAndroid", content::TimeZoneMonitorAndroid::Register},
{"TouchEventSynthesizer",
content::SyntheticGestureTargetAndroid::RegisterTouchEventSynthesizer},
{"TracingControllerAndroid", content::RegisterTracingControllerAndroid},
@@ -82,8 +86,7 @@ base::android::RegistrationMethod kContentRegisteredMethods[] = {
{"WebContentsAndroid", content::WebContentsAndroid::Register},
{"WebContentsObserverAndroid", content::RegisterWebContentsObserverAndroid},
{"WebViewStatics", content::RegisterWebViewStatics},
- {"BatterStatusManagerAndroid",
- content::BatteryStatusManagerAndroid::Register}, };
+};
} // namespace
diff --git a/content/browser/browser_main_loop.cc b/content/browser/browser_main_loop.cc
index 316d7c3..b5db4bc1 100644
--- a/content/browser/browser_main_loop.cc
+++ b/content/browser/browser_main_loop.cc
@@ -41,6 +41,7 @@
#include "content/browser/renderer_host/media/media_stream_manager.h"
#include "content/browser/speech/speech_recognition_manager_impl.h"
#include "content/browser/startup_task_runner.h"
+#include "content/browser/time_zone_monitor.h"
#include "content/browser/webui/content_web_ui_controller_factory.h"
#include "content/browser/webui/url_data_manager.h"
#include "content/public/browser/browser_main_parts.h"
@@ -325,7 +326,7 @@ BrowserMainLoop::~BrowserMainLoop() {
}
void BrowserMainLoop::Init() {
- TRACE_EVENT0("startup", "BrowserMainLoop::Init")
+ TRACE_EVENT0("startup", "BrowserMainLoop::Init");
parts_.reset(
GetContentClient()->browser()->CreateBrowserMainParts(parameters_));
}
@@ -397,7 +398,7 @@ void BrowserMainLoop::EarlyInitialization() {
}
void BrowserMainLoop::MainMessageLoopStart() {
- TRACE_EVENT0("startup", "BrowserMainLoop::MainMessageLoopStart")
+ TRACE_EVENT0("startup", "BrowserMainLoop::MainMessageLoopStart");
if (parts_) {
TRACE_EVENT0("startup",
"BrowserMainLoop::MainMessageLoopStart:PreMainMessageLoopStart");
@@ -420,50 +421,51 @@ void BrowserMainLoop::MainMessageLoopStart() {
InitializeMainThread();
{
- TRACE_EVENT0("startup", "BrowserMainLoop::Subsystem:SystemMonitor")
+ TRACE_EVENT0("startup", "BrowserMainLoop::Subsystem:SystemMonitor");
system_monitor_.reset(new base::SystemMonitor);
}
{
- TRACE_EVENT0("startup", "BrowserMainLoop::Subsystem:PowerMonitor")
+ TRACE_EVENT0("startup", "BrowserMainLoop::Subsystem:PowerMonitor");
scoped_ptr<base::PowerMonitorSource> power_monitor_source(
new base::PowerMonitorDeviceSource());
power_monitor_.reset(new base::PowerMonitor(power_monitor_source.Pass()));
}
{
- TRACE_EVENT0("startup", "BrowserMainLoop::Subsystem:HighResTimerManager")
+ TRACE_EVENT0("startup", "BrowserMainLoop::Subsystem:HighResTimerManager");
hi_res_timer_manager_.reset(new base::HighResolutionTimerManager);
}
{
- TRACE_EVENT0("startup", "BrowserMainLoop::Subsystem:NetworkChangeNotifier")
+ TRACE_EVENT0("startup", "BrowserMainLoop::Subsystem:NetworkChangeNotifier");
network_change_notifier_.reset(net::NetworkChangeNotifier::Create());
}
#if !defined(OS_IOS)
{
- TRACE_EVENT0("startup", "BrowserMainLoop::Subsystem:MediaFeatures")
+ TRACE_EVENT0("startup", "BrowserMainLoop::Subsystem:MediaFeatures");
media::InitializeCPUSpecificMediaFeatures();
}
{
- TRACE_EVENT0("startup", "BrowserMainLoop::Subsystem:AudioMan")
+ TRACE_EVENT0("startup", "BrowserMainLoop::Subsystem:AudioMan");
audio_manager_.reset(media::AudioManager::Create(
MediaInternals::GetInstance()));
}
{
- TRACE_EVENT0("startup", "BrowserMainLoop::Subsystem:MidiManager")
+ TRACE_EVENT0("startup", "BrowserMainLoop::Subsystem:MidiManager");
midi_manager_.reset(media::MidiManager::Create());
}
{
- TRACE_EVENT0("startup", "BrowserMainLoop::Subsystem:ContentWebUIController")
+ TRACE_EVENT0("startup",
+ "BrowserMainLoop::Subsystem:ContentWebUIController");
WebUIControllerFactory::RegisterFactory(
ContentWebUIControllerFactory::GetInstance());
}
{
- TRACE_EVENT0("startup", "BrowserMainLoop::Subsystem:AudioMirroringManager")
+ TRACE_EVENT0("startup", "BrowserMainLoop::Subsystem:AudioMirroringManager");
audio_mirroring_manager_.reset(new AudioMirroringManager());
}
{
- TRACE_EVENT0("startup", "BrowserMainLoop::Subsystem:OnlineStateObserver")
+ TRACE_EVENT0("startup", "BrowserMainLoop::Subsystem:OnlineStateObserver");
online_state_observer_.reset(new BrowserOnlineStateObserver);
}
@@ -485,20 +487,20 @@ void BrowserMainLoop::MainMessageLoopStart() {
// message loop to avoid calling MessagePumpForUI::ScheduleWork() before
// MessagePumpForUI::Start() as it will crash the browser.
if (is_tracing_startup_) {
- TRACE_EVENT0("startup", "BrowserMainLoop::InitStartupTracing")
+ TRACE_EVENT0("startup", "BrowserMainLoop::InitStartupTracing");
InitStartupTracing(parsed_command_line_);
}
#endif // !defined(OS_IOS)
#if defined(OS_ANDROID)
{
- TRACE_EVENT0("startup", "BrowserMainLoop::Subsystem:SurfaceTexturePeer")
+ TRACE_EVENT0("startup", "BrowserMainLoop::Subsystem:SurfaceTexturePeer");
SurfaceTexturePeer::InitInstance(new SurfaceTexturePeerBrowserImpl());
}
#endif
if (parsed_command_line_.HasSwitch(switches::kMemoryMetrics)) {
- TRACE_EVENT0("startup", "BrowserMainLoop::Subsystem:MemoryObserver")
+ TRACE_EVENT0("startup", "BrowserMainLoop::Subsystem:MemoryObserver");
memory_observer_.reset(new MemoryObserver());
base::MessageLoop::current()->AddTaskObserver(memory_observer_.get());
}
@@ -526,7 +528,7 @@ int BrowserMainLoop::PreCreateThreads() {
// but must be created on the main thread. The service ctor is
// inexpensive and does not invoke the io_thread() accessor.
{
- TRACE_EVENT0("startup", "BrowserMainLoop::CreateThreads:PluginService")
+ TRACE_EVENT0("startup", "BrowserMainLoop::CreateThreads:PluginService");
PluginService::GetInstance()->Init();
}
#endif
@@ -712,7 +714,7 @@ void BrowserMainLoop::ShutdownThreadsAndCleanUp() {
// Called early, nothing to do
return;
}
- TRACE_EVENT0("shutdown", "BrowserMainLoop::ShutdownThreadsAndCleanUp")
+ TRACE_EVENT0("shutdown", "BrowserMainLoop::ShutdownThreadsAndCleanUp");
// Teardown may start in PostMainMessageLoopRun, and during teardown we
// need to be able to perform IO.
@@ -893,7 +895,7 @@ void BrowserMainLoop::ShutdownThreadsAndCleanUp() {
}
void BrowserMainLoop::InitializeMainThread() {
- TRACE_EVENT0("startup", "BrowserMainLoop::InitializeMainThread")
+ TRACE_EVENT0("startup", "BrowserMainLoop::InitializeMainThread");
const char* kThreadName = "CrBrowserMain";
base::PlatformThread::SetName(kThreadName);
if (main_message_loop_)
@@ -905,7 +907,7 @@ void BrowserMainLoop::InitializeMainThread() {
}
int BrowserMainLoop::BrowserThreadsStarted() {
- TRACE_EVENT0("startup", "BrowserMainLoop::BrowserThreadsStarted")
+ TRACE_EVENT0("startup", "BrowserMainLoop::BrowserThreadsStarted");
#if !defined(OS_IOS)
indexed_db_thread_.reset(new base::Thread("IndexedDB"));
@@ -992,6 +994,12 @@ int BrowserMainLoop::BrowserThreadsStarted() {
io_thread_->message_loop_proxy(), main_thread_->message_loop_proxy());
}
+ {
+ TRACE_EVENT0("startup",
+ "BrowserMainLoop::BrowserThreadsStarted::TimeZoneMonitor");
+ time_zone_monitor_ = TimeZoneMonitor::Create();
+ }
+
// Alert the clipboard class to which threads are allowed to access the
// clipboard:
std::vector<base::PlatformThreadId> allowed_clipboard_threads;
@@ -1030,7 +1038,7 @@ int BrowserMainLoop::BrowserThreadsStarted() {
}
bool BrowserMainLoop::InitializeToolkit() {
- TRACE_EVENT0("startup", "BrowserMainLoop::InitializeToolkit")
+ TRACE_EVENT0("startup", "BrowserMainLoop::InitializeToolkit");
// TODO(evan): this function is rather subtle, due to the variety
// of intersecting ifdefs we have. To keep it easy to follow, there
// are no #else branches on any #ifs.
diff --git a/content/browser/browser_main_loop.h b/content/browser/browser_main_loop.h
index e308117..f38ac42 100644
--- a/content/browser/browser_main_loop.h
+++ b/content/browser/browser_main_loop.h
@@ -44,13 +44,15 @@ class MediaStreamManager;
class ResourceDispatcherHostImpl;
class SpeechRecognitionManagerImpl;
class StartupTaskRunner;
-class SystemMessageWindowWin;
+class TimeZoneMonitor;
struct MainFunctionParams;
#if defined(OS_LINUX)
class DeviceMonitorLinux;
#elif defined(OS_MACOSX)
class DeviceMonitorMac;
+#elif defined(OS_WIN)
+class SystemMessageWindowWin;
#endif
// Implements the main browser loop stages called from BrowserMainRunner.
@@ -173,6 +175,7 @@ class CONTENT_EXPORT BrowserMainLoop {
// Members initialized in |BrowserThreadsStarted()| --------------------------
scoped_ptr<ResourceDispatcherHostImpl> resource_dispatcher_host_;
scoped_ptr<SpeechRecognitionManagerImpl> speech_recognition_manager_;
+ scoped_ptr<TimeZoneMonitor> time_zone_monitor_;
// Members initialized in |RunMainMessageLoopParts()| ------------------------
scoped_ptr<BrowserProcessSubThread> db_thread_;
diff --git a/content/browser/time_zone_monitor.cc b/content/browser/time_zone_monitor.cc
new file mode 100644
index 0000000..0c17f8e
--- /dev/null
+++ b/content/browser/time_zone_monitor.cc
@@ -0,0 +1,31 @@
+// 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 "base/logging.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/render_process_host.h"
+
+namespace content {
+
+TimeZoneMonitor::TimeZoneMonitor() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+}
+
+TimeZoneMonitor::~TimeZoneMonitor() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+}
+
+void TimeZoneMonitor::NotifyRenderers() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ for (RenderProcessHost::iterator iterator =
+ RenderProcessHost::AllHostsIterator();
+ !iterator.IsAtEnd();
+ iterator.Advance()) {
+ iterator.GetCurrentValue()->NotifyTimezoneChange();
+ }
+}
+
+} // namespace content
diff --git a/content/browser/time_zone_monitor.h b/content/browser/time_zone_monitor.h
new file mode 100644
index 0000000..fed177f
--- /dev/null
+++ b/content/browser/time_zone_monitor.h
@@ -0,0 +1,51 @@
+// 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.
+
+#ifndef CONTENT_BROWSER_TIME_ZONE_MONITOR_H_
+#define CONTENT_BROWSER_TIME_ZONE_MONITOR_H_
+
+#include "base/basictypes.h"
+#include "base/memory/scoped_ptr.h"
+
+namespace content {
+
+// TimeZoneMonitor watches the system time zone, and notifies renderers
+// when it changes. Some renderer code caches the system time zone, so
+// this notification is necessary to inform such code that cached
+// timezone data may have become invalid. Due to sandboxing, it is not
+// possible for renderer processes to monitor for system time zone
+// changes themselves, so this must happen in the browser process.
+//
+// Sandboxing also may prevent renderer processes from reading the time
+// zone when it does change, so platforms may have to deal with this in
+// platform-specific ways:
+// - Mac uses a sandbox hole defined in content/renderer/renderer.sb.
+// - Linux-based platforms use ProxyLocaltimeCallToBrowser in
+// content/zygote/zygote_main_linux.cc and HandleLocaltime in
+// content/browser/renderer_host/sandbox_ipc_linux.cc to override
+// localtime in renderer processes with custom code that calls
+// localtime in the browser process via Chrome IPC.
+
+class TimeZoneMonitor {
+ public:
+ // Returns a new TimeZoneMonitor object (likely a subclass) specific to the
+ // platform.
+ static scoped_ptr<TimeZoneMonitor> Create();
+
+ virtual ~TimeZoneMonitor();
+
+ protected:
+ TimeZoneMonitor();
+
+ // Loop over all renderers and notify them that the system time zone may
+ // have changed.
+ void NotifyRenderers();
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(TimeZoneMonitor);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_TIME_ZONE_MONITOR_H_
diff --git a/content/browser/time_zone_monitor_android.cc b/content/browser/time_zone_monitor_android.cc
new file mode 100644
index 0000000..af57f80
--- /dev/null
+++ b/content/browser/time_zone_monitor_android.cc
@@ -0,0 +1,38 @@
+// 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_android.h"
+
+#include "base/android/jni_android.h"
+#include "jni/TimeZoneMonitor_jni.h"
+
+namespace content {
+
+TimeZoneMonitorAndroid::TimeZoneMonitorAndroid() : TimeZoneMonitor() {
+ impl_.Reset(Java_TimeZoneMonitor_getInstance(
+ base::android::AttachCurrentThread(),
+ base::android::GetApplicationContext(),
+ reinterpret_cast<intptr_t>(this)));
+}
+
+TimeZoneMonitorAndroid::~TimeZoneMonitorAndroid() {
+ Java_TimeZoneMonitor_stop(base::android::AttachCurrentThread(), impl_.obj());
+}
+
+// static
+bool TimeZoneMonitorAndroid::Register(JNIEnv* env) {
+ return RegisterNativesImpl(env);
+}
+
+void TimeZoneMonitorAndroid::TimeZoneChangedFromJava(JNIEnv* env,
+ jobject caller) {
+ NotifyRenderers();
+}
+
+// static
+scoped_ptr<TimeZoneMonitor> TimeZoneMonitor::Create() {
+ return scoped_ptr<TimeZoneMonitor>(new TimeZoneMonitorAndroid());
+}
+
+} // namespace content
diff --git a/content/browser/time_zone_monitor_android.h b/content/browser/time_zone_monitor_android.h
new file mode 100644
index 0000000..a462eb5
--- /dev/null
+++ b/content/browser/time_zone_monitor_android.h
@@ -0,0 +1,37 @@
+// 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.
+
+#ifndef CONTENT_BROWSER_TIME_ZONE_MONITOR_ANDROID_H_
+#define CONTENT_BROWSER_TIME_ZONE_MONITOR_ANDROID_H_
+
+#include "content/browser/time_zone_monitor.h"
+
+#include <jni.h>
+
+#include "base/android/scoped_java_ref.h"
+#include "base/basictypes.h"
+
+namespace content {
+
+class TimeZoneMonitorAndroid : public TimeZoneMonitor {
+ public:
+ TimeZoneMonitorAndroid();
+ virtual ~TimeZoneMonitorAndroid();
+
+ // Must be called at startup.
+ static bool Register(JNIEnv* env);
+
+ // Called by the Java implementation when the system time zone changes.
+ void TimeZoneChangedFromJava(JNIEnv* env, jobject caller);
+
+ private:
+ // Java provider of system time zone change notifications.
+ base::android::ScopedJavaGlobalRef<jobject> impl_;
+
+ DISALLOW_COPY_AND_ASSIGN(TimeZoneMonitorAndroid);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_TIME_ZONE_MONITOR_ANDROID_H_
diff --git a/content/browser/time_zone_monitor_chromeos.cc b/content/browser/time_zone_monitor_chromeos.cc
new file mode 100644
index 0000000..6fc885e
--- /dev/null
+++ b/content/browser/time_zone_monitor_chromeos.cc
@@ -0,0 +1,37 @@
+// 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 "chromeos/settings/timezone_settings.h"
+
+namespace content {
+
+class TimeZoneMonitorChromeOS
+ : public TimeZoneMonitor,
+ public chromeos::system::TimezoneSettings::Observer {
+ public:
+ TimeZoneMonitorChromeOS() : TimeZoneMonitor() {
+ chromeos::system::TimezoneSettings::GetInstance()->AddObserver(this);
+ }
+
+ virtual ~TimeZoneMonitorChromeOS() {
+ chromeos::system::TimezoneSettings::GetInstance()->RemoveObserver(this);
+ }
+
+ // chromeos::system::TimezoneSettings::Observer implementation.
+ virtual void TimezoneChanged(const icu::TimeZone& time_zone) OVERRIDE {
+ NotifyRenderers();
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(TimeZoneMonitorChromeOS);
+};
+
+// static
+scoped_ptr<TimeZoneMonitor> TimeZoneMonitor::Create() {
+ return scoped_ptr<TimeZoneMonitor>(new TimeZoneMonitorChromeOS());
+}
+
+} // namespace content
diff --git a/content/browser/time_zone_monitor_linux.cc b/content/browser/time_zone_monitor_linux.cc
new file mode 100644
index 0000000..f8cae0e
--- /dev/null
+++ b/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
diff --git a/content/browser/time_zone_monitor_mac.mm b/content/browser/time_zone_monitor_mac.mm
new file mode 100644
index 0000000..c435aae
--- /dev/null
+++ b/content/browser/time_zone_monitor_mac.mm
@@ -0,0 +1,40 @@
+// 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"
+
+#import <Foundation/Foundation.h>
+
+namespace content {
+
+class TimeZoneMonitorMac : public TimeZoneMonitor {
+ public:
+ TimeZoneMonitorMac() : TimeZoneMonitor() {
+ NSNotificationCenter* nc = [NSNotificationCenter defaultCenter];
+ notification_observer_ =
+ [nc addObserverForName:NSSystemTimeZoneDidChangeNotification
+ object:nil
+ queue:nil
+ usingBlock:^(NSNotification* notification) {
+ NotifyRenderers();
+ }];
+ }
+
+ virtual ~TimeZoneMonitorMac() {
+ NSNotificationCenter* nc = [NSNotificationCenter defaultCenter];
+ [nc removeObserver:notification_observer_];
+ }
+
+ private:
+ id notification_observer_;
+
+ DISALLOW_COPY_AND_ASSIGN(TimeZoneMonitorMac);
+};
+
+// static
+scoped_ptr<TimeZoneMonitor> TimeZoneMonitor::Create() {
+ return scoped_ptr<TimeZoneMonitor>(new TimeZoneMonitorMac());
+}
+
+} // namespace content
diff --git a/content/browser/time_zone_monitor_win.cc b/content/browser/time_zone_monitor_win.cc
new file mode 100644
index 0000000..6d99b94
--- /dev/null
+++ b/content/browser/time_zone_monitor_win.cc
@@ -0,0 +1,46 @@
+// 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 <windows.h>
+
+#include "base/basictypes.h"
+#include "ui/gfx/win/singleton_hwnd.h"
+
+namespace content {
+
+class TimeZoneMonitorWin : public TimeZoneMonitor,
+ public gfx::SingletonHwnd::Observer {
+ public:
+ TimeZoneMonitorWin() : TimeZoneMonitor() {
+ gfx::SingletonHwnd::GetInstance()->AddObserver(this);
+ }
+
+ virtual ~TimeZoneMonitorWin() {
+ gfx::SingletonHwnd::GetInstance()->RemoveObserver(this);
+ }
+
+ // gfx::SingletonHwnd::Observer implementation.
+ virtual void OnWndProc(HWND hwnd,
+ UINT message,
+ WPARAM wparam,
+ LPARAM lparam) OVERRIDE {
+ if (message != WM_TIMECHANGE) {
+ return;
+ }
+
+ NotifyRenderers();
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(TimeZoneMonitorWin);
+};
+
+// static
+scoped_ptr<TimeZoneMonitor> TimeZoneMonitor::Create() {
+ return scoped_ptr<TimeZoneMonitor>(new TimeZoneMonitorWin());
+}
+
+} // namespace content