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

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

Issue 599653002: SRT Bubble (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Moar CR Comments... Created 6 years, 2 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
OLDNEW
1 // Copyright (c) 2014 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/component_updater/sw_reporter_installer_win.h" 5 #include "chrome/browser/component_updater/sw_reporter_installer_win.h"
6 6
7 #include <string> 7 #include <string>
8 #include <vector> 8 #include <vector>
9 9
10 #include "base/base_paths.h" 10 #include "base/base_paths.h"
11 #include "base/bind.h" 11 #include "base/bind.h"
12 #include "base/bind_helpers.h" 12 #include "base/bind_helpers.h"
13 #include "base/command_line.h" 13 #include "base/command_line.h"
14 #include "base/files/file_path.h" 14 #include "base/files/file_path.h"
15 #include "base/files/file_util.h" 15 #include "base/files/file_util.h"
16 #include "base/logging.h" 16 #include "base/logging.h"
17 #include "base/metrics/histogram.h" 17 #include "base/metrics/histogram.h"
18 #include "base/metrics/sparse_histogram.h" 18 #include "base/metrics/sparse_histogram.h"
19 #include "base/path_service.h" 19 #include "base/path_service.h"
20 #include "base/prefs/pref_registry_simple.h" 20 #include "base/prefs/pref_registry_simple.h"
21 #include "base/prefs/pref_service.h" 21 #include "base/prefs/pref_service.h"
22 #include "base/process/kill.h" 22 #include "base/process/kill.h"
23 #include "base/process/launch.h" 23 #include "base/process/launch.h"
24 #include "base/task_runner_util.h" 24 #include "base/task_runner_util.h"
25 #include "base/threading/worker_pool.h" 25 #include "base/threading/worker_pool.h"
26 #include "base/time/time.h" 26 #include "base/time/time.h"
27 #include "base/win/registry.h" 27 #include "base/win/registry.h"
28 #include "chrome/browser/browser_process.h" 28 #include "chrome/browser/browser_process.h"
29 #include "chrome/browser/metrics/chrome_metrics_service_accessor.h" 29 #include "chrome/browser/metrics/chrome_metrics_service_accessor.h"
30 #include "chrome/browser/profiles/profile.h"
31 #include "chrome/browser/safe_browsing/srt_global_error_win.h"
32 #include "chrome/browser/ui/browser_finder.h"
33 #include "chrome/browser/ui/global_error/global_error_service.h"
34 #include "chrome/browser/ui/global_error/global_error_service_factory.h"
30 #include "chrome/common/pref_names.h" 35 #include "chrome/common/pref_names.h"
31 #include "components/component_updater/component_updater_paths.h" 36 #include "components/component_updater/component_updater_paths.h"
32 #include "components/component_updater/component_updater_service.h" 37 #include "components/component_updater/component_updater_service.h"
33 #include "components/component_updater/component_updater_utils.h" 38 #include "components/component_updater/component_updater_utils.h"
34 #include "components/component_updater/default_component_installer.h" 39 #include "components/component_updater/default_component_installer.h"
35 #include "components/component_updater/pref_names.h" 40 #include "components/component_updater/pref_names.h"
41 #include "components/pref_registry/pref_registry_syncable.h"
36 #include "content/public/browser/browser_thread.h" 42 #include "content/public/browser/browser_thread.h"
37 43
38 using content::BrowserThread; 44 using content::BrowserThread;
39 45
40 namespace component_updater { 46 namespace component_updater {
41 47
42 namespace { 48 namespace {
43 49
44 // These values are used to send UMA information and are replicated in the 50 // These values are used to send UMA information and are replicated in the
45 // histograms.xml file, so the order MUST NOT CHANGE. 51 // histograms.xml file, so the order MUST NOT CHANGE.
(...skipping 23 matching lines...) Expand all
69 0x5f, 0xea, 0xf0, 0x88, 0xf6, 0x97, 0x9b, 0xc7}; 75 0x5f, 0xea, 0xf0, 0x88, 0xf6, 0x97, 0x9b, 0xc7};
70 76
71 const base::FilePath::CharType kSwReporterExeName[] = 77 const base::FilePath::CharType kSwReporterExeName[] =
72 FILE_PATH_LITERAL("software_reporter_tool.exe"); 78 FILE_PATH_LITERAL("software_reporter_tool.exe");
73 79
74 // Where to fetch the reporter exit code in the registry. 80 // Where to fetch the reporter exit code in the registry.
75 const wchar_t kSoftwareRemovalToolRegistryKey[] = 81 const wchar_t kSoftwareRemovalToolRegistryKey[] =
76 L"Software\\Google\\Software Removal Tool"; 82 L"Software\\Google\\Software Removal Tool";
77 const wchar_t kExitCodeRegistryValueName[] = L"ExitCode"; 83 const wchar_t kExitCodeRegistryValueName[] = L"ExitCode";
78 84
85 // Exit codes that identify that a cleanup is needed.
86 const int kCleanupNeeded = 0;
87 const int kPostRebootCleanupNeeded = 4;
88
79 void ReportUmaStep(SwReporterUmaValue value) { 89 void ReportUmaStep(SwReporterUmaValue value) {
80 UMA_HISTOGRAM_ENUMERATION("SoftwareReporter.Step", value, SW_REPORTER_MAX); 90 UMA_HISTOGRAM_ENUMERATION("SoftwareReporter.Step", value, SW_REPORTER_MAX);
81 } 91 }
82 92
93 void ReportUmaVersion(const base::Version& version) {
94 DCHECK(!version.components().empty());
95 UMA_HISTOGRAM_SPARSE_SLOWLY("SoftwareReporter.MinorVersion",
96 version.components().back());
97 // The major version uses the 1st component value (when there is more than
98 // one, since the last one is always the minor version) as a hi word in a
99 // double word. The low word is either the second component (when there are
100 // only three) or the 3rd one if there are at least 4. E.g., for W.X.Y.Z, we
101 // ignore X, and Z is the minor version. We compute the major version with W
102 // as the hi word, and Y as the low word. For X.Y.Z, we use X and Y as hi and
103 // low words, and if we would have Y.Z we would use Y as the hi word and 0 as
104 // the low word. major version is 0 if the version only has one component.
105 uint32_t major_version = 0;
106 if (version.components().size() > 1)
107 major_version = 0x10000 * version.components()[0];
108 if (version.components().size() < 4 && version.components().size() > 2)
109 major_version += version.components()[1];
110 else if (version.components().size() > 3)
111 major_version += version.components()[2];
112 UMA_HISTOGRAM_SPARSE_SLOWLY("SoftwareReporter.MajorVersion", major_version);
113 }
114
83 // This function is called on the UI thread to report the SwReporter exit code 115 // This function is called on the UI thread to report the SwReporter exit code
84 // and then clear it from the registry as well as clear the execution state 116 // and then clear it from the registry as well as clear the execution state
85 // from the local state. This could be called from an interruptible worker 117 // from the local state. This could be called from an interruptible worker
86 // thread so should be resilient to unexpected shutdown. 118 // thread so should be resilient to unexpected shutdown. |version| is provided
87 void ReportAndClearExitCode(int exit_code) { 119 // so the kSwReporterPromptVersion prefs can be set.
120 void ReportAndClearExitCode(int exit_code, const std::string& version) {
88 UMA_HISTOGRAM_SPARSE_SLOWLY("SoftwareReporter.ExitCode", exit_code); 121 UMA_HISTOGRAM_SPARSE_SLOWLY("SoftwareReporter.ExitCode", exit_code);
122 if (g_browser_process && g_browser_process->local_state()) {
123 g_browser_process->local_state()->SetInteger(prefs::kSwReporterLastExitCode,
124 exit_code);
125 }
126
127 if (exit_code == kPostRebootCleanupNeeded || exit_code == kCleanupNeeded) {
128 // Find the last active browser, which may be NULL, in which case we won't
129 // show the prompt this time and will wait until the next run of the
130 // reporter. We can't use other ways of finding a browser because we don't
131 // have a profile.
132 chrome::HostDesktopType desktop_type = chrome::GetActiveDesktop();
133 Browser* browser = chrome::FindLastActiveWithHostDesktopType(desktop_type);
134 if (browser) {
135 Profile* profile = browser->profile();
136 DCHECK(profile);
137 // Now that we have a profile, make sure we have a tabbed browser since we
138 // need to anchor the bubble to the toolbar's wrench menu. Create one if
139 // none exist already.
140 if (browser->type() != Browser::TYPE_TABBED) {
141 browser = chrome::FindTabbedBrowser(profile, false, desktop_type);
142 if (!browser)
143 browser = new Browser(Browser::CreateParams(profile, desktop_type));
gab 2014/09/25 16:26:29 Are you sure you want to create a browser for this
MAD 2014/09/25 16:41:42 Well, I thought the suggestion of using the scope
144 }
145 const std::string prompt_version =
146 profile->GetPrefs()->GetString(prefs::kSwReporterPromptVersion);
147 // Don't show the prompt again if it's been shown before.
148 if (prompt_version.empty()) {
gab 2014/09/25 16:26:29 This check should go above the TYPE_TABBED check o
MAD 2014/09/25 16:41:42 Ho! Good point... Damn!
149 profile->GetPrefs()->SetString(prefs::kSwReporterPromptVersion,
150 version);
151 profile->GetPrefs()->SetInteger(prefs::kSwReporterPromptReason,
152 exit_code);
153 GlobalErrorService* global_error_service =
154 GlobalErrorServiceFactory::GetForProfile(profile);
155 SRTGlobalError* global_error = new SRTGlobalError(global_error_service);
156 // |global_error_service| takes ownership of |global_error| and keeps it
157 // alive until RemoveGlobalError() is called, and even then, the object
158 // is not destroyed, the caller of RemoveGlobalError is responsible to
159 // destroy it, and in the case of the SRTGlobalError, it deletes itself
160 // but only after the bubble has been interacted with.
161 global_error_service->AddGlobalError(global_error);
162
163 // Do not try to show bubble if another GlobalError is already showing
164 // one. The bubble will be shown once the others have been dismissed.
165 const GlobalErrorService::GlobalErrorList& global_errors(
166 global_error_service->errors());
167 GlobalErrorService::GlobalErrorList::const_iterator it;
168 for (it = global_errors.begin(); it != global_errors.end(); ++it) {
169 if ((*it)->GetBubbleView())
170 break;
171 }
172 if (it == global_errors.end())
173 global_error->ShowBubbleView(browser);
174 }
175 }
176 }
89 177
90 base::win::RegKey srt_key( 178 base::win::RegKey srt_key(
91 HKEY_CURRENT_USER, kSoftwareRemovalToolRegistryKey, KEY_WRITE); 179 HKEY_CURRENT_USER, kSoftwareRemovalToolRegistryKey, KEY_WRITE);
92 srt_key.DeleteValue(kExitCodeRegistryValueName); 180 srt_key.DeleteValue(kExitCodeRegistryValueName);
93 } 181 }
94 182
95 // This function is called from a worker thread to launch the SwReporter and 183 // This function is called from a worker thread to launch the SwReporter and
96 // wait for termination to collect its exit code. This task could be interrupted 184 // wait for termination to collect its exit code. This task could be interrupted
97 // by a shutdown at anytime, so it shouldn't depend on anything external that 185 // by a shutdown at anytime, so it shouldn't depend on anything external that
98 // could be shutdown beforehand. 186 // could be shutdown beforehand.
99 void LaunchAndWaitForExit(const base::FilePath& exe_path) { 187 void LaunchAndWaitForExit(const base::FilePath& exe_path,
188 const std::string& version) {
100 const base::CommandLine reporter_command_line(exe_path); 189 const base::CommandLine reporter_command_line(exe_path);
101 base::ProcessHandle scan_reporter_process = base::kNullProcessHandle; 190 base::ProcessHandle scan_reporter_process = base::kNullProcessHandle;
102 if (!base::LaunchProcess(reporter_command_line, 191 if (!base::LaunchProcess(reporter_command_line,
103 base::LaunchOptions(), 192 base::LaunchOptions(),
104 &scan_reporter_process)) { 193 &scan_reporter_process)) {
105 ReportUmaStep(SW_REPORTER_FAILED_TO_START); 194 ReportUmaStep(SW_REPORTER_FAILED_TO_START);
106 return; 195 return;
107 } 196 }
108 ReportUmaStep(SW_REPORTER_START_EXECUTION); 197 ReportUmaStep(SW_REPORTER_START_EXECUTION);
109 198
110 int exit_code = -1; 199 int exit_code = -1;
111 bool success = base::WaitForExitCode(scan_reporter_process, &exit_code); 200 bool success = base::WaitForExitCode(scan_reporter_process, &exit_code);
112 DCHECK(success); 201 DCHECK(success);
113 base::CloseProcessHandle(scan_reporter_process); 202 base::CloseProcessHandle(scan_reporter_process);
114 scan_reporter_process = base::kNullProcessHandle; 203 scan_reporter_process = base::kNullProcessHandle;
115 // It's OK if this doesn't complete, the work will continue on next startup. 204 // It's OK if this doesn't complete, the work will continue on next startup.
116 BrowserThread::PostTask(BrowserThread::UI, 205 BrowserThread::PostTask(
117 FROM_HERE, 206 BrowserThread::UI,
118 base::Bind(&ReportAndClearExitCode, exit_code));
119 }
120
121 void ExecuteReporter(const base::FilePath& install_dir) {
122 base::WorkerPool::PostTask(
123 FROM_HERE, 207 FROM_HERE,
124 base::Bind(&LaunchAndWaitForExit, install_dir.Append(kSwReporterExeName)), 208 base::Bind(&ReportAndClearExitCode, exit_code, version));
125 true);
126 } 209 }
127 210
128 class SwReporterInstallerTraits : public ComponentInstallerTraits { 211 class SwReporterInstallerTraits : public ComponentInstallerTraits {
129 public: 212 public:
130 explicit SwReporterInstallerTraits(PrefService* prefs) : prefs_(prefs) {} 213 explicit SwReporterInstallerTraits(PrefService* prefs) : prefs_(prefs) {}
131 214
132 virtual ~SwReporterInstallerTraits() {} 215 virtual ~SwReporterInstallerTraits() {}
133 216
134 virtual bool VerifyInstallation(const base::FilePath& dir) const { 217 virtual bool VerifyInstallation(const base::FilePath& dir) const {
135 return base::PathExists(dir.Append(kSwReporterExeName)); 218 return base::PathExists(dir.Append(kSwReporterExeName));
136 } 219 }
137 220
138 virtual bool CanAutoUpdate() const { return true; } 221 virtual bool CanAutoUpdate() const { return true; }
139 222
140 virtual bool OnCustomInstall(const base::DictionaryValue& manifest, 223 virtual bool OnCustomInstall(const base::DictionaryValue& manifest,
141 const base::FilePath& install_dir) { 224 const base::FilePath& install_dir) {
142 return true; 225 return true;
143 } 226 }
144 227
145 virtual void ComponentReady(const base::Version& version, 228 virtual void ComponentReady(const base::Version& version,
146 const base::FilePath& install_dir, 229 const base::FilePath& install_dir,
147 scoped_ptr<base::DictionaryValue> manifest) { 230 scoped_ptr<base::DictionaryValue> manifest) {
148 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 231 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
232 ReportUmaVersion(version);
149 233
150 wcsncpy_s(version_dir_, 234 wcsncpy_s(version_dir_,
151 _MAX_PATH, 235 _MAX_PATH,
152 install_dir.value().c_str(), 236 install_dir.value().c_str(),
153 install_dir.value().size()); 237 install_dir.value().size());
154 238
155 // A previous run may have results in the registry, so check and report 239 // A previous run may have results in the registry, so check and report
156 // them if present. 240 // them if present.
241 std::string version_string(version.GetString());
157 base::win::RegKey srt_key( 242 base::win::RegKey srt_key(
158 HKEY_CURRENT_USER, kSoftwareRemovalToolRegistryKey, KEY_READ); 243 HKEY_CURRENT_USER, kSoftwareRemovalToolRegistryKey, KEY_READ);
159 DWORD exit_code; 244 DWORD exit_code;
160 if (srt_key.Valid() && 245 if (srt_key.Valid() &&
161 srt_key.ReadValueDW(kExitCodeRegistryValueName, &exit_code) == 246 srt_key.ReadValueDW(kExitCodeRegistryValueName, &exit_code) ==
162 ERROR_SUCCESS) { 247 ERROR_SUCCESS) {
163 ReportUmaStep(SW_REPORTER_REGISTRY_EXIT_CODE); 248 ReportUmaStep(SW_REPORTER_REGISTRY_EXIT_CODE);
164 ReportAndClearExitCode(exit_code); 249 ReportAndClearExitCode(exit_code, version_string);
165 } 250 }
166 251
167 // If we can't access local state, we can't see when we last ran, so 252 // If we can't access local state, we can't see when we last ran, so
168 // just exit without running. 253 // just exit without running.
169 if (!g_browser_process || !g_browser_process->local_state()) 254 if (!g_browser_process || !g_browser_process->local_state())
170 return; 255 return;
171 256
172 // Run the reporter if it hasn't been triggered in the 257 // Run the reporter if it hasn't been triggered in the
173 // kDaysBetweenSwReporterRuns days. 258 // kDaysBetweenSwReporterRuns days.
174 const base::Time last_time_triggered = base::Time::FromInternalValue( 259 const base::Time last_time_triggered = base::Time::FromInternalValue(
175 g_browser_process->local_state()->GetInt64( 260 g_browser_process->local_state()->GetInt64(
176 prefs::kSwReporterLastTimeTriggered)); 261 prefs::kSwReporterLastTimeTriggered));
177 if ((base::Time::Now() - last_time_triggered).InDays() >= 262 if ((base::Time::Now() - last_time_triggered).InDays() >=
178 kDaysBetweenSwReporterRuns) { 263 kDaysBetweenSwReporterRuns) {
179 g_browser_process->local_state()->SetInt64( 264 g_browser_process->local_state()->SetInt64(
180 prefs::kSwReporterLastTimeTriggered, 265 prefs::kSwReporterLastTimeTriggered,
181 base::Time::Now().ToInternalValue()); 266 base::Time::Now().ToInternalValue());
182 267
183 ExecuteReporter(install_dir); 268 base::WorkerPool::PostTask(
269 FROM_HERE,
270 base::Bind(&LaunchAndWaitForExit,
271 install_dir.Append(kSwReporterExeName),
272 version_string),
273 true);
184 } 274 }
185 } 275 }
186 276
187 virtual base::FilePath GetBaseDirectory() const { return install_dir(); } 277 virtual base::FilePath GetBaseDirectory() const { return install_dir(); }
188 278
189 virtual void GetHash(std::vector<uint8>* hash) const { GetPkHash(hash); } 279 virtual void GetHash(std::vector<uint8>* hash) const { GetPkHash(hash); }
190 280
191 virtual std::string GetName() const { return "Software Reporter Tool"; } 281 virtual std::string GetName() const { return "Software Reporter Tool"; }
192 282
193 static base::FilePath install_dir() { 283 static base::FilePath install_dir() {
(...skipping 22 matching lines...) Expand all
216 PrefService* prefs_; 306 PrefService* prefs_;
217 static wchar_t version_dir_[_MAX_PATH]; 307 static wchar_t version_dir_[_MAX_PATH];
218 }; 308 };
219 309
220 wchar_t SwReporterInstallerTraits::version_dir_[] = {}; 310 wchar_t SwReporterInstallerTraits::version_dir_[] = {};
221 311
222 } // namespace 312 } // namespace
223 313
224 void RegisterSwReporterComponent(ComponentUpdateService* cus, 314 void RegisterSwReporterComponent(ComponentUpdateService* cus,
225 PrefService* prefs) { 315 PrefService* prefs) {
226 // The Sw reporter shouldn't run if the user isn't reporting metrics.
227 if (!ChromeMetricsServiceAccessor::IsMetricsReportingEnabled())
228 return;
229
230 // Install the component. 316 // Install the component.
231 scoped_ptr<ComponentInstallerTraits> traits( 317 scoped_ptr<ComponentInstallerTraits> traits(
232 new SwReporterInstallerTraits(prefs)); 318 new SwReporterInstallerTraits(prefs));
233 // |cus| will take ownership of |installer| during installer->Register(cus). 319 // |cus| will take ownership of |installer| during installer->Register(cus).
234 DefaultComponentInstaller* installer = 320 DefaultComponentInstaller* installer =
235 new DefaultComponentInstaller(traits.Pass()); 321 new DefaultComponentInstaller(traits.Pass());
236 installer->Register(cus); 322 installer->Register(cus);
237 } 323 }
238 324
239 void RegisterPrefsForSwReporter(PrefRegistrySimple* registry) { 325 void RegisterPrefsForSwReporter(PrefRegistrySimple* registry) {
240 registry->RegisterInt64Pref(prefs::kSwReporterLastTimeTriggered, 0); 326 registry->RegisterInt64Pref(prefs::kSwReporterLastTimeTriggered, 0);
327 registry->RegisterIntegerPref(prefs::kSwReporterLastExitCode, -1);
328 }
329
330 void RegisterProfilePrefsForSwReporter(
331 user_prefs::PrefRegistrySyncable* registry) {
332 registry->RegisterIntegerPref(
333 prefs::kSwReporterPromptReason,
334 -1,
335 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
336
337 registry->RegisterStringPref(
338 prefs::kSwReporterPromptVersion,
339 "",
340 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
241 } 341 }
242 342
243 } // namespace component_updater 343 } // namespace component_updater
OLDNEW
« no previous file with comments | « chrome/browser/component_updater/sw_reporter_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