OLD | NEW |
---|---|
(Empty) | |
1 // Copyright (c) 2012 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 "chromeos/system/statistics_provider.h" | |
6 | |
7 #include "base/bind.h" | |
8 #include "base/command_line.h" | |
9 #include "base/files/file_path.h" | |
10 #include "base/location.h" | |
11 #include "base/logging.h" | |
12 #include "base/path_service.h" | |
13 #include "base/synchronization/lock.h" | |
14 #include "base/synchronization/waitable_event.h" | |
15 #include "base/sys_info.h" | |
16 #include "base/task_runner.h" | |
17 #include "base/task_runner_util.h" | |
18 #include "base/threading/thread_restrictions.h" | |
19 #include "base/time/time.h" | |
20 #include "chromeos/app_mode/kiosk_oem_manifest_parser.h" | |
21 #include "chromeos/chromeos_constants.h" | |
22 #include "chromeos/chromeos_switches.h" | |
23 #include "chromeos/system/name_value_pairs_parser.h" | |
24 | |
25 namespace chromeos { | |
26 namespace system { | |
27 | |
28 namespace { | |
29 | |
30 // Path to the tool used to get system info, and delimiters for the output | |
31 // format of the tool. | |
32 const char* kCrosSystemTool[] = { "/usr/bin/crossystem" }; | |
33 const char kCrosSystemEq[] = "="; | |
34 const char kCrosSystemDelim[] = "\n"; | |
35 const char kCrosSystemCommentDelim[] = "#"; | |
36 const char kCrosSystemUnknownValue[] = "(error)"; | |
37 | |
38 const char kHardwareClassCrosSystemKey[] = "hwid"; | |
39 const char kUnknownHardwareClass[] = "unknown"; | |
40 | |
41 // File to get machine hardware info from, and key/value delimiters of | |
42 // the file. | |
43 // /tmp/machine-info is generated by platform/init/chromeos_startup. | |
44 const char kMachineHardwareInfoFile[] = "/tmp/machine-info"; | |
45 const char kMachineHardwareInfoEq[] = "="; | |
46 const char kMachineHardwareInfoDelim[] = " \n"; | |
47 | |
48 // File to get ECHO coupon info from, and key/value delimiters of | |
49 // the file. | |
50 const char kEchoCouponFile[] = "/var/cache/echo/vpd_echo.txt"; | |
51 const char kEchoCouponEq[] = "="; | |
52 const char kEchoCouponDelim[] = "\n"; | |
53 | |
54 // File to get VPD info from, and key/value delimiters of the file. | |
55 const char kVpdFile[] = "/var/log/vpd_2.0.txt"; | |
56 const char kVpdEq[] = "="; | |
57 const char kVpdDelim[] = "\n"; | |
58 | |
59 // Timeout that we should wait for statistics to get loaded | |
60 const int kTimeoutSecs = 3; | |
61 | |
62 // The location of OEM manifest file used to trigger OOBE flow for kiosk mode. | |
63 const CommandLine::CharType kOemManifestFilePath[] = | |
64 FILE_PATH_LITERAL("/usr/share/oem/oobe/manifest.json"); | |
65 | |
66 void LoadMachineStatistics(NameValuePairsParser::NameValueMap* name_value_map) { | |
67 // Parse all of the key/value pairs from the crossystem tool. | |
68 NameValuePairsParser parser(name_value_map); | |
69 if (!parser.ParseNameValuePairsFromTool(arraysize(kCrosSystemTool), | |
70 kCrosSystemTool, | |
71 kCrosSystemEq, | |
72 kCrosSystemDelim, | |
73 kCrosSystemCommentDelim)) { | |
74 LOG(WARNING) << "There were errors parsing the output of " | |
75 << kCrosSystemTool << "."; | |
76 } | |
77 parser.GetNameValuePairsFromFile(base::FilePath(kMachineHardwareInfoFile), | |
78 kMachineHardwareInfoEq, | |
79 kMachineHardwareInfoDelim); | |
80 parser.GetNameValuePairsFromFile( | |
81 base::FilePath(kEchoCouponFile), kEchoCouponEq, kEchoCouponDelim); | |
82 parser.GetNameValuePairsFromFile(base::FilePath(kVpdFile), kVpdEq, kVpdDelim); | |
83 } | |
84 | |
85 } // namespace | |
86 | |
87 // Key values for GetMachineStatistic()/GetMachineFlag() calls. | |
88 const char kDevSwitchBootMode[] = "devsw_boot"; | |
89 const char kHardwareClassKey[] = "hardware_class"; | |
90 const char kOffersCouponCodeKey[] = "ubind_attribute"; | |
91 const char kOffersGroupCodeKey[] = "gbind_attribute"; | |
92 const char kOemCanExitEnterpriseEnrollmentKey[] = "oem_can_exit_enrollment"; | |
93 const char kOemDeviceRequisitionKey[] = "oem_device_requisition"; | |
94 const char kOemIsEnterpriseManagedKey[] = "oem_enterprise_managed"; | |
95 const char kOemKeyboardDrivenOobeKey[] = "oem_keyboard_driven_oobe"; | |
96 | |
97 // The StatisticsProvider implementation used in production. | |
98 class StatisticsProviderImpl : public StatisticsProvider { | |
99 public: | |
100 explicit StatisticsProviderImpl( | |
101 const scoped_refptr<base::TaskRunner>& io_task_runner); | |
102 virtual ~StatisticsProviderImpl(); | |
103 | |
104 // StatisticsProvider implementation: | |
105 virtual void StartLoadingMachineStatistics(bool load_oem_manifest) OVERRIDE; | |
106 virtual bool GetMachineStatistic(const std::string& name, | |
107 std::string* result) OVERRIDE; | |
108 virtual bool GetMachineFlag(const std::string& name, bool* result) OVERRIDE; | |
109 | |
110 // Completes loading of machine statistcs from system files. | |
111 void MachineStatisticsLoaded( | |
112 NameValuePairsParser::NameValueMap* name_value_map, | |
113 bool load_oem_manifest); | |
114 | |
115 // Completes loading the OEM manifest statistcs. | |
116 void OemManifestLoaded(KioskOemManifestParser::Manifest* oem_manifest, | |
117 bool success); | |
118 | |
119 protected: | |
120 typedef std::map<std::string, bool> MachineFlags; | |
121 | |
122 bool load_statistics_started_; | |
123 base::Lock lock_; | |
124 scoped_refptr<base::TaskRunner> io_task_runner_; | |
125 NameValuePairsParser::NameValueMap machine_info_; | |
126 MachineFlags machine_flags_; | |
satorux1
2013/10/02 01:36:55
; // guarded by lock_
stevenjb
2013/10/03 01:17:23
I removed lock_ and made it so that both machine_f
| |
127 base::WaitableEvent on_statistics_loaded_; | |
128 base::WeakPtrFactory<StatisticsProviderImpl> weak_ptr_factory_; | |
129 | |
130 private: | |
131 DISALLOW_COPY_AND_ASSIGN(StatisticsProviderImpl); | |
132 }; | |
133 | |
134 StatisticsProviderImpl::StatisticsProviderImpl( | |
135 const scoped_refptr<base::TaskRunner>& io_task_runner) | |
136 : load_statistics_started_(false), | |
137 io_task_runner_(io_task_runner), | |
138 on_statistics_loaded_(true /* manual_reset */, | |
139 false /* initially_signaled */), | |
140 weak_ptr_factory_(this) { | |
141 } | |
142 | |
143 StatisticsProviderImpl::~StatisticsProviderImpl() { | |
144 } | |
145 | |
146 void StatisticsProviderImpl::StartLoadingMachineStatistics( | |
147 bool load_oem_manifest) { | |
148 CHECK(!load_statistics_started_); | |
149 load_statistics_started_ = true; | |
150 | |
151 VLOG(1) << "Started loading statistics. Load OEM Manifest: " | |
152 << load_oem_manifest; | |
153 | |
154 NameValuePairsParser::NameValueMap* name_value_map = | |
155 new NameValuePairsParser::NameValueMap; | |
156 io_task_runner_->PostTaskAndReply( | |
157 FROM_HERE, | |
158 base::Bind(&LoadMachineStatistics, name_value_map), | |
159 base::Bind(&StatisticsProviderImpl::MachineStatisticsLoaded, | |
160 weak_ptr_factory_.GetWeakPtr(), | |
161 base::Owned(name_value_map), | |
162 load_oem_manifest)); | |
163 } | |
164 | |
165 bool StatisticsProviderImpl::GetMachineStatistic( | |
166 const std::string& name, std::string* result) { | |
167 // TODO(stevenjb): Thes should be made fatal once fixed. crbug.com/302798. | |
168 if (!load_statistics_started_) { | |
169 LOG(ERROR) << "GetMachineStatistic called before load started: " << name; | |
170 return false; | |
171 } | |
172 | |
173 VLOG(1) << "Statistic is requested for " << name; | |
174 // Block if the statistics are not loaded yet. Normally this shouldn't | |
175 // happen excpet during OOBE. | |
176 if (!on_statistics_loaded_.IsSignaled()) { | |
177 base::Time start_time = base::Time::Now(); | |
178 base::ThreadRestrictions::ScopedAllowWait allow_wait; | |
179 on_statistics_loaded_.TimedWait(base::TimeDelta::FromSeconds(kTimeoutSecs)); | |
180 base::TimeDelta dtime = base::Time::Now() - start_time; | |
181 if (!on_statistics_loaded_.IsSignaled()) { | |
182 LOG(ERROR) << "Statistics weren't loaded after waiting " | |
183 << dtime.InMilliseconds() << "ms. " | |
184 << "Requested statistic: " << name; | |
185 return false; | |
186 } else { | |
187 LOG(ERROR) << "Statistic loaded after waiting " | |
188 << dtime.InMilliseconds() << "ms. " | |
189 << "Requested statistic: " << name; | |
190 } | |
191 } | |
192 | |
193 NameValuePairsParser::NameValueMap::iterator iter = machine_info_.find(name); | |
satorux1
2013/10/02 01:36:55
shouldn't we guard machine_info_ with lock_?
stevenjb
2013/10/03 01:17:23
Done.
| |
194 if (iter == machine_info_.end()) { | |
195 if (base::SysInfo::IsRunningOnChromeOS()) | |
196 LOG(ERROR) << "Requested statistic not found: " << name; | |
197 return false; | |
198 } | |
199 | |
200 *result = iter->second; | |
201 return true; | |
202 } | |
203 | |
204 bool StatisticsProviderImpl::GetMachineFlag(const std::string& name, | |
205 bool* result) { | |
206 base::AutoLock lock(lock_); | |
207 MachineFlags::const_iterator iter = machine_flags_.find(name); | |
208 if (iter == machine_flags_.end()) { | |
209 if (base::SysInfo::IsRunningOnChromeOS()) | |
210 LOG(ERROR) << "Requested machine flag not found: " << name; | |
211 return false; | |
212 } | |
213 *result = iter->second; | |
214 return true; | |
215 } | |
216 | |
217 void StatisticsProviderImpl::MachineStatisticsLoaded( | |
218 NameValuePairsParser::NameValueMap* name_value_map, | |
219 bool load_oem_manifest) { | |
220 base::AutoLock lock(lock_); | |
221 | |
222 machine_info_.swap(*name_value_map); | |
223 // Ensure that the hardware class key is present with the expected | |
224 // key name, and if it couldn't be retrieved, that the value is "unknown". | |
225 std::string hardware_class = machine_info_[kHardwareClassCrosSystemKey]; | |
226 if (hardware_class.empty() || hardware_class == kCrosSystemUnknownValue) | |
227 machine_info_[kHardwareClassKey] = kUnknownHardwareClass; | |
228 else | |
229 machine_info_[kHardwareClassKey] = hardware_class; | |
230 | |
231 if (load_oem_manifest) { | |
232 VLOG(1) << "Started loading OEM Manifest"; | |
233 KioskOemManifestParser::Manifest* oem_manifest = | |
234 new KioskOemManifestParser::Manifest; | |
235 base::PostTaskAndReplyWithResult( | |
236 io_task_runner_.get(), | |
237 FROM_HERE, | |
238 base::Bind(&KioskOemManifestParser::Load, | |
239 base::FilePath(kOemManifestFilePath), | |
240 oem_manifest), | |
241 base::Bind(&StatisticsProviderImpl::OemManifestLoaded, | |
242 weak_ptr_factory_.GetWeakPtr(), | |
243 base::Owned(oem_manifest))); | |
244 return; | |
245 } | |
246 // Finished loading the statistics. | |
247 on_statistics_loaded_.Signal(); | |
248 VLOG(1) << "Finished loading statistics"; | |
249 } | |
250 | |
251 void StatisticsProviderImpl::OemManifestLoaded( | |
252 KioskOemManifestParser::Manifest* oem_manifest, | |
253 bool success) { | |
254 if (success) { | |
255 machine_info_[kOemDeviceRequisitionKey] = oem_manifest->device_requisition; | |
256 machine_flags_[kOemIsEnterpriseManagedKey] = | |
257 oem_manifest->enterprise_managed; | |
258 machine_flags_[kOemCanExitEnterpriseEnrollmentKey] = | |
259 oem_manifest->can_exit_enrollment; | |
260 machine_flags_[kOemKeyboardDrivenOobeKey] = | |
261 oem_manifest->keyboard_driven_oobe; | |
262 } | |
263 // Finished loading the statistics. | |
264 on_statistics_loaded_.Signal(); | |
265 VLOG(1) << "Finished loading statistics and OEM Manifest"; | |
266 } | |
267 | |
268 // The stub StatisticsProvider implementation used on Linux desktop. | |
269 class StatisticsProviderStubImpl : public StatisticsProviderImpl { | |
270 public: | |
271 explicit StatisticsProviderStubImpl( | |
272 const scoped_refptr<base::TaskRunner>& io_task_runner) | |
273 : StatisticsProviderImpl(io_task_runner) {} | |
274 virtual ~StatisticsProviderStubImpl() {} | |
275 | |
276 // StatisticsProvider implementation: | |
277 virtual void StartLoadingMachineStatistics(bool load_oem_manifest) OVERRIDE { | |
278 load_statistics_started_ = true; | |
279 if (!load_oem_manifest) { | |
280 on_statistics_loaded_.Signal(); | |
281 return; | |
282 } | |
283 | |
284 // If kAppOemManifestFile switch is specified, load OEM Manifest file. | |
285 CommandLine* command_line = CommandLine::ForCurrentProcess(); | |
286 if (!command_line->HasSwitch(switches::kAppOemManifestFile)) { | |
287 on_statistics_loaded_.Signal(); | |
288 return; | |
289 } | |
290 KioskOemManifestParser::Manifest* oem_manifest = | |
291 new KioskOemManifestParser::Manifest; | |
292 base::FilePath file_path = | |
293 command_line->GetSwitchValuePath(switches::kAppOemManifestFile); | |
294 base::PostTaskAndReplyWithResult( | |
295 io_task_runner_.get(), | |
296 FROM_HERE, | |
297 base::Bind(&KioskOemManifestParser::Load, | |
298 base::FilePath(kOemManifestFilePath), | |
299 oem_manifest), | |
300 base::Bind(&StatisticsProviderImpl::OemManifestLoaded, | |
301 weak_ptr_factory_.GetWeakPtr(), | |
302 base::Owned(oem_manifest))); | |
303 } | |
304 | |
305 private: | |
306 DISALLOW_COPY_AND_ASSIGN(StatisticsProviderStubImpl); | |
307 }; | |
308 | |
309 static StatisticsProvider* g_statistics_provider = NULL; | |
310 | |
311 // static | |
312 void StatisticsProvider::Initialize( | |
313 const scoped_refptr<base::TaskRunner>& io_task_runner) { | |
314 CHECK(!g_statistics_provider); | |
315 if (base::SysInfo::IsRunningOnChromeOS()) { | |
316 g_statistics_provider = new StatisticsProviderImpl(io_task_runner); | |
317 } else { | |
318 g_statistics_provider = new StatisticsProviderStubImpl(io_task_runner); | |
319 } | |
320 } | |
321 | |
322 // static | |
323 void StatisticsProvider::Shutdown() { | |
324 delete g_statistics_provider; | |
325 g_statistics_provider = NULL; | |
326 } | |
327 | |
328 StatisticsProvider* StatisticsProvider::GetInstance() { | |
329 CHECK(g_statistics_provider); | |
330 return g_statistics_provider; | |
331 } | |
332 | |
333 } // namespace system | |
334 } // namespace chromeos | |
OLD | NEW |