OLD | NEW |
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/chromeos/system_access.h" | 5 #include "chrome/browser/chromeos/system_access.h" |
6 | 6 |
7 #include "base/basictypes.h" | |
8 #include "base/command_line.h" | |
9 #include "base/file_path.h" | 7 #include "base/file_path.h" |
10 #include "base/file_util.h" | 8 #include "base/file_util.h" |
11 #include "base/logging.h" | 9 #include "base/logging.h" |
12 #include "base/process_util.h" | 10 #include "base/observer_list.h" |
13 #include "base/string_tokenizer.h" | 11 #include "base/memory/scoped_ptr.h" |
14 #include "base/string_util.h" | 12 #include "base/memory/singleton.h" |
15 #include "base/threading/thread_restrictions.h" | |
16 #include "base/utf_string_conversions.h" | 13 #include "base/utf_string_conversions.h" |
| 14 #include "chrome/browser/chromeos/name_value_pairs_parser.h" |
17 | 15 |
18 namespace chromeos { // NOLINT | 16 namespace chromeos { // NOLINT |
19 | 17 |
20 namespace { // NOLINT | 18 namespace { // NOLINT |
21 | 19 |
22 // The filepath to the timezone file that symlinks to the actual timezone file. | 20 // The filepath to the timezone file that symlinks to the actual timezone file. |
23 static const char kTimezoneSymlink[] = "/var/lib/timezone/localtime"; | 21 const char kTimezoneSymlink[] = "/var/lib/timezone/localtime"; |
24 static const char kTimezoneSymlink2[] = "/var/lib/timezone/localtime2"; | 22 const char kTimezoneSymlink2[] = "/var/lib/timezone/localtime2"; |
25 | 23 |
26 // The directory that contains all the timezone files. So for timezone | 24 // The directory that contains all the timezone files. So for timezone |
27 // "US/Pacific", the actual timezone file is: "/usr/share/zoneinfo/US/Pacific" | 25 // "US/Pacific", the actual timezone file is: "/usr/share/zoneinfo/US/Pacific" |
28 static const char kTimezoneFilesDir[] = "/usr/share/zoneinfo/"; | 26 const char kTimezoneFilesDir[] = "/usr/share/zoneinfo/"; |
29 | 27 |
30 // The system command that returns the hardware class. | 28 // The system command that returns the hardware class. |
31 static const char kHardwareClassKey[] = "hardware_class"; | 29 const char kHardwareClassKey[] = "hardware_class"; |
32 static const char* kHardwareClassTool[] = { "/usr/bin/hardware_class" }; | 30 const char* kHardwareClassTool[] = { "/usr/bin/hardware_class" }; |
33 static const char kUnknownHardwareClass[] = "unknown"; | 31 const char kUnknownHardwareClass[] = "unknown"; |
34 | 32 |
35 // Command to get machine hardware info and key/value delimiters. | 33 // Command to get machine hardware info and key/value delimiters. |
36 // /tmp/machine-info is generated by platform/init/chromeos_startup. | 34 // /tmp/machine-info is generated by platform/init/chromeos_startup. |
37 static const char* kMachineHardwareInfoTool[] = { "cat", "/tmp/machine-info" }; | 35 const char* kMachineHardwareInfoTool[] = { "cat", "/tmp/machine-info" }; |
38 static const char kMachineHardwareInfoEq[] = "="; | 36 const char kMachineHardwareInfoEq[] = "="; |
39 static const char kMachineHardwareInfoDelim[] = " \n"; | 37 const char kMachineHardwareInfoDelim[] = " \n"; |
40 | 38 |
41 // Command to get machine OS info and key/value delimiters. | 39 // Command to get machine OS info and key/value delimiters. |
42 static const char* kMachineOSInfoTool[] = { "cat", "/etc/lsb-release" }; | 40 const char* kMachineOSInfoTool[] = { "cat", "/etc/lsb-release" }; |
43 static const char kMachineOSInfoEq[] = "="; | 41 const char kMachineOSInfoEq[] = "="; |
44 static const char kMachineOSInfoDelim[] = "\n"; | 42 const char kMachineOSInfoDelim[] = "\n"; |
| 43 |
| 44 // Command to get HWID and key. |
| 45 const char kHwidKey[] = "hwid"; |
| 46 const char* kHwidTool[] = { "cat", "/sys/devices/platform/chromeos_acpi/HWID" }; |
| 47 |
| 48 // Command to get VPD info and key/value delimiters. |
| 49 const char* kVpdTool[] = { "cat", "/var/log/vpd_2.0.txt" }; |
| 50 const char kVpdEq[] = "="; |
| 51 const char kVpdDelim[] = "\n"; |
45 | 52 |
46 // Fallback time zone ID used in case of an unexpected error. | 53 // Fallback time zone ID used in case of an unexpected error. |
47 static const char kFallbackTimeZoneId[] = "America/Los_Angeles"; | 54 const char kFallbackTimeZoneId[] = "America/Los_Angeles"; |
| 55 |
| 56 class SystemAccessImpl : public SystemAccess { |
| 57 public: |
| 58 // SystemAccess.implementation: |
| 59 virtual const icu::TimeZone& GetTimezone(); |
| 60 virtual void SetTimezone(const icu::TimeZone& timezone); |
| 61 virtual bool GetMachineStatistic(const std::string& name, |
| 62 std::string* result); |
| 63 virtual void AddObserver(Observer* observer); |
| 64 virtual void RemoveObserver(Observer* observer); |
| 65 |
| 66 static SystemAccessImpl* GetInstance(); |
| 67 |
| 68 private: |
| 69 friend struct DefaultSingletonTraits<SystemAccessImpl>; |
| 70 |
| 71 SystemAccessImpl(); |
| 72 |
| 73 // Updates the machine statistcs by examining the system. |
| 74 void UpdateMachineStatistics(); |
| 75 |
| 76 scoped_ptr<icu::TimeZone> timezone_; |
| 77 ObserverList<Observer> observers_; |
| 78 NameValuePairsParser::NameValueMap machine_info_; |
| 79 |
| 80 DISALLOW_COPY_AND_ASSIGN(SystemAccessImpl); |
| 81 }; |
48 | 82 |
49 std::string GetTimezoneIDAsString() { | 83 std::string GetTimezoneIDAsString() { |
50 // Look at kTimezoneSymlink, see which timezone we are symlinked to. | 84 // Look at kTimezoneSymlink, see which timezone we are symlinked to. |
51 char buf[256]; | 85 char buf[256]; |
52 const ssize_t len = readlink(kTimezoneSymlink, buf, | 86 const ssize_t len = readlink(kTimezoneSymlink, buf, |
53 sizeof(buf)-1); | 87 sizeof(buf)-1); |
54 if (len == -1) { | 88 if (len == -1) { |
55 LOG(ERROR) << "GetTimezoneID: Cannot read timezone symlink " | 89 LOG(ERROR) << "GetTimezoneID: Cannot read timezone symlink " |
56 << kTimezoneSymlink; | 90 << kTimezoneSymlink; |
57 return std::string(); | 91 return std::string(); |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
96 } | 130 } |
97 | 131 |
98 // Move symlink2 to symlink. | 132 // Move symlink2 to symlink. |
99 if (!file_util::ReplaceFile(timezone_symlink2, timezone_symlink)) { | 133 if (!file_util::ReplaceFile(timezone_symlink2, timezone_symlink)) { |
100 LOG(ERROR) << "SetTimezoneID: Unable to move symlink " | 134 LOG(ERROR) << "SetTimezoneID: Unable to move symlink " |
101 << timezone_symlink2.value() << " to " | 135 << timezone_symlink2.value() << " to " |
102 << timezone_symlink.value(); | 136 << timezone_symlink.value(); |
103 } | 137 } |
104 } | 138 } |
105 | 139 |
106 } // namespace | 140 const icu::TimeZone& SystemAccessImpl::GetTimezone() { |
107 | |
108 SystemAccess* SystemAccess::GetInstance() { | |
109 return Singleton<SystemAccess, DefaultSingletonTraits<SystemAccess> >::get(); | |
110 } | |
111 | |
112 const icu::TimeZone& SystemAccess::GetTimezone() { | |
113 return *timezone_.get(); | 141 return *timezone_.get(); |
114 } | 142 } |
115 | 143 |
116 void SystemAccess::SetTimezone(const icu::TimeZone& timezone) { | 144 void SystemAccessImpl::SetTimezone(const icu::TimeZone& timezone) { |
117 timezone_.reset(timezone.clone()); | 145 timezone_.reset(timezone.clone()); |
118 icu::UnicodeString unicode; | 146 icu::UnicodeString unicode; |
119 timezone.getID(unicode); | 147 timezone.getID(unicode); |
120 std::string id; | 148 std::string id; |
121 UTF16ToUTF8(unicode.getBuffer(), unicode.length(), &id); | 149 UTF16ToUTF8(unicode.getBuffer(), unicode.length(), &id); |
122 VLOG(1) << "Setting timezone to " << id; | 150 VLOG(1) << "Setting timezone to " << id; |
123 chromeos::SetTimezoneIDFromString(id); | 151 chromeos::SetTimezoneIDFromString(id); |
124 icu::TimeZone::setDefault(timezone); | 152 icu::TimeZone::setDefault(timezone); |
125 FOR_EACH_OBSERVER(Observer, observers_, TimezoneChanged(timezone)); | 153 FOR_EACH_OBSERVER(Observer, observers_, TimezoneChanged(timezone)); |
126 } | 154 } |
127 | 155 |
128 bool SystemAccess::GetMachineStatistic( | 156 bool SystemAccessImpl::GetMachineStatistic( |
129 const std::string& name, std::string* result) { | 157 const std::string& name, std::string* result) { |
130 MachineInfo::iterator iter = machine_info_.find(name); | 158 NameValuePairsParser::NameValueMap::iterator iter = machine_info_.find(name); |
131 if (iter != machine_info_.end()) { | 159 if (iter != machine_info_.end()) { |
132 *result = iter->second; | 160 *result = iter->second; |
133 return true; | 161 return true; |
134 } | 162 } |
135 return false; | 163 return false; |
136 } | 164 } |
137 | 165 |
138 void SystemAccess::AddObserver(Observer* observer) { | 166 void SystemAccessImpl::AddObserver(Observer* observer) { |
139 observers_.AddObserver(observer); | 167 observers_.AddObserver(observer); |
140 } | 168 } |
141 | 169 |
142 void SystemAccess::RemoveObserver(Observer* observer) { | 170 void SystemAccessImpl::RemoveObserver(Observer* observer) { |
143 observers_.RemoveObserver(observer); | 171 observers_.RemoveObserver(observer); |
144 } | 172 } |
145 | 173 |
146 SystemAccess::SystemAccess() { | 174 SystemAccessImpl::SystemAccessImpl() { |
147 // Get Statistics | 175 // Get Statistics |
148 UpdateMachineStatistics(); | 176 UpdateMachineStatistics(); |
149 // Get Timezone | 177 // Get Timezone |
150 std::string id = GetTimezoneIDAsString(); | 178 std::string id = GetTimezoneIDAsString(); |
151 if (id.empty()) { | 179 if (id.empty()) { |
152 id = kFallbackTimeZoneId; | 180 id = kFallbackTimeZoneId; |
153 LOG(ERROR) << "Got an empty string for timezone, default to " << id; | 181 LOG(ERROR) << "Got an empty string for timezone, default to " << id; |
154 } | 182 } |
155 icu::TimeZone* timezone = | 183 icu::TimeZone* timezone = |
156 icu::TimeZone::createTimeZone(icu::UnicodeString::fromUTF8(id)); | 184 icu::TimeZone::createTimeZone(icu::UnicodeString::fromUTF8(id)); |
157 timezone_.reset(timezone); | 185 timezone_.reset(timezone); |
158 icu::TimeZone::setDefault(*timezone); | 186 icu::TimeZone::setDefault(*timezone); |
159 VLOG(1) << "Timezone is " << id; | 187 VLOG(1) << "Timezone is " << id; |
160 } | 188 } |
161 | 189 |
162 void SystemAccess::UpdateMachineStatistics() { | 190 void SystemAccessImpl::UpdateMachineStatistics() { |
163 NameValuePairsParser parser(&machine_info_); | 191 NameValuePairsParser parser(&machine_info_); |
164 if (!parser.GetSingleValueFromTool(arraysize(kHardwareClassTool), | 192 if (!parser.GetSingleValueFromTool(arraysize(kHardwareClassTool), |
165 kHardwareClassTool, | 193 kHardwareClassTool, |
166 kHardwareClassKey)) { | 194 kHardwareClassKey)) { |
167 // Use kUnknownHardwareClass if the hardware class command fails. | 195 // Use kUnknownHardwareClass if the hardware class command fails. |
168 parser.AddNameValuePair(kHardwareClassKey, kUnknownHardwareClass); | 196 parser.AddNameValuePair(kHardwareClassKey, kUnknownHardwareClass); |
169 } | 197 } |
170 parser.ParseNameValuePairsFromTool(arraysize(kMachineHardwareInfoTool), | 198 parser.ParseNameValuePairsFromTool(arraysize(kMachineHardwareInfoTool), |
171 kMachineHardwareInfoTool, | 199 kMachineHardwareInfoTool, |
172 kMachineHardwareInfoEq, | 200 kMachineHardwareInfoEq, |
173 kMachineHardwareInfoDelim); | 201 kMachineHardwareInfoDelim); |
174 parser.ParseNameValuePairsFromTool(arraysize(kMachineOSInfoTool), | 202 parser.ParseNameValuePairsFromTool(arraysize(kMachineOSInfoTool), |
175 kMachineOSInfoTool, | 203 kMachineOSInfoTool, |
176 kMachineOSInfoEq, | 204 kMachineOSInfoEq, |
177 kMachineOSInfoDelim); | 205 kMachineOSInfoDelim); |
| 206 parser.GetSingleValueFromTool(arraysize(kHwidTool), kHwidTool, kHwidKey); |
| 207 parser.ParseNameValuePairsFromTool( |
| 208 arraysize(kVpdTool), kVpdTool, kVpdEq, kVpdDelim); |
178 } | 209 } |
179 | 210 |
180 NameValuePairsParser::NameValuePairsParser(MachineInfo* machine_info) | 211 SystemAccessImpl* SystemAccessImpl::GetInstance() { |
181 : machine_info_(machine_info) { | 212 return Singleton<SystemAccessImpl, |
| 213 DefaultSingletonTraits<SystemAccessImpl> >::get(); |
182 } | 214 } |
183 | 215 |
184 void NameValuePairsParser::AddNameValuePair(const std::string& key, | 216 } // namespace |
185 const std::string& value) { | |
186 (*machine_info_)[key] = value; | |
187 VLOG(1) << "name: " << key << ", value: " << value; | |
188 } | |
189 | 217 |
190 bool NameValuePairsParser::ParseNameValuePairs(const std::string& in_string, | 218 SystemAccess* SystemAccess::GetInstance() { |
191 const std::string& eq, | 219 return SystemAccessImpl::GetInstance(); |
192 const std::string& delim) { | |
193 // Set up the pair tokenizer. | |
194 StringTokenizer pair_toks(in_string, delim); | |
195 pair_toks.set_quote_chars("\""); | |
196 // Process token pairs. | |
197 while (pair_toks.GetNext()) { | |
198 std::string pair(pair_toks.token()); | |
199 if (pair.find(eq) == 0) { | |
200 LOG(WARNING) << "Empty key: '" << pair << "'. Aborting."; | |
201 return false; | |
202 } | |
203 StringTokenizer keyvalue(pair, eq); | |
204 std::string key,value; | |
205 if (keyvalue.GetNext()) { | |
206 key = keyvalue.token(); | |
207 if (keyvalue.GetNext()) { | |
208 value = keyvalue.token(); | |
209 if (keyvalue.GetNext()) { | |
210 LOG(WARNING) << "Multiple key tokens: '" << pair << "'. Aborting."; | |
211 return false; | |
212 } | |
213 } | |
214 } | |
215 if (key.empty()) { | |
216 LOG(WARNING) << "Invalid token pair: '" << pair << "'. Aborting."; | |
217 return false; | |
218 } | |
219 AddNameValuePair(key, value); | |
220 } | |
221 return true; | |
222 } | |
223 | |
224 bool NameValuePairsParser::GetSingleValueFromTool(int argc, | |
225 const char* argv[], | |
226 const std::string& key) { | |
227 CommandLine command_line(argc, argv); | |
228 std::string output_string; | |
229 // TODO(stevenjb,satorux): Make this non blocking: crosbug.com/5603. | |
230 base::ThreadRestrictions::ScopedAllowIO allow_io_for_thread_join; | |
231 if (argc < 1 || !base::GetAppOutput(command_line, &output_string)) { | |
232 LOG(WARNING) << "Error excuting: " << command_line.command_line_string(); | |
233 return false; | |
234 } | |
235 TrimWhitespaceASCII(output_string, TRIM_ALL, &output_string); | |
236 AddNameValuePair(key, output_string); | |
237 return true; | |
238 } | |
239 | |
240 bool NameValuePairsParser::ParseNameValuePairsFromTool( | |
241 int argc, | |
242 const char* argv[], | |
243 const std::string& eq, | |
244 const std::string& delim) { | |
245 CommandLine command_line(argc, argv); | |
246 std::string output_string; | |
247 // TODO(stevenjb,satorux): Make this non blocking: crosbug.com/5603. | |
248 base::ThreadRestrictions::ScopedAllowIO allow_io_for_thread_join; | |
249 if (argc < 1 || !base::GetAppOutput(command_line, &output_string)) { | |
250 LOG(WARNING) << "Error excuting: " << command_line.command_line_string(); | |
251 return false; | |
252 } | |
253 if (!ParseNameValuePairs(output_string, eq, delim)) { | |
254 LOG(WARNING) << "Error parsing values while excuting: " | |
255 << command_line.command_line_string(); | |
256 return false; | |
257 } | |
258 return true; | |
259 } | 220 } |
260 | 221 |
261 } // namespace chromeos | 222 } // namespace chromeos |
OLD | NEW |