Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright (c) 2012 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/path_service.h" | |
| 13 #include "base/synchronization/lock.h" | |
| 14 #include "base/synchronization/waitable_event.h" | |
| 15 #include "base/sys_info.h" | |
| 16 #include "base/task_runner.h" | |
| 17 #include "base/task_runner_util.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 void LoadMachineStatistics(NameValuePairsParser::NameValueMap* name_value_map) { | |
| 67 // Parse all of the key/value pairs from the crossystem tool. | |
| 68 NameValuePairsParser parser(name_value_map); | |
| 69 if (!parser.ParseNameValuePairsFromTool(arraysize(kCrosSystemTool), | |
| 70 kCrosSystemTool, | |
| 71 kCrosSystemEq, | |
| 72 kCrosSystemDelim, | |
| 73 kCrosSystemCommentDelim)) { | |
| 74 LOG(WARNING) << "There were errors parsing the output of " | |
| 75 << kCrosSystemTool << "."; | |
| 76 } | |
| 77 parser.GetNameValuePairsFromFile(base::FilePath(kMachineHardwareInfoFile), | |
| 78 kMachineHardwareInfoEq, | |
| 79 kMachineHardwareInfoDelim); | |
| 80 parser.GetNameValuePairsFromFile( | |
| 81 base::FilePath(kEchoCouponFile), kEchoCouponEq, kEchoCouponDelim); | |
| 82 parser.GetNameValuePairsFromFile(base::FilePath(kVpdFile), kVpdEq, kVpdDelim); | |
| 83 } | |
| 84 | |
| 85 } // namespace | |
| 86 | |
| 87 // Key values for GetMachineStatistic()/GetMachineFlag() calls. | |
| 88 const char kDevSwitchBootMode[] = "devsw_boot"; | |
| 89 const char kHardwareClassKey[] = "hardware_class"; | |
| 90 const char kOffersCouponCodeKey[] = "ubind_attribute"; | |
| 91 const char kOffersGroupCodeKey[] = "gbind_attribute"; | |
| 92 const char kOemCanExitEnterpriseEnrollmentKey[] = "oem_can_exit_enrollment"; | |
| 93 const char kOemDeviceRequisitionKey[] = "oem_device_requisition"; | |
| 94 const char kOemIsEnterpriseManagedKey[] = "oem_enterprise_managed"; | |
| 95 const char kOemKeyboardDrivenOobeKey[] = "oem_keyboard_driven_oobe"; | |
| 96 | |
| 97 // The StatisticsProvider implementation used in production. | |
| 98 class StatisticsProviderImpl : public StatisticsProvider { | |
| 99 public: | |
| 100 explicit StatisticsProviderImpl( | |
| 101 const scoped_refptr<base::TaskRunner>& io_task_runner); | |
| 102 virtual ~StatisticsProviderImpl(); | |
| 103 | |
| 104 // StatisticsProvider implementation: | |
| 105 virtual void StartLoadingMachineStatistics(bool load_oem_manifest) OVERRIDE; | |
| 106 virtual bool GetMachineStatistic(const std::string& name, | |
| 107 std::string* result) OVERRIDE; | |
| 108 virtual bool GetMachineFlag(const std::string& name, bool* result) OVERRIDE; | |
| 109 | |
| 110 // Completes loading of machine statistcs from system files. | |
| 111 void MachineStatisticsLoaded( | |
| 112 NameValuePairsParser::NameValueMap* name_value_map, | |
| 113 bool load_oem_manifest); | |
| 114 | |
| 115 // Completes loading the OEM manifest statistcs. | |
| 116 void OemManifestLoaded(KioskOemManifestParser::Manifest* oem_manifest, | |
| 117 bool success); | |
| 118 | |
| 119 protected: | |
| 120 typedef std::map<std::string, bool> MachineFlags; | |
| 121 | |
| 122 bool load_statistics_started_; | |
| 123 base::Lock lock_; | |
| 124 scoped_refptr<base::TaskRunner> io_task_runner_; | |
| 125 NameValuePairsParser::NameValueMap machine_info_; | |
| 126 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
| |
| 127 base::WaitableEvent on_statistics_loaded_; | |
| 128 base::WeakPtrFactory<StatisticsProviderImpl> weak_ptr_factory_; | |
| 129 | |
| 130 private: | |
| 131 DISALLOW_COPY_AND_ASSIGN(StatisticsProviderImpl); | |
| 132 }; | |
| 133 | |
| 134 StatisticsProviderImpl::StatisticsProviderImpl( | |
| 135 const scoped_refptr<base::TaskRunner>& io_task_runner) | |
| 136 : load_statistics_started_(false), | |
| 137 io_task_runner_(io_task_runner), | |
| 138 on_statistics_loaded_(true /* manual_reset */, | |
| 139 false /* initially_signaled */), | |
| 140 weak_ptr_factory_(this) { | |
| 141 } | |
| 142 | |
| 143 StatisticsProviderImpl::~StatisticsProviderImpl() { | |
| 144 } | |
| 145 | |
| 146 void StatisticsProviderImpl::StartLoadingMachineStatistics( | |
| 147 bool load_oem_manifest) { | |
| 148 CHECK(!load_statistics_started_); | |
| 149 load_statistics_started_ = true; | |
| 150 | |
| 151 VLOG(1) << "Started loading statistics. Load OEM Manifest: " | |
| 152 << load_oem_manifest; | |
| 153 | |
| 154 NameValuePairsParser::NameValueMap* name_value_map = | |
| 155 new NameValuePairsParser::NameValueMap; | |
| 156 io_task_runner_->PostTaskAndReply( | |
| 157 FROM_HERE, | |
| 158 base::Bind(&LoadMachineStatistics, name_value_map), | |
| 159 base::Bind(&StatisticsProviderImpl::MachineStatisticsLoaded, | |
| 160 weak_ptr_factory_.GetWeakPtr(), | |
| 161 base::Owned(name_value_map), | |
| 162 load_oem_manifest)); | |
| 163 } | |
| 164 | |
| 165 bool StatisticsProviderImpl::GetMachineStatistic( | |
| 166 const std::string& name, std::string* result) { | |
| 167 // TODO(stevenjb): Thes should be made fatal once fixed. crbug.com/302798. | |
| 168 if (!load_statistics_started_) { | |
| 169 LOG(ERROR) << "GetMachineStatistic called before load started: " << name; | |
| 170 return false; | |
| 171 } | |
| 172 | |
| 173 VLOG(1) << "Statistic is requested for " << name; | |
| 174 // Block if the statistics are not loaded yet. Normally this shouldn't | |
| 175 // happen excpet during OOBE. | |
| 176 if (!on_statistics_loaded_.IsSignaled()) { | |
| 177 base::Time start_time = base::Time::Now(); | |
| 178 base::ThreadRestrictions::ScopedAllowWait allow_wait; | |
| 179 on_statistics_loaded_.TimedWait(base::TimeDelta::FromSeconds(kTimeoutSecs)); | |
| 180 base::TimeDelta dtime = base::Time::Now() - start_time; | |
| 181 if (!on_statistics_loaded_.IsSignaled()) { | |
| 182 LOG(ERROR) << "Statistics weren't loaded after waiting " | |
| 183 << dtime.InMilliseconds() << "ms. " | |
| 184 << "Requested statistic: " << name; | |
| 185 return false; | |
| 186 } else { | |
| 187 LOG(ERROR) << "Statistic loaded after waiting " | |
| 188 << dtime.InMilliseconds() << "ms. " | |
| 189 << "Requested statistic: " << name; | |
| 190 } | |
| 191 } | |
| 192 | |
| 193 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.
| |
| 194 if (iter == machine_info_.end()) { | |
| 195 if (base::SysInfo::IsRunningOnChromeOS()) | |
| 196 LOG(ERROR) << "Requested statistic not found: " << name; | |
| 197 return false; | |
| 198 } | |
| 199 | |
| 200 *result = iter->second; | |
| 201 return true; | |
| 202 } | |
| 203 | |
| 204 bool StatisticsProviderImpl::GetMachineFlag(const std::string& name, | |
| 205 bool* result) { | |
| 206 base::AutoLock lock(lock_); | |
| 207 MachineFlags::const_iterator iter = machine_flags_.find(name); | |
| 208 if (iter == machine_flags_.end()) { | |
| 209 if (base::SysInfo::IsRunningOnChromeOS()) | |
| 210 LOG(ERROR) << "Requested machine flag not found: " << name; | |
| 211 return false; | |
| 212 } | |
| 213 *result = iter->second; | |
| 214 return true; | |
| 215 } | |
| 216 | |
| 217 void StatisticsProviderImpl::MachineStatisticsLoaded( | |
| 218 NameValuePairsParser::NameValueMap* name_value_map, | |
| 219 bool load_oem_manifest) { | |
| 220 base::AutoLock lock(lock_); | |
| 221 | |
| 222 machine_info_.swap(*name_value_map); | |
| 223 // Ensure that the hardware class key is present with the expected | |
| 224 // key name, and if it couldn't be retrieved, that the value is "unknown". | |
| 225 std::string hardware_class = machine_info_[kHardwareClassCrosSystemKey]; | |
| 226 if (hardware_class.empty() || hardware_class == kCrosSystemUnknownValue) | |
| 227 machine_info_[kHardwareClassKey] = kUnknownHardwareClass; | |
| 228 else | |
| 229 machine_info_[kHardwareClassKey] = hardware_class; | |
| 230 | |
| 231 if (load_oem_manifest) { | |
| 232 VLOG(1) << "Started loading OEM Manifest"; | |
| 233 KioskOemManifestParser::Manifest* oem_manifest = | |
| 234 new KioskOemManifestParser::Manifest; | |
| 235 base::PostTaskAndReplyWithResult( | |
| 236 io_task_runner_.get(), | |
| 237 FROM_HERE, | |
| 238 base::Bind(&KioskOemManifestParser::Load, | |
| 239 base::FilePath(kOemManifestFilePath), | |
| 240 oem_manifest), | |
| 241 base::Bind(&StatisticsProviderImpl::OemManifestLoaded, | |
| 242 weak_ptr_factory_.GetWeakPtr(), | |
| 243 base::Owned(oem_manifest))); | |
| 244 return; | |
| 245 } | |
| 246 // Finished loading the statistics. | |
| 247 on_statistics_loaded_.Signal(); | |
| 248 VLOG(1) << "Finished loading statistics"; | |
| 249 } | |
| 250 | |
| 251 void StatisticsProviderImpl::OemManifestLoaded( | |
| 252 KioskOemManifestParser::Manifest* oem_manifest, | |
| 253 bool success) { | |
| 254 if (success) { | |
| 255 machine_info_[kOemDeviceRequisitionKey] = oem_manifest->device_requisition; | |
| 256 machine_flags_[kOemIsEnterpriseManagedKey] = | |
| 257 oem_manifest->enterprise_managed; | |
| 258 machine_flags_[kOemCanExitEnterpriseEnrollmentKey] = | |
| 259 oem_manifest->can_exit_enrollment; | |
| 260 machine_flags_[kOemKeyboardDrivenOobeKey] = | |
| 261 oem_manifest->keyboard_driven_oobe; | |
| 262 } | |
| 263 // Finished loading the statistics. | |
| 264 on_statistics_loaded_.Signal(); | |
| 265 VLOG(1) << "Finished loading statistics and OEM Manifest"; | |
| 266 } | |
| 267 | |
| 268 // The stub StatisticsProvider implementation used on Linux desktop. | |
| 269 class StatisticsProviderStubImpl : public StatisticsProviderImpl { | |
| 270 public: | |
| 271 explicit StatisticsProviderStubImpl( | |
| 272 const scoped_refptr<base::TaskRunner>& io_task_runner) | |
| 273 : StatisticsProviderImpl(io_task_runner) {} | |
| 274 virtual ~StatisticsProviderStubImpl() {} | |
| 275 | |
| 276 // StatisticsProvider implementation: | |
| 277 virtual void StartLoadingMachineStatistics(bool load_oem_manifest) OVERRIDE { | |
| 278 load_statistics_started_ = true; | |
| 279 if (!load_oem_manifest) { | |
| 280 on_statistics_loaded_.Signal(); | |
| 281 return; | |
| 282 } | |
| 283 | |
| 284 // If kAppOemManifestFile switch is specified, load OEM Manifest file. | |
| 285 CommandLine* command_line = CommandLine::ForCurrentProcess(); | |
| 286 if (!command_line->HasSwitch(switches::kAppOemManifestFile)) { | |
| 287 on_statistics_loaded_.Signal(); | |
| 288 return; | |
| 289 } | |
| 290 KioskOemManifestParser::Manifest* oem_manifest = | |
| 291 new KioskOemManifestParser::Manifest; | |
| 292 base::FilePath file_path = | |
| 293 command_line->GetSwitchValuePath(switches::kAppOemManifestFile); | |
| 294 base::PostTaskAndReplyWithResult( | |
| 295 io_task_runner_.get(), | |
| 296 FROM_HERE, | |
| 297 base::Bind(&KioskOemManifestParser::Load, | |
| 298 base::FilePath(kOemManifestFilePath), | |
| 299 oem_manifest), | |
| 300 base::Bind(&StatisticsProviderImpl::OemManifestLoaded, | |
| 301 weak_ptr_factory_.GetWeakPtr(), | |
| 302 base::Owned(oem_manifest))); | |
| 303 } | |
| 304 | |
| 305 private: | |
| 306 DISALLOW_COPY_AND_ASSIGN(StatisticsProviderStubImpl); | |
| 307 }; | |
| 308 | |
| 309 static StatisticsProvider* g_statistics_provider = NULL; | |
| 310 | |
| 311 // static | |
| 312 void StatisticsProvider::Initialize( | |
| 313 const scoped_refptr<base::TaskRunner>& io_task_runner) { | |
| 314 CHECK(!g_statistics_provider); | |
| 315 if (base::SysInfo::IsRunningOnChromeOS()) { | |
| 316 g_statistics_provider = new StatisticsProviderImpl(io_task_runner); | |
| 317 } else { | |
| 318 g_statistics_provider = new StatisticsProviderStubImpl(io_task_runner); | |
| 319 } | |
| 320 } | |
| 321 | |
| 322 // static | |
| 323 void StatisticsProvider::Shutdown() { | |
| 324 delete g_statistics_provider; | |
| 325 g_statistics_provider = NULL; | |
| 326 } | |
| 327 | |
| 328 StatisticsProvider* StatisticsProvider::GetInstance() { | |
| 329 CHECK(g_statistics_provider); | |
| 330 return g_statistics_provider; | |
| 331 } | |
| 332 | |
| 333 } // namespace system | |
| 334 } // namespace chromeos | |
| OLD | NEW |