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

Side by Side Diff: chrome/browser/component_updater/sw_reporter_installer_win.cc

Issue 333193002: Adding a SW reporter component updater (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Prevent re-registration. 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 unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "chrome/browser/component_updater/sw_reporter_installer_win.h"
6
7 #include <string>
8 #include <vector>
9
10 #include "base/base_paths.h"
11 #include "base/bind.h"
12 #include "base/bind_helpers.h"
13 #include "base/command_line.h"
14 #include "base/file_util.h"
15 #include "base/files/file_path.h"
16 #include "base/logging.h"
17 #include "base/metrics/histogram.h"
18 #include "base/metrics/sparse_histogram.h"
19 #include "base/path_service.h"
20 #include "base/prefs/pref_registry_simple.h"
21 #include "base/prefs/pref_service.h"
22 #include "base/process/kill.h"
23 #include "base/process/launch.h"
24 #include "base/threading/worker_pool.h"
25 #include "base/win/registry.h"
26 #include "chrome/browser/browser_process.h"
27 #include "chrome/browser/component_updater/component_updater_service.h"
28 #include "chrome/browser/component_updater/default_component_installer.h"
29 #include "chrome/common/chrome_paths.h"
30 #include "chrome/common/pref_names.h"
31 #include "content/public/browser/browser_thread.h"
32
33 using content::BrowserThread;
34
35 namespace component_updater {
36
37 namespace {
38
39 // These values are used to send UMA information and are replicated in the
40 // histograms.xml file, so the order MUST NOT CHANGE.
41 enum SwReporterUmaValue {
42 SW_REPORTER_EXPLICIT_REQUEST = 0,
43 SW_REPORTER_STARTUP_RETRY = 1,
44 SW_REPORTER_RETRIED_TOO_MANY_TIMES = 2,
45 SW_REPORTER_START_EXECUTION = 3,
46 SW_REPORTER_FAILED_TO_START = 4,
47 SW_REPORTER_UPDATE_WITHOUT_REQUEST = 5,
48 SW_REPORTER_REGISTRY_EXIT_CODE = 6,
49 SW_REPORTER_MAX,
50 };
51
52 // The maximum number of times to retry a download on startup.
53 const int kMaxRetry = 7;
54
55 // CRX hash. The extension id is: gkmgaooipdjhmangpemjhigmamcehddo. The hash was
56 // generated in Python with something like this:
57 // hashlib.sha256().update(open("<file>.crx").read()[16:16+294]).digest().
58 const uint8 kSha256Hash[] = {0x6a, 0xc6, 0x0e, 0xe8, 0xf3, 0x97, 0xc0, 0xd6,
59 0xf4, 0xc9, 0x78, 0x6c, 0x0c, 0x24, 0x73, 0x3e,
60 0x05, 0xa5, 0x62, 0x4b, 0x2e, 0xc7, 0xb7, 0x1c,
61 0x5f, 0xea, 0xf0, 0x88, 0xf6, 0x97, 0x9b, 0xc7};
62
63 const base::FilePath::CharType kSwReporterExeName[] =
64 FILE_PATH_LITERAL("software_reporter_tool.exe");
65
66 // Where to fetch the reporter exit code in the registry.
67 const wchar_t kSoftwareRemovalToolRegistryKey[] =
68 L"Software\\Google\\Software Removal Tool";
69 const wchar_t kExitCodeRegistryValueName[] = L"ExitCode";
70
71 void ReportUmaStep(SwReporterUmaValue value) {
72 UMA_HISTOGRAM_ENUMERATION("SoftwareReporter.Step", value, SW_REPORTER_MAX);
73 }
74
75 // This function is called on the UI thread to report the SwReporter exit code
76 // and then clear it from the registry as well as clear the execution state
77 // from the local state. This could be called from an interruptible worker
78 // thread so should be resilient to unexpected shutdown.
79 void ReportAndClearExitCode(int exit_code) {
80 UMA_HISTOGRAM_SPARSE_SLOWLY("SoftwareReporter.ExitCode", exit_code);
81
82 base::win::RegKey srt_key(
83 HKEY_CURRENT_USER, kSoftwareRemovalToolRegistryKey, KEY_WRITE);
84 srt_key.DeleteValue(kExitCodeRegistryValueName);
85
86 // Now that we are done we can reset the try count.
87 g_browser_process->local_state()->SetInteger(
88 prefs::kSwReporterExecuteTryCount, 0);
89 }
90
91 // This function is called from a worker thread to launch the SwReporter and
92 // wait for termination to collect its exit code. This task could be interrupted
93 // by a shutdown at anytime, so it shouldn't depend on anything external that
94 // could be shutdown beforehand.
95 void LaunchAndWaitForExit(const base::FilePath& exe_path) {
96 const base::CommandLine reporter_command_line(exe_path);
97 base::ProcessHandle scan_reporter_process = base::kNullProcessHandle;
98 if (!base::LaunchProcess(reporter_command_line,
99 base::LaunchOptions(),
100 &scan_reporter_process)) {
101 ReportUmaStep(SW_REPORTER_FAILED_TO_START);
102 return;
103 }
104 ReportUmaStep(SW_REPORTER_START_EXECUTION);
105
106 int exit_code = -1;
107 bool success = base::WaitForExitCode(scan_reporter_process, &exit_code);
108 DCHECK(success);
109 base::CloseProcessHandle(scan_reporter_process);
110 scan_reporter_process = NULL;
111 // It's OK if this doesn't complete, the work will continue on next startup.
112 BrowserThread::PostTask(BrowserThread::UI,
113 FROM_HERE,
114 base::Bind(&ReportAndClearExitCode, exit_code));
115 }
116
117 void ExecuteReporter(const base::FilePath& install_dir) {
118 base::WorkerPool::PostTask(
119 FROM_HERE,
120 base::Bind(&LaunchAndWaitForExit, install_dir.Append(kSwReporterExeName)),
121 true);
122 }
123
124 class SwReporterComponentInstallerTraits : public ComponentInstallerTraits {
125 public:
126 explicit SwReporterComponentInstallerTraits(PrefService* prefs)
127 : prefs_(prefs) {
128 // We should not be called to register when we already did it.
129 DCHECK(install_dir_.empty());
130 }
131
132 virtual ~SwReporterComponentInstallerTraits() {}
133
134 virtual bool VerifyInstallation(const base::FilePath& dir) const {
135 return base::PathExists(dir.Append(kSwReporterExeName));
136 }
137
138 virtual bool CanAutoUpdate() const { return true; }
139
140 virtual bool OnCustomInstall(const base::DictionaryValue& manifest,
141 const base::FilePath& install_dir) {
142 return true;
143 }
144
145 virtual void ComponentReady(const base::Version& version,
146 const base::FilePath& install_dir,
147 scoped_ptr<base::DictionaryValue> manifest) {
148 // Remember the path, in case we get called again.
149 install_dir_ = install_dir;
150 // If we get here without an execute try count, this means that the
151 // component have been silently updated to a new version, so we don't want
152 // to execute.
153 if (prefs_->GetInteger(prefs::kSwReporterExecuteTryCount) == 0) {
154 ReportUmaStep(SW_REPORTER_UPDATE_WITHOUT_REQUEST);
155 return;
156 }
157
158 // Now execute the reporter from a worker thread.
159 ExecuteReporter(install_dir);
160 }
161
162 virtual base::FilePath GetBaseDirectory() const {
163 // The base directory on windows looks like:
164 // <profile>\AppData\Local\Google\Chrome\User Data\SwReporter\.
165 base::FilePath result;
166 PathService::Get(chrome::DIR_USER_DATA, &result);
167 return result.Append(FILE_PATH_LITERAL("SwReporter"));
168 }
169
170 virtual void GetHash(std::vector<uint8>* hash) const {
171 DCHECK(hash);
172 hash->assign(kSha256Hash, &kSha256Hash[sizeof(kSha256Hash)]);
173 }
174
175 virtual std::string GetName() const { return ID(); }
176
177 static const base::FilePath& install_dir() { return install_dir_; }
178 static const char* ID() { return "Software Reporter Tool"; }
179
180 private:
181 PrefService* prefs_;
182 static base::FilePath install_dir_;
183 };
184
185 base::FilePath SwReporterComponentInstallerTraits::install_dir_;
186
187 void RegisterComponent(ComponentUpdateService* cus, PrefService* prefs) {
188 scoped_ptr<ComponentInstallerTraits> traits(
189 new SwReporterComponentInstallerTraits(prefs));
190 // |cus| will take ownership of |installer| during installer->Register(cus).
191 DefaultComponentInstaller* installer =
192 new DefaultComponentInstaller(traits.Pass());
193 installer->Register(cus);
194 }
195
196 void RegisterOrExecuteReporter(ComponentUpdateService* cus,
197 PrefService* prefs) {
198 if (!SwReporterComponentInstallerTraits::install_dir().empty())
199 ExecuteReporter(SwReporterComponentInstallerTraits::install_dir());
200 std::vector<std::string> registered_components(cus->GetComponentIDs());
201 if (std::find(registered_components.begin(),
202 registered_components.end(),
203 SwReporterComponentInstallerTraits::ID()) ==
204 registered_components.end()) {
205 RegisterComponent(cus, prefs);
206 }
207 }
208
209 } // namespace
210
211 void ExecuteSwReporter(ComponentUpdateService* cus, PrefService* prefs) {
212 // This is an explicit call, so let's forget about previous incomplete
213 // execution attempts and start from scratch.
214 prefs->SetInteger(prefs::kSwReporterExecuteTryCount, 1);
215 ReportUmaStep(SW_REPORTER_EXPLICIT_REQUEST);
216 RegisterOrExecuteReporter(cus, prefs);
217 }
218
219 void ExecutePendingSwReporter(ComponentUpdateService* cus, PrefService* prefs) {
220 // Only continue registration / execute if we have a pending execution.
221 int execute_try_count = prefs->GetInteger(prefs::kSwReporterExecuteTryCount);
222 if (execute_try_count == 0)
223 return;
224 // We have a pending execution, let's check if it completed or not.
225 base::win::RegKey srt_key(
226 HKEY_CURRENT_USER, kSoftwareRemovalToolRegistryKey, KEY_READ);
227 DWORD exit_code = -1;
228 if (srt_key.Valid() &&
229 srt_key.ReadValueDW(kExitCodeRegistryValueName, &exit_code) ==
230 ERROR_SUCCESS) {
231 ReportUmaStep(SW_REPORTER_REGISTRY_EXIT_CODE);
232 ReportAndClearExitCode(exit_code);
233 return;
234 }
235
236 // If it didn't complete, let's make sure we didn't go beyond the maximum
237 // retry count yet.
238 if (++execute_try_count > kMaxRetry) {
239 ReportUmaStep(SW_REPORTER_RETRIED_TOO_MANY_TIMES);
240 // Let's forget about this attempt.
241 prefs->SetInteger(prefs::kSwReporterExecuteTryCount, 0);
242 return;
243 }
244 prefs->SetInteger(prefs::kSwReporterExecuteTryCount, execute_try_count);
245 ReportUmaStep(SW_REPORTER_STARTUP_RETRY);
246 RegisterOrExecuteReporter(cus, prefs);
247 }
248
249 void RegisterPrefsForSwReporter(PrefRegistrySimple* registry) {
250 registry->RegisterIntegerPref(prefs::kSwReporterExecuteTryCount, 0);
251 }
252
253 } // namespace component_updater
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698