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