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 |