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