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

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: Small change DCHECK() -> clear() 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;
Sorin Jianu 2014/06/20 00:31:43 base::kNullProcessHandle Is there any need to res
MAD 2014/06/20 04:51:59 Done. I always prefer not keeping an invalid value
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 might get called to be registered again if files were manually deleted
129 // so make sure to start from scratch.
130 install_dir_.clear();
131 }
132
133 virtual ~SwReporterComponentInstallerTraits() {}
134
135 virtual bool VerifyInstallation(const base::FilePath& dir) const {
136 return base::PathExists(dir.Append(kSwReporterExeName));
137 }
138
139 virtual bool CanAutoUpdate() const { return true; }
140
141 virtual bool OnCustomInstall(const base::DictionaryValue& manifest,
142 const base::FilePath& install_dir) {
143 return true;
144 }
145
146 virtual void ComponentReady(const base::Version& version,
147 const base::FilePath& install_dir,
148 scoped_ptr<base::DictionaryValue> manifest) {
149 // Remember the path, in case we get called again.
Sorin Jianu 2014/06/20 00:31:43 Comment is redundant. We would need specific comme
MAD 2014/06/20 04:51:59 Done.
150 install_dir_ = install_dir;
151 // If we get here without an execute try count, this means that the
152 // component have been silently updated to a new version, so we don't want
153 // to execute.
154 if (prefs_->GetInteger(prefs::kSwReporterExecuteTryCount) == 0) {
155 ReportUmaStep(SW_REPORTER_UPDATE_WITHOUT_REQUEST);
156 return;
157 }
158
159 // Now execute the reporter from a worker thread.
160 ExecuteReporter(install_dir);
161 }
162
163 virtual base::FilePath GetBaseDirectory() const {
164 // The base directory on windows looks like:
165 // <profile>\AppData\Local\Google\Chrome\User Data\SwReporter\.
166 base::FilePath result;
167 PathService::Get(chrome::DIR_USER_DATA, &result);
168 return result.Append(FILE_PATH_LITERAL("SwReporter"));
169 }
170
171 virtual void GetHash(std::vector<uint8>* hash) const {
172 DCHECK(hash);
173 hash->assign(kSha256Hash, &kSha256Hash[sizeof(kSha256Hash)]);
Sorin Jianu 2014/06/20 00:31:43 small nit, I would write something to better see t
MAD 2014/06/20 04:51:59 Done.
174 }
175
176 virtual std::string GetName() const { return ID(); }
177
178 static const base::FilePath& install_dir() { return install_dir_; }
179 static const char* ID() { return "Software Reporter Tool"; }
Sorin Jianu 2014/06/20 00:31:43 This could be a bug I believe, since we should be
MAD 2014/06/20 04:51:59 Done.
180
181 private:
182 PrefService* prefs_;
183 static base::FilePath install_dir_;
Sorin Jianu 2014/06/20 00:31:43 static members of user defined types are forbidden
MAD 2014/06/20 04:51:59 Done.
184 };
185
186 base::FilePath SwReporterComponentInstallerTraits::install_dir_;
187
188 void RegisterComponent(ComponentUpdateService* cus, PrefService* prefs) {
189 scoped_ptr<ComponentInstallerTraits> traits(
190 new SwReporterComponentInstallerTraits(prefs));
191 // |cus| will take ownership of |installer| during installer->Register(cus).
192 DefaultComponentInstaller* installer =
193 new DefaultComponentInstaller(traits.Pass());
194 installer->Register(cus);
195 }
196
197 void RegisterOrExecuteReporter(ComponentUpdateService* cus,
198 PrefService* prefs) {
199 if (!SwReporterComponentInstallerTraits::install_dir().empty())
200 ExecuteReporter(SwReporterComponentInstallerTraits::install_dir());
201 std::vector<std::string> registered_components(cus->GetComponentIDs());
Sorin Jianu 2014/06/20 00:31:43 const
MAD 2014/06/20 04:51:59 Done.
202 if (std::find(registered_components.begin(),
203 registered_components.end(),
204 SwReporterComponentInstallerTraits::ID()) ==
Sorin Jianu 2014/06/20 00:31:43 See the ID comment above.
MAD 2014/06/20 04:51:59 Done.
205 registered_components.end()) {
206 RegisterComponent(cus, prefs);
207 }
208 }
209
210 } // namespace
211
212 void ExecuteSwReporter(ComponentUpdateService* cus, PrefService* prefs) {
213 // This is an explicit call, so let's forget about previous incomplete
214 // execution attempts and start from scratch.
215 prefs->SetInteger(prefs::kSwReporterExecuteTryCount, 1);
216 ReportUmaStep(SW_REPORTER_EXPLICIT_REQUEST);
217 RegisterOrExecuteReporter(cus, prefs);
218 }
219
220 void ExecutePendingSwReporter(ComponentUpdateService* cus, PrefService* prefs) {
221 // Only continue registration / execute if we have a pending execution.
222 int execute_try_count = prefs->GetInteger(prefs::kSwReporterExecuteTryCount);
223 if (execute_try_count == 0)
224 return;
225 // We have a pending execution, let's check if it completed or not.
226 base::win::RegKey srt_key(
227 HKEY_CURRENT_USER, kSoftwareRemovalToolRegistryKey, KEY_READ);
228 DWORD exit_code = -1;
229 if (srt_key.Valid() &&
230 srt_key.ReadValueDW(kExitCodeRegistryValueName, &exit_code) ==
231 ERROR_SUCCESS) {
232 ReportUmaStep(SW_REPORTER_REGISTRY_EXIT_CODE);
233 ReportAndClearExitCode(exit_code);
234 return;
235 }
236
237 // If it didn't complete, let's make sure we didn't go beyond the maximum
238 // retry count yet.
239 if (++execute_try_count > kMaxRetry) {
240 ReportUmaStep(SW_REPORTER_RETRIED_TOO_MANY_TIMES);
241 // Let's forget about this attempt.
242 prefs->SetInteger(prefs::kSwReporterExecuteTryCount, 0);
243 return;
244 }
245 prefs->SetInteger(prefs::kSwReporterExecuteTryCount, execute_try_count);
246 ReportUmaStep(SW_REPORTER_STARTUP_RETRY);
247 RegisterOrExecuteReporter(cus, prefs);
Sorin Jianu 2014/06/20 00:31:43 We must register for update at startup if we have
MAD 2014/06/20 04:51:59 Done.
248 }
249
250 void RegisterPrefsForSwReporter(PrefRegistrySimple* registry) {
251 registry->RegisterIntegerPref(prefs::kSwReporterExecuteTryCount, 0);
252 }
253
254 } // namespace component_updater
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698