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

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

Issue 359443002: Elevated install of recovery component when needed (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: comment out unused function on chromeos Created 6 years 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 9aadd24c0c7364422689bdcdcfbee828ce331041..ebcb2064aa23cf84864ed5bbfccd88c9f1ff69d5 100644
--- a/chrome/browser/component_updater/recovery_component_installer.cc
+++ b/chrome/browser/component_updater/recovery_component_installer.cc
@@ -13,13 +13,17 @@
#include "base/compiler_specific.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
+#include "base/json/json_file_value_serializer.h"
#include "base/logging.h"
+#include "base/memory/scoped_ptr.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 "base/threading/worker_pool.h"
+#include "chrome/common/chrome_switches.h"
+#include "chrome/common/pref_names.h"
#include "components/component_updater/component_updater_paths.h"
#include "components/component_updater/component_updater_service.h"
#include "components/component_updater/pref_names.h"
@@ -47,13 +51,89 @@ const base::FilePath::CharType kRecoveryFileName[] =
const char kRecoveryManifestName[] = "ChromeRecovery";
+// ChromeRecovery process exit codes.
+enum ChromeRecoveryExitCode {
+ EXIT_CODE_RECOVERY_SUCCEEDED = 0,
+ EXIT_CODE_RECOVERY_SKIPPED = 1,
+ EXIT_CODE_ELEVATION_NEEDED = 2,
+};
+
+#if !defined(OS_CHROMEOS)
+// Checks if elevated recovery simulation switch was present on the command
+// line. This is for testing purpose.
+bool SimulatingElevatedRecovery() {
+ return CommandLine::ForCurrentProcess()->
+ HasSwitch(switches::kSimulateElevatedRecovery);
+}
+#endif
+
+#if defined(OS_WIN)
+scoped_ptr<base::DictionaryValue> ReadManifest(const base::FilePath& manifest) {
+ JSONFileValueSerializer serializer(manifest);
+ std::string error;
+ scoped_ptr<base::Value> root(serializer.Deserialize(NULL, &error));
+ if (root.get() && root->IsType(base::Value::TYPE_DICTIONARY)) {
+ return scoped_ptr<base::DictionaryValue>(
+ static_cast<base::DictionaryValue*>(root.release()));
+ }
+ return scoped_ptr<base::DictionaryValue>();
+}
+
+void DoElevatedInstallRecoveryComponent(const base::FilePath& path) {
+ const base::FilePath main_file = path.Append(kRecoveryFileName);
+ const base::FilePath manifest_file =
+ path.Append(FILE_PATH_LITERAL("manifest.json"));
+ if (!base::PathExists(main_file) || !base::PathExists(manifest_file))
+ return;
+
+ scoped_ptr<base::DictionaryValue> manifest(ReadManifest(manifest_file));
+ std::string name;
+ manifest->GetStringASCII("name", &name);
+ if (name != kRecoveryManifestName)
+ return;
+ std::string proposed_version;
+ manifest->GetStringASCII("version", &proposed_version);
+ const Version version(proposed_version.c_str());
+ if (!version.IsValid())
+ return;
+
+ CommandLine cmdline(main_file);
+ std::string arguments;
+ if (manifest->GetStringASCII("x-recovery-args", &arguments))
+ cmdline.AppendArg(arguments);
+ std::string add_version;
+ if (manifest->GetStringASCII("x-recovery-add-version", &add_version) &&
+ add_version == "yes") {
+ cmdline.AppendSwitchASCII("version", version.GetString());
+ }
+
+ base::LaunchOptions options;
+ options.start_hidden = true;
+ base::LaunchElevatedProcess(cmdline, options);
+}
+
+void ElevatedInstallRecoveryComponent(const base::FilePath& installer_path) {
+ base::WorkerPool::PostTask(
+ FROM_HERE,
+ base::Bind(&DoElevatedInstallRecoveryComponent, installer_path),
+ true);
+}
+#endif
+
} // namespace
+// Component installer that is responsible to repair the chrome installation
+// or repair the Google update installation. This is a last resort safety
+// mechanism.
+// For user Chrome, recovery component just installs silently. For machine
+// Chrome, elevation may be needed. If that happens, the installer will set
+// preference flag prefs::kRecoveryComponentNeedsElevation to request that.
+// There is a global error service monitors this flag and will pop up
+// bubble if the flag is set to true.
+// See chrome/browser/recovery/recovery_install_global_error.cc for details.
class RecoveryComponentInstaller : public ComponentInstaller {
public:
- explicit RecoveryComponentInstaller(const Version& version,
- PrefService* prefs);
-
+ RecoveryComponentInstaller(const Version& version, PrefService* prefs);
~RecoveryComponentInstaller() override {}
void OnUpdateError(int error) override;
@@ -65,10 +145,17 @@ class RecoveryComponentInstaller : public ComponentInstaller {
base::FilePath* installed_file) override;
private:
+ bool RunInstallCommand(const CommandLine& cmdline,
+ const base::FilePath& installer_folder) const;
+
Version current_version_;
PrefService* prefs_;
};
+void SimulateElevatedRecoveryHelper(PrefService* prefs) {
+ prefs->SetBoolean(prefs::kRecoveryComponentNeedsElevation, true);
+}
+
void RecoveryRegisterHelper(ComponentUpdateService* cus, PrefService* prefs) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
Version version(prefs->GetString(prefs::kRecoveryComponentVersion));
@@ -92,6 +179,13 @@ void RecoveryUpdateVersionHelper(const Version& version, PrefService* prefs) {
prefs->SetString(prefs::kRecoveryComponentVersion, version.GetString());
}
+void SetPrefsForElevatedRecoveryInstall(const base::FilePath& unpack_path,
+ PrefService* prefs) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ prefs->SetFilePath(prefs::kRecoveryComponentUnpackPath, unpack_path);
+ prefs->SetBoolean(prefs::kRecoveryComponentNeedsElevation, true);
+}
+
RecoveryComponentInstaller::RecoveryComponentInstaller(const Version& version,
PrefService* prefs)
: current_version_(version), prefs_(prefs) {
@@ -102,6 +196,53 @@ void RecoveryComponentInstaller::OnUpdateError(int error) {
NOTREACHED() << "Recovery component update error: " << error;
}
+#if defined(OS_WIN)
+void WaitForInstallToComplete(base::ProcessHandle process_handle,
+ const base::FilePath& installer_folder,
+ PrefService* prefs) {
+ int installer_exit_code = 0;
+ const base::TimeDelta kMaxWaitTime = base::TimeDelta::FromSeconds(600);
+ if (base::WaitForExitCodeWithTimeout(process_handle,
+ &installer_exit_code,
+ kMaxWaitTime) &&
+ installer_exit_code == EXIT_CODE_ELEVATION_NEEDED) {
+ BrowserThread::PostTask(
+ BrowserThread::UI,
+ FROM_HERE,
+ base::Bind(&SetPrefsForElevatedRecoveryInstall,
+ installer_folder,
+ prefs));
+ }
+ base::CloseProcessHandle(process_handle);
+}
+
+bool RecoveryComponentInstaller::RunInstallCommand(
+ const CommandLine& cmdline, const base::FilePath& installer_folder) const {
+ base::ProcessHandle process_handle;
+ base::LaunchOptions options;
+ options.start_hidden = true;
+ if (!base::LaunchProcess(cmdline, options, &process_handle))
+ return false;
+
+ // Let worker pool thread wait for us so we don't block Chrome shutdown.
+ base::WorkerPool::PostTask(
+ FROM_HERE,
+ base::Bind(&WaitForInstallToComplete,
+ process_handle, installer_folder, prefs_),
+ true);
+
+ // Returns true regardless of install result since from updater service
+ // perspective the install is done, even we may need to do elevated
+ // install later.
+ return true;
+}
+#else
+bool RecoveryComponentInstaller::RunInstallCommand(
+ const CommandLine& cmdline, const base::FilePath&) const {
+ return base::LaunchProcess(cmdline, base::LaunchOptions(), NULL);
+}
+#endif
+
bool RecoveryComponentInstaller::Install(const base::DictionaryValue& manifest,
const base::FilePath& unpack_path) {
std::string name;
@@ -120,11 +261,8 @@ bool RecoveryComponentInstaller::Install(const base::DictionaryValue& manifest,
base::FilePath path;
if (!PathService::Get(DIR_RECOVERY_BASE, &path))
return false;
- if (!base::PathExists(path)) {
- if (!base::CreateDirectory(path)) {
+ if (!base::PathExists(path) && !base::CreateDirectory(path))
return false;
- }
- }
path = path.AppendASCII(version.GetString());
if (base::PathExists(path) && !base::DeleteFile(path, true))
return false;
@@ -142,10 +280,15 @@ bool RecoveryComponentInstaller::Install(const base::DictionaryValue& manifest,
if (manifest.GetStringASCII("x-recovery-args", &arguments))
cmdline.AppendArg(arguments);
std::string add_version;
- if (manifest.GetStringASCII("x-recovery-add-version", &add_version)) {
- if (add_version == "yes")
- cmdline.AppendSwitchASCII("version", current_version_.GetString());
+ if (manifest.GetStringASCII("x-recovery-add-version", &add_version) &&
+ add_version == "yes") {
+ cmdline.AppendSwitchASCII("version", current_version_.GetString());
}
+
+ if (!RunInstallCommand(cmdline, path)) {
+ return false;
+ }
+
current_version_ = version;
if (prefs_) {
BrowserThread::PostTask(
@@ -153,7 +296,7 @@ bool RecoveryComponentInstaller::Install(const base::DictionaryValue& manifest,
FROM_HERE,
base::Bind(&RecoveryUpdateVersionHelper, version, prefs_));
}
- return base::LaunchProcess(cmdline, base::LaunchOptions(), NULL);
+ return true;
}
bool RecoveryComponentInstaller::GetInstalledFile(
@@ -165,6 +308,13 @@ bool RecoveryComponentInstaller::GetInstalledFile(
void RegisterRecoveryComponent(ComponentUpdateService* cus,
PrefService* prefs) {
#if !defined(OS_CHROMEOS)
+ if (SimulatingElevatedRecovery()) {
+ BrowserThread::PostTask(
+ BrowserThread::UI,
+ FROM_HERE,
+ base::Bind(&SimulateElevatedRecoveryHelper, prefs));
+ }
+
// We delay execute the registration because we are not required in
// the critical path during browser startup.
BrowserThread::PostDelayedTask(
@@ -177,14 +327,24 @@ void RegisterRecoveryComponent(ComponentUpdateService* cus,
void RegisterPrefsForRecoveryComponent(PrefRegistrySimple* registry) {
registry->RegisterStringPref(prefs::kRecoveryComponentVersion, "0.0.0.0");
+ registry->RegisterFilePathPref(prefs::kRecoveryComponentUnpackPath,
+ base::FilePath());
+ registry->RegisterBooleanPref(prefs::kRecoveryComponentNeedsElevation, false);
}
void AcceptedElevatedRecoveryInstall(PrefService* prefs) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+#if defined(OS_WIN)
+ ElevatedInstallRecoveryComponent(
+ prefs->GetFilePath(prefs::kRecoveryComponentUnpackPath));
+#endif
+ prefs->SetBoolean(prefs::kRecoveryComponentNeedsElevation, false);
}
void DeclinedElevatedRecoveryInstall(PrefService* prefs) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ prefs->SetBoolean(prefs::kRecoveryComponentNeedsElevation, false);
}
} // namespace component_updater
« no previous file with comments | « chrome/browser/component_updater/recovery_component_installer.h ('k') | components/component_updater/pref_names.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698