Upstream version 7.35.139.0
[platform/framework/web/crosswalk.git] / src / chromeos / system / statistics_provider.cc
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.
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/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"
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 }  // namespace
67
68 // Key values for GetMachineStatistic()/GetMachineFlag() calls.
69 const char kDevSwitchBootMode[] = "devsw_boot";
70 const char kCustomizationIdKey[] = "customization_id";
71 const char kHardwareClassKey[] = "hardware_class";
72 const char kOffersCouponCodeKey[] = "ubind_attribute";
73 const char kOffersGroupCodeKey[] = "gbind_attribute";
74 const char kRlzBrandCodeKey[] = "rlz_brand_code";
75 const char kDiskSerialNumber[] = "root_disk_serial_number";
76
77 // OEM specific statistics. Must be prefixed with "oem_".
78 const char kOemCanExitEnterpriseEnrollmentKey[] = "oem_can_exit_enrollment";
79 const char kOemDeviceRequisitionKey[] = "oem_device_requisition";
80 const char kOemIsEnterpriseManagedKey[] = "oem_enterprise_managed";
81 const char kOemKeyboardDrivenOobeKey[] = "oem_keyboard_driven_oobe";
82
83 bool HasOemPrefix(const std::string& name) {
84   return name.substr(0, 4) == "oem_";
85 }
86
87 // The StatisticsProvider implementation used in production.
88 class StatisticsProviderImpl : public StatisticsProvider {
89  public:
90   // StatisticsProvider implementation:
91   virtual void StartLoadingMachineStatistics(
92       const scoped_refptr<base::TaskRunner>& file_task_runner,
93       bool load_oem_manifest) OVERRIDE;
94   virtual bool GetMachineStatistic(const std::string& name,
95                                    std::string* result) OVERRIDE;
96   virtual bool GetMachineFlag(const std::string& name, bool* result) OVERRIDE;
97   virtual void Shutdown() OVERRIDE;
98
99   static StatisticsProviderImpl* GetInstance();
100
101  protected:
102   typedef std::map<std::string, bool> MachineFlags;
103   friend struct DefaultSingletonTraits<StatisticsProviderImpl>;
104
105   StatisticsProviderImpl();
106   virtual ~StatisticsProviderImpl();
107
108   // Waits up to |kTimeoutSecs| for statistics to be loaded. Returns true if
109   // they were loaded successfully.
110   bool WaitForStatisticsLoaded();
111
112   // Loads the machine statistics off of disk. Runs on the file thread.
113   void LoadMachineStatistics(bool load_oem_manifest);
114
115   // Loads the OEM statistics off of disk. Runs on the file thread.
116   void LoadOemManifestFromFile(const base::FilePath& file);
117
118   bool load_statistics_started_;
119   NameValuePairsParser::NameValueMap machine_info_;
120   MachineFlags machine_flags_;
121   base::CancellationFlag cancellation_flag_;
122   // |on_statistics_loaded_| protects |machine_info_| and |machine_flags_|.
123   base::WaitableEvent on_statistics_loaded_;
124   bool oem_manifest_loaded_;
125
126  private:
127   DISALLOW_COPY_AND_ASSIGN(StatisticsProviderImpl);
128 };
129
130 bool StatisticsProviderImpl::WaitForStatisticsLoaded() {
131   CHECK(load_statistics_started_);
132   if (on_statistics_loaded_.IsSignaled())
133     return true;
134
135   // Block if the statistics are not loaded yet. Normally this shouldn't
136   // happen excpet during OOBE.
137   base::Time start_time = base::Time::Now();
138   base::ThreadRestrictions::ScopedAllowWait allow_wait;
139   on_statistics_loaded_.TimedWait(base::TimeDelta::FromSeconds(kTimeoutSecs));
140
141   base::TimeDelta dtime = base::Time::Now() - start_time;
142   if (on_statistics_loaded_.IsSignaled()) {
143     LOG(ERROR) << "Statistics loaded after waiting "
144                << dtime.InMilliseconds() << "ms. ";
145     return true;
146   }
147
148   LOG(ERROR) << "Statistics not loaded after waiting "
149              << dtime.InMilliseconds() << "ms. ";
150   return false;
151 }
152
153 bool StatisticsProviderImpl::GetMachineStatistic(const std::string& name,
154                                                  std::string* result) {
155   VLOG(1) << "Machine Statistic requested: " << name;
156   if (!WaitForStatisticsLoaded()) {
157     LOG(ERROR) << "GetMachineStatistic called before load started: " << name;
158     return false;
159   }
160
161   NameValuePairsParser::NameValueMap::iterator iter = machine_info_.find(name);
162   if (iter == machine_info_.end()) {
163     if (base::SysInfo::IsRunningOnChromeOS() &&
164         (oem_manifest_loaded_ || !HasOemPrefix(name))) {
165       LOG(WARNING) << "Requested statistic not found: " << name;
166     }
167     return false;
168   }
169   *result = iter->second;
170   return true;
171 }
172
173 bool StatisticsProviderImpl::GetMachineFlag(const std::string& name,
174                                             bool* result) {
175   VLOG(1) << "Machine Flag requested: " << name;
176   if (!WaitForStatisticsLoaded()) {
177     LOG(ERROR) << "GetMachineFlag called before load started: " << name;
178     return false;
179   }
180
181   MachineFlags::const_iterator iter = machine_flags_.find(name);
182   if (iter == machine_flags_.end()) {
183     if (base::SysInfo::IsRunningOnChromeOS() &&
184         (oem_manifest_loaded_ || !HasOemPrefix(name))) {
185       LOG(WARNING) << "Requested machine flag not found: " << name;
186     }
187     return false;
188   }
189   *result = iter->second;
190   return true;
191 }
192
193 void StatisticsProviderImpl::Shutdown() {
194   cancellation_flag_.Set();  // Cancel any pending loads
195 }
196
197 StatisticsProviderImpl::StatisticsProviderImpl()
198     : load_statistics_started_(false),
199       on_statistics_loaded_(true  /* manual_reset */,
200                             false /* initially_signaled */),
201       oem_manifest_loaded_(false) {
202 }
203
204 StatisticsProviderImpl::~StatisticsProviderImpl() {
205 }
206
207 void StatisticsProviderImpl::StartLoadingMachineStatistics(
208     const scoped_refptr<base::TaskRunner>& file_task_runner,
209     bool load_oem_manifest) {
210   CHECK(!load_statistics_started_);
211   load_statistics_started_ = true;
212
213   VLOG(1) << "Started loading statistics. Load OEM Manifest: "
214           << load_oem_manifest;
215
216   file_task_runner->PostTask(
217       FROM_HERE,
218       base::Bind(&StatisticsProviderImpl::LoadMachineStatistics,
219                  base::Unretained(this),
220                  load_oem_manifest));
221 }
222
223 void StatisticsProviderImpl::LoadMachineStatistics(bool load_oem_manifest) {
224   // Run from the file task runner. StatisticsProviderImpl is a Singleton<> and
225   // will not be destroyed until after threads have been stopped, so this test
226   // is always safe.
227   if (cancellation_flag_.IsSet())
228     return;
229
230   NameValuePairsParser parser(&machine_info_);
231   if (base::SysInfo::IsRunningOnChromeOS()) {
232     // Parse all of the key/value pairs from the crossystem tool.
233     if (!parser.ParseNameValuePairsFromTool(arraysize(kCrosSystemTool),
234                                             kCrosSystemTool,
235                                             kCrosSystemEq,
236                                             kCrosSystemDelim,
237                                             kCrosSystemCommentDelim)) {
238       LOG(ERROR) << "Errors parsing output from: " << kCrosSystemTool;
239     }
240   }
241
242   parser.GetNameValuePairsFromFile(base::FilePath(kMachineHardwareInfoFile),
243                                    kMachineHardwareInfoEq,
244                                    kMachineHardwareInfoDelim);
245   parser.GetNameValuePairsFromFile(base::FilePath(kEchoCouponFile),
246                                    kEchoCouponEq,
247                                    kEchoCouponDelim);
248   parser.GetNameValuePairsFromFile(base::FilePath(kVpdFile),
249                                    kVpdEq,
250                                    kVpdDelim);
251
252   // Ensure that the hardware class key is present with the expected
253   // key name, and if it couldn't be retrieved, that the value is "unknown".
254   std::string hardware_class = machine_info_[kHardwareClassCrosSystemKey];
255   if (hardware_class.empty() || hardware_class == kCrosSystemUnknownValue)
256     machine_info_[kHardwareClassKey] = kUnknownHardwareClass;
257   else
258     machine_info_[kHardwareClassKey] = hardware_class;
259
260   if (load_oem_manifest) {
261     // If kAppOemManifestFile switch is specified, load OEM Manifest file.
262     CommandLine* command_line = CommandLine::ForCurrentProcess();
263     if (command_line->HasSwitch(switches::kAppOemManifestFile)) {
264       LoadOemManifestFromFile(
265           command_line->GetSwitchValuePath(switches::kAppOemManifestFile));
266     } else if (base::SysInfo::IsRunningOnChromeOS()) {
267       LoadOemManifestFromFile(base::FilePath(kOemManifestFilePath));
268     }
269     oem_manifest_loaded_ = true;
270   }
271
272   // Finished loading the statistics.
273   on_statistics_loaded_.Signal();
274   VLOG(1) << "Finished loading statistics.";
275 }
276
277 void StatisticsProviderImpl::LoadOemManifestFromFile(
278     const base::FilePath& file) {
279   // Called from LoadMachineStatistics. Check cancellation_flag_ again here.
280   if (cancellation_flag_.IsSet())
281     return;
282
283   KioskOemManifestParser::Manifest oem_manifest;
284   if (!KioskOemManifestParser::Load(file, &oem_manifest)) {
285     LOG(WARNING) << "Unable to load OEM Manifest file: " << file.value();
286     return;
287   }
288   machine_info_[kOemDeviceRequisitionKey] =
289       oem_manifest.device_requisition;
290   machine_flags_[kOemIsEnterpriseManagedKey] =
291       oem_manifest.enterprise_managed;
292   machine_flags_[kOemCanExitEnterpriseEnrollmentKey] =
293       oem_manifest.can_exit_enrollment;
294   machine_flags_[kOemKeyboardDrivenOobeKey] =
295       oem_manifest.keyboard_driven_oobe;
296
297   VLOG(1) << "Loaded OEM Manifest statistics from " << file.value();
298 }
299
300 StatisticsProviderImpl* StatisticsProviderImpl::GetInstance() {
301   return Singleton<StatisticsProviderImpl,
302                    DefaultSingletonTraits<StatisticsProviderImpl> >::get();
303 }
304
305 static StatisticsProvider* g_test_statistics_provider = NULL;
306
307 // static
308 StatisticsProvider* StatisticsProvider::GetInstance() {
309   if (g_test_statistics_provider)
310     return g_test_statistics_provider;
311   return StatisticsProviderImpl::GetInstance();
312 }
313
314 // static
315 void StatisticsProvider::SetTestProvider(StatisticsProvider* test_provider) {
316   g_test_statistics_provider = test_provider;
317 }
318
319 }  // namespace system
320 }  // namespace chromeos