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 "base/sys_info.h" 6 7#include <stddef.h> 8#include <stdint.h> 9 10#include "base/environment.h" 11#include "base/files/file.h" 12#include "base/files/file_path.h" 13#include "base/files/file_util.h" 14#include "base/lazy_instance.h" 15#include "base/macros.h" 16#include "base/strings/string_number_conversions.h" 17#include "base/strings/string_piece.h" 18#include "base/strings/string_split.h" 19#include "base/strings/string_tokenizer.h" 20#include "base/strings/string_util.h" 21#include "base/threading/thread_restrictions.h" 22 23namespace base { 24 25namespace { 26 27const char* const kLinuxStandardBaseVersionKeys[] = { 28 "CHROMEOS_RELEASE_VERSION", 29 "GOOGLE_RELEASE", 30 "DISTRIB_RELEASE", 31}; 32 33const char kChromeOsReleaseNameKey[] = "CHROMEOS_RELEASE_NAME"; 34 35const char* const kChromeOsReleaseNames[] = { 36 "Chrome OS", 37 "Chromium OS", 38}; 39 40const char kLinuxStandardBaseReleaseFile[] = "/etc/lsb-release"; 41 42const char kLsbReleaseKey[] = "LSB_RELEASE"; 43const char kLsbReleaseTimeKey[] = "LSB_RELEASE_TIME"; // Seconds since epoch 44 45const char kLsbReleaseSourceKey[] = "lsb-release"; 46const char kLsbReleaseSourceEnv[] = "env"; 47const char kLsbReleaseSourceFile[] = "file"; 48 49class ChromeOSVersionInfo { 50 public: 51 ChromeOSVersionInfo() { 52 Parse(); 53 } 54 55 void Parse() { 56 lsb_release_map_.clear(); 57 major_version_ = 0; 58 minor_version_ = 0; 59 bugfix_version_ = 0; 60 is_running_on_chromeos_ = false; 61 62 std::string lsb_release, lsb_release_time_str; 63 scoped_ptr<Environment> env(Environment::Create()); 64 bool parsed_from_env = 65 env->GetVar(kLsbReleaseKey, &lsb_release) && 66 env->GetVar(kLsbReleaseTimeKey, &lsb_release_time_str); 67 if (parsed_from_env) { 68 double us = 0; 69 if (StringToDouble(lsb_release_time_str, &us)) 70 lsb_release_time_ = Time::FromDoubleT(us); 71 } else { 72 // If the LSB_RELEASE and LSB_RELEASE_TIME environment variables are not 73 // set, fall back to a blocking read of the lsb_release file. This should 74 // only happen in non Chrome OS environments. 75 ThreadRestrictions::ScopedAllowIO allow_io; 76 FilePath path(kLinuxStandardBaseReleaseFile); 77 ReadFileToString(path, &lsb_release); 78 File::Info fileinfo; 79 if (GetFileInfo(path, &fileinfo)) 80 lsb_release_time_ = fileinfo.creation_time; 81 } 82 ParseLsbRelease(lsb_release); 83 // For debugging: 84 lsb_release_map_[kLsbReleaseSourceKey] = 85 parsed_from_env ? kLsbReleaseSourceEnv : kLsbReleaseSourceFile; 86 } 87 88 bool GetLsbReleaseValue(const std::string& key, std::string* value) { 89 SysInfo::LsbReleaseMap::const_iterator iter = lsb_release_map_.find(key); 90 if (iter == lsb_release_map_.end()) 91 return false; 92 *value = iter->second; 93 return true; 94 } 95 96 void GetVersionNumbers(int32_t* major_version, 97 int32_t* minor_version, 98 int32_t* bugfix_version) { 99 *major_version = major_version_; 100 *minor_version = minor_version_; 101 *bugfix_version = bugfix_version_; 102 } 103 104 const Time& lsb_release_time() const { return lsb_release_time_; } 105 const SysInfo::LsbReleaseMap& lsb_release_map() const { 106 return lsb_release_map_; 107 } 108 bool is_running_on_chromeos() const { return is_running_on_chromeos_; } 109 110 private: 111 void ParseLsbRelease(const std::string& lsb_release) { 112 // Parse and cache lsb_release key pairs. There should only be a handful 113 // of entries so the overhead for this will be small, and it can be 114 // useful for debugging. 115 base::StringPairs pairs; 116 SplitStringIntoKeyValuePairs(lsb_release, '=', '\n', &pairs); 117 for (size_t i = 0; i < pairs.size(); ++i) { 118 std::string key, value; 119 TrimWhitespaceASCII(pairs[i].first, TRIM_ALL, &key); 120 TrimWhitespaceASCII(pairs[i].second, TRIM_ALL, &value); 121 if (key.empty()) 122 continue; 123 lsb_release_map_[key] = value; 124 } 125 // Parse the version from the first matching recognized version key. 126 std::string version; 127 for (size_t i = 0; i < arraysize(kLinuxStandardBaseVersionKeys); ++i) { 128 std::string key = kLinuxStandardBaseVersionKeys[i]; 129 if (GetLsbReleaseValue(key, &version) && !version.empty()) 130 break; 131 } 132 StringTokenizer tokenizer(version, "."); 133 if (tokenizer.GetNext()) { 134 StringToInt(StringPiece(tokenizer.token_begin(), tokenizer.token_end()), 135 &major_version_); 136 } 137 if (tokenizer.GetNext()) { 138 StringToInt(StringPiece(tokenizer.token_begin(), tokenizer.token_end()), 139 &minor_version_); 140 } 141 if (tokenizer.GetNext()) { 142 StringToInt(StringPiece(tokenizer.token_begin(), tokenizer.token_end()), 143 &bugfix_version_); 144 } 145 146 // Check release name for Chrome OS. 147 std::string release_name; 148 if (GetLsbReleaseValue(kChromeOsReleaseNameKey, &release_name)) { 149 for (size_t i = 0; i < arraysize(kChromeOsReleaseNames); ++i) { 150 if (release_name == kChromeOsReleaseNames[i]) { 151 is_running_on_chromeos_ = true; 152 break; 153 } 154 } 155 } 156 } 157 158 Time lsb_release_time_; 159 SysInfo::LsbReleaseMap lsb_release_map_; 160 int32_t major_version_; 161 int32_t minor_version_; 162 int32_t bugfix_version_; 163 bool is_running_on_chromeos_; 164}; 165 166static LazyInstance<ChromeOSVersionInfo> 167 g_chrome_os_version_info = LAZY_INSTANCE_INITIALIZER; 168 169ChromeOSVersionInfo& GetChromeOSVersionInfo() { 170 return g_chrome_os_version_info.Get(); 171} 172 173} // namespace 174 175// static 176void SysInfo::OperatingSystemVersionNumbers(int32_t* major_version, 177 int32_t* minor_version, 178 int32_t* bugfix_version) { 179 return GetChromeOSVersionInfo().GetVersionNumbers( 180 major_version, minor_version, bugfix_version); 181} 182 183// static 184const SysInfo::LsbReleaseMap& SysInfo::GetLsbReleaseMap() { 185 return GetChromeOSVersionInfo().lsb_release_map(); 186} 187 188// static 189bool SysInfo::GetLsbReleaseValue(const std::string& key, std::string* value) { 190 return GetChromeOSVersionInfo().GetLsbReleaseValue(key, value); 191} 192 193// static 194std::string SysInfo::GetLsbReleaseBoard() { 195 const char kMachineInfoBoard[] = "CHROMEOS_RELEASE_BOARD"; 196 std::string board; 197 if (!GetLsbReleaseValue(kMachineInfoBoard, &board)) 198 board = "unknown"; 199 return board; 200} 201 202// static 203Time SysInfo::GetLsbReleaseTime() { 204 return GetChromeOSVersionInfo().lsb_release_time(); 205} 206 207// static 208bool SysInfo::IsRunningOnChromeOS() { 209 return GetChromeOSVersionInfo().is_running_on_chromeos(); 210} 211 212// static 213void SysInfo::SetChromeOSVersionInfoForTest(const std::string& lsb_release, 214 const Time& lsb_release_time) { 215 scoped_ptr<Environment> env(Environment::Create()); 216 env->SetVar(kLsbReleaseKey, lsb_release); 217 env->SetVar(kLsbReleaseTimeKey, 218 DoubleToString(lsb_release_time.ToDoubleT())); 219 g_chrome_os_version_info.Get().Parse(); 220} 221 222} // namespace base 223