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

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

Issue 333193002: Adding a SW reporter component updater (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Improved retry accounting... 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/sw_reporter_component_installer_win.cc
diff --git a/chrome/browser/component_updater/sw_reporter_component_installer_win.cc b/chrome/browser/component_updater/sw_reporter_component_installer_win.cc
new file mode 100644
index 0000000000000000000000000000000000000000..c01cf6534720367afe21313374d6b4cd85cc8c55
--- /dev/null
+++ b/chrome/browser/component_updater/sw_reporter_component_installer_win.cc
@@ -0,0 +1,305 @@
+// Copyright (c) 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/component_updater/sw_reporter_component_installer_win.h"
+
+#include <string>
+#include <vector>
+
+#include "base/base_paths.h"
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/command_line.h"
+#include "base/file_util.h"
+#include "base/files/file_enumerator.h"
+#include "base/files/file_path.h"
+#include "base/logging.h"
+#include "base/metrics/histogram.h"
+#include "base/metrics/sparse_histogram.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/threading/worker_pool.h"
+#include "base/values.h"
+#include "base/win/registry.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/component_updater/component_updater_service.h"
+#include "chrome/browser/component_updater/default_component_installer.h"
+#include "chrome/common/chrome_paths.h"
+#include "chrome/common/pref_names.h"
+#include "content/public/browser/browser_thread.h"
+
+using content::BrowserThread;
+
+namespace component_updater {
+
+namespace {
+
+// These values are used to send UMA information and are replicated in the
+// histograms.xml file, so the order MUST NOT CHANGE.
+enum SwReporterUmaValue {
+ SW_REPORTER_START_DOWNLOAD = 0,
+ SW_REPORTER_RETRYING_DOWNLOAD = 1,
+ SW_REPORTER_RETRIED_TOO_MANY_DOWNLOADS = 2,
+ SW_REPORTER_START_EXECUTION = 3,
+ SW_REPORTER_RETRYING_EXECUTION = 4,
+ SW_REPORTER_RETRIED_TOO_MANY_EXECUTIONS = 5,
+ SW_REPORTER_FAILED_TO_LAUNCH_REPORTER = 6,
+ SW_REPORTER_MAX,
+};
+
+// The maximum number of times to retry a download on startup.
+const int kMaxRetry = 7;
+
+// CRX hash. The extension id is: gkmgaooipdjhmangpemjhigmamcehddo. The hash was
+// generated in Python with something like this:
+// hashlib.sha256().update(open("<file>.crx").read()[16:16+294]).digest().
+const uint8 kSha256Hash[] = {0x6a, 0xc6, 0x0e, 0xe8, 0xf3, 0x97, 0xc0, 0xd6,
+ 0xf4, 0xc9, 0x78, 0x6c, 0x0c, 0x24, 0x73, 0x3e,
+ 0x05, 0xa5, 0x62, 0x4b, 0x2e, 0xc7, 0xb7, 0x1c,
+ 0x5f, 0xea, 0xf0, 0x88, 0xf6, 0x97, 0x9b, 0xc7};
+
+const base::FilePath::CharType kSwReporterExeName[] =
+ FILE_PATH_LITERAL("software_reporter_tool.exe");
+
+// Where to fetch the reporter exit code in the registry.
+const wchar_t kSoftwareRemovalToolRegistryKey[] =
+ L"Software\\Google\\Software Removal Tool";
+const wchar_t kExitCodeRegistryValueName[] = L"ExitCode";
+
+void ReportSwReporterStep(SwReporterUmaValue value) {
+ UMA_HISTOGRAM_ENUMERATION(
+ "ComponentUpdater.SwReporterStep", value, SW_REPORTER_MAX);
+}
+
+// This function is called on the UI thread to report the SwReporter exit code
+// and then to clear it from the registry as well as clear the execution state
+// from the local state.
+void ReportAndClearSwReporterExitCode(int exit_code) {
+ UMA_HISTOGRAM_SPARSE_SLOWLY("ComponentUpdater.SwReporterExitCode", exit_code);
+
+ base::win::RegKey srt_key(
+ HKEY_CURRENT_USER, kSoftwareRemovalToolRegistryKey, KEY_WRITE);
+ srt_key.DeleteValue(kExitCodeRegistryValueName);
+
+ // Now that we are done we can reset the try count.
+ g_browser_process->local_state()->SetInteger(
+ prefs::kSwReporterComponentExecuteTryCount, 0);
+}
+
+// This function is called from a worker thread to wait for the SwReporter to
+// complete and then collect its exit code.
+void LaunchProcessAndWaitForTermination(const base::FilePath& exe_path) {
+ base::CommandLine reporter_command_line(exe_path);
+ base::ProcessHandle scan_reporter_process = NULL;
+ if (!base::LaunchProcess(reporter_command_line,
+ base::LaunchOptions(),
+ &scan_reporter_process)) {
+ ReportSwReporterStep(SW_REPORTER_FAILED_TO_LAUNCH_REPORTER);
+ return;
+ }
+
+ int exit_code = -1;
+ bool success = base::WaitForExitCode(scan_reporter_process, &exit_code);
+ DCHECK(success);
+ ::CloseHandle(scan_reporter_process);
+ scan_reporter_process = NULL;
+
+ BrowserThread::PostTask(
+ BrowserThread::UI,
+ FROM_HERE,
+ base::Bind(&ReportAndClearSwReporterExitCode, exit_code));
+}
+
+void SwReporterExecutionUITask(const base::FilePath& executable_path,
+ PrefService* prefs) {
+ // If we get here without a register or an execute try count, this means that
+ // the component have been silently updated to a new version, so we don't want
+ // to execute.
+ int execute_try_count =
+ prefs->GetInteger(prefs::kSwReporterComponentExecuteTryCount);
+ if (execute_try_count == 0 &&
+ prefs->GetInteger(prefs::kSwReporterComponentRegisterTryCount) == 0) {
+ return;
+ }
+
+ // If we get here, we're done with the registration so clear the number of
+ // retries, and add one more try at execution.
+ prefs->SetInteger(prefs::kSwReporterComponentRegisterTryCount, 0);
+ ReportSwReporterStep(execute_try_count ? SW_REPORTER_RETRYING_EXECUTION
+ : SW_REPORTER_START_EXECUTION);
+ prefs->SetInteger(prefs::kSwReporterComponentExecuteTryCount,
+ execute_try_count + 1);
+
+ // Now execute the reporter from a worker thread.
+ base::WorkerPool::PostTask(
+ FROM_HERE,
+ base::Bind(&LaunchProcessAndWaitForTermination,
+ executable_path.Append(kSwReporterExeName)),
+ true);
+}
+
+// The base directory on windows looks like:
+// <profile>\AppData\Local\Google\Chrome\User Data\SwReporter\.
+base::FilePath GetSwReporterBaseDirectory() {
+ base::FilePath result;
+ PathService::Get(chrome::DIR_USER_DATA, &result);
+ return result.Append(FILE_PATH_LITERAL("SwReporter"));
+}
+
+// Enumerate the version directories to find the latest one. On success,
+// latest_version_path is set to something like:
+// [user-data-dir]\SwReporter\<ver>.
+bool GetLatestSwReporterDirectory(base::FilePath* latest_version_path) {
waffles 2014/06/19 17:50:54 As mentioned, I was hoping switching to defaultcom
MAD 2014/06/19 21:31:50 Done.
+ base::FilePath base_dir = GetSwReporterBaseDirectory();
+ bool found = false;
+ base::FileEnumerator file_enumerator(
+ base_dir, false, base::FileEnumerator::DIRECTORIES);
+ Version latest_version("0.0.0.0");
+ for (base::FilePath path = file_enumerator.Next(); !path.value().empty();
+ path = file_enumerator.Next()) {
+ Version version(path.BaseName().MaybeAsASCII());
+ if (!version.IsValid())
+ continue;
+ if (version.CompareTo(latest_version) > 0 &&
+ base::PathExists(path.Append(kSwReporterExeName))) {
+ *latest_version_path = path;
+ latest_version = version;
+ found = true;
+ }
+ }
+ return found;
+}
+
+class SwReporterComponentInstallerTraits : public ComponentInstallerTraits {
+ public:
+ explicit SwReporterComponentInstallerTraits(PrefService* prefs)
+ : prefs_(prefs) {}
+
+ virtual ~SwReporterComponentInstallerTraits() {}
+
+ virtual bool VerifyInstallation(const base::FilePath& dir) const {
+ return base::PathExists(dir.Append(kSwReporterExeName));
+ }
+
+ virtual bool CanAutoUpdate() const { return true; }
+
+ virtual bool OnCustomInstall(const base::DictionaryValue& manifest,
+ const base::FilePath& install_dir) {
+ return true;
+ }
+
+ virtual void ComponentReady(const base::Version& version,
+ const base::FilePath& install_dir,
+ scoped_ptr<base::DictionaryValue> manifest) {
+ // Installation is over, now check if we have a pending execution.
+ SwReporterExecutionUITask(install_dir, prefs_);
+ }
+
+ virtual base::FilePath GetBaseDirectory() const {
+ return GetSwReporterBaseDirectory();
+ }
+
+ virtual void GetHash(std::vector<uint8>* hash) const {
+ DCHECK(hash);
+ hash->assign(kSha256Hash, &kSha256Hash[sizeof(kSha256Hash)]);
+ }
+
+ virtual std::string GetName() const { return "Software Reporter Tool"; }
+
+ private:
+ PrefService* prefs_;
+};
+
+void FindSwReporterComponentOnFileThread(ComponentUpdateService* cus,
+ PrefService* prefs) {
+ base::FilePath latest_version_path;
+ if (!GetLatestSwReporterDirectory(&latest_version_path)) {
+ scoped_ptr<ComponentInstallerTraits> traits(
+ new SwReporterComponentInstallerTraits(prefs));
+ // |cus| will take ownership of |installer| during installer->Register(cus).
+ DefaultComponentInstaller* installer =
+ new DefaultComponentInstaller(traits.Pass());
+ installer->Register(cus);
+ } else {
+ BrowserThread::PostTask(
+ BrowserThread::UI,
+ FROM_HERE,
+ base::Bind(&SwReporterExecutionUITask, latest_version_path, prefs));
+ }
+}
+
+void ExecuteSwReporterComponentImpl(ComponentUpdateService* cus,
waffles 2014/06/19 17:50:54 Given that this is in an anonymous namespace, mayb
MAD 2014/06/19 21:31:50 Naming is hard... I prefer to have clear names...
+ PrefService* prefs,
+ int register_try_count) {
+ if (register_try_count > kMaxRetry) {
+ ReportSwReporterStep(SW_REPORTER_RETRIED_TOO_MANY_DOWNLOADS);
+ // Let's forget about this attempt.
+ prefs->SetInteger(prefs::kSwReporterComponentRegisterTryCount, 0);
+ return;
+ }
+
+ ReportSwReporterStep(register_try_count ? SW_REPORTER_RETRYING_DOWNLOAD
+ : SW_REPORTER_START_DOWNLOAD);
+ prefs->SetInteger(prefs::kSwReporterComponentRegisterTryCount,
+ register_try_count + 1);
+ BrowserThread::PostTask(
+ BrowserThread::FILE,
+ FROM_HERE,
+ base::Bind(&FindSwReporterComponentOnFileThread, cus, prefs));
+}
+
+} // namespace
+
+void ExecuteSwReporterComponent(ComponentUpdateService* cus,
+ PrefService* prefs) {
+ // This is an explicit call, so let's forget about previous incomplete
+ // attempts and start from scratch.
+ prefs->SetInteger(prefs::kSwReporterComponentExecuteTryCount, 0);
+ prefs->SetInteger(prefs::kSwReporterComponentRegisterTryCount, 0);
+ ExecuteSwReporterComponentImpl(cus, prefs, 0);
+}
+
+void ExecutePendingSwReporterComponent(ComponentUpdateService* cus,
waffles 2014/06/19 17:50:54 To restate what I said in the meeting: In my opin
MAD 2014/06/19 21:31:50 Done.
+ PrefService* prefs) {
+ // Only register / execute if we have a pending registration / execution.
+ int register_try_count =
+ prefs->GetInteger(prefs::kSwReporterComponentRegisterTryCount);
+ int execute_try_count =
+ prefs->GetInteger(prefs::kSwReporterComponentExecuteTryCount);
+ if (register_try_count == 0) {
+ if (execute_try_count == 0)
+ return;
+ // We have a pending execution, let's check if it completed or not.
+ base::win::RegKey srt_key(
+ HKEY_CURRENT_USER, kSoftwareRemovalToolRegistryKey, KEY_READ);
+ DWORD exit_code = -1;
+ if (srt_key.Valid() &&
+ srt_key.ReadValueDW(kExitCodeRegistryValueName, &exit_code) ==
+ ERROR_SUCCESS) {
+ ReportAndClearSwReporterExitCode(exit_code);
+ return;
+ }
+
+ // If it didn't complete, let's make sure we didn't go beyond the maximum
+ // retry count yet.
+ if (execute_try_count > kMaxRetry) {
+ ReportSwReporterStep(SW_REPORTER_RETRIED_TOO_MANY_EXECUTIONS);
+ // Let's forget about this attempt.
+ prefs->SetInteger(prefs::kSwReporterComponentExecuteTryCount, 0);
+ return;
+ }
+ }
+
+ ExecuteSwReporterComponentImpl(cus, prefs, register_try_count);
+}
+
+void RegisterPrefsForSwReporterComponent(PrefRegistrySimple* registry) {
+ registry->RegisterIntegerPref(prefs::kSwReporterComponentRegisterTryCount, 0);
+ registry->RegisterIntegerPref(prefs::kSwReporterComponentExecuteTryCount, 0);
+}
+
+} // namespace component_updater
« no previous file with comments | « chrome/browser/component_updater/sw_reporter_component_installer_win.h ('k') | chrome/browser/prefs/browser_prefs.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698