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/file_path.h"
     10 #include "base/file_util.h"
     11 #include "base/message_loop.h"
     12 #include "base/string_split.h"
     13 #include "base/string_util.h"
     14 #include "base/threading/thread.h"
     15 #include "base/time.h"
     16 #include "chrome/browser/browser_process.h"
     17 #include "content/browser/browser_thread.h"
     18 
     19 namespace chromeos {
     20 
     21 // File to look for version number in.
     22 static const char kPathVersion[] = "/etc/lsb-release";
     23 
     24 // TODO(rkc): Remove once we change over the Chrome OS version format.
     25 // Done for http://code.google.com/p/chromium-os/issues/detail?id=15789
     26 static const size_t kTrimVersion = 2;
     27 
     28 // File to look for firmware number in.
     29 static const char kPathFirmware[] = "/var/log/bios_info.txt";
     30 
     31 VersionLoader::VersionLoader() : backend_(new Backend()) {
     32 }
     33 
     34 // Beginning of line we look for that gives full version number.
     35 // Format: x.x.xx.x (Developer|Official build extra info) board info
     36 // static
     37 const char VersionLoader::kFullVersionPrefix[] =
     38     "CHROMEOS_RELEASE_DESCRIPTION=";
     39 
     40 // Same but for short version (x.x.xx.x).
     41 // static
     42 const char VersionLoader::kVersionPrefix[] = "CHROMEOS_RELEASE_VERSION=";
     43 
     44 // Beginning of line we look for that gives the firmware version.
     45 const char VersionLoader::kFirmwarePrefix[] = "version";
     46 
     47 VersionLoader::Handle VersionLoader::GetVersion(
     48     CancelableRequestConsumerBase* consumer,
     49     VersionLoader::GetVersionCallback* callback,
     50     VersionFormat format) {
     51   if (!g_browser_process->file_thread()) {
     52     // This should only happen if Chrome is shutting down, so we don't do
     53     // anything.
     54     return 0;
     55   }
     56 
     57   scoped_refptr<GetVersionRequest> request(new GetVersionRequest(callback));
     58   AddRequest(request, consumer);
     59 
     60   g_browser_process->file_thread()->message_loop()->PostTask(
     61       FROM_HERE,
     62       NewRunnableMethod(backend_.get(), &Backend::GetVersion, request, format));
     63   return request->handle();
     64 }
     65 
     66 VersionLoader::Handle VersionLoader::GetFirmware(
     67     CancelableRequestConsumerBase* consumer,
     68     VersionLoader::GetFirmwareCallback* callback) {
     69   if (!g_browser_process->file_thread()) {
     70     // This should only happen if Chrome is shutting down, so we don't do
     71     // anything.
     72     return 0;
     73   }
     74 
     75   scoped_refptr<GetFirmwareRequest> request(new GetFirmwareRequest(callback));
     76   AddRequest(request, consumer);
     77 
     78   g_browser_process->file_thread()->message_loop()->PostTask(
     79       FROM_HERE,
     80       NewRunnableMethod(backend_.get(), &Backend::GetFirmware, request));
     81   return request->handle();
     82 }
     83 
     84 void VersionLoader::EnablePlatformVersions(bool enable) {
     85   backend_.get()->set_parse_as_platform(enable);
     86 }
     87 
     88 // static
     89 std::string VersionLoader::ParseVersion(const std::string& contents,
     90                                         const std::string& prefix) {
     91   // The file contains lines such as:
     92   // XXX=YYY
     93   // AAA=ZZZ
     94   // Split the lines and look for the one that starts with prefix. The version
     95   // file is small, which is why we don't try and be tricky.
     96   std::vector<std::string> lines;
     97   base::SplitString(contents, '\n', &lines);
     98   for (size_t i = 0; i < lines.size(); ++i) {
     99     if (StartsWithASCII(lines[i], prefix, false)) {
    100       std::string version = lines[i].substr(std::string(prefix).size());
    101       if (version.size() > 1 && version[0] == '"' &&
    102           version[version.size() - 1] == '"') {
    103         // Trim trailing and leading quotes.
    104         version = version.substr(1, version.size() - 2);
    105       }
    106       return version;
    107     }
    108   }
    109   return std::string();
    110 }
    111 
    112 // static
    113 std::string VersionLoader::ParseFirmware(const std::string& contents) {
    114   // The file contains lines such as:
    115   // vendor           | ...
    116   // version          | ...
    117   // release_date     | ...
    118   // We don't make any assumption that the spaces between "version" and "|" is
    119   //   fixed. So we just match kFirmwarePrefix at the start of the line and find
    120   //   the first character that is not "|" or space
    121 
    122   std::vector<std::string> lines;
    123   base::SplitString(contents, '\n', &lines);
    124   for (size_t i = 0; i < lines.size(); ++i) {
    125     if (StartsWithASCII(lines[i], kFirmwarePrefix, false)) {
    126       std::string str = lines[i].substr(std::string(kFirmwarePrefix).size());
    127       size_t found = str.find_first_not_of("| ");
    128       if (found != std::string::npos)
    129         return str.substr(found);
    130     }
    131   }
    132   return std::string();
    133 }
    134 
    135 void VersionLoader::Backend::GetVersion(
    136     scoped_refptr<GetVersionRequest> request,
    137     VersionFormat format) {
    138   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
    139   if (request->canceled())
    140     return;
    141 
    142   std::string version;
    143   std::string contents;
    144   const FilePath file_path(kPathVersion);
    145   if (file_util::ReadFileToString(file_path, &contents)) {
    146     version = ParseVersion(
    147         contents,
    148         (format == VERSION_FULL) ? kFullVersionPrefix : kVersionPrefix);
    149 
    150     // TODO(rkc): Fix this once we move to xx.yyy version numbers for Chrome OS
    151     // instead of 0.xx.yyy
    152     // Done for http://code.google.com/p/chromium-os/issues/detail?id=15789
    153     if (parse_as_platform_) {
    154       if (version.size() > kTrimVersion) {
    155         version = version.substr(kTrimVersion);
    156         // Strip the major version.
    157         size_t first_dot = version.find(".");
    158         if (first_dot != std::string::npos) {
    159           version = version.substr(first_dot + 1);
    160         }
    161       }
    162     }
    163   }
    164 
    165   if (format == VERSION_SHORT_WITH_DATE) {
    166     base::PlatformFileInfo fileinfo;
    167     if (file_util::GetFileInfo(file_path, &fileinfo)) {
    168       base::Time::Exploded ctime;
    169       fileinfo.creation_time.UTCExplode(&ctime);
    170       version += StringPrintf("-%02u.%02u.%02u",
    171                               ctime.year % 100,
    172                               ctime.month,
    173                               ctime.day_of_month);
    174     }
    175   }
    176 
    177   request->ForwardResult(GetVersionCallback::TupleType(request->handle(),
    178                                                        version));
    179 }
    180 
    181 void VersionLoader::Backend::GetFirmware(
    182     scoped_refptr<GetFirmwareRequest> request) {
    183   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
    184   if (request->canceled())
    185     return;
    186 
    187   std::string firmware;
    188   std::string contents;
    189   const FilePath file_path(kPathFirmware);
    190   if (file_util::ReadFileToString(file_path, &contents)) {
    191     firmware = ParseFirmware(contents);
    192   }
    193 
    194   request->ForwardResult(GetFirmwareCallback::TupleType(request->handle(),
    195                                                         firmware));
    196 }
    197 
    198 }  // namespace chromeos
    199