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 16 matching lines...) Expand all Loading... | |
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 Loading... | |
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, ¶ms); |
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 Loading... | |
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 |
OLD | NEW |