1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "content/browser/time_zone_monitor.h"
11 #include "base/basictypes.h"
12 #include "base/bind.h"
13 #include "base/files/file_path.h"
14 #include "base/files/file_path_watcher.h"
15 #include "base/memory/ref_counted.h"
16 #include "base/stl_util.h"
17 #include "content/public/browser/browser_thread.h"
19 #if !defined(OS_CHROMEOS)
24 class TimeZoneMonitorLinuxImpl
;
27 class TimeZoneMonitorLinux
: public TimeZoneMonitor
{
29 TimeZoneMonitorLinux();
30 ~TimeZoneMonitorLinux() override
;
32 void NotifyRenderersFromImpl() {
37 scoped_refptr
<TimeZoneMonitorLinuxImpl
> impl_
;
39 DISALLOW_COPY_AND_ASSIGN(TimeZoneMonitorLinux
);
44 // FilePathWatcher needs to run on the FILE thread, but TimeZoneMonitor runs
45 // on the UI thread. TimeZoneMonitorLinuxImpl is the bridge between these
47 class TimeZoneMonitorLinuxImpl
48 : public base::RefCountedThreadSafe
<TimeZoneMonitorLinuxImpl
> {
50 explicit TimeZoneMonitorLinuxImpl(TimeZoneMonitorLinux
* owner
)
51 : base::RefCountedThreadSafe
<TimeZoneMonitorLinuxImpl
>(),
52 file_path_watchers_(),
54 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
55 BrowserThread::PostTask(
58 base::Bind(&TimeZoneMonitorLinuxImpl::StartWatchingOnFileThread
, this));
62 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
64 BrowserThread::PostTask(
67 base::Bind(&TimeZoneMonitorLinuxImpl::StopWatchingOnFileThread
, this));
71 friend class base::RefCountedThreadSafe
<TimeZoneMonitorLinuxImpl
>;
73 ~TimeZoneMonitorLinuxImpl() {
75 STLDeleteElements(&file_path_watchers_
);
78 void StartWatchingOnFileThread() {
79 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
81 // There is no true standard for where time zone information is actually
82 // stored. glibc uses /etc/localtime, uClibc uses /etc/TZ, and some older
83 // systems store the name of the time zone file within /usr/share/zoneinfo
84 // in /etc/timezone. Different libraries and custom builds may mean that
85 // still more paths are used. Just watch all three of these paths, because
86 // false positives are harmless, assuming the false positive rate is
88 const char* kFilesToWatch
[] = {
94 for (size_t index
= 0; index
< arraysize(kFilesToWatch
); ++index
) {
95 file_path_watchers_
.push_back(new base::FilePathWatcher());
96 file_path_watchers_
.back()->Watch(
97 base::FilePath(kFilesToWatch
[index
]),
99 base::Bind(&TimeZoneMonitorLinuxImpl::OnTimeZoneFileChanged
, this));
103 void StopWatchingOnFileThread() {
104 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
105 STLDeleteElements(&file_path_watchers_
);
108 void OnTimeZoneFileChanged(const base::FilePath
& path
, bool error
) {
109 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
110 BrowserThread::PostTask(
113 base::Bind(&TimeZoneMonitorLinuxImpl::OnTimeZoneFileChangedOnUIThread
,
117 void OnTimeZoneFileChangedOnUIThread() {
118 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
120 owner_
->NotifyRenderersFromImpl();
124 std::vector
<base::FilePathWatcher
*> file_path_watchers_
;
125 TimeZoneMonitorLinux
* owner_
;
127 DISALLOW_COPY_AND_ASSIGN(TimeZoneMonitorLinuxImpl
);
132 TimeZoneMonitorLinux::TimeZoneMonitorLinux()
135 // If the TZ environment variable is set, its value specifies the time zone
136 // specification, and it's pointless to monitor any files in /etc for
137 // changes because such changes would have no effect on the TZ environment
138 // variable and thus the interpretation of the local time zone in the
139 // or renderer processes.
141 // The system-specific format for the TZ environment variable beginning with
142 // a colon is implemented by glibc as the path to a time zone data file, and
143 // it would be possible to monitor this file for changes if a TZ variable of
144 // this format was encountered, but this is not necessary: when loading a
145 // time zone specification in this way, glibc does not reload the file when
146 // it changes, so it's pointless to respond to a notification that it has
149 impl_
= new TimeZoneMonitorLinuxImpl(this);
153 TimeZoneMonitorLinux::~TimeZoneMonitorLinux() {
155 impl_
->StopWatching();
160 scoped_ptr
<TimeZoneMonitor
> TimeZoneMonitor::Create() {
161 return scoped_ptr
<TimeZoneMonitor
>(new TimeZoneMonitorLinux());
164 } // namespace content
166 #endif // !OS_CHROMEOS