sys_info_chromeos.cc revision a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7
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
19namespace base {
20
21namespace {
22
23const char* kLinuxStandardBaseVersionKeys[] = {
24  "CHROMEOS_RELEASE_VERSION",
25  "GOOGLE_RELEASE",
26  "DISTRIB_RELEASE",
27};
28
29const char kChromeOsReleaseNameKey[] = "CHROMEOS_RELEASE_NAME";
30
31const char* const kChromeOsReleaseNames[] = {
32  "Chrome OS",
33  "Chromium OS",
34};
35
36const char kLinuxStandardBaseReleaseFile[] = "/etc/lsb-release";
37
38const char kLsbReleaseKey[] = "LSB_RELEASE";
39const char kLsbReleaseTimeKey[] = "LSB_RELEASE_TIME";  // Seconds since epoch
40
41const char kLsbReleaseSourceKey[] = "lsb-release";
42const char kLsbReleaseSourceEnv[] = "env";
43const char kLsbReleaseSourceFile[] = "file";
44
45class 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
162static LazyInstance<ChromeOSVersionInfo>
163    g_chrome_os_version_info = LAZY_INSTANCE_INITIALIZER;
164
165ChromeOSVersionInfo& GetChromeOSVersionInfo() {
166  return g_chrome_os_version_info.Get();
167}
168
169}  // namespace
170
171// static
172void 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
180const SysInfo::LsbReleaseMap& SysInfo::GetLsbReleaseMap() {
181  return GetChromeOSVersionInfo().lsb_release_map();
182}
183
184// static
185bool SysInfo::GetLsbReleaseValue(const std::string& key, std::string* value) {
186  return GetChromeOSVersionInfo().GetLsbReleaseValue(key, value);
187}
188
189// static
190std::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
199Time SysInfo::GetLsbReleaseTime() {
200  return GetChromeOSVersionInfo().lsb_release_time();
201}
202
203// static
204bool SysInfo::IsRunningOnChromeOS() {
205  return GetChromeOSVersionInfo().is_running_on_chromeos();
206}
207
208// static
209void 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