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/files/file_path.h"
11#include "base/files/file_util.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/sys_info.h"
18#include "base/threading/sequenced_worker_pool.h"
19#include "base/threading/thread.h"
20#include "base/time/time.h"
21#include "chrome/browser/browser_process.h"
22#include "content/public/browser/browser_thread.h"
23
24using content::BrowserThread;
25
26namespace {
27
28// Beginning of line we look for that gives full version number.
29// Format: x.x.xx.x (Developer|Official build extra info) board info
30const char kFullVersionKey[] = "CHROMEOS_RELEASE_DESCRIPTION";
31
32// Same but for short version (x.x.xx.x).
33const char kVersionKey[] = "CHROMEOS_RELEASE_VERSION";
34
35// Beginning of line we look for that gives the firmware version.
36const char kFirmwarePrefix[] = "version";
37
38// File to look for firmware number in.
39const char kPathFirmware[] = "/var/log/bios_info.txt";
40
41// Converts const string* to const string&.
42void VersionLoaderCallbackHelper(
43    base::Callback<void(const std::string&)> callback,
44    const std::string* version) {
45  callback.Run(*version);
46}
47
48}  // namespace
49
50namespace chromeos {
51
52VersionLoader::VersionLoader() : backend_(new Backend()) {}
53
54VersionLoader::~VersionLoader() {}
55
56base::CancelableTaskTracker::TaskId VersionLoader::GetVersion(
57    VersionFormat format,
58    const GetVersionCallback& callback,
59    base::CancelableTaskTracker* tracker) {
60  std::string* version = new std::string();
61  return tracker->PostTaskAndReply(
62      BrowserThread::GetBlockingPool(),
63      FROM_HERE,
64      base::Bind(&Backend::GetVersion, backend_.get(), format, version),
65      base::Bind(&VersionLoaderCallbackHelper, callback, base::Owned(version)));
66}
67
68base::CancelableTaskTracker::TaskId VersionLoader::GetFirmware(
69    const GetFirmwareCallback& callback,
70    base::CancelableTaskTracker* tracker) {
71  std::string* firmware = new std::string();
72  return tracker->PostTaskAndReply(
73      BrowserThread::GetBlockingPool(),
74      FROM_HERE,
75      base::Bind(&Backend::GetFirmware, backend_.get(), firmware),
76      base::Bind(&VersionLoaderCallbackHelper,
77                 callback, base::Owned(firmware)));
78}
79
80// static
81std::string VersionLoader::ParseFirmware(const std::string& contents) {
82  // The file contains lines such as:
83  // vendor           | ...
84  // version          | ...
85  // release_date     | ...
86  // We don't make any assumption that the spaces between "version" and "|" is
87  //   fixed. So we just match kFirmwarePrefix at the start of the line and find
88  //   the first character that is not "|" or space
89
90  std::vector<std::string> lines;
91  base::SplitString(contents, '\n', &lines);
92  for (size_t i = 0; i < lines.size(); ++i) {
93    if (StartsWithASCII(lines[i], kFirmwarePrefix, false)) {
94      std::string str = lines[i].substr(std::string(kFirmwarePrefix).size());
95      size_t found = str.find_first_not_of("| ");
96      if (found != std::string::npos)
97        return str.substr(found);
98    }
99  }
100  return std::string();
101}
102
103void VersionLoader::Backend::GetVersion(VersionFormat format,
104                                        std::string* version) {
105  DCHECK(BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread());
106
107  std::string key = (format == VERSION_FULL) ? kFullVersionKey : kVersionKey;
108  if (!base::SysInfo::GetLsbReleaseValue(key, version)) {
109    LOG_IF(ERROR, base::SysInfo::IsRunningOnChromeOS())
110        << "No LSB version key: " << key;
111    *version = "0.0.0.0";
112  }
113  if (format == VERSION_SHORT_WITH_DATE) {
114    base::Time::Exploded ctime;
115    base::SysInfo::GetLsbReleaseTime().UTCExplode(&ctime);
116    *version += base::StringPrintf("-%02u.%02u.%02u",
117                                   ctime.year % 100,
118                                   ctime.month,
119                                   ctime.day_of_month);
120  }
121}
122
123void VersionLoader::Backend::GetFirmware(std::string* firmware) {
124  DCHECK(BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread());
125
126  std::string contents;
127  const base::FilePath file_path(kPathFirmware);
128  if (base::ReadFileToString(file_path, &contents)) {
129    *firmware = ParseFirmware(contents);
130  }
131}
132
133}  // namespace chromeos
134