Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(3787)

Unified Diff: chrome/browser/component_updater/recovery_component_installer.cc

Issue 321473003: Elevated install of recovery component (component update part) (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Initial upload Created 6 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: chrome/browser/component_updater/recovery_component_installer.cc
diff --git a/chrome/browser/component_updater/recovery_component_installer.cc b/chrome/browser/component_updater/recovery_component_installer.cc
index 4baa3666db5b1d6e3a8e2e4ab269c5ae4fb8d7f7..bad65945e347f2846726b790ec95614a7a9ff157 100644
--- a/chrome/browser/component_updater/recovery_component_installer.cc
+++ b/chrome/browser/component_updater/recovery_component_installer.cc
@@ -13,12 +13,15 @@
#include "base/file_util.h"
#include "base/files/file_path.h"
#include "base/logging.h"
+#include "base/memory/singleton.h"
#include "base/path_service.h"
#include "base/prefs/pref_registry_simple.h"
#include "base/prefs/pref_service.h"
+#include "base/process/kill.h"
#include "base/process/launch.h"
#include "base/strings/string_util.h"
#include "base/values.h"
+#include "chrome/browser/component_updater/component_unpacker.h"
#include "chrome/browser/component_updater/component_updater_service.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_version_info.h"
@@ -47,12 +50,21 @@ const base::FilePath::CharType kRecoveryFileName[] =
const char kRecoveryManifestName[] = "ChromeRecovery";
+// This is a contract between ChromeRecovery and this installer for the
+// meaning of ChromeRecovery process exit code.
+enum ChromeRecvoeryExitCode {
+ EXIT_CODE_RECOVERY_SUCCEEDED = 0,
+ EXIT_CODE_RECOVERY_SKIPPED = 1,
+ EXIT_CODE_ELEVATION_NEEDED = 2,
+};
+
} // namespace
class RecoveryComponentInstaller : public ComponentInstaller {
public:
- explicit RecoveryComponentInstaller(const Version& version,
- PrefService* prefs);
+ RecoveryComponentInstaller(const Version& version,
+ PrefService* prefs,
+ bool elevated_install);
virtual ~RecoveryComponentInstaller() {}
@@ -61,15 +73,53 @@ class RecoveryComponentInstaller : public ComponentInstaller {
virtual bool Install(const base::DictionaryValue& manifest,
const base::FilePath& unpack_path) OVERRIDE;
+ virtual void OnInstallError(
+ const InstallerSourceSerializer& serializer) OVERRIDE;
+
virtual bool GetInstalledFile(const std::string& file,
base::FilePath* installed_file) OVERRIDE;
private:
+ static void DoneSaveInstallSourceInfo(PrefService* prefs, bool result);
+
Version current_version_;
PrefService* prefs_;
+ bool elevated_install_;
+ int installer_exit_code_;
+};
+
+class ElevatedInstallWrapper {
+ public:
+ static ElevatedInstallWrapper* GetInstance();
+ void SaveInstallSourceInfo(const InstallerSourceSerializer& serializer,
+ const base::Callback<void(bool)>& callback);
+
+ void Install(PrefService* prefs, bool elevation_allowed,
+ const base::Closure& callback);
+
+ private:
+ friend struct DefaultSingletonTraits<ElevatedInstallWrapper>;
+
+ ElevatedInstallWrapper();
+
+ bool DoSaveInstallSourceInfo(const InstallerSourceSerializer& serializer);
+
+ void DoInstall(PrefService* prefs, const Version& version);
+ void DoneInstall(ComponentUnpacker::Error error, int extended_error);
+
+ static base::FilePath GetInstallerBackupPath();
+
+ PrefService* prefs_;
+ scoped_refptr<ComponentUnpacker> unpacker_;
+ scoped_ptr<RecoveryComponentInstaller> rc_installer_;
+
+ scoped_refptr<base::SequencedTaskRunner> blocking_task_runner_;
+
+ DISALLOW_COPY_AND_ASSIGN(ElevatedInstallWrapper);
};
-void RecoveryRegisterHelper(ComponentUpdateService* cus, PrefService* prefs) {
+void RecoveryRegisterHelper(ComponentUpdateService* cus,
+ PrefService* prefs) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
Version version(prefs->GetString(prefs::kRecoveryComponentVersion));
if (!version.IsValid()) {
@@ -79,7 +129,7 @@ void RecoveryRegisterHelper(ComponentUpdateService* cus, PrefService* prefs) {
CrxComponent recovery;
recovery.name = "recovery";
- recovery.installer = new RecoveryComponentInstaller(version, prefs);
+ recovery.installer = new RecoveryComponentInstaller(version, prefs, false);
recovery.version = version;
recovery.pk_hash.assign(kSha2Hash, &kSha2Hash[sizeof(kSha2Hash)]);
if (cus->RegisterComponent(recovery) != ComponentUpdateService::kOk) {
@@ -92,9 +142,17 @@ void RecoveryUpdateVersionHelper(const Version& version, PrefService* prefs) {
prefs->SetString(prefs::kRecoveryComponentVersion, version.GetString());
}
-RecoveryComponentInstaller::RecoveryComponentInstaller(const Version& version,
- PrefService* prefs)
- : current_version_(version), prefs_(prefs) {
+void RecoveryUpdateElevationHelper(bool needs_elevation, PrefService* prefs) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ prefs->SetBoolean(prefs::kRecoveryComponentNeedsElevation, needs_elevation);
+}
+
+RecoveryComponentInstaller::RecoveryComponentInstaller(
+ const Version& version, PrefService* prefs, bool elevated_install)
+ : current_version_(version),
+ prefs_(prefs),
+ elevated_install_(elevated_install),
+ installer_exit_code_(0) {
DCHECK(version.IsValid());
}
@@ -115,23 +173,11 @@ bool RecoveryComponentInstaller::Install(const base::DictionaryValue& manifest,
return false;
if (current_version_.CompareTo(version) >= 0)
return false;
-
- // Passed the basic tests. Copy the installation to a permanent directory.
- base::FilePath path;
- if (!PathService::Get(chrome::DIR_RECOVERY_BASE, &path))
- return false;
- path = path.AppendASCII(version.GetString());
- if (base::PathExists(path) && !base::DeleteFile(path, true))
- return false;
- if (!base::Move(unpack_path, path)) {
- DVLOG(1) << "Recovery component move failed.";
- return false;
- }
-
- base::FilePath main_file = path.Append(kRecoveryFileName);
+ base::FilePath main_file = unpack_path.Append(kRecoveryFileName);
if (!base::PathExists(main_file))
return false;
- // Run the recovery component.
+ // Passed the basic tests. The installation continues with the
+ // recovery component itself running from the temp directory.
CommandLine cmdline(main_file);
std::string arguments;
if (manifest.GetStringASCII("x-recovery-args", &arguments))
@@ -143,20 +189,141 @@ bool RecoveryComponentInstaller::Install(const base::DictionaryValue& manifest,
}
current_version_ = version;
if (prefs_) {
- BrowserThread::PostTask(
- BrowserThread::UI,
- FROM_HERE,
+ BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
base::Bind(&RecoveryUpdateVersionHelper, version, prefs_));
}
- return base::LaunchProcess(cmdline, base::LaunchOptions(), NULL);
+
+ if (elevated_install_) {
+ return base::LaunchElevatedProcess(cmdline, base::LaunchOptions(), NULL);
+ }
+
+ base::ProcessHandle process_handle;
+ if (!base::LaunchProcess(cmdline, base::LaunchOptions(), &process_handle)) {
+ return false;
+ }
+
+ installer_exit_code_ = 0;
+ const base::TimeDelta kMaxWaitTime = base::TimeDelta::FromSeconds(60);
+ if (!base::WaitForExitCodeWithTimeout(process_handle,
+ &installer_exit_code_,
+ kMaxWaitTime)) {
+ // Ensure that the process terminates.
+ base::KillProcess(process_handle, -1, true);
+ return false;
+ }
+
+ return true;
+}
+
+void RecoveryComponentInstaller::OnInstallError(
+ const InstallerSourceSerializer& serializer) {
+ if (installer_exit_code_ == EXIT_CODE_ELEVATION_NEEDED && prefs_) {
+ ElevatedInstallWrapper::GetInstance()->SaveInstallSourceInfo(
+ serializer,
+ base::Bind(&RecoveryComponentInstaller::DoneSaveInstallSourceInfo,
+ prefs_));
+ }
}
bool RecoveryComponentInstaller::GetInstalledFile(
- const std::string& file,
- base::FilePath* installed_file) {
+ const std::string& file, base::FilePath* installed_file) {
return false;
}
+void RecoveryComponentInstaller::DoneSaveInstallSourceInfo(PrefService* prefs,
+ bool result) {
+ if (!result) {
+ DLOG(WARNING) << "Failed to save CRX file for elevated install.";
+ return;
+ }
+
+ // Set a flag in the preference so UpgradeDetector can detect and notify user.
+ BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
+ base::Bind(&RecoveryUpdateElevationHelper, true, prefs));
+}
+
+ElevatedInstallWrapper::ElevatedInstallWrapper() : prefs_(NULL) {
+ // |blocking_task_runner_| is responsbile for elevated install of recovery
+ // component and other related file operations (namely installer source backup
+ // and cleanup).
+ blocking_task_runner_ = BrowserThread::GetBlockingPool()->
+ GetSequencedTaskRunnerWithShutdownBehavior(
+ BrowserThread::GetBlockingPool()->GetSequenceToken(),
+ base::SequencedWorkerPool::SKIP_ON_SHUTDOWN);
+}
+
+ElevatedInstallWrapper* ElevatedInstallWrapper::GetInstance() {
+ return Singleton<ElevatedInstallWrapper>::get();
+}
+
+base::FilePath ElevatedInstallWrapper::GetInstallerBackupPath() {
+ base::FilePath path;
+ PathService::Get(chrome::DIR_RECOVERY_COMPONENT_INSTALLER, &path);
+ return path.NormalizePathSeparators();
+}
+
+void ElevatedInstallWrapper::SaveInstallSourceInfo(
+ const InstallerSourceSerializer& serializer,
+ const base::Callback<void(bool)>& callback) {
+ base::PostTaskAndReplyWithResult(
+ ElevatedInstallWrapper::GetInstance()->blocking_task_runner_,
+ FROM_HERE,
+ base::Bind(&ElevatedInstallWrapper::DoSaveInstallSourceInfo,
+ base::Unretained(this), serializer),
+ callback);
+}
+
+bool ElevatedInstallWrapper::DoSaveInstallSourceInfo(
+ const InstallerSourceSerializer& serializer) {
+ return serializer.Run(GetInstallerBackupPath());
+}
+
+void ElevatedInstallWrapper::Install(PrefService* prefs,
+ bool elevation_allowed,
+ const base::Closure& callback) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+ BrowserThread::PostTaskAndReply(BrowserThread::UI, FROM_HERE,
+ base::Bind(&RecoveryUpdateElevationHelper, false, prefs),
+ callback);
+ if (!elevation_allowed) {
+ return;
+ }
+
+ Version version(prefs->GetString(prefs::kRecoveryComponentVersion));
+ blocking_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&ElevatedInstallWrapper::DoInstall,
+ base::Unretained(this),
+ prefs,
+ version));
+}
+
+void ElevatedInstallWrapper::DoInstall(PrefService* prefs,
+ const Version& version) {
+ prefs_ = prefs;
+
+ rc_installer_.reset(new RecoveryComponentInstaller(version, prefs, true));
+
+ unpacker_ = ComponentUnpacker::CreateFromBackup(GetInstallerBackupPath(),
+ rc_installer_.get(),
+ blocking_task_runner_);
+
+ if (unpacker_.get()) {
+ unpacker_->Unpack(base::Bind(&ElevatedInstallWrapper::DoneInstall,
+ base::Unretained(this)));
+ }
+}
+
+void ElevatedInstallWrapper::DoneInstall(ComponentUnpacker::Error error,
+ int extended_error) {
+ base::DeleteFile(GetInstallerBackupPath(), true);
+
+ prefs_ = NULL;
+ unpacker_ = NULL;
+ rc_installer_.reset();
+}
+
void RegisterRecoveryComponent(ComponentUpdateService* cus,
PrefService* prefs) {
#if !defined(OS_CHROMEOS)
@@ -172,6 +339,15 @@ void RegisterRecoveryComponent(ComponentUpdateService* cus,
void RegisterPrefsForRecoveryComponent(PrefRegistrySimple* registry) {
registry->RegisterStringPref(prefs::kRecoveryComponentVersion, "0.0.0.0");
+ registry->RegisterBooleanPref(prefs::kRecoveryComponentNeedsElevation, false);
+}
+
+void PerformRecoveryElevated(
+ PrefService* prefs, bool elevation_allowed, const base::Closure& callback) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ ElevatedInstallWrapper::GetInstance()->Install(prefs, elevation_allowed,
+ callback);
}
} // namespace component_updater
+

Powered by Google App Engine
This is Rietveld 408576698