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