Home | History | Annotate | Download | only in chromeos
      1 // Copyright (c) 2011 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 "chrome/browser/chromeos/version_loader.h"
      6 
      7 #include <vector>
      8 
      9 #include "base/bind.h"
     10 #include "base/file_util.h"
     11 #include "base/files/file_path.h"
     12 #include "base/location.h"
     13 #include "base/message_loop/message_loop.h"
     14 #include "base/strings/string_split.h"
     15 #include "base/strings/string_util.h"
     16 #include "base/strings/stringprintf.h"
     17 #include "base/threading/sequenced_worker_pool.h"
     18 #include "base/threading/thread.h"
     19 #include "base/time/time.h"
     20 #include "chrome/browser/browser_process.h"
     21 #include "content/public/browser/browser_thread.h"
     22 
     23 using content::BrowserThread;
     24 
     25 namespace {
     26 
     27 // Converts const string* to const string&.
     28 void VersionLoaderCallbackHelper(
     29     base::Callback<void(const std::string&)> callback,
     30     const std::string* version) {
     31   callback.Run(*version);
     32 }
     33 
     34 }  // namespace
     35 
     36 namespace chromeos {
     37 
     38 // File to look for version number in.
     39 static const char kPathVersion[] = "/etc/lsb-release";
     40 
     41 // File to look for firmware number in.
     42 static const char kPathFirmware[] = "/var/log/bios_info.txt";
     43 
     44 VersionLoader::VersionLoader() : backend_(new Backend()) {}
     45 
     46 VersionLoader::~VersionLoader() {}
     47 
     48 // Beginning of line we look for that gives full version number.
     49 // Format: x.x.xx.x (Developer|Official build extra info) board info
     50 // static
     51 const char VersionLoader::kFullVersionPrefix[] =
     52     "CHROMEOS_RELEASE_DESCRIPTION=";
     53 
     54 // Same but for short version (x.x.xx.x).
     55 // static
     56 const char VersionLoader::kVersionPrefix[] = "CHROMEOS_RELEASE_VERSION=";
     57 
     58 // Beginning of line we look for that gives the firmware version.
     59 const char VersionLoader::kFirmwarePrefix[] = "version";
     60 
     61 CancelableTaskTracker::TaskId VersionLoader::GetVersion(
     62     VersionFormat format,
     63     const GetVersionCallback& callback,
     64     CancelableTaskTracker* tracker) {
     65   std::string* version = new std::string();
     66   return tracker->PostTaskAndReply(
     67       BrowserThread::GetBlockingPool(),
     68       FROM_HERE,
     69       base::Bind(&Backend::GetVersion, backend_.get(), format, version),
     70       base::Bind(&VersionLoaderCallbackHelper, callback, base::Owned(version)));
     71 }
     72 
     73 CancelableTaskTracker::TaskId VersionLoader::GetFirmware(
     74     const GetFirmwareCallback& callback,
     75     CancelableTaskTracker* tracker) {
     76   std::string* firmware = new std::string();
     77   return tracker->PostTaskAndReply(
     78       BrowserThread::GetBlockingPool(),
     79       FROM_HERE,
     80       base::Bind(&Backend::GetFirmware, backend_.get(), firmware),
     81       base::Bind(&VersionLoaderCallbackHelper,
     82                  callback, base::Owned(firmware)));
     83 }
     84 
     85 // static
     86 std::string VersionLoader::ParseVersion(const std::string& contents,
     87                                         const std::string& prefix) {
     88   // The file contains lines such as:
     89   // XXX=YYY
     90   // AAA=ZZZ
     91   // Split the lines and look for the one that starts with prefix. The version
     92   // file is small, which is why we don't try and be tricky.
     93   std::vector<std::string> lines;
     94   base::SplitString(contents, '\n', &lines);
     95   for (size_t i = 0; i < lines.size(); ++i) {
     96     if (StartsWithASCII(lines[i], prefix, false)) {
     97       std::string version = lines[i].substr(std::string(prefix).size());
     98       if (version.size() > 1 && version[0] == '"' &&
     99           version[version.size() - 1] == '"') {
    100         // Trim trailing and leading quotes.
    101         version = version.substr(1, version.size() - 2);
    102       }
    103       return version;
    104     }
    105   }
    106   return std::string();
    107 }
    108 
    109 // static
    110 std::string VersionLoader::ParseFirmware(const std::string& contents) {
    111   // The file contains lines such as:
    112   // vendor           | ...
    113   // version          | ...
    114   // release_date     | ...
    115   // We don't make any assumption that the spaces between "version" and "|" is
    116   //   fixed. So we just match kFirmwarePrefix at the start of the line and find
    117   //   the first character that is not "|" or space
    118 
    119   std::vector<std::string> lines;
    120   base::SplitString(contents, '\n', &lines);
    121   for (size_t i = 0; i < lines.size(); ++i) {
    122     if (StartsWithASCII(lines[i], kFirmwarePrefix, false)) {
    123       std::string str = lines[i].substr(std::string(kFirmwarePrefix).size());
    124       size_t found = str.find_first_not_of("| ");
    125       if (found != std::string::npos)
    126         return str.substr(found);
    127     }
    128   }
    129   return std::string();
    130 }
    131 
    132 void VersionLoader::Backend::GetVersion(VersionFormat format,
    133                                         std::string* version) {
    134   DCHECK(BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread());
    135 
    136   std::string contents;
    137   const base::FilePath file_path(kPathVersion);
    138   if (file_util::ReadFileToString(file_path, &contents)) {
    139     *version = ParseVersion(
    140         contents,
    141         (format == VERSION_FULL) ? kFullVersionPrefix : kVersionPrefix);
    142   }
    143 
    144   if (format == VERSION_SHORT_WITH_DATE) {
    145     base::PlatformFileInfo fileinfo;
    146     if (file_util::GetFileInfo(file_path, &fileinfo)) {
    147       base::Time::Exploded ctime;
    148       fileinfo.creation_time.UTCExplode(&ctime);
    149       *version += base::StringPrintf("-%02u.%02u.%02u",
    150                                      ctime.year % 100,
    151                                      ctime.month,
    152                                      ctime.day_of_month);
    153     }
    154   }
    155 }
    156 
    157 void VersionLoader::Backend::GetFirmware(std::string* firmware) {
    158   DCHECK(BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread());
    159 
    160   std::string contents;
    161   const base::FilePath file_path(kPathFirmware);
    162   if (file_util::ReadFileToString(file_path, &contents)) {
    163     *firmware = ParseFirmware(contents);
    164   }
    165 }
    166 
    167 }  // namespace chromeos
    168