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

Side by Side 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: 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_component_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_enumerator.h"
16 #include "base/files/file_path.h"
17 #include "base/logging.h"
18 #include "base/metrics/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/values.h"
26 #include "base/win/registry.h"
27 #include "chrome/browser/browser_process.h"
28 #include "chrome/browser/component_updater/component_updater_service.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 // UMA identifiers.
40 const char kSwReporterComponentHistogramName[] = "component_updater.SwReporter";
41 const char kSwReporterComponentExiCodeHistogramName[] =
42 "component_updater.SwReporterExitCode";
43 const int kMaxSwReporterExitCodeUMAValue = 100;
44
45 enum {
46 SW_REPORTER_START_DOWNLOAD = 0,
47 SW_REPORTER_RETRYING_DOWNLOAD,
48 SW_REPORTER_RETRIED_TOO_MANY_DOWNLOADS,
49 SW_REPORTER_START_EXECUTION,
50 SW_REPORTER_RETRYING_EXECUTION,
51 SW_REPORTER_RETRIED_TOO_MANY_EXECUTIONS,
52 SW_REPORTER_MAX,
53 };
54
55 // The maximum number of times to retry a download on startup.
56 const int kMaxRetry = 7;
57
58 // CRX hash. The extension id is: gkmgaooipdjhmangpemjhigmamcehddo.
59 // hashlib.sha256().update(open(".crx").read()[16:16+294]).digest().
60 const uint8 kSha2Hash[] = {0x6a, 0xc6, 0x0e, 0xe8, 0xf3, 0x97, 0xc0, 0xd6,
61 0xf4, 0xc9, 0x78, 0x6c, 0x0c, 0x24, 0x73, 0x3e,
62 0x05, 0xa5, 0x62, 0x4b, 0x2e, 0xc7, 0xb7, 0x1c,
63 0x5f, 0xea, 0xf0, 0x88, 0xf6, 0x97, 0x9b, 0xc7};
64
65 const char kSwReporterManifestName[] = "Software Reporter Tool";
66
67 const base::FilePath::CharType kSwReporterExeName[] =
68 FILE_PATH_LITERAL("software_reporter_tool.exe");
69 const base::FilePath::CharType kSwReporterBaseDirectory[] =
70 FILE_PATH_LITERAL("SwReporter");
71
72 // If we don't have a SwReporter component, this is the version we claim.
73 const char kNullVersion[] = "0.0.0.0";
74
75 // Where to fetch the reporter exit code in the registry.
76 const wchar_t kSoftwareRemovalToolRegistryKey[] =
77 L"Software\\Google\\Software Removal Tool";
78 const wchar_t kExitCodeRegistryValueName[] = L"ExitCode";
79
80 // This function is called on the UI thread to report the SwReporter exit code
81 // and then to clear it from the registry as well as clear the execution state
82 // from the local state.
83 void ReportAndClearSwReporterExitCode(int exit_code) {
84 DCHECK(exit_code < kMaxSwReporterExitCodeUMAValue);
85 UMA_HISTOGRAM_ENUMERATION(kSwReporterComponentExiCodeHistogramName,
86 exit_code,
87 kMaxSwReporterExitCodeUMAValue);
88
89 base::win::RegKey srt_key(
90 HKEY_CURRENT_USER, kSoftwareRemovalToolRegistryKey, KEY_WRITE);
91 srt_key.DeleteValue(kExitCodeRegistryValueName);
92
93 // Now that we are done we can reset the try count.
94 g_browser_process->local_state()->SetInteger(
95 prefs::kSwReporterComponentExecuteTryCount, 0);
96 }
97
98 // This function is called from a worker thread to wait for the SwReporter to
99 // complete and then collect it's exit code to be sent to
100 // ReportAndClearSwReporterExitCode on the UI thread.
101 void WaitForProcessTermination(base::ProcessHandle process_handle) {
102 int exit_code = -1;
103 bool success = base::WaitForExitCode(process_handle, &exit_code);
104 DCHECK(success);
105 BrowserThread::PostTask(
106 BrowserThread::UI,
107 FROM_HERE,
108 base::Bind(&ReportAndClearSwReporterExitCode, exit_code));
109 }
110
111 // The base directory on windows looks like:
112 // <profile>\AppData\Local\Google\Chrome\User Data\SwReporter\.
113 base::FilePath GetSwReporterBaseDirectory() {
114 base::FilePath result;
115 PathService::Get(chrome::DIR_USER_DATA, &result);
116 return result.Append(kSwReporterBaseDirectory);
117 }
118
119 // SwReporter has version encoded in the path itself so we need to enumerate the
120 // directories to find the full path. On success it returns something like:
121 // <profile>\AppData\Local\Google\Chrome\User Data\SwReporter\1.0.1.5\.
122 void GetLatestSwReporterDirectory(base::FilePath* result,
123 Version* latest,
124 std::vector<base::FilePath>* older_dirs) {
125 base::FilePath base_dir = GetSwReporterBaseDirectory();
126 bool found = false;
127 base::FileEnumerator file_enumerator(
128 base_dir, false, base::FileEnumerator::DIRECTORIES);
129 for (base::FilePath path = file_enumerator.Next(); !path.value().empty();
130 path = file_enumerator.Next()) {
131 Version version(path.BaseName().MaybeAsASCII());
132 if (!version.IsValid())
133 continue;
134 if (version.CompareTo(*latest) > 0 &&
135 base::PathExists(path.Append(kSwReporterExeName))) {
136 if (found && older_dirs)
137 older_dirs->push_back(*result);
138 *latest = version;
139 *result = path;
140 found = true;
141 } else {
142 if (older_dirs)
143 older_dirs->push_back(path);
144 }
145 }
146 }
147
148 class SwReporterComponentInstaller : public ComponentInstaller {
149 public:
150 explicit SwReporterComponentInstaller(const Version& version,
151 PrefService* prefs);
152 virtual ~SwReporterComponentInstaller() {}
153
154 // ComponentInstaller overrides.
155 virtual void OnUpdateError(int error) OVERRIDE;
156 virtual bool Install(const base::DictionaryValue& manifest,
157 const base::FilePath& unpack_path) OVERRIDE;
158 virtual bool GetInstalledFile(const std::string& file,
159 base::FilePath* installed_file) OVERRIDE;
160
161 private:
162 void UpdateInstallPrefsOnUIThread();
163
164 Version current_version_;
165 PrefService* prefs_;
166 };
167
168 SwReporterComponentInstaller::SwReporterComponentInstaller(
169 const Version& version,
170 PrefService* prefs)
171 : current_version_(version), prefs_(prefs) {
172 DCHECK(version.IsValid());
173 DCHECK(prefs_);
174 }
175
176 void SwReporterComponentInstaller::OnUpdateError(int error) {
177 NOTREACHED() << "SwReporter update error: " << error;
178 }
179
180 bool SwReporterComponentInstaller::Install(
181 const base::DictionaryValue& manifest,
182 const base::FilePath& unpack_path) {
183 std::string name;
184 manifest.GetStringASCII("name", &name);
185 if (name != kSwReporterManifestName)
186 return false;
187
188 std::string proposed_version;
189 manifest.GetStringASCII("version", &proposed_version);
190 Version new_version(proposed_version.c_str());
191 if (!new_version.IsValid())
192 return false;
193
194 base::FilePath sw_reporter_path(GetSwReporterBaseDirectory());
195 base::FilePath new_version_path(
196 sw_reporter_path.AppendASCII(proposed_version));
197 if (current_version_.CompareTo(new_version) < 0) {
198 if (!base::PathExists(unpack_path.Append(kSwReporterExeName)) ||
199 base::PathExists(new_version_path) ||
robertshield 2014/06/16 03:47:53 Is it intended to return an error if the binary al
MAD 2014/06/16 13:03:55 Good catch, I copied this from the swift shader, a
200 !base::Move(unpack_path, new_version_path)) {
201 PLOG(ERROR) << "Couldn't move files to new_version_path.\n"
202 << unpack_path.value() << " -> " << new_version_path.value();
203 return false;
204 }
205 } else {
206 // We should never get an older version than the current one.
207 DCHECK(current_version_.CompareTo(new_version) == 0);
208 if (!base::PathExists(new_version_path.Append(kSwReporterExeName))) {
209 PLOG(INFO) << "existing version_path doesn't contain file.";
210 return false;
211 }
212 }
213
214 // Passed the basic tests, update the prefs on the UI thread.
215 BrowserThread::PostTask(
216 BrowserThread::UI,
217 FROM_HERE,
218 base::Bind(&SwReporterComponentInstaller::UpdateInstallPrefsOnUIThread,
219 base::Unretained(this)));
220
221 // Installation is done. Now execute the reporter.
222 base::CommandLine reporter_command_line(
223 new_version_path.Append(kSwReporterExeName));
224 base::ProcessHandle scan_reporter_process = NULL;
225 bool success = base::LaunchProcess(
226 reporter_command_line, base::LaunchOptions(), &scan_reporter_process);
227 if (success) {
228 base::WorkerPool::PostTask(
229 FROM_HERE,
230 base::Bind(&WaitForProcessTermination, scan_reporter_process),
231 true);
232 return true;
233 }
234 return false;
235 }
236
237 bool SwReporterComponentInstaller::GetInstalledFile(
238 const std::string& file,
239 base::FilePath* installed_file) {
240 return false;
241 }
242
243 void SwReporterComponentInstaller::UpdateInstallPrefsOnUIThread() {
244 // We're done with the registration so clean the number of retries,
245 prefs_->SetInteger(prefs::kSwReporterComponentRegisterTryCount, 0);
246
247 int tries = prefs_->GetInteger(prefs::kSwReporterComponentExecuteTryCount);
248 UMA_HISTOGRAM_ENUMERATION(
249 kSwReporterComponentHistogramName,
250 tries ? SW_REPORTER_RETRYING_EXECUTION : SW_REPORTER_START_EXECUTION,
251 SW_REPORTER_MAX);
252 prefs_->SetInteger(prefs::kSwReporterComponentExecuteTryCount, tries + 1);
253 }
254
255 // Complete the registration of the component on the UI thread...
256 void FinishSwReporterUpdateRegistration(ComponentUpdateService* cus,
257 const Version& version,
258 PrefService* prefs) {
259 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
260
261 CrxComponent SwReporter;
262 SwReporter.name = "SwReporter";
263 SwReporter.installer = new SwReporterComponentInstaller(version, prefs);
264 SwReporter.version = version;
265 SwReporter.pk_hash.assign(kSha2Hash, &kSha2Hash[sizeof(kSha2Hash)]);
266 if (cus->RegisterComponent(SwReporter) == ComponentUpdateService::kError)
267 NOTREACHED() << "SwReporter component registration fail";
268 }
269
270 // Check if there already is a version of SwReporter installed, and if so
271 // register it.
272 void RegisterSwReporterComponentOnFileThread(ComponentUpdateService* cus,
273 PrefService* prefs) {
274 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
275 base::FilePath path = GetSwReporterBaseDirectory();
276 if (!base::PathExists(path)) {
277 if (!base::CreateDirectory(path)) {
278 NOTREACHED() << "Could not create SwReporter directory.";
279 return;
280 }
281 }
282
283 Version version(kNullVersion);
284 std::vector<base::FilePath> older_dirs;
285 GetLatestSwReporterDirectory(&path, &version, &older_dirs);
286
287 BrowserThread::PostTask(
288 BrowserThread::UI,
289 FROM_HERE,
290 base::Bind(&FinishSwReporterUpdateRegistration, cus, version, prefs));
291
292 // Remove older versions of SwReporter.
293 for (std::vector<base::FilePath>::iterator iter = older_dirs.begin();
294 iter != older_dirs.end();
295 ++iter) {
296 base::DeleteFile(*iter, true);
297 }
298 }
299
300 } // namespace
301
302 void RegisterSwReporterComponent(ComponentUpdateService* cus,
303 PrefService* prefs) {
304 int tries = prefs->GetInteger(prefs::kSwReporterComponentRegisterTryCount);
305 if (tries > kMaxRetry) {
306 UMA_HISTOGRAM_ENUMERATION(kSwReporterComponentHistogramName,
307 SW_REPORTER_RETRIED_TOO_MANY_DOWNLOADS,
308 SW_REPORTER_MAX);
309 // Let's forget about this attempt.
310 prefs->SetInteger(prefs::kSwReporterComponentRegisterTryCount, 0);
311 return;
312 }
313
314 UMA_HISTOGRAM_ENUMERATION(
315 kSwReporterComponentHistogramName,
316 tries ? SW_REPORTER_RETRYING_DOWNLOAD : SW_REPORTER_START_DOWNLOAD,
317 SW_REPORTER_MAX);
318 prefs->SetInteger(prefs::kSwReporterComponentRegisterTryCount, tries + 1);
319 BrowserThread::PostTask(
320 BrowserThread::FILE,
321 FROM_HERE,
322 base::Bind(&RegisterSwReporterComponentOnFileThread, cus, prefs));
323 }
324
325 void MaybeRegisterSwReporterComponent(ComponentUpdateService* cus,
326 PrefService* prefs) {
327 // Only register if we have a pending registration / execution.
328 if (prefs->GetInteger(prefs::kSwReporterComponentRegisterTryCount) == 0) {
329 if (prefs->GetInteger(prefs::kSwReporterComponentExecuteTryCount) == 0)
330 return;
331 // We have a pending execution, let's check if it completed or not.
332 base::win::RegKey srt_key(
333 HKEY_CURRENT_USER, kSoftwareRemovalToolRegistryKey, KEY_READ);
334 DWORD exit_code = -1;
335 if (srt_key.Valid() &&
336 srt_key.ReadValueDW(kExitCodeRegistryValueName, &exit_code) ==
337 ERROR_SUCCESS) {
338 ReportAndClearSwReporterExitCode(exit_code);
339 return;
340 }
341
342 // If it didn't complete, let's make sure we didn't go beyond the maximum
343 // retry count yet.
344 if (prefs->GetInteger(prefs::kSwReporterComponentExecuteTryCount) >
345 kMaxRetry) {
346 UMA_HISTOGRAM_ENUMERATION(kSwReporterComponentHistogramName,
347 SW_REPORTER_RETRIED_TOO_MANY_EXECUTIONS,
348 SW_REPORTER_MAX);
349 // Let's forget about this attempt.
350 prefs->SetInteger(prefs::kSwReporterComponentExecuteTryCount, 0);
351 return;
352 }
353 }
354
355 RegisterSwReporterComponent(cus, prefs);
356 }
357
358 void RegisterPrefsForSwReporterComponent(PrefRegistrySimple* registry) {
359 registry->RegisterIntegerPref(prefs::kSwReporterComponentRegisterTryCount, 0);
360 registry->RegisterIntegerPref(prefs::kSwReporterComponentExecuteTryCount, 0);
361 }
362
363 } // namespace component_updater
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698