Refactor management of overview window copy lifetime into a separate class.
[chromium-blink-merge.git] / chromeos / system / statistics_provider.cc
blob803c8fd6a1bd0acde3d99c11f47f05990f392db7
1 // Copyright 2013 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 "chromeos/system/statistics_provider.h"
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/memory/singleton.h"
13 #include "base/path_service.h"
14 #include "base/synchronization/cancellation_flag.h"
15 #include "base/synchronization/waitable_event.h"
16 #include "base/sys_info.h"
17 #include "base/task_runner.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"
25 namespace chromeos {
26 namespace system {
28 namespace {
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)";
38 const char kHardwareClassCrosSystemKey[] = "hwid";
39 const char kUnknownHardwareClass[] = "unknown";
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";
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";
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";
59 // Timeout that we should wait for statistics to get loaded
60 const int kTimeoutSecs = 3;
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");
66 } // namespace
68 // Key values for GetMachineStatistic()/GetMachineFlag() calls.
69 const char kDevSwitchBootMode[] = "devsw_boot";
70 const char kHardwareClassKey[] = "hardware_class";
71 const char kOffersCouponCodeKey[] = "ubind_attribute";
72 const char kOffersGroupCodeKey[] = "gbind_attribute";
73 const char kOemCanExitEnterpriseEnrollmentKey[] = "oem_can_exit_enrollment";
74 const char kOemDeviceRequisitionKey[] = "oem_device_requisition";
75 const char kOemIsEnterpriseManagedKey[] = "oem_enterprise_managed";
76 const char kOemKeyboardDrivenOobeKey[] = "oem_keyboard_driven_oobe";
78 // The StatisticsProvider implementation used in production.
79 class StatisticsProviderImpl : public StatisticsProvider {
80 public:
81 // StatisticsProvider implementation:
82 virtual void StartLoadingMachineStatistics(
83 const scoped_refptr<base::TaskRunner>& file_task_runner,
84 bool load_oem_manifest) OVERRIDE;
85 virtual bool GetMachineStatistic(const std::string& name,
86 std::string* result) OVERRIDE;
87 virtual bool GetMachineFlag(const std::string& name, bool* result) OVERRIDE;
88 virtual void Shutdown() OVERRIDE;
90 static StatisticsProviderImpl* GetInstance();
92 protected:
93 typedef std::map<std::string, bool> MachineFlags;
94 friend struct DefaultSingletonTraits<StatisticsProviderImpl>;
96 StatisticsProviderImpl();
97 virtual ~StatisticsProviderImpl();
99 // Waits up to |kTimeoutSecs| for statistics to be loaded. Returns true if
100 // they were loaded successfully.
101 bool WaitForStatisticsLoaded();
103 // Loads the machine statistics off of disk. Runs on the file thread.
104 void LoadMachineStatistics(bool load_oem_manifest);
106 // Loads the OEM statistics off of disk. Runs on the file thread.
107 void LoadOemManifestFromFile(const base::FilePath& file);
109 bool load_statistics_started_;
110 NameValuePairsParser::NameValueMap machine_info_;
111 MachineFlags machine_flags_;
112 base::CancellationFlag cancellation_flag_;
113 // |on_statistics_loaded_| protects |machine_info_| and |machine_flags_|.
114 base::WaitableEvent on_statistics_loaded_;
116 private:
117 DISALLOW_COPY_AND_ASSIGN(StatisticsProviderImpl);
120 bool StatisticsProviderImpl::WaitForStatisticsLoaded() {
121 CHECK(load_statistics_started_);
122 if (on_statistics_loaded_.IsSignaled())
123 return true;
125 // Block if the statistics are not loaded yet. Normally this shouldn't
126 // happen excpet during OOBE.
127 base::Time start_time = base::Time::Now();
128 base::ThreadRestrictions::ScopedAllowWait allow_wait;
129 on_statistics_loaded_.TimedWait(base::TimeDelta::FromSeconds(kTimeoutSecs));
131 base::TimeDelta dtime = base::Time::Now() - start_time;
132 if (on_statistics_loaded_.IsSignaled()) {
133 LOG(ERROR) << "Statistics loaded after waiting "
134 << dtime.InMilliseconds() << "ms. ";
135 return true;
138 LOG(ERROR) << "Statistics not loaded after waiting "
139 << dtime.InMilliseconds() << "ms. ";
140 return false;
143 bool StatisticsProviderImpl::GetMachineStatistic(const std::string& name,
144 std::string* result) {
145 VLOG(1) << "Machine Statistic requested: " << name;
146 if (!WaitForStatisticsLoaded()) {
147 LOG(ERROR) << "GetMachineStatistic called before load started: " << name;
148 return false;
151 NameValuePairsParser::NameValueMap::iterator iter = machine_info_.find(name);
152 if (iter == machine_info_.end()) {
153 if (base::SysInfo::IsRunningOnChromeOS())
154 LOG(WARNING) << "Requested statistic not found: " << name;
155 return false;
157 *result = iter->second;
158 return true;
161 bool StatisticsProviderImpl::GetMachineFlag(const std::string& name,
162 bool* result) {
163 VLOG(1) << "Machine Flag requested: " << name;
164 if (!WaitForStatisticsLoaded()) {
165 LOG(ERROR) << "GetMachineFlag called before load started: " << name;
166 return false;
169 MachineFlags::const_iterator iter = machine_flags_.find(name);
170 if (iter == machine_flags_.end()) {
171 if (base::SysInfo::IsRunningOnChromeOS())
172 LOG(WARNING) << "Requested machine flag not found: " << name;
173 return false;
175 *result = iter->second;
176 return true;
179 void StatisticsProviderImpl::Shutdown() {
180 cancellation_flag_.Set(); // Cancel any pending loads
183 StatisticsProviderImpl::StatisticsProviderImpl()
184 : load_statistics_started_(false),
185 on_statistics_loaded_(true /* manual_reset */,
186 false /* initially_signaled */) {
189 StatisticsProviderImpl::~StatisticsProviderImpl() {
192 void StatisticsProviderImpl::StartLoadingMachineStatistics(
193 const scoped_refptr<base::TaskRunner>& file_task_runner,
194 bool load_oem_manifest) {
195 CHECK(!load_statistics_started_);
196 load_statistics_started_ = true;
198 VLOG(1) << "Started loading statistics. Load OEM Manifest: "
199 << load_oem_manifest;
201 file_task_runner->PostTask(
202 FROM_HERE,
203 base::Bind(&StatisticsProviderImpl::LoadMachineStatistics,
204 base::Unretained(this),
205 load_oem_manifest));
208 void StatisticsProviderImpl::LoadMachineStatistics(bool load_oem_manifest) {
209 // Run from the file task runner. StatisticsProviderImpl is a Singleton<> and
210 // will not be destroyed until after threads have been stopped, so this test
211 // is always safe.
212 if (cancellation_flag_.IsSet())
213 return;
215 if (base::SysInfo::IsRunningOnChromeOS()) {
216 // Parse all of the key/value pairs from the crossystem tool.
217 NameValuePairsParser parser(&machine_info_);
218 if (!parser.ParseNameValuePairsFromTool(arraysize(kCrosSystemTool),
219 kCrosSystemTool,
220 kCrosSystemEq,
221 kCrosSystemDelim,
222 kCrosSystemCommentDelim)) {
223 LOG(ERROR) << "Errors parsing output from: " << kCrosSystemTool;
226 parser.GetNameValuePairsFromFile(base::FilePath(kMachineHardwareInfoFile),
227 kMachineHardwareInfoEq,
228 kMachineHardwareInfoDelim);
229 parser.GetNameValuePairsFromFile(base::FilePath(kEchoCouponFile),
230 kEchoCouponEq,
231 kEchoCouponDelim);
232 parser.GetNameValuePairsFromFile(base::FilePath(kVpdFile),
233 kVpdEq,
234 kVpdDelim);
237 // Ensure that the hardware class key is present with the expected
238 // key name, and if it couldn't be retrieved, that the value is "unknown".
239 std::string hardware_class = machine_info_[kHardwareClassCrosSystemKey];
240 if (hardware_class.empty() || hardware_class == kCrosSystemUnknownValue)
241 machine_info_[kHardwareClassKey] = kUnknownHardwareClass;
242 else
243 machine_info_[kHardwareClassKey] = hardware_class;
245 if (load_oem_manifest) {
246 // If kAppOemManifestFile switch is specified, load OEM Manifest file.
247 CommandLine* command_line = CommandLine::ForCurrentProcess();
248 if (command_line->HasSwitch(switches::kAppOemManifestFile)) {
249 LoadOemManifestFromFile(
250 command_line->GetSwitchValuePath(switches::kAppOemManifestFile));
251 } else if (base::SysInfo::IsRunningOnChromeOS()) {
252 LoadOemManifestFromFile(base::FilePath(kOemManifestFilePath));
256 // Finished loading the statistics.
257 on_statistics_loaded_.Signal();
258 VLOG(1) << "Finished loading statistics.";
261 void StatisticsProviderImpl::LoadOemManifestFromFile(
262 const base::FilePath& file) {
263 // Called from LoadMachineStatistics. Check cancellation_flag_ again here.
264 if (cancellation_flag_.IsSet())
265 return;
267 KioskOemManifestParser::Manifest oem_manifest;
268 if (!KioskOemManifestParser::Load(file, &oem_manifest)) {
269 LOG(WARNING) << "Unable to load OEM Manifest file: " << file.value();
270 return;
272 machine_info_[kOemDeviceRequisitionKey] =
273 oem_manifest.device_requisition;
274 machine_flags_[kOemIsEnterpriseManagedKey] =
275 oem_manifest.enterprise_managed;
276 machine_flags_[kOemCanExitEnterpriseEnrollmentKey] =
277 oem_manifest.can_exit_enrollment;
278 machine_flags_[kOemKeyboardDrivenOobeKey] =
279 oem_manifest.keyboard_driven_oobe;
281 VLOG(1) << "Loaded OEM Manifest statistics from " << file.value();
284 StatisticsProviderImpl* StatisticsProviderImpl::GetInstance() {
285 return Singleton<StatisticsProviderImpl,
286 DefaultSingletonTraits<StatisticsProviderImpl> >::get();
289 static StatisticsProvider* g_test_statistics_provider = NULL;
291 // static
292 StatisticsProvider* StatisticsProvider::GetInstance() {
293 if (g_test_statistics_provider)
294 return g_test_statistics_provider;
295 return StatisticsProviderImpl::GetInstance();
298 // static
299 void StatisticsProvider::SetTestProvider(StatisticsProvider* test_provider) {
300 g_test_statistics_provider = test_provider;
303 } // namespace system
304 } // namespace chromeos