• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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:
ChromeOSVersionInfo()48   ChromeOSVersionInfo() {
49     Parse();
50   }
51 
Parse()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 
GetLsbReleaseValue(const std::string & key,std::string * value)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 
GetVersionNumbers(int32 * major_version,int32 * minor_version,int32 * bugfix_version)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 
lsb_release_time() const101   const Time& lsb_release_time() const { return lsb_release_time_; }
lsb_release_map() const102   const SysInfo::LsbReleaseMap& lsb_release_map() const {
103     return lsb_release_map_;
104   }
is_running_on_chromeos() const105   bool is_running_on_chromeos() const { return is_running_on_chromeos_; }
106 
107  private:
ParseLsbRelease(const std::string & lsb_release)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 
GetChromeOSVersionInfo()166 ChromeOSVersionInfo& GetChromeOSVersionInfo() {
167   return g_chrome_os_version_info.Get();
168 }
169 
170 }  // namespace
171 
172 // static
OperatingSystemVersionNumbers(int32 * major_version,int32 * minor_version,int32 * bugfix_version)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
GetLsbReleaseMap()181 const SysInfo::LsbReleaseMap& SysInfo::GetLsbReleaseMap() {
182   return GetChromeOSVersionInfo().lsb_release_map();
183 }
184 
185 // static
GetLsbReleaseValue(const std::string & key,std::string * value)186 bool SysInfo::GetLsbReleaseValue(const std::string& key, std::string* value) {
187   return GetChromeOSVersionInfo().GetLsbReleaseValue(key, value);
188 }
189 
190 // static
GetLsbReleaseBoard()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
GetLsbReleaseTime()200 Time SysInfo::GetLsbReleaseTime() {
201   return GetChromeOSVersionInfo().lsb_release_time();
202 }
203 
204 // static
IsRunningOnChromeOS()205 bool SysInfo::IsRunningOnChromeOS() {
206   return GetChromeOSVersionInfo().is_running_on_chromeos();
207 }
208 
209 // static
SetChromeOSVersionInfoForTest(const std::string & lsb_release,const Time & lsb_release_time)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