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

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: 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 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/metrics/sparse_histogram.h"
20 #include "base/path_service.h"
21 #include "base/prefs/pref_registry_simple.h"
22 #include "base/prefs/pref_service.h"
23 #include "base/process/kill.h"
24 #include "base/process/launch.h"
25 #include "base/threading/worker_pool.h"
26 #include "base/values.h"
27 #include "base/win/registry.h"
28 #include "chrome/browser/browser_process.h"
29 #include "chrome/browser/component_updater/component_updater_service.h"
30 #include "chrome/browser/component_updater/default_component_installer.h"
31 #include "chrome/common/chrome_paths.h"
32 #include "chrome/common/pref_names.h"
33 #include "content/public/browser/browser_thread.h"
34
35 using content::BrowserThread;
36
37 namespace component_updater {
38
39 namespace {
40
41 // These values are used to send UMA information and are replicated in the
42 // histograms.xml file, so the order MUST NOT CHANGE.
43 enum SwReporterUmaValue {
44 SW_REPORTER_START_DOWNLOAD = 0,
45 SW_REPORTER_RETRYING_DOWNLOAD = 1,
46 SW_REPORTER_RETRIED_TOO_MANY_DOWNLOADS = 2,
47 SW_REPORTER_START_EXECUTION = 3,
48 SW_REPORTER_RETRYING_EXECUTION = 4,
49 SW_REPORTER_RETRIED_TOO_MANY_EXECUTIONS = 5,
50 SW_REPORTER_FAILED_TO_LAUNCH_REPORTER = 6,
51 SW_REPORTER_MAX,
52 };
53
54 // The maximum number of times to retry a download on startup.
55 const int kMaxRetry = 7;
56
57 // CRX hash. The extension id is: gkmgaooipdjhmangpemjhigmamcehddo. The hash was
58 // generated in Python with something like this:
59 // hashlib.sha256().update(open("<file>.crx").read()[16:16+294]).digest().
60 const uint8 kSha256Hash[] = {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 base::FilePath::CharType kSwReporterExeName[] =
66 FILE_PATH_LITERAL("software_reporter_tool.exe");
67
68 // Where to fetch the reporter exit code in the registry.
69 const wchar_t kSoftwareRemovalToolRegistryKey[] =
70 L"Software\\Google\\Software Removal Tool";
71 const wchar_t kExitCodeRegistryValueName[] = L"ExitCode";
72
73 void ReportSwReporterStep(SwReporterUmaValue value) {
74 UMA_HISTOGRAM_ENUMERATION(
75 "ComponentUpdater.SwReporterStep", value, SW_REPORTER_MAX);
76 }
77
78 // This function is called on the UI thread to report the SwReporter exit code
79 // and then to clear it from the registry as well as clear the execution state
80 // from the local state.
81 void ReportAndClearSwReporterExitCode(int exit_code) {
82 UMA_HISTOGRAM_SPARSE_SLOWLY("ComponentUpdater.SwReporterExitCode", exit_code);
83
84 base::win::RegKey srt_key(
85 HKEY_CURRENT_USER, kSoftwareRemovalToolRegistryKey, KEY_WRITE);
86 srt_key.DeleteValue(kExitCodeRegistryValueName);
87
88 // Now that we are done we can reset the try count.
89 g_browser_process->local_state()->SetInteger(
90 prefs::kSwReporterComponentExecuteTryCount, 0);
91 }
92
93 // This function is called from a worker thread to wait for the SwReporter to
94 // complete and then collect its exit code.
95 void LaunchProcessAndWaitForTermination(const base::FilePath& exe_path) {
96 base::CommandLine reporter_command_line(exe_path);
97 base::ProcessHandle scan_reporter_process = NULL;
98 if (!base::LaunchProcess(reporter_command_line,
99 base::LaunchOptions(),
100 &scan_reporter_process)) {
101 ReportSwReporterStep(SW_REPORTER_FAILED_TO_LAUNCH_REPORTER);
102 return;
103 }
104
105 int exit_code = -1;
106 bool success = base::WaitForExitCode(scan_reporter_process, &exit_code);
107 DCHECK(success);
108 ::CloseHandle(scan_reporter_process);
109 scan_reporter_process = NULL;
110
111 BrowserThread::PostTask(
112 BrowserThread::UI,
113 FROM_HERE,
114 base::Bind(&ReportAndClearSwReporterExitCode, exit_code));
115 }
116
117 void SwReporterExecutionUITask(const base::FilePath& executable_path,
118 PrefService* prefs) {
119 // If we get here without a register or an execute try count, this means that
120 // the component have been silently updated to a new version, so we don't want
121 // to execute.
122 int execute_try_count =
123 prefs->GetInteger(prefs::kSwReporterComponentExecuteTryCount);
124 if (execute_try_count == 0 &&
125 prefs->GetInteger(prefs::kSwReporterComponentRegisterTryCount) == 0) {
126 return;
127 }
128
129 // If we get here, we're done with the registration so clear the number of
130 // retries, and add one more try at execution.
131 prefs->SetInteger(prefs::kSwReporterComponentRegisterTryCount, 0);
132 ReportSwReporterStep(execute_try_count ? SW_REPORTER_RETRYING_EXECUTION
133 : SW_REPORTER_START_EXECUTION);
134 prefs->SetInteger(prefs::kSwReporterComponentExecuteTryCount,
135 execute_try_count + 1);
136
137 // Now execute the reporter from a worker thread.
138 base::WorkerPool::PostTask(
139 FROM_HERE,
140 base::Bind(&LaunchProcessAndWaitForTermination,
141 executable_path.Append(kSwReporterExeName)),
142 true);
143 }
144
145 // The base directory on windows looks like:
146 // <profile>\AppData\Local\Google\Chrome\User Data\SwReporter\.
147 base::FilePath GetSwReporterBaseDirectory() {
148 base::FilePath result;
149 PathService::Get(chrome::DIR_USER_DATA, &result);
150 return result.Append(FILE_PATH_LITERAL("SwReporter"));
151 }
152
153 // Enumerate the version directories to find the latest one. On success,
154 // latest_version_path is set to something like:
155 // [user-data-dir]\SwReporter\<ver>.
156 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.
157 base::FilePath base_dir = GetSwReporterBaseDirectory();
158 bool found = false;
159 base::FileEnumerator file_enumerator(
160 base_dir, false, base::FileEnumerator::DIRECTORIES);
161 Version latest_version("0.0.0.0");
162 for (base::FilePath path = file_enumerator.Next(); !path.value().empty();
163 path = file_enumerator.Next()) {
164 Version version(path.BaseName().MaybeAsASCII());
165 if (!version.IsValid())
166 continue;
167 if (version.CompareTo(latest_version) > 0 &&
168 base::PathExists(path.Append(kSwReporterExeName))) {
169 *latest_version_path = path;
170 latest_version = version;
171 found = true;
172 }
173 }
174 return found;
175 }
176
177 class SwReporterComponentInstallerTraits : public ComponentInstallerTraits {
178 public:
179 explicit SwReporterComponentInstallerTraits(PrefService* prefs)
180 : prefs_(prefs) {}
181
182 virtual ~SwReporterComponentInstallerTraits() {}
183
184 virtual bool VerifyInstallation(const base::FilePath& dir) const {
185 return base::PathExists(dir.Append(kSwReporterExeName));
186 }
187
188 virtual bool CanAutoUpdate() const { return true; }
189
190 virtual bool OnCustomInstall(const base::DictionaryValue& manifest,
191 const base::FilePath& install_dir) {
192 return true;
193 }
194
195 virtual void ComponentReady(const base::Version& version,
196 const base::FilePath& install_dir,
197 scoped_ptr<base::DictionaryValue> manifest) {
198 // Installation is over, now check if we have a pending execution.
199 SwReporterExecutionUITask(install_dir, prefs_);
200 }
201
202 virtual base::FilePath GetBaseDirectory() const {
203 return GetSwReporterBaseDirectory();
204 }
205
206 virtual void GetHash(std::vector<uint8>* hash) const {
207 DCHECK(hash);
208 hash->assign(kSha256Hash, &kSha256Hash[sizeof(kSha256Hash)]);
209 }
210
211 virtual std::string GetName() const { return "Software Reporter Tool"; }
212
213 private:
214 PrefService* prefs_;
215 };
216
217 void FindSwReporterComponentOnFileThread(ComponentUpdateService* cus,
218 PrefService* prefs) {
219 base::FilePath latest_version_path;
220 if (!GetLatestSwReporterDirectory(&latest_version_path)) {
221 scoped_ptr<ComponentInstallerTraits> traits(
222 new SwReporterComponentInstallerTraits(prefs));
223 // |cus| will take ownership of |installer| during installer->Register(cus).
224 DefaultComponentInstaller* installer =
225 new DefaultComponentInstaller(traits.Pass());
226 installer->Register(cus);
227 } else {
228 BrowserThread::PostTask(
229 BrowserThread::UI,
230 FROM_HERE,
231 base::Bind(&SwReporterExecutionUITask, latest_version_path, prefs));
232 }
233 }
234
235 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...
236 PrefService* prefs,
237 int register_try_count) {
238 if (register_try_count > kMaxRetry) {
239 ReportSwReporterStep(SW_REPORTER_RETRIED_TOO_MANY_DOWNLOADS);
240 // Let's forget about this attempt.
241 prefs->SetInteger(prefs::kSwReporterComponentRegisterTryCount, 0);
242 return;
243 }
244
245 ReportSwReporterStep(register_try_count ? SW_REPORTER_RETRYING_DOWNLOAD
246 : SW_REPORTER_START_DOWNLOAD);
247 prefs->SetInteger(prefs::kSwReporterComponentRegisterTryCount,
248 register_try_count + 1);
249 BrowserThread::PostTask(
250 BrowserThread::FILE,
251 FROM_HERE,
252 base::Bind(&FindSwReporterComponentOnFileThread, cus, prefs));
253 }
254
255 } // namespace
256
257 void ExecuteSwReporterComponent(ComponentUpdateService* cus,
258 PrefService* prefs) {
259 // This is an explicit call, so let's forget about previous incomplete
260 // attempts and start from scratch.
261 prefs->SetInteger(prefs::kSwReporterComponentExecuteTryCount, 0);
262 prefs->SetInteger(prefs::kSwReporterComponentRegisterTryCount, 0);
263 ExecuteSwReporterComponentImpl(cus, prefs, 0);
264 }
265
266 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.
267 PrefService* prefs) {
268 // Only register / execute if we have a pending registration / execution.
269 int register_try_count =
270 prefs->GetInteger(prefs::kSwReporterComponentRegisterTryCount);
271 int execute_try_count =
272 prefs->GetInteger(prefs::kSwReporterComponentExecuteTryCount);
273 if (register_try_count == 0) {
274 if (execute_try_count == 0)
275 return;
276 // We have a pending execution, let's check if it completed or not.
277 base::win::RegKey srt_key(
278 HKEY_CURRENT_USER, kSoftwareRemovalToolRegistryKey, KEY_READ);
279 DWORD exit_code = -1;
280 if (srt_key.Valid() &&
281 srt_key.ReadValueDW(kExitCodeRegistryValueName, &exit_code) ==
282 ERROR_SUCCESS) {
283 ReportAndClearSwReporterExitCode(exit_code);
284 return;
285 }
286
287 // If it didn't complete, let's make sure we didn't go beyond the maximum
288 // retry count yet.
289 if (execute_try_count > kMaxRetry) {
290 ReportSwReporterStep(SW_REPORTER_RETRIED_TOO_MANY_EXECUTIONS);
291 // Let's forget about this attempt.
292 prefs->SetInteger(prefs::kSwReporterComponentExecuteTryCount, 0);
293 return;
294 }
295 }
296
297 ExecuteSwReporterComponentImpl(cus, prefs, register_try_count);
298 }
299
300 void RegisterPrefsForSwReporterComponent(PrefRegistrySimple* registry) {
301 registry->RegisterIntegerPref(prefs::kSwReporterComponentRegisterTryCount, 0);
302 registry->RegisterIntegerPref(prefs::kSwReporterComponentExecuteTryCount, 0);
303 }
304
305 } // namespace component_updater
OLDNEW
« 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