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

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