14e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved.
24e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
34e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// found in the LICENSE file.
44e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
54e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "chromeos/system/statistics_provider.h"
64e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
74e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "base/bind.h"
84e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "base/command_line.h"
94e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "base/files/file_path.h"
104e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "base/location.h"
114e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "base/logging.h"
124e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "base/memory/singleton.h"
134e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "base/path_service.h"
14010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#include "base/strings/string_number_conversions.h"
154e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "base/synchronization/cancellation_flag.h"
164e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "base/synchronization/waitable_event.h"
174e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "base/sys_info.h"
184e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "base/task_runner.h"
194e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "base/threading/thread_restrictions.h"
204e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "base/time/time.h"
214e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "chromeos/app_mode/kiosk_oem_manifest_parser.h"
224e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "chromeos/chromeos_constants.h"
234e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "chromeos/chromeos_switches.h"
244e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "chromeos/system/name_value_pairs_parser.h"
254e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
264e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)namespace chromeos {
274e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)namespace system {
284e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
294e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)namespace {
304e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
314e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// Path to the tool used to get system info, and delimiters for the output
324e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// format of the tool.
334e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)const char* kCrosSystemTool[] = { "/usr/bin/crossystem" };
344e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)const char kCrosSystemEq[] = "=";
354e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)const char kCrosSystemDelim[] = "\n";
364e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)const char kCrosSystemCommentDelim[] = "#";
374e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)const char kCrosSystemUnknownValue[] = "(error)";
384e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
394e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)const char kHardwareClassCrosSystemKey[] = "hwid";
404e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)const char kUnknownHardwareClass[] = "unknown";
41010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)const char kSerialNumber[] = "sn";
424e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
434e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// File to get machine hardware info from, and key/value delimiters of
44116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch// the file. machine-info is generated only for OOBE and enterprise enrollment
45116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch// and may not be present. See login-manager/init/machine-info.conf.
464e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)const char kMachineHardwareInfoFile[] = "/tmp/machine-info";
474e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)const char kMachineHardwareInfoEq[] = "=";
484e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)const char kMachineHardwareInfoDelim[] = " \n";
494e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
504e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// File to get ECHO coupon info from, and key/value delimiters of
514e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// the file.
524e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)const char kEchoCouponFile[] = "/var/cache/echo/vpd_echo.txt";
534e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)const char kEchoCouponEq[] = "=";
544e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)const char kEchoCouponDelim[] = "\n";
554e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
564e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// File to get VPD info from, and key/value delimiters of the file.
574e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)const char kVpdFile[] = "/var/log/vpd_2.0.txt";
584e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)const char kVpdEq[] = "=";
594e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)const char kVpdDelim[] = "\n";
604e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
614e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// Timeout that we should wait for statistics to get loaded
624e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)const int kTimeoutSecs = 3;
634e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
644e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// The location of OEM manifest file used to trigger OOBE flow for kiosk mode.
654e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)const CommandLine::CharType kOemManifestFilePath[] =
664e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    FILE_PATH_LITERAL("/usr/share/oem/oobe/manifest.json");
674e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
684e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}  // namespace
694e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
704e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// Key values for GetMachineStatistic()/GetMachineFlag() calls.
714e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)const char kDevSwitchBootMode[] = "devsw_boot";
72a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)const char kCustomizationIdKey[] = "customization_id";
734e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)const char kHardwareClassKey[] = "hardware_class";
744e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)const char kOffersCouponCodeKey[] = "ubind_attribute";
754e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)const char kOffersGroupCodeKey[] = "gbind_attribute";
76a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)const char kRlzBrandCodeKey[] = "rlz_brand_code";
77a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
78a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// OEM specific statistics. Must be prefixed with "oem_".
794e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)const char kOemCanExitEnterpriseEnrollmentKey[] = "oem_can_exit_enrollment";
804e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)const char kOemDeviceRequisitionKey[] = "oem_device_requisition";
814e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)const char kOemIsEnterpriseManagedKey[] = "oem_enterprise_managed";
824e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)const char kOemKeyboardDrivenOobeKey[] = "oem_keyboard_driven_oobe";
834e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
84a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)bool HasOemPrefix(const std::string& name) {
85a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  return name.substr(0, 4) == "oem_";
86a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
87a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
884e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// The StatisticsProvider implementation used in production.
894e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)class StatisticsProviderImpl : public StatisticsProvider {
904e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) public:
914e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // StatisticsProvider implementation:
924e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  virtual void StartLoadingMachineStatistics(
934e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      const scoped_refptr<base::TaskRunner>& file_task_runner,
944e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      bool load_oem_manifest) OVERRIDE;
954e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  virtual bool GetMachineStatistic(const std::string& name,
964e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                                   std::string* result) OVERRIDE;
974e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  virtual bool GetMachineFlag(const std::string& name, bool* result) OVERRIDE;
984e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  virtual void Shutdown() OVERRIDE;
994e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1004e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  static StatisticsProviderImpl* GetInstance();
1014e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1024e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) protected:
1034e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  typedef std::map<std::string, bool> MachineFlags;
1044e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  friend struct DefaultSingletonTraits<StatisticsProviderImpl>;
1054e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1064e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  StatisticsProviderImpl();
1074e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  virtual ~StatisticsProviderImpl();
1084e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1094e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // Waits up to |kTimeoutSecs| for statistics to be loaded. Returns true if
1104e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // they were loaded successfully.
1114e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  bool WaitForStatisticsLoaded();
1124e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1134e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // Loads the machine statistics off of disk. Runs on the file thread.
1144e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  void LoadMachineStatistics(bool load_oem_manifest);
1154e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1164e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // Loads the OEM statistics off of disk. Runs on the file thread.
1174e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  void LoadOemManifestFromFile(const base::FilePath& file);
1184e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1194e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  bool load_statistics_started_;
1204e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  NameValuePairsParser::NameValueMap machine_info_;
1214e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  MachineFlags machine_flags_;
1224e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  base::CancellationFlag cancellation_flag_;
1234e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // |on_statistics_loaded_| protects |machine_info_| and |machine_flags_|.
1244e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  base::WaitableEvent on_statistics_loaded_;
125a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  bool oem_manifest_loaded_;
1264e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1274e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) private:
1284e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(StatisticsProviderImpl);
1294e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)};
1304e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1314e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)bool StatisticsProviderImpl::WaitForStatisticsLoaded() {
1324e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  CHECK(load_statistics_started_);
1334e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (on_statistics_loaded_.IsSignaled())
1344e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    return true;
1354e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1364e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // Block if the statistics are not loaded yet. Normally this shouldn't
137116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // happen except during OOBE.
1384e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  base::Time start_time = base::Time::Now();
1394e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  base::ThreadRestrictions::ScopedAllowWait allow_wait;
1404e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  on_statistics_loaded_.TimedWait(base::TimeDelta::FromSeconds(kTimeoutSecs));
1414e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1424e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  base::TimeDelta dtime = base::Time::Now() - start_time;
1434e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (on_statistics_loaded_.IsSignaled()) {
1444e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    LOG(ERROR) << "Statistics loaded after waiting "
1454e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)               << dtime.InMilliseconds() << "ms. ";
1464e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    return true;
1474e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
1484e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1494e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  LOG(ERROR) << "Statistics not loaded after waiting "
1504e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)             << dtime.InMilliseconds() << "ms. ";
1514e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  return false;
1524e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
1534e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1544e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)bool StatisticsProviderImpl::GetMachineStatistic(const std::string& name,
1554e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                                                 std::string* result) {
1564e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  VLOG(1) << "Machine Statistic requested: " << name;
1574e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (!WaitForStatisticsLoaded()) {
1584e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    LOG(ERROR) << "GetMachineStatistic called before load started: " << name;
1594e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    return false;
1604e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
1614e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1624e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  NameValuePairsParser::NameValueMap::iterator iter = machine_info_.find(name);
1634e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (iter == machine_info_.end()) {
164a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    if (base::SysInfo::IsRunningOnChromeOS() &&
165a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        (oem_manifest_loaded_ || !HasOemPrefix(name))) {
1664e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      LOG(WARNING) << "Requested statistic not found: " << name;
167a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    }
1684e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    return false;
1694e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
1704e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  *result = iter->second;
1714e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  return true;
1724e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
1734e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1744e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)bool StatisticsProviderImpl::GetMachineFlag(const std::string& name,
1754e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                                            bool* result) {
1764e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  VLOG(1) << "Machine Flag requested: " << name;
1774e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (!WaitForStatisticsLoaded()) {
1784e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    LOG(ERROR) << "GetMachineFlag called before load started: " << name;
1794e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    return false;
1804e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
1814e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1824e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  MachineFlags::const_iterator iter = machine_flags_.find(name);
1834e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (iter == machine_flags_.end()) {
184a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    if (base::SysInfo::IsRunningOnChromeOS() &&
185a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        (oem_manifest_loaded_ || !HasOemPrefix(name))) {
1864e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      LOG(WARNING) << "Requested machine flag not found: " << name;
187a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    }
1884e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    return false;
1894e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
1904e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  *result = iter->second;
1914e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  return true;
1924e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
1934e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1944e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void StatisticsProviderImpl::Shutdown() {
1954e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  cancellation_flag_.Set();  // Cancel any pending loads
1964e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
1974e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1984e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)StatisticsProviderImpl::StatisticsProviderImpl()
1994e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    : load_statistics_started_(false),
2004e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      on_statistics_loaded_(true  /* manual_reset */,
201a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                            false /* initially_signaled */),
202a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      oem_manifest_loaded_(false) {
2034e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
2044e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
2054e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)StatisticsProviderImpl::~StatisticsProviderImpl() {
2064e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
2074e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
2084e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void StatisticsProviderImpl::StartLoadingMachineStatistics(
2094e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    const scoped_refptr<base::TaskRunner>& file_task_runner,
2104e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    bool load_oem_manifest) {
2114e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  CHECK(!load_statistics_started_);
2124e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  load_statistics_started_ = true;
2134e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
2144e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  VLOG(1) << "Started loading statistics. Load OEM Manifest: "
2154e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)          << load_oem_manifest;
2164e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
2174e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  file_task_runner->PostTask(
2184e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      FROM_HERE,
2194e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      base::Bind(&StatisticsProviderImpl::LoadMachineStatistics,
2204e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                 base::Unretained(this),
2214e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                 load_oem_manifest));
2224e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
2234e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
2244e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void StatisticsProviderImpl::LoadMachineStatistics(bool load_oem_manifest) {
2254e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // Run from the file task runner. StatisticsProviderImpl is a Singleton<> and
2264e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // will not be destroyed until after threads have been stopped, so this test
2274e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // is always safe.
2284e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (cancellation_flag_.IsSet())
2294e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    return;
2304e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
231effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  NameValuePairsParser parser(&machine_info_);
2324e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (base::SysInfo::IsRunningOnChromeOS()) {
2334e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    // Parse all of the key/value pairs from the crossystem tool.
2344e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    if (!parser.ParseNameValuePairsFromTool(arraysize(kCrosSystemTool),
2354e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                                            kCrosSystemTool,
2364e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                                            kCrosSystemEq,
2374e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                                            kCrosSystemDelim,
2384e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                                            kCrosSystemCommentDelim)) {
2394e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      LOG(ERROR) << "Errors parsing output from: " << kCrosSystemTool;
2404e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    }
2414e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
2424e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
243effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  parser.GetNameValuePairsFromFile(base::FilePath(kMachineHardwareInfoFile),
244effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                                   kMachineHardwareInfoEq,
245effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                                   kMachineHardwareInfoDelim);
246effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  parser.GetNameValuePairsFromFile(base::FilePath(kEchoCouponFile),
247effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                                   kEchoCouponEq,
248effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                                   kEchoCouponDelim);
249effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  parser.GetNameValuePairsFromFile(base::FilePath(kVpdFile),
250effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                                   kVpdEq,
251effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                                   kVpdDelim);
252effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
2534e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // Ensure that the hardware class key is present with the expected
2544e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // key name, and if it couldn't be retrieved, that the value is "unknown".
2554e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  std::string hardware_class = machine_info_[kHardwareClassCrosSystemKey];
2564e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (hardware_class.empty() || hardware_class == kCrosSystemUnknownValue)
2574e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    machine_info_[kHardwareClassKey] = kUnknownHardwareClass;
2584e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  else
2594e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    machine_info_[kHardwareClassKey] = hardware_class;
2604e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
2614e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (load_oem_manifest) {
2624e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    // If kAppOemManifestFile switch is specified, load OEM Manifest file.
2634e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    CommandLine* command_line = CommandLine::ForCurrentProcess();
2644e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    if (command_line->HasSwitch(switches::kAppOemManifestFile)) {
2654e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      LoadOemManifestFromFile(
2664e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)          command_line->GetSwitchValuePath(switches::kAppOemManifestFile));
2674e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    } else if (base::SysInfo::IsRunningOnChromeOS()) {
2684e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      LoadOemManifestFromFile(base::FilePath(kOemManifestFilePath));
2694e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    }
2704e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
2714e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
272010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  if (!base::SysInfo::IsRunningOnChromeOS() &&
273010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      machine_info_.find(kSerialNumber) == machine_info_.end()) {
274010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    // Set stub value for testing. A time value is appended to avoid clashes of
275010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    // the same serial for the same domain, which would invalidate earlier
276010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    // enrollments. A fake /tmp/machine-info file should be used instead if
277010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    // a stable serial is needed, e.g. to test re-enrollment.
278010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    base::TimeDelta time = base::Time::Now() - base::Time::UnixEpoch();
279010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    machine_info_[kSerialNumber] =
280010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)        "stub_serial_number_" + base::Int64ToString(time.InSeconds());
281010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  }
282010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
2834e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // Finished loading the statistics.
2844e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  on_statistics_loaded_.Signal();
2854e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  VLOG(1) << "Finished loading statistics.";
2864e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
2874e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
2884e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void StatisticsProviderImpl::LoadOemManifestFromFile(
2894e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    const base::FilePath& file) {
2904e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // Called from LoadMachineStatistics. Check cancellation_flag_ again here.
2914e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (cancellation_flag_.IsSet())
2924e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    return;
2934e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
2944e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  KioskOemManifestParser::Manifest oem_manifest;
2954e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (!KioskOemManifestParser::Load(file, &oem_manifest)) {
2964e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    LOG(WARNING) << "Unable to load OEM Manifest file: " << file.value();
2974e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    return;
2984e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
2994e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  machine_info_[kOemDeviceRequisitionKey] =
3004e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      oem_manifest.device_requisition;
3014e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  machine_flags_[kOemIsEnterpriseManagedKey] =
3024e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      oem_manifest.enterprise_managed;
3034e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  machine_flags_[kOemCanExitEnterpriseEnrollmentKey] =
3044e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      oem_manifest.can_exit_enrollment;
3054e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  machine_flags_[kOemKeyboardDrivenOobeKey] =
3064e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      oem_manifest.keyboard_driven_oobe;
3074e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
3086e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  oem_manifest_loaded_ = true;
3094e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  VLOG(1) << "Loaded OEM Manifest statistics from " << file.value();
3104e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
3114e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
3124e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)StatisticsProviderImpl* StatisticsProviderImpl::GetInstance() {
3134e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  return Singleton<StatisticsProviderImpl,
3144e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                   DefaultSingletonTraits<StatisticsProviderImpl> >::get();
3154e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
3164e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
3174e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)static StatisticsProvider* g_test_statistics_provider = NULL;
3184e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
3194e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// static
3204e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)StatisticsProvider* StatisticsProvider::GetInstance() {
3214e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (g_test_statistics_provider)
3224e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    return g_test_statistics_provider;
3234e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  return StatisticsProviderImpl::GetInstance();
3244e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
3254e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
3264e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// static
3274e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void StatisticsProvider::SetTestProvider(StatisticsProvider* test_provider) {
3284e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  g_test_statistics_provider = test_provider;
3294e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
3304e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
3314e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}  // namespace system
3324e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}  // namespace chromeos
333