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_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