Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / content / browser / time_zone_monitor_linux.cc
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.
4
5 #include "content/browser/time_zone_monitor.h"
6
7 #include <stdlib.h>
8
9 #include <vector>
10
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"
18
19 #if !defined(OS_CHROMEOS)
20
21 namespace content {
22
23 namespace {
24 class TimeZoneMonitorLinuxImpl;
25 }  // namespace
26
27 class TimeZoneMonitorLinux : public TimeZoneMonitor {
28  public:
29   TimeZoneMonitorLinux();
30   virtual ~TimeZoneMonitorLinux();
31
32   void NotifyRenderersFromImpl() {
33     NotifyRenderers();
34   }
35
36  private:
37   scoped_refptr<TimeZoneMonitorLinuxImpl> impl_;
38
39   DISALLOW_COPY_AND_ASSIGN(TimeZoneMonitorLinux);
40 };
41
42 namespace {
43
44 // FilePathWatcher needs to run on the FILE thread, but TimeZoneMonitor runs
45 // on the UI thread. TimeZoneMonitorLinuxImpl is the bridge between these
46 // threads.
47 class TimeZoneMonitorLinuxImpl
48     : public base::RefCountedThreadSafe<TimeZoneMonitorLinuxImpl> {
49  public:
50   explicit TimeZoneMonitorLinuxImpl(TimeZoneMonitorLinux* owner)
51       : base::RefCountedThreadSafe<TimeZoneMonitorLinuxImpl>(),
52         file_path_watchers_(),
53         owner_(owner) {
54     DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
55     BrowserThread::PostTask(
56         BrowserThread::FILE,
57         FROM_HERE,
58         base::Bind(&TimeZoneMonitorLinuxImpl::StartWatchingOnFileThread, this));
59   }
60
61   void StopWatching() {
62     DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
63     owner_ = NULL;
64     BrowserThread::PostTask(
65         BrowserThread::FILE,
66         FROM_HERE,
67         base::Bind(&TimeZoneMonitorLinuxImpl::StopWatchingOnFileThread, this));
68   }
69
70  private:
71   friend class base::RefCountedThreadSafe<TimeZoneMonitorLinuxImpl>;
72
73   ~TimeZoneMonitorLinuxImpl() {
74     DCHECK(!owner_);
75     STLDeleteElements(&file_path_watchers_);
76   }
77
78   void StartWatchingOnFileThread() {
79     DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
80
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
87     // reasonable.
88     const char* kFilesToWatch[] = {
89       "/etc/localtime",
90       "/etc/timezone",
91       "/etc/TZ",
92     };
93
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]),
98           false,
99           base::Bind(&TimeZoneMonitorLinuxImpl::OnTimeZoneFileChanged, this));
100     }
101   }
102
103   void StopWatchingOnFileThread() {
104     DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
105     STLDeleteElements(&file_path_watchers_);
106   }
107
108   void OnTimeZoneFileChanged(const base::FilePath& path, bool error) {
109     DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
110     BrowserThread::PostTask(
111         BrowserThread::UI,
112         FROM_HERE,
113         base::Bind(&TimeZoneMonitorLinuxImpl::OnTimeZoneFileChangedOnUIThread,
114                    this));
115   }
116
117   void OnTimeZoneFileChangedOnUIThread() {
118     DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
119     if (owner_) {
120       owner_->NotifyRenderersFromImpl();
121     }
122   }
123
124   std::vector<base::FilePathWatcher*> file_path_watchers_;
125   TimeZoneMonitorLinux* owner_;
126
127   DISALLOW_COPY_AND_ASSIGN(TimeZoneMonitorLinuxImpl);
128 };
129
130 }  // namespace
131
132 TimeZoneMonitorLinux::TimeZoneMonitorLinux()
133     : TimeZoneMonitor(),
134       impl_() {
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.
140   //
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
147   // changed.
148   if (!getenv("TZ")) {
149     impl_ = new TimeZoneMonitorLinuxImpl(this);
150   }
151 }
152
153 TimeZoneMonitorLinux::~TimeZoneMonitorLinux() {
154   if (impl_) {
155     impl_->StopWatching();
156   }
157 }
158
159 // static
160 scoped_ptr<TimeZoneMonitor> TimeZoneMonitor::Create() {
161   return scoped_ptr<TimeZoneMonitor>(new TimeZoneMonitorLinux());
162 }
163
164 }  // namespace content
165
166 #endif  // !OS_CHROMEOS