Home | History | Annotate | Download | only in base
      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