Chromium Code Reviews| Index: chromeos/system/statistics_provider.cc |
| diff --git a/chromeos/system/statistics_provider.cc b/chromeos/system/statistics_provider.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..ebd10777474f34c4c0e8e2cd7b881394458b02ab |
| --- /dev/null |
| +++ b/chromeos/system/statistics_provider.cc |
| @@ -0,0 +1,334 @@ |
| +// Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +#include "chromeos/system/statistics_provider.h" |
| + |
| +#include "base/bind.h" |
| +#include "base/command_line.h" |
| +#include "base/files/file_path.h" |
| +#include "base/location.h" |
| +#include "base/logging.h" |
| +#include "base/path_service.h" |
| +#include "base/synchronization/lock.h" |
| +#include "base/synchronization/waitable_event.h" |
| +#include "base/sys_info.h" |
| +#include "base/task_runner.h" |
| +#include "base/task_runner_util.h" |
| +#include "base/threading/thread_restrictions.h" |
| +#include "base/time/time.h" |
| +#include "chromeos/app_mode/kiosk_oem_manifest_parser.h" |
| +#include "chromeos/chromeos_constants.h" |
| +#include "chromeos/chromeos_switches.h" |
| +#include "chromeos/system/name_value_pairs_parser.h" |
| + |
| +namespace chromeos { |
| +namespace system { |
| + |
| +namespace { |
| + |
| +// Path to the tool used to get system info, and delimiters for the output |
| +// format of the tool. |
| +const char* kCrosSystemTool[] = { "/usr/bin/crossystem" }; |
| +const char kCrosSystemEq[] = "="; |
| +const char kCrosSystemDelim[] = "\n"; |
| +const char kCrosSystemCommentDelim[] = "#"; |
| +const char kCrosSystemUnknownValue[] = "(error)"; |
| + |
| +const char kHardwareClassCrosSystemKey[] = "hwid"; |
| +const char kUnknownHardwareClass[] = "unknown"; |
| + |
| +// File to get machine hardware info from, and key/value delimiters of |
| +// the file. |
| +// /tmp/machine-info is generated by platform/init/chromeos_startup. |
| +const char kMachineHardwareInfoFile[] = "/tmp/machine-info"; |
| +const char kMachineHardwareInfoEq[] = "="; |
| +const char kMachineHardwareInfoDelim[] = " \n"; |
| + |
| +// File to get ECHO coupon info from, and key/value delimiters of |
| +// the file. |
| +const char kEchoCouponFile[] = "/var/cache/echo/vpd_echo.txt"; |
| +const char kEchoCouponEq[] = "="; |
| +const char kEchoCouponDelim[] = "\n"; |
| + |
| +// File to get VPD info from, and key/value delimiters of the file. |
| +const char kVpdFile[] = "/var/log/vpd_2.0.txt"; |
| +const char kVpdEq[] = "="; |
| +const char kVpdDelim[] = "\n"; |
| + |
| +// Timeout that we should wait for statistics to get loaded |
| +const int kTimeoutSecs = 3; |
| + |
| +// The location of OEM manifest file used to trigger OOBE flow for kiosk mode. |
| +const CommandLine::CharType kOemManifestFilePath[] = |
| + FILE_PATH_LITERAL("/usr/share/oem/oobe/manifest.json"); |
| + |
| +void LoadMachineStatistics(NameValuePairsParser::NameValueMap* name_value_map) { |
| + // Parse all of the key/value pairs from the crossystem tool. |
| + NameValuePairsParser parser(name_value_map); |
| + if (!parser.ParseNameValuePairsFromTool(arraysize(kCrosSystemTool), |
| + kCrosSystemTool, |
| + kCrosSystemEq, |
| + kCrosSystemDelim, |
| + kCrosSystemCommentDelim)) { |
| + LOG(WARNING) << "There were errors parsing the output of " |
| + << kCrosSystemTool << "."; |
| + } |
| + parser.GetNameValuePairsFromFile(base::FilePath(kMachineHardwareInfoFile), |
| + kMachineHardwareInfoEq, |
| + kMachineHardwareInfoDelim); |
| + parser.GetNameValuePairsFromFile( |
| + base::FilePath(kEchoCouponFile), kEchoCouponEq, kEchoCouponDelim); |
| + parser.GetNameValuePairsFromFile(base::FilePath(kVpdFile), kVpdEq, kVpdDelim); |
| +} |
| + |
| +} // namespace |
| + |
| +// Key values for GetMachineStatistic()/GetMachineFlag() calls. |
| +const char kDevSwitchBootMode[] = "devsw_boot"; |
| +const char kHardwareClassKey[] = "hardware_class"; |
| +const char kOffersCouponCodeKey[] = "ubind_attribute"; |
| +const char kOffersGroupCodeKey[] = "gbind_attribute"; |
| +const char kOemCanExitEnterpriseEnrollmentKey[] = "oem_can_exit_enrollment"; |
| +const char kOemDeviceRequisitionKey[] = "oem_device_requisition"; |
| +const char kOemIsEnterpriseManagedKey[] = "oem_enterprise_managed"; |
| +const char kOemKeyboardDrivenOobeKey[] = "oem_keyboard_driven_oobe"; |
| + |
| +// The StatisticsProvider implementation used in production. |
| +class StatisticsProviderImpl : public StatisticsProvider { |
| + public: |
| + explicit StatisticsProviderImpl( |
| + const scoped_refptr<base::TaskRunner>& io_task_runner); |
| + virtual ~StatisticsProviderImpl(); |
| + |
| + // StatisticsProvider implementation: |
| + virtual void StartLoadingMachineStatistics(bool load_oem_manifest) OVERRIDE; |
| + virtual bool GetMachineStatistic(const std::string& name, |
| + std::string* result) OVERRIDE; |
| + virtual bool GetMachineFlag(const std::string& name, bool* result) OVERRIDE; |
| + |
| + // Completes loading of machine statistcs from system files. |
| + void MachineStatisticsLoaded( |
| + NameValuePairsParser::NameValueMap* name_value_map, |
| + bool load_oem_manifest); |
| + |
| + // Completes loading the OEM manifest statistcs. |
| + void OemManifestLoaded(KioskOemManifestParser::Manifest* oem_manifest, |
| + bool success); |
| + |
| + protected: |
| + typedef std::map<std::string, bool> MachineFlags; |
| + |
| + bool load_statistics_started_; |
| + base::Lock lock_; |
| + scoped_refptr<base::TaskRunner> io_task_runner_; |
| + NameValuePairsParser::NameValueMap machine_info_; |
| + 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
|
| + base::WaitableEvent on_statistics_loaded_; |
| + base::WeakPtrFactory<StatisticsProviderImpl> weak_ptr_factory_; |
| + |
| + private: |
| + DISALLOW_COPY_AND_ASSIGN(StatisticsProviderImpl); |
| +}; |
| + |
| +StatisticsProviderImpl::StatisticsProviderImpl( |
| + const scoped_refptr<base::TaskRunner>& io_task_runner) |
| + : load_statistics_started_(false), |
| + io_task_runner_(io_task_runner), |
| + on_statistics_loaded_(true /* manual_reset */, |
| + false /* initially_signaled */), |
| + weak_ptr_factory_(this) { |
| +} |
| + |
| +StatisticsProviderImpl::~StatisticsProviderImpl() { |
| +} |
| + |
| +void StatisticsProviderImpl::StartLoadingMachineStatistics( |
| + bool load_oem_manifest) { |
| + CHECK(!load_statistics_started_); |
| + load_statistics_started_ = true; |
| + |
| + VLOG(1) << "Started loading statistics. Load OEM Manifest: " |
| + << load_oem_manifest; |
| + |
| + NameValuePairsParser::NameValueMap* name_value_map = |
| + new NameValuePairsParser::NameValueMap; |
| + io_task_runner_->PostTaskAndReply( |
| + FROM_HERE, |
| + base::Bind(&LoadMachineStatistics, name_value_map), |
| + base::Bind(&StatisticsProviderImpl::MachineStatisticsLoaded, |
| + weak_ptr_factory_.GetWeakPtr(), |
| + base::Owned(name_value_map), |
| + load_oem_manifest)); |
| +} |
| + |
| +bool StatisticsProviderImpl::GetMachineStatistic( |
| + const std::string& name, std::string* result) { |
| + // TODO(stevenjb): Thes should be made fatal once fixed. crbug.com/302798. |
| + if (!load_statistics_started_) { |
| + LOG(ERROR) << "GetMachineStatistic called before load started: " << name; |
| + return false; |
| + } |
| + |
| + VLOG(1) << "Statistic is requested for " << name; |
| + // Block if the statistics are not loaded yet. Normally this shouldn't |
| + // happen excpet during OOBE. |
| + if (!on_statistics_loaded_.IsSignaled()) { |
| + base::Time start_time = base::Time::Now(); |
| + base::ThreadRestrictions::ScopedAllowWait allow_wait; |
| + on_statistics_loaded_.TimedWait(base::TimeDelta::FromSeconds(kTimeoutSecs)); |
| + base::TimeDelta dtime = base::Time::Now() - start_time; |
| + if (!on_statistics_loaded_.IsSignaled()) { |
| + LOG(ERROR) << "Statistics weren't loaded after waiting " |
| + << dtime.InMilliseconds() << "ms. " |
| + << "Requested statistic: " << name; |
| + return false; |
| + } else { |
| + LOG(ERROR) << "Statistic loaded after waiting " |
| + << dtime.InMilliseconds() << "ms. " |
| + << "Requested statistic: " << name; |
| + } |
| + } |
| + |
| + 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.
|
| + if (iter == machine_info_.end()) { |
| + if (base::SysInfo::IsRunningOnChromeOS()) |
| + LOG(ERROR) << "Requested statistic not found: " << name; |
| + return false; |
| + } |
| + |
| + *result = iter->second; |
| + return true; |
| +} |
| + |
| +bool StatisticsProviderImpl::GetMachineFlag(const std::string& name, |
| + bool* result) { |
| + base::AutoLock lock(lock_); |
| + MachineFlags::const_iterator iter = machine_flags_.find(name); |
| + if (iter == machine_flags_.end()) { |
| + if (base::SysInfo::IsRunningOnChromeOS()) |
| + LOG(ERROR) << "Requested machine flag not found: " << name; |
| + return false; |
| + } |
| + *result = iter->second; |
| + return true; |
| +} |
| + |
| +void StatisticsProviderImpl::MachineStatisticsLoaded( |
| + NameValuePairsParser::NameValueMap* name_value_map, |
| + bool load_oem_manifest) { |
| + base::AutoLock lock(lock_); |
| + |
| + machine_info_.swap(*name_value_map); |
| + // Ensure that the hardware class key is present with the expected |
| + // key name, and if it couldn't be retrieved, that the value is "unknown". |
| + std::string hardware_class = machine_info_[kHardwareClassCrosSystemKey]; |
| + if (hardware_class.empty() || hardware_class == kCrosSystemUnknownValue) |
| + machine_info_[kHardwareClassKey] = kUnknownHardwareClass; |
| + else |
| + machine_info_[kHardwareClassKey] = hardware_class; |
| + |
| + if (load_oem_manifest) { |
| + VLOG(1) << "Started loading OEM Manifest"; |
| + KioskOemManifestParser::Manifest* oem_manifest = |
| + new KioskOemManifestParser::Manifest; |
| + base::PostTaskAndReplyWithResult( |
| + io_task_runner_.get(), |
| + FROM_HERE, |
| + base::Bind(&KioskOemManifestParser::Load, |
| + base::FilePath(kOemManifestFilePath), |
| + oem_manifest), |
| + base::Bind(&StatisticsProviderImpl::OemManifestLoaded, |
| + weak_ptr_factory_.GetWeakPtr(), |
| + base::Owned(oem_manifest))); |
| + return; |
| + } |
| + // Finished loading the statistics. |
| + on_statistics_loaded_.Signal(); |
| + VLOG(1) << "Finished loading statistics"; |
| +} |
| + |
| +void StatisticsProviderImpl::OemManifestLoaded( |
| + KioskOemManifestParser::Manifest* oem_manifest, |
| + bool success) { |
| + if (success) { |
| + machine_info_[kOemDeviceRequisitionKey] = oem_manifest->device_requisition; |
| + machine_flags_[kOemIsEnterpriseManagedKey] = |
| + oem_manifest->enterprise_managed; |
| + machine_flags_[kOemCanExitEnterpriseEnrollmentKey] = |
| + oem_manifest->can_exit_enrollment; |
| + machine_flags_[kOemKeyboardDrivenOobeKey] = |
| + oem_manifest->keyboard_driven_oobe; |
| + } |
| + // Finished loading the statistics. |
| + on_statistics_loaded_.Signal(); |
| + VLOG(1) << "Finished loading statistics and OEM Manifest"; |
| +} |
| + |
| +// The stub StatisticsProvider implementation used on Linux desktop. |
| +class StatisticsProviderStubImpl : public StatisticsProviderImpl { |
| + public: |
| + explicit StatisticsProviderStubImpl( |
| + const scoped_refptr<base::TaskRunner>& io_task_runner) |
| + : StatisticsProviderImpl(io_task_runner) {} |
| + virtual ~StatisticsProviderStubImpl() {} |
| + |
| + // StatisticsProvider implementation: |
| + virtual void StartLoadingMachineStatistics(bool load_oem_manifest) OVERRIDE { |
| + load_statistics_started_ = true; |
| + if (!load_oem_manifest) { |
| + on_statistics_loaded_.Signal(); |
| + return; |
| + } |
| + |
| + // If kAppOemManifestFile switch is specified, load OEM Manifest file. |
| + CommandLine* command_line = CommandLine::ForCurrentProcess(); |
| + if (!command_line->HasSwitch(switches::kAppOemManifestFile)) { |
| + on_statistics_loaded_.Signal(); |
| + return; |
| + } |
| + KioskOemManifestParser::Manifest* oem_manifest = |
| + new KioskOemManifestParser::Manifest; |
| + base::FilePath file_path = |
| + command_line->GetSwitchValuePath(switches::kAppOemManifestFile); |
| + base::PostTaskAndReplyWithResult( |
| + io_task_runner_.get(), |
| + FROM_HERE, |
| + base::Bind(&KioskOemManifestParser::Load, |
| + base::FilePath(kOemManifestFilePath), |
| + oem_manifest), |
| + base::Bind(&StatisticsProviderImpl::OemManifestLoaded, |
| + weak_ptr_factory_.GetWeakPtr(), |
| + base::Owned(oem_manifest))); |
| + } |
| + |
| + private: |
| + DISALLOW_COPY_AND_ASSIGN(StatisticsProviderStubImpl); |
| +}; |
| + |
| +static StatisticsProvider* g_statistics_provider = NULL; |
| + |
| +// static |
| +void StatisticsProvider::Initialize( |
| + const scoped_refptr<base::TaskRunner>& io_task_runner) { |
| + CHECK(!g_statistics_provider); |
| + if (base::SysInfo::IsRunningOnChromeOS()) { |
| + g_statistics_provider = new StatisticsProviderImpl(io_task_runner); |
| + } else { |
| + g_statistics_provider = new StatisticsProviderStubImpl(io_task_runner); |
| + } |
| +} |
| + |
| +// static |
| +void StatisticsProvider::Shutdown() { |
| + delete g_statistics_provider; |
| + g_statistics_provider = NULL; |
| +} |
| + |
| +StatisticsProvider* StatisticsProvider::GetInstance() { |
| + CHECK(g_statistics_provider); |
| + return g_statistics_provider; |
| +} |
| + |
| +} // namespace system |
| +} // namespace chromeos |