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

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

Issue 856393005: Re-prompt Chrome users to run the SRT when a finch param changes. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 years, 11 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
« no previous file with comments | « no previous file | chrome/browser/prefs/chrome_pref_service_factory.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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
9 #include <map>
8 #include <string> 10 #include <string>
9 #include <vector> 11 #include <vector>
10 12
11 #include "base/base_paths.h" 13 #include "base/base_paths.h"
12 #include "base/bind.h" 14 #include "base/bind.h"
13 #include "base/bind_helpers.h" 15 #include "base/bind_helpers.h"
14 #include "base/command_line.h" 16 #include "base/command_line.h"
15 #include "base/files/file_path.h" 17 #include "base/files/file_path.h"
16 #include "base/files/file_util.h" 18 #include "base/files/file_util.h"
17 #include "base/logging.h" 19 #include "base/logging.h"
(...skipping 16 matching lines...) Expand all
34 #include "chrome/browser/ui/browser_finder.h" 36 #include "chrome/browser/ui/browser_finder.h"
35 #include "chrome/browser/ui/global_error/global_error_service.h" 37 #include "chrome/browser/ui/global_error/global_error_service.h"
36 #include "chrome/browser/ui/global_error/global_error_service_factory.h" 38 #include "chrome/browser/ui/global_error/global_error_service_factory.h"
37 #include "chrome/common/pref_names.h" 39 #include "chrome/common/pref_names.h"
38 #include "components/component_updater/component_updater_paths.h" 40 #include "components/component_updater/component_updater_paths.h"
39 #include "components/component_updater/component_updater_service.h" 41 #include "components/component_updater/component_updater_service.h"
40 #include "components/component_updater/component_updater_utils.h" 42 #include "components/component_updater/component_updater_utils.h"
41 #include "components/component_updater/default_component_installer.h" 43 #include "components/component_updater/default_component_installer.h"
42 #include "components/component_updater/pref_names.h" 44 #include "components/component_updater/pref_names.h"
43 #include "components/pref_registry/pref_registry_syncable.h" 45 #include "components/pref_registry/pref_registry_syncable.h"
46 #include "components/variations/variations_associated_data.h"
44 #include "content/public/browser/browser_thread.h" 47 #include "content/public/browser/browser_thread.h"
45 48
46 using content::BrowserThread; 49 using content::BrowserThread;
47 50
48 namespace component_updater { 51 namespace component_updater {
49 52
50 namespace { 53 namespace {
51 54
52 // These values are used to send UMA information and are replicated in the 55 // These values are used to send UMA information and are replicated in the
53 // histograms.xml file, so the order MUST NOT CHANGE. 56 // histograms.xml file, so the order MUST NOT CHANGE.
(...skipping 30 matching lines...) Expand all
84 L"Software\\Google\\Software Removal Tool"; 87 L"Software\\Google\\Software Removal Tool";
85 const wchar_t kCleanerSuffixRegistryKey[] = L"Cleaner"; 88 const wchar_t kCleanerSuffixRegistryKey[] = L"Cleaner";
86 const wchar_t kExitCodeRegistryValueName[] = L"ExitCode"; 89 const wchar_t kExitCodeRegistryValueName[] = L"ExitCode";
87 const wchar_t kVersionRegistryValueName[] = L"Version"; 90 const wchar_t kVersionRegistryValueName[] = L"Version";
88 const wchar_t kStartTimeRegistryValueName[] = L"StartTime"; 91 const wchar_t kStartTimeRegistryValueName[] = L"StartTime";
89 const wchar_t kEndTimeRegistryValueName[] = L"EndTime"; 92 const wchar_t kEndTimeRegistryValueName[] = L"EndTime";
90 93
91 // Field trial strings. 94 // Field trial strings.
92 const char kSRTPromptTrialName[] = "SRTPromptFieldTrial"; 95 const char kSRTPromptTrialName[] = "SRTPromptFieldTrial";
93 const char kSRTPromptOnGroup[] = "On"; 96 const char kSRTPromptOnGroup[] = "On";
97 const char kSRTPromptSeedParamName[] = "Seed";
94 98
95 // Exit codes that identify that a cleanup is needed. 99 // Exit codes that identify that a cleanup is needed.
96 const int kCleanupNeeded = 0; 100 const int kCleanupNeeded = 0;
97 const int kPostRebootCleanupNeeded = 4; 101 const int kPostRebootCleanupNeeded = 4;
98 102
99 void ReportUmaStep(SwReporterUmaValue value) { 103 void ReportUmaStep(SwReporterUmaValue value) {
100 UMA_HISTOGRAM_ENUMERATION("SoftwareReporter.Step", value, SW_REPORTER_MAX); 104 UMA_HISTOGRAM_ENUMERATION("SoftwareReporter.Step", value, SW_REPORTER_MAX);
101 } 105 }
102 106
103 void ReportVersionWithUma(const base::Version& version) { 107 void ReportVersionWithUma(const base::Version& version) {
104 DCHECK(!version.components().empty()); 108 DCHECK(!version.components().empty());
105 // The minor version is the 2nd last component of the version, 109 // The minor version is the 2nd last component of the version,
106 // or just the first component if there is only 1. 110 // or just the first component if there is only 1.
107 uint32_t minor_version = 0; 111 uint32_t minor_version = 0;
108 if (version.components().size() > 1) 112 if (version.components().size() > 1)
109 minor_version = version.components()[version.components().size() - 2]; 113 minor_version = version.components()[version.components().size() - 2];
110 else 114 else
111 minor_version = version.components()[0]; 115 minor_version = version.components()[0];
112 UMA_HISTOGRAM_SPARSE_SLOWLY("SoftwareReporter.MinorVersion", minor_version); 116 UMA_HISTOGRAM_SPARSE_SLOWLY("SoftwareReporter.MinorVersion", minor_version);
113 117
114 // The major version for X.Y.Z is X*256^3+Y*256+Z. If there are additional 118 // The major version for X.Y.Z is X*256^3+Y*256+Z. If there are additional
115 // components, only the first three count, and if there are less than 3, the 119 // components, only the first three count, and if there are less than 3, the
116 // missing values are just replaced by zero. So 1 is equivalent 1.0.0. 120 // missing values are just replaced by zero. So 1 is equivalent 1.0.0.
117 DCHECK(version.components()[0] < 0x100); 121 DCHECK_LT(version.components()[0], 0x100);
118 uint32_t major_version = 0x1000000 * version.components()[0]; 122 uint32_t major_version = 0x1000000 * version.components()[0];
119 if (version.components().size() >= 2) { 123 if (version.components().size() >= 2) {
120 DCHECK(version.components()[1] < 0x10000); 124 DCHECK_LT(version.components()[1], 0x10000);
121 major_version += 0x100 * version.components()[1]; 125 major_version += 0x100 * version.components()[1];
122 } 126 }
123 if (version.components().size() >= 3) { 127 if (version.components().size() >= 3) {
124 DCHECK(version.components()[2] < 0x100); 128 DCHECK_LT(version.components()[2], 0x100);
125 major_version += version.components()[2]; 129 major_version += version.components()[2];
126 } 130 }
127 UMA_HISTOGRAM_SPARSE_SLOWLY("SoftwareReporter.MajorVersion", major_version); 131 UMA_HISTOGRAM_SPARSE_SLOWLY("SoftwareReporter.MajorVersion", major_version);
128 } 132 }
129 133
130 // This function is called on the UI thread to report the SwReporter exit code 134 // This function is called on the UI thread to report the SwReporter exit code
131 // and then clear it from the registry as well as clear the execution state 135 // and then clear it from the registry as well as clear the execution state
132 // from the local state. This could be called from an interruptible worker 136 // from the local state. This could be called from an interruptible worker
133 // thread so should be resilient to unexpected shutdown. |version| is provided 137 // thread so should be resilient to unexpected shutdown. |version| is provided
134 // so the kSwReporterPromptVersion prefs can be set. 138 // so the kSwReporterPromptVersion prefs can be set.
135 void ReportAndClearExitCode(int exit_code, const std::string& version) { 139 void ReportAndClearExitCode(int exit_code, const std::string& version) {
136 UMA_HISTOGRAM_SPARSE_SLOWLY("SoftwareReporter.ExitCode", exit_code); 140 UMA_HISTOGRAM_SPARSE_SLOWLY("SoftwareReporter.ExitCode", exit_code);
141 base::win::RegKey srt_key(HKEY_CURRENT_USER, kSoftwareRemovalToolRegistryKey,
142 KEY_WRITE);
143 srt_key.DeleteValue(kExitCodeRegistryValueName);
144
137 if (g_browser_process && g_browser_process->local_state()) { 145 if (g_browser_process && g_browser_process->local_state()) {
138 g_browser_process->local_state()->SetInteger(prefs::kSwReporterLastExitCode, 146 g_browser_process->local_state()->SetInteger(prefs::kSwReporterLastExitCode,
139 exit_code); 147 exit_code);
140 } 148 }
141 149
142 if ((exit_code == kPostRebootCleanupNeeded || exit_code == kCleanupNeeded) && 150 if ((exit_code != kPostRebootCleanupNeeded && exit_code != kCleanupNeeded) ||
143 base::FieldTrialList::FindFullName(kSRTPromptTrialName) == 151 base::FieldTrialList::FindFullName(kSRTPromptTrialName) !=
144 kSRTPromptOnGroup) { 152 kSRTPromptOnGroup) {
145 // Find the last active browser, which may be NULL, in which case we won't 153 return;
146 // show the prompt this time and will wait until the next run of the 154 }
147 // reporter. We can't use other ways of finding a browser because we don't 155 // Find the last active browser, which may be NULL, in which case we won't
148 // have a profile. 156 // show the prompt this time and will wait until the next run of the
149 chrome::HostDesktopType desktop_type = chrome::GetActiveDesktop(); 157 // reporter. We can't use other ways of finding a browser because we don't
150 Browser* browser = chrome::FindLastActiveWithHostDesktopType(desktop_type); 158 // have a profile.
151 if (browser) { 159 chrome::HostDesktopType desktop_type = chrome::GetActiveDesktop();
152 Profile* profile = browser->profile(); 160 Browser* browser = chrome::FindLastActiveWithHostDesktopType(desktop_type);
153 // Don't show the prompt again if it's been shown before for this profile. 161 if (!browser)
154 DCHECK(profile); 162 return;
155 const std::string prompt_version =
156 profile->GetPrefs()->GetString(prefs::kSwReporterPromptVersion);
157 if (prompt_version.empty()) {
158 profile->GetPrefs()->SetString(prefs::kSwReporterPromptVersion,
159 version);
160 profile->GetPrefs()->SetInteger(prefs::kSwReporterPromptReason,
161 exit_code);
162 // Now that we have a profile, make sure we have a tabbed browser since
163 // we need to anchor the bubble to the toolbar's wrench menu. Create one
164 // if none exist already.
165 if (browser->type() != Browser::TYPE_TABBED) {
166 browser = chrome::FindTabbedBrowser(profile, false, desktop_type);
167 if (!browser)
168 browser = new Browser(Browser::CreateParams(profile, desktop_type));
169 }
170 GlobalErrorService* global_error_service =
171 GlobalErrorServiceFactory::GetForProfile(profile);
172 SRTGlobalError* global_error = new SRTGlobalError(global_error_service);
173 // |global_error_service| takes ownership of |global_error| and keeps it
174 // alive until RemoveGlobalError() is called, and even then, the object
175 // is not destroyed, the caller of RemoveGlobalError is responsible to
176 // destroy it, and in the case of the SRTGlobalError, it deletes itself
177 // but only after the bubble has been interacted with.
178 global_error_service->AddGlobalError(global_error);
179 163
180 // Do not try to show bubble if another GlobalError is already showing 164 Profile* profile = browser->profile();
181 // one. The bubble will be shown once the others have been dismissed. 165 DCHECK(profile);
182 const GlobalErrorService::GlobalErrorList& global_errors( 166
183 global_error_service->errors()); 167 PrefService* prefs = profile->GetPrefs();
184 GlobalErrorService::GlobalErrorList::const_iterator it; 168 DCHECK(prefs);
185 for (it = global_errors.begin(); it != global_errors.end(); ++it) { 169
186 if ((*it)->GetBubbleView()) 170 // Don't show the prompt again if it's been shown before for this profile
187 break; 171 // and for the current Finch seed.
188 } 172 std::map<std::string, std::string> params;
189 if (it == global_errors.end()) 173 variations::GetVariationParams(kSRTPromptTrialName, &params);
190 global_error->ShowBubbleView(browser); 174 const std::string previous_prompt_seed =
191 } 175 prefs->GetString(prefs::kSwReporterPromptSeed);
192 } 176 std::map<std::string, std::string>::const_iterator seed_iter(
177 params.find(std::string(kSRTPromptSeedParamName)));
178 bool valid_new_seed = seed_iter != params.end() && !seed_iter->second.empty();
macourteau 2015/01/21 20:53:14 nit: this doesn't mean there is necessarily a new
MAD 2015/01/23 04:34:03 I was trying to differentiate the Finch incoming s
179 if (valid_new_seed && seed_iter->second == previous_prompt_seed)
180 return;
181
182 // If we don't have a new seed, and have shown the prompt before, don't show
183 // it again.
184 const std::string prompt_version =
185 prefs->GetString(prefs::kSwReporterPromptVersion);
186 if (!valid_new_seed && !prompt_version.empty())
187 return;
188
189 if (valid_new_seed)
190 prefs->SetString(prefs::kSwReporterPromptSeed, seed_iter->second);
191 prefs->SetString(prefs::kSwReporterPromptVersion, version);
192 prefs->SetInteger(prefs::kSwReporterPromptReason, exit_code);
193
194 // Make sure we have a tabbed browser since we need to anchor the bubble to
195 // the toolbar's wrench menu. Create one if none exist already.
196 if (browser->type() != Browser::TYPE_TABBED) {
197 browser = chrome::FindTabbedBrowser(profile, false, desktop_type);
198 if (!browser)
199 browser = new Browser(Browser::CreateParams(profile, desktop_type));
macourteau 2015/01/21 20:53:14 Any chance this can leak? (not familiar with Brows
MAD 2015/01/23 04:34:03 This opens a window that the user will close. So w
193 } 200 }
201 GlobalErrorService* global_error_service =
202 GlobalErrorServiceFactory::GetForProfile(profile);
203 SRTGlobalError* global_error = new SRTGlobalError(global_error_service);
194 204
195 base::win::RegKey srt_key( 205 // |global_error_service| takes ownership of |global_error| and keeps it
196 HKEY_CURRENT_USER, kSoftwareRemovalToolRegistryKey, KEY_WRITE); 206 // alive until RemoveGlobalError() is called, and even then, the object
197 srt_key.DeleteValue(kExitCodeRegistryValueName); 207 // is not destroyed, the caller of RemoveGlobalError is responsible to
208 // destroy it, and in the case of the SRTGlobalError, it deletes itself
209 // but only after the bubble has been interacted with.
210 global_error_service->AddGlobalError(global_error);
211
212 // Do not try to show bubble if another GlobalError is already showing
213 // one. The bubble will be shown once the others have been dismissed.
214 const GlobalErrorService::GlobalErrorList& global_errors(
215 global_error_service->errors());
216 GlobalErrorService::GlobalErrorList::const_iterator it;
217 for (it = global_errors.begin(); it != global_errors.end(); ++it) {
218 if ((*it)->GetBubbleView())
219 break;
220 }
221 if (it == global_errors.end())
222 global_error->ShowBubbleView(browser);
198 } 223 }
199 224
200 // This function is called from a worker thread to launch the SwReporter and 225 // This function is called from a worker thread to launch the SwReporter and
201 // wait for termination to collect its exit code. This task could be interrupted 226 // wait for termination to collect its exit code. This task could be interrupted
202 // by a shutdown at anytime, so it shouldn't depend on anything external that 227 // by a shutdown at anytime, so it shouldn't depend on anything external that
203 // could be shutdown beforehand. 228 // could be shutdown beforehand.
204 void LaunchAndWaitForExit(const base::FilePath& exe_path, 229 void LaunchAndWaitForExit(const base::FilePath& exe_path,
205 const std::string& version) { 230 const std::string& version) {
206 const base::CommandLine reporter_command_line(exe_path); 231 const base::CommandLine reporter_command_line(exe_path);
207 base::Process scan_reporter_process = 232 base::Process scan_reporter_process =
(...skipping 187 matching lines...) Expand 10 before | Expand all | Expand 10 after
395 user_prefs::PrefRegistrySyncable* registry) { 420 user_prefs::PrefRegistrySyncable* registry) {
396 registry->RegisterIntegerPref( 421 registry->RegisterIntegerPref(
397 prefs::kSwReporterPromptReason, 422 prefs::kSwReporterPromptReason,
398 -1, 423 -1,
399 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); 424 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
400 425
401 registry->RegisterStringPref( 426 registry->RegisterStringPref(
402 prefs::kSwReporterPromptVersion, 427 prefs::kSwReporterPromptVersion,
403 "", 428 "",
404 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); 429 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
430
431 registry->RegisterStringPref(
432 prefs::kSwReporterPromptSeed, "",
macourteau 2015/01/21 20:53:14 nit: Maybe keep the "" on a separate line for cons
MAD 2015/01/23 04:34:03 git cl format did that, so I updated the others.
433 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
405 } 434 }
406 435
407 } // namespace component_updater 436 } // namespace component_updater
OLDNEW
« no previous file with comments | « no previous file | chrome/browser/prefs/chrome_pref_service_factory.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698