recovery_component_installer.cc revision cedac228d2dd51db4b79ea1e72c7f249408ee061
12a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
22a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
32a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// found in the LICENSE file.
490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
52a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/component_updater/recovery_component_installer.h"
62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <string>
82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/base_paths.h"
10a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)#include "base/bind.h"
112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/command_line.h"
12ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch#include "base/compiler_specific.h"
132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/file_util.h"
142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/files/file_path.h"
152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/logging.h"
16868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/path_service.h"
17ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch#include "base/prefs/pref_registry_simple.h"
182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/prefs/pref_service.h"
192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/process/launch.h"
202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/strings/string_util.h"
212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/values.h"
222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/component_updater/component_updater_service.h"
232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/common/chrome_paths.h"
242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/common/chrome_version_info.h"
252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/common/pref_names.h"
262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/public/browser/browser_thread.h"
272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)using content::BrowserThread;
292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace component_updater {
312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace {
332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// CRX hash. The extension id is: npdjjkjlcidkjlamlmmdelcjbcpdjocm.
352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const uint8 kSha2Hash[] = {0xdf, 0x39, 0x9a, 0x9b, 0x28, 0x3a, 0x9b, 0x0c,
362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                           0xbc, 0xc3, 0x4b, 0x29, 0x12, 0xf3, 0x9e, 0x2c,
372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                           0x19, 0x7a, 0x71, 0x4b, 0x0a, 0x7c, 0x80, 0x1c,
382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                           0xf6, 0x29, 0x7c, 0x0a, 0x5f, 0xea, 0x67, 0xb7};
392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// File name of the recovery binary on different platforms.
412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const base::FilePath::CharType kRecoveryFileName[] =
422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#if defined(OS_WIN)
432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    FILE_PATH_LITERAL("ChromeRecovery.exe");
442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#else  // OS_LINUX, OS_MACOSX, etc.
452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    FILE_PATH_LITERAL("ChromeRecovery");
46c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#endif
472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const char kRecoveryManifestName[] = "ChromeRecovery";
492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
50ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch}  // namespace
512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)class RecoveryComponentInstaller : public ComponentInstaller {
532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) public:
542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  explicit RecoveryComponentInstaller(const Version& version,
552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                      PrefService* prefs);
562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual ~RecoveryComponentInstaller() {}
587d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
597d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  virtual void OnUpdateError(int error) OVERRIDE;
60ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
6190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  virtual bool Install(const base::DictionaryValue& manifest,
6290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                       const base::FilePath& unpack_path) OVERRIDE;
632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
64c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  virtual bool GetInstalledFile(const std::string& file,
65c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                base::FilePath* installed_file) OVERRIDE;
66ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
67a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch private:
68a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  Version current_version_;
69c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  PrefService* prefs_;
70a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch};
71a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch
72a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)void RecoveryRegisterHelper(ComponentUpdateService* cus, PrefService* prefs) {
73a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
74a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch  Version version(prefs->GetString(prefs::kRecoveryComponentVersion));
75c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!version.IsValid()) {
76ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    NOTREACHED();
77c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return;
78c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
79c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
80ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  CrxComponent recovery;
81c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  recovery.name = "recovery";
82c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  recovery.installer = new RecoveryComponentInstaller(version, prefs);
837d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  recovery.version = version;
847d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  recovery.pk_hash.assign(kSha2Hash, &kSha2Hash[sizeof(kSha2Hash)]);
85ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  if (cus->RegisterComponent(recovery) != ComponentUpdateService::kOk) {
86a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch    NOTREACHED() << "Recovery component registration failed.";
87a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch  }
88a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch}
89ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
9090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void RecoveryUpdateVersionHelper(const Version& version, PrefService* prefs) {
9190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
92c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  prefs->SetString(prefs::kRecoveryComponentVersion, version.GetString());
93a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch}
94a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch
95ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben MurdochRecoveryComponentInstaller::RecoveryComponentInstaller(const Version& version,
96a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch                                                       PrefService* prefs)
97a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch    : current_version_(version), prefs_(prefs) {
98a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch  DCHECK(version.IsValid());
99a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch}
100a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch
101ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdochvoid RecoveryComponentInstaller::OnUpdateError(int error) {
102a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch  NOTREACHED() << "Recovery component update error: " << error;
103a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch}
104a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch
105ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdochbool RecoveryComponentInstaller::Install(const base::DictionaryValue& manifest,
106ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch                                         const base::FilePath& unpack_path) {
107ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  std::string name;
108ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  manifest.GetStringASCII("name", &name);
109ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  if (name != kRecoveryManifestName)
110ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    return false;
111ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  std::string proposed_version;
11290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  manifest.GetStringASCII("version", &proposed_version);
1132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  Version version(proposed_version.c_str());
1147d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  if (!version.IsValid())
1152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
1162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (current_version_.CompareTo(version) >= 0)
1172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
11990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // Passed the basic tests. Copy the installation to a permanent directory.
1202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath path;
1217d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  if (!PathService::Get(chrome::DIR_RECOVERY_BASE, &path))
1222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
1232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  path = path.AppendASCII(version.GetString());
1242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (base::PathExists(path) && !base::DeleteFile(path, true))
1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return false;
1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!base::Move(unpack_path, path)) {
1277d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    DVLOG(1) << "Recovery component move failed.";
1282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
129ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  }
13090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
131a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  base::FilePath main_file = path.Append(kRecoveryFileName);
13290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if (!base::PathExists(main_file))
13390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    return false;
1342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Run the recovery component.
1352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  CommandLine cmdline(main_file);
1362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string arguments;
1372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (manifest.GetStringASCII("x-recovery-args", &arguments))
1382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    cmdline.AppendArg(arguments);
13990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  std::string add_version;
14090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if (manifest.GetStringASCII("x-recovery-add-version", &add_version)) {
14190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    if (add_version == "yes")
14290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      cmdline.AppendSwitchASCII("version", current_version_.GetString());
1432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  current_version_ = version;
1452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (prefs_) {
1462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    BrowserThread::PostTask(
1472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        BrowserThread::UI,
1482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        FROM_HERE,
149a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)        base::Bind(&RecoveryUpdateVersionHelper, version, prefs_));
1502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return base::LaunchProcess(cmdline, base::LaunchOptions(), NULL);
1522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool RecoveryComponentInstaller::GetInstalledFile(
1552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& file,
1567d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    base::FilePath* installed_file) {
1577d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return false;
158ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch}
15990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
16090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void RegisterRecoveryComponent(ComponentUpdateService* cus,
1612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                               PrefService* prefs) {
1622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#if !defined(OS_CHROMEOS)
1632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // We delay execute the registration because we are not required in
1642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // the critical path during browser startup.
1652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  BrowserThread::PostDelayedTask(
166ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      BrowserThread::UI,
1672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      FROM_HERE,
168a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      base::Bind(&RecoveryRegisterHelper, cus, prefs),
1692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::TimeDelta::FromSeconds(6));
1702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#endif
1712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void RegisterPrefsForRecoveryComponent(PrefRegistrySimple* registry) {
1742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  registry->RegisterStringPref(prefs::kRecoveryComponentVersion, "0.0.0.0");
1752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // namespace component_updater
1782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)