OLD | NEW |
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 17 matching lines...) Expand all Loading... |
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/default_component_installer.h" | 42 #include "components/component_updater/default_component_installer.h" |
41 #include "components/component_updater/pref_names.h" | 43 #include "components/component_updater/pref_names.h" |
42 #include "components/pref_registry/pref_registry_syncable.h" | 44 #include "components/pref_registry/pref_registry_syncable.h" |
43 #include "components/update_client/update_client.h" | 45 #include "components/update_client/update_client.h" |
44 #include "components/update_client/utils.h" | 46 #include "components/update_client/utils.h" |
| 47 #include "components/variations/variations_associated_data.h" |
45 #include "content/public/browser/browser_thread.h" | 48 #include "content/public/browser/browser_thread.h" |
46 | 49 |
47 using content::BrowserThread; | 50 using content::BrowserThread; |
48 | 51 |
49 namespace component_updater { | 52 namespace component_updater { |
50 | 53 |
51 namespace { | 54 namespace { |
52 | 55 |
53 // These values are used to send UMA information and are replicated in the | 56 // These values are used to send UMA information and are replicated in the |
54 // histograms.xml file, so the order MUST NOT CHANGE. | 57 // histograms.xml file, so the order MUST NOT CHANGE. |
(...skipping 30 matching lines...) Expand all Loading... |
85 L"Software\\Google\\Software Removal Tool"; | 88 L"Software\\Google\\Software Removal Tool"; |
86 const wchar_t kCleanerSuffixRegistryKey[] = L"Cleaner"; | 89 const wchar_t kCleanerSuffixRegistryKey[] = L"Cleaner"; |
87 const wchar_t kExitCodeRegistryValueName[] = L"ExitCode"; | 90 const wchar_t kExitCodeRegistryValueName[] = L"ExitCode"; |
88 const wchar_t kVersionRegistryValueName[] = L"Version"; | 91 const wchar_t kVersionRegistryValueName[] = L"Version"; |
89 const wchar_t kStartTimeRegistryValueName[] = L"StartTime"; | 92 const wchar_t kStartTimeRegistryValueName[] = L"StartTime"; |
90 const wchar_t kEndTimeRegistryValueName[] = L"EndTime"; | 93 const wchar_t kEndTimeRegistryValueName[] = L"EndTime"; |
91 | 94 |
92 // Field trial strings. | 95 // Field trial strings. |
93 const char kSRTPromptTrialName[] = "SRTPromptFieldTrial"; | 96 const char kSRTPromptTrialName[] = "SRTPromptFieldTrial"; |
94 const char kSRTPromptOnGroup[] = "On"; | 97 const char kSRTPromptOnGroup[] = "On"; |
| 98 const char kSRTPromptSeedParamName[] = "Seed"; |
95 | 99 |
96 // Exit codes that identify that a cleanup is needed. | 100 // Exit codes that identify that a cleanup is needed. |
97 const int kCleanupNeeded = 0; | 101 const int kCleanupNeeded = 0; |
98 const int kNothingFound = 2; | 102 const int kNothingFound = 2; |
99 const int kPostRebootCleanupNeeded = 4; | 103 const int kPostRebootCleanupNeeded = 4; |
100 const int kDelayedPostRebootCleanupNeeded = 15; | 104 const int kDelayedPostRebootCleanupNeeded = 15; |
101 | 105 |
102 void ReportUmaStep(SwReporterUmaValue value) { | 106 void ReportUmaStep(SwReporterUmaValue value) { |
103 UMA_HISTOGRAM_ENUMERATION("SoftwareReporter.Step", value, SW_REPORTER_MAX); | 107 UMA_HISTOGRAM_ENUMERATION("SoftwareReporter.Step", value, SW_REPORTER_MAX); |
104 } | 108 } |
(...skipping 25 matching lines...) Expand all Loading... |
130 UMA_HISTOGRAM_SPARSE_SLOWLY("SoftwareReporter.MajorVersion", major_version); | 134 UMA_HISTOGRAM_SPARSE_SLOWLY("SoftwareReporter.MajorVersion", major_version); |
131 } | 135 } |
132 | 136 |
133 // This function is called on the UI thread to report the SwReporter exit code | 137 // This function is called on the UI thread to report the SwReporter exit code |
134 // and then clear it from the registry as well as clear the execution state | 138 // and then clear it from the registry as well as clear the execution state |
135 // from the local state. This could be called from an interruptible worker | 139 // from the local state. This could be called from an interruptible worker |
136 // thread so should be resilient to unexpected shutdown. |version| is provided | 140 // thread so should be resilient to unexpected shutdown. |version| is provided |
137 // so the kSwReporterPromptVersion prefs can be set. | 141 // so the kSwReporterPromptVersion prefs can be set. |
138 void ReportAndClearExitCode(int exit_code, const std::string& version) { | 142 void ReportAndClearExitCode(int exit_code, const std::string& version) { |
139 UMA_HISTOGRAM_SPARSE_SLOWLY("SoftwareReporter.ExitCode", exit_code); | 143 UMA_HISTOGRAM_SPARSE_SLOWLY("SoftwareReporter.ExitCode", exit_code); |
| 144 base::win::RegKey srt_key(HKEY_CURRENT_USER, kSoftwareRemovalToolRegistryKey, |
| 145 KEY_WRITE); |
| 146 srt_key.DeleteValue(kExitCodeRegistryValueName); |
| 147 |
140 if (g_browser_process && g_browser_process->local_state()) { | 148 if (g_browser_process && g_browser_process->local_state()) { |
141 g_browser_process->local_state()->SetInteger(prefs::kSwReporterLastExitCode, | 149 g_browser_process->local_state()->SetInteger(prefs::kSwReporterLastExitCode, |
142 exit_code); | 150 exit_code); |
143 } | 151 } |
144 | 152 |
145 if ((exit_code == kPostRebootCleanupNeeded || exit_code == kCleanupNeeded) && | 153 if ((exit_code != kPostRebootCleanupNeeded && exit_code != kCleanupNeeded) || |
146 base::FieldTrialList::FindFullName(kSRTPromptTrialName) == | 154 base::FieldTrialList::FindFullName(kSRTPromptTrialName) != |
147 kSRTPromptOnGroup) { | 155 kSRTPromptOnGroup) { |
148 // Find the last active browser, which may be NULL, in which case we won't | 156 return; |
149 // show the prompt this time and will wait until the next run of the | 157 } |
150 // reporter. We can't use other ways of finding a browser because we don't | 158 // Find the last active browser, which may be NULL, in which case we won't |
151 // have a profile. | 159 // show the prompt this time and will wait until the next run of the |
152 chrome::HostDesktopType desktop_type = chrome::GetActiveDesktop(); | 160 // reporter. We can't use other ways of finding a browser because we don't |
153 Browser* browser = chrome::FindLastActiveWithHostDesktopType(desktop_type); | 161 // have a profile. |
154 if (browser) { | 162 chrome::HostDesktopType desktop_type = chrome::GetActiveDesktop(); |
155 Profile* profile = browser->profile(); | 163 Browser* browser = chrome::FindLastActiveWithHostDesktopType(desktop_type); |
156 // Don't show the prompt again if it's been shown before for this profile. | 164 if (!browser) |
157 DCHECK(profile); | 165 return; |
158 const std::string prompt_version = | |
159 profile->GetPrefs()->GetString(prefs::kSwReporterPromptVersion); | |
160 if (prompt_version.empty()) { | |
161 profile->GetPrefs()->SetString(prefs::kSwReporterPromptVersion, | |
162 version); | |
163 profile->GetPrefs()->SetInteger(prefs::kSwReporterPromptReason, | |
164 exit_code); | |
165 // Now that we have a profile, make sure we have a tabbed browser since | |
166 // we need to anchor the bubble to the toolbar's wrench menu. Create one | |
167 // if none exist already. | |
168 if (browser->type() != Browser::TYPE_TABBED) { | |
169 browser = chrome::FindTabbedBrowser(profile, false, desktop_type); | |
170 if (!browser) | |
171 browser = new Browser(Browser::CreateParams(profile, desktop_type)); | |
172 } | |
173 GlobalErrorService* global_error_service = | |
174 GlobalErrorServiceFactory::GetForProfile(profile); | |
175 SRTGlobalError* global_error = new SRTGlobalError(global_error_service); | |
176 // |global_error_service| takes ownership of |global_error| and keeps it | |
177 // alive until RemoveGlobalError() is called, and even then, the object | |
178 // is not destroyed, the caller of RemoveGlobalError is responsible to | |
179 // destroy it, and in the case of the SRTGlobalError, it deletes itself | |
180 // but only after the bubble has been interacted with. | |
181 global_error_service->AddGlobalError(global_error); | |
182 | 166 |
183 // Do not try to show bubble if another GlobalError is already showing | 167 Profile* profile = browser->profile(); |
184 // one. The bubble will be shown once the others have been dismissed. | 168 DCHECK(profile); |
185 const GlobalErrorService::GlobalErrorList& global_errors( | 169 |
186 global_error_service->errors()); | 170 PrefService* prefs = profile->GetPrefs(); |
187 GlobalErrorService::GlobalErrorList::const_iterator it; | 171 DCHECK(prefs); |
188 for (it = global_errors.begin(); it != global_errors.end(); ++it) { | 172 |
189 if ((*it)->GetBubbleView()) | 173 // Don't show the prompt again if it's been shown before for this profile |
190 break; | 174 // and for the current Finch seed. |
191 } | 175 std::map<std::string, std::string> params; |
192 if (it == global_errors.end()) | 176 variations::GetVariationParams(kSRTPromptTrialName, ¶ms); |
193 global_error->ShowBubbleView(browser); | 177 const std::string previous_prompt_seed = |
194 } | 178 prefs->GetString(prefs::kSwReporterPromptSeed); |
195 } | 179 std::map<std::string, std::string>::const_iterator seed_iter( |
| 180 params.find(std::string(kSRTPromptSeedParamName))); |
| 181 bool valid_incoming_seed = |
| 182 seed_iter != params.end() && !seed_iter->second.empty(); |
| 183 if (valid_incoming_seed && seed_iter->second == previous_prompt_seed) |
| 184 return; |
| 185 |
| 186 // If we don't have a new seed, and have shown the prompt before, don't show |
| 187 // it again. |
| 188 const std::string prompt_version = |
| 189 prefs->GetString(prefs::kSwReporterPromptVersion); |
| 190 if (!valid_incoming_seed && !prompt_version.empty()) |
| 191 return; |
| 192 |
| 193 if (valid_incoming_seed) |
| 194 prefs->SetString(prefs::kSwReporterPromptSeed, seed_iter->second); |
| 195 prefs->SetString(prefs::kSwReporterPromptVersion, version); |
| 196 prefs->SetInteger(prefs::kSwReporterPromptReason, exit_code); |
| 197 |
| 198 // Make sure we have a tabbed browser since we need to anchor the bubble to |
| 199 // the toolbar's wrench menu. Create one if none exist already. |
| 200 if (browser->type() != Browser::TYPE_TABBED) { |
| 201 browser = chrome::FindTabbedBrowser(profile, false, desktop_type); |
| 202 if (!browser) |
| 203 browser = new Browser(Browser::CreateParams(profile, desktop_type)); |
196 } | 204 } |
| 205 GlobalErrorService* global_error_service = |
| 206 GlobalErrorServiceFactory::GetForProfile(profile); |
| 207 SRTGlobalError* global_error = new SRTGlobalError(global_error_service); |
197 | 208 |
198 base::win::RegKey srt_key( | 209 // |global_error_service| takes ownership of |global_error| and keeps it |
199 HKEY_CURRENT_USER, kSoftwareRemovalToolRegistryKey, KEY_WRITE); | 210 // alive until RemoveGlobalError() is called, and even then, the object |
200 srt_key.DeleteValue(kExitCodeRegistryValueName); | 211 // is not destroyed, the caller of RemoveGlobalError is responsible to |
| 212 // destroy it, and in the case of the SRTGlobalError, it deletes itself |
| 213 // but only after the bubble has been interacted with. |
| 214 global_error_service->AddGlobalError(global_error); |
| 215 |
| 216 // Do not try to show bubble if another GlobalError is already showing |
| 217 // one. The bubble will be shown once the others have been dismissed. |
| 218 const GlobalErrorService::GlobalErrorList& global_errors( |
| 219 global_error_service->errors()); |
| 220 GlobalErrorService::GlobalErrorList::const_iterator it; |
| 221 for (it = global_errors.begin(); it != global_errors.end(); ++it) { |
| 222 if ((*it)->GetBubbleView()) |
| 223 break; |
| 224 } |
| 225 if (it == global_errors.end()) |
| 226 global_error->ShowBubbleView(browser); |
201 } | 227 } |
202 | 228 |
203 // This function is called from a worker thread to launch the SwReporter and | 229 // This function is called from a worker thread to launch the SwReporter and |
204 // wait for termination to collect its exit code. This task could be interrupted | 230 // wait for termination to collect its exit code. This task could be interrupted |
205 // by a shutdown at anytime, so it shouldn't depend on anything external that | 231 // by a shutdown at anytime, so it shouldn't depend on anything external that |
206 // could be shutdown beforehand. | 232 // could be shutdown beforehand. |
207 void LaunchAndWaitForExit(const base::FilePath& exe_path, | 233 void LaunchAndWaitForExit(const base::FilePath& exe_path, |
208 const std::string& version) { | 234 const std::string& version) { |
209 const base::CommandLine reporter_command_line(exe_path); | 235 const base::CommandLine reporter_command_line(exe_path); |
210 base::Process scan_reporter_process = | 236 base::Process scan_reporter_process = |
(...skipping 191 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
402 } | 428 } |
403 | 429 |
404 void RegisterPrefsForSwReporter(PrefRegistrySimple* registry) { | 430 void RegisterPrefsForSwReporter(PrefRegistrySimple* registry) { |
405 registry->RegisterInt64Pref(prefs::kSwReporterLastTimeTriggered, 0); | 431 registry->RegisterInt64Pref(prefs::kSwReporterLastTimeTriggered, 0); |
406 registry->RegisterIntegerPref(prefs::kSwReporterLastExitCode, -1); | 432 registry->RegisterIntegerPref(prefs::kSwReporterLastExitCode, -1); |
407 } | 433 } |
408 | 434 |
409 void RegisterProfilePrefsForSwReporter( | 435 void RegisterProfilePrefsForSwReporter( |
410 user_prefs::PrefRegistrySyncable* registry) { | 436 user_prefs::PrefRegistrySyncable* registry) { |
411 registry->RegisterIntegerPref( | 437 registry->RegisterIntegerPref( |
412 prefs::kSwReporterPromptReason, | 438 prefs::kSwReporterPromptReason, -1, |
413 -1, | |
414 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); | 439 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); |
415 | 440 |
416 registry->RegisterStringPref( | 441 registry->RegisterStringPref( |
417 prefs::kSwReporterPromptVersion, | 442 prefs::kSwReporterPromptVersion, "", |
418 "", | 443 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); |
| 444 |
| 445 registry->RegisterStringPref( |
| 446 prefs::kSwReporterPromptSeed, "", |
419 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); | 447 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); |
420 } | 448 } |
421 | 449 |
422 } // namespace component_updater | 450 } // namespace component_updater |
OLD | NEW |