15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2011 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/chromeos/version_loader.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <vector>
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h"
102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/files/file_path.h"
111320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "base/files/file_util.h"
122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/location.h"
139ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch#include "base/message_loop/message_loop.h"
142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/strings/string_split.h"
155e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles)#include "base/strings/string_util.h"
165e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles)#include "base/strings/stringprintf.h"
174e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "base/sys_info.h"
182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/threading/sequenced_worker_pool.h"
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/threading/thread.h"
20eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "base/time/time.h"
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/browser_process.h"
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/browser_thread.h"
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using content::BrowserThread;
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace {
272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
284e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// Beginning of line we look for that gives full version number.
294e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// Format: x.x.xx.x (Developer|Official build extra info) board info
304e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)const char kFullVersionKey[] = "CHROMEOS_RELEASE_DESCRIPTION";
314e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
324e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// Same but for short version (x.x.xx.x).
334e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)const char kVersionKey[] = "CHROMEOS_RELEASE_VERSION";
344e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
354e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// Beginning of line we look for that gives the firmware version.
364e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)const char kFirmwarePrefix[] = "version";
374e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
384e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// File to look for firmware number in.
394e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)const char kPathFirmware[] = "/var/log/bios_info.txt";
404e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Converts const string* to const string&.
422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void VersionLoaderCallbackHelper(
432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::Callback<void(const std::string&)> callback,
442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string* version) {
452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  callback.Run(*version);
462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // namespace
492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace chromeos {
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)VersionLoader::VersionLoader() : backend_(new Backend()) {}
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)VersionLoader::~VersionLoader() {}
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)base::CancelableTaskTracker::TaskId VersionLoader::GetVersion(
572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    VersionFormat format,
582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const GetVersionCallback& callback,
595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    base::CancelableTaskTracker* tracker) {
602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string* version = new std::string();
612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return tracker->PostTaskAndReply(
622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      BrowserThread::GetBlockingPool(),
632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      FROM_HERE,
642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::Bind(&Backend::GetVersion, backend_.get(), format, version),
652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::Bind(&VersionLoaderCallbackHelper, callback, base::Owned(version)));
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)base::CancelableTaskTracker::TaskId VersionLoader::GetFirmware(
692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const GetFirmwareCallback& callback,
705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    base::CancelableTaskTracker* tracker) {
712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string* firmware = new std::string();
722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return tracker->PostTaskAndReply(
732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      BrowserThread::GetBlockingPool(),
742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      FROM_HERE,
752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::Bind(&Backend::GetFirmware, backend_.get(), firmware),
762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::Bind(&VersionLoaderCallbackHelper,
772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                 callback, base::Owned(firmware)));
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::string VersionLoader::ParseFirmware(const std::string& contents) {
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The file contains lines such as:
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // vendor           | ...
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // version          | ...
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // release_date     | ...
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We don't make any assumption that the spaces between "version" and "|" is
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //   fixed. So we just match kFirmwarePrefix at the start of the line and find
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //   the first character that is not "|" or space
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<std::string> lines;
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::SplitString(contents, '\n', &lines);
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < lines.size(); ++i) {
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (StartsWithASCII(lines[i], kFirmwarePrefix, false)) {
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      std::string str = lines[i].substr(std::string(kFirmwarePrefix).size());
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      size_t found = str.find_first_not_of("| ");
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (found != std::string::npos)
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return str.substr(found);
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return std::string();
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void VersionLoader::Backend::GetVersion(VersionFormat format,
1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                        std::string* version) {
1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread());
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1074e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  std::string key = (format == VERSION_FULL) ? kFullVersionKey : kVersionKey;
1084e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (!base::SysInfo::GetLsbReleaseValue(key, version)) {
1094e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    LOG_IF(ERROR, base::SysInfo::IsRunningOnChromeOS())
1104e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        << "No LSB version key: " << key;
1114e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    *version = "0.0.0.0";
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (format == VERSION_SHORT_WITH_DATE) {
1144e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    base::Time::Exploded ctime;
1154e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    base::SysInfo::GetLsbReleaseTime().UTCExplode(&ctime);
1164e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    *version += base::StringPrintf("-%02u.%02u.%02u",
1174e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                                   ctime.year % 100,
1184e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                                   ctime.month,
1194e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                                   ctime.day_of_month);
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void VersionLoader::Backend::GetFirmware(std::string* firmware) {
1242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread());
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string contents;
1272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  const base::FilePath file_path(kPathFirmware);
12858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  if (base::ReadFileToString(file_path, &contents)) {
1292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    *firmware = ParseFirmware(contents);
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace chromeos
134