Chromium Code Reviews| 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 <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.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 Loading... | |
| 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 |
| 83 // This function is called on the UI thread to report the SwReporter exit code | 93 // 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 | 94 // 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 | 95 // from the local state. This could be called from an interruptible worker |
| 86 // thread so should be resilient to unexpected shutdown. | 96 // thread so should be resilient to unexpected shutdown. |
| 87 void ReportAndClearExitCode(int exit_code) { | 97 void ReportAndClearExitCode(int exit_code, const std::string& version) { |
|
gab
2014/09/24 16:22:36
Augment method comment with |version|.
MAD
2014/09/24 20:40:35
Done.
| |
| 88 UMA_HISTOGRAM_SPARSE_SLOWLY("SoftwareReporter.ExitCode", exit_code); | 98 UMA_HISTOGRAM_SPARSE_SLOWLY("SoftwareReporter.ExitCode", exit_code); |
| 89 | 99 |
| 100 if (exit_code == kPostRebootCleanupNeeded || exit_code == kCleanupNeeded) { | |
| 101 Browser* browser = | |
| 102 chrome::FindLastActiveWithHostDesktopType(chrome::GetActiveDesktop()); | |
|
gab
2014/09/24 16:22:36
I don't think this is what you want. This may be N
MAD
2014/09/24 20:40:35
The problem is that I don't have a profile here, s
| |
| 103 if (browser) { | |
| 104 Profile* profile = browser->profile(); | |
| 105 DCHECK(profile); | |
| 106 const std::string prompt_state = | |
| 107 profile->GetPrefs()->GetString(prefs::kSwReporterPromptState); | |
| 108 // Don't show the prompt again if it's been shown before. | |
| 109 if (prompt_state.empty()) { | |
| 110 profile->GetPrefs()->SetString(prefs::kSwReporterPromptState, version); | |
|
gab
2014/09/24 16:22:36
Only set this pref if we actually end up showing t
MAD
2014/09/24 20:40:35
No, because we still create the global error which
| |
| 111 GlobalErrorService* global_error_service = | |
| 112 GlobalErrorServiceFactory::GetForProfile(profile); | |
| 113 SRTGlobalError* global_error = new SRTGlobalError(global_error_service); | |
| 114 global_error_service->AddGlobalError(global_error); | |
|
gab
2014/09/24 16:22:36
This gives ownership of |global_error|, make this
MAD
2014/09/24 20:40:35
If I release it here, I won't be able to use it be
| |
| 115 | |
| 116 // Do not try to show bubble if another GlobalError is already showing | |
| 117 // one. | |
| 118 const GlobalErrorService::GlobalErrorList& global_errors( | |
| 119 global_error_service->errors()); | |
| 120 GlobalErrorService::GlobalErrorList::const_iterator it; | |
| 121 for (it = global_errors.begin(); it != global_errors.end(); ++it) { | |
| 122 if ((*it)->GetBubbleView()) | |
|
robertshield
2014/09/24 13:02:12
Just to double check: GetBubbleView() should retur
MAD
2014/09/24 20:40:35
Yes.
| |
| 123 break; | |
| 124 } | |
| 125 if (it == global_errors.end()) | |
| 126 global_error->ShowBubbleView(browser); | |
|
gab
2014/09/24 16:22:36
This is not safe as you gave up ownership of |glob
MAD
2014/09/24 20:40:35
But then if we release it above, we still can't us
| |
| 127 } | |
| 128 } | |
| 129 } | |
| 130 | |
| 90 base::win::RegKey srt_key( | 131 base::win::RegKey srt_key( |
| 91 HKEY_CURRENT_USER, kSoftwareRemovalToolRegistryKey, KEY_WRITE); | 132 HKEY_CURRENT_USER, kSoftwareRemovalToolRegistryKey, KEY_WRITE); |
| 92 srt_key.DeleteValue(kExitCodeRegistryValueName); | 133 srt_key.DeleteValue(kExitCodeRegistryValueName); |
| 93 } | 134 } |
| 94 | 135 |
| 95 // This function is called from a worker thread to launch the SwReporter and | 136 // 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 | 137 // 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 | 138 // by a shutdown at anytime, so it shouldn't depend on anything external that |
| 98 // could be shutdown beforehand. | 139 // could be shutdown beforehand. |
| 99 void LaunchAndWaitForExit(const base::FilePath& exe_path) { | 140 void LaunchAndWaitForExit(const base::FilePath& exe_path, |
| 141 const std::string& version) { | |
| 100 const base::CommandLine reporter_command_line(exe_path); | 142 const base::CommandLine reporter_command_line(exe_path); |
| 101 base::ProcessHandle scan_reporter_process = base::kNullProcessHandle; | 143 base::ProcessHandle scan_reporter_process = base::kNullProcessHandle; |
| 102 if (!base::LaunchProcess(reporter_command_line, | 144 if (!base::LaunchProcess(reporter_command_line, |
| 103 base::LaunchOptions(), | 145 base::LaunchOptions(), |
| 104 &scan_reporter_process)) { | 146 &scan_reporter_process)) { |
| 105 ReportUmaStep(SW_REPORTER_FAILED_TO_START); | 147 ReportUmaStep(SW_REPORTER_FAILED_TO_START); |
| 106 return; | 148 return; |
| 107 } | 149 } |
| 108 ReportUmaStep(SW_REPORTER_START_EXECUTION); | 150 ReportUmaStep(SW_REPORTER_START_EXECUTION); |
| 109 | 151 |
| 110 int exit_code = -1; | 152 int exit_code = -1; |
| 111 bool success = base::WaitForExitCode(scan_reporter_process, &exit_code); | 153 bool success = base::WaitForExitCode(scan_reporter_process, &exit_code); |
| 112 DCHECK(success); | 154 DCHECK(success); |
| 113 base::CloseProcessHandle(scan_reporter_process); | 155 base::CloseProcessHandle(scan_reporter_process); |
| 114 scan_reporter_process = base::kNullProcessHandle; | 156 scan_reporter_process = base::kNullProcessHandle; |
| 115 // It's OK if this doesn't complete, the work will continue on next startup. | 157 // It's OK if this doesn't complete, the work will continue on next startup. |
| 116 BrowserThread::PostTask(BrowserThread::UI, | 158 BrowserThread::PostTask( |
| 117 FROM_HERE, | 159 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, | 160 FROM_HERE, |
| 124 base::Bind(&LaunchAndWaitForExit, install_dir.Append(kSwReporterExeName)), | 161 base::Bind(&ReportAndClearExitCode, exit_code, version)); |
| 125 true); | |
| 126 } | 162 } |
| 127 | 163 |
| 128 class SwReporterInstallerTraits : public ComponentInstallerTraits { | 164 class SwReporterInstallerTraits : public ComponentInstallerTraits { |
| 129 public: | 165 public: |
| 130 explicit SwReporterInstallerTraits(PrefService* prefs) : prefs_(prefs) {} | 166 explicit SwReporterInstallerTraits(PrefService* prefs) : prefs_(prefs) {} |
| 131 | 167 |
| 132 virtual ~SwReporterInstallerTraits() {} | 168 virtual ~SwReporterInstallerTraits() {} |
| 133 | 169 |
| 134 virtual bool VerifyInstallation(const base::FilePath& dir) const { | 170 virtual bool VerifyInstallation(const base::FilePath& dir) const { |
| 135 return base::PathExists(dir.Append(kSwReporterExeName)); | 171 return base::PathExists(dir.Append(kSwReporterExeName)); |
| (...skipping 18 matching lines...) Expand all Loading... | |
| 154 | 190 |
| 155 // A previous run may have results in the registry, so check and report | 191 // A previous run may have results in the registry, so check and report |
| 156 // them if present. | 192 // them if present. |
| 157 base::win::RegKey srt_key( | 193 base::win::RegKey srt_key( |
| 158 HKEY_CURRENT_USER, kSoftwareRemovalToolRegistryKey, KEY_READ); | 194 HKEY_CURRENT_USER, kSoftwareRemovalToolRegistryKey, KEY_READ); |
| 159 DWORD exit_code; | 195 DWORD exit_code; |
| 160 if (srt_key.Valid() && | 196 if (srt_key.Valid() && |
| 161 srt_key.ReadValueDW(kExitCodeRegistryValueName, &exit_code) == | 197 srt_key.ReadValueDW(kExitCodeRegistryValueName, &exit_code) == |
| 162 ERROR_SUCCESS) { | 198 ERROR_SUCCESS) { |
| 163 ReportUmaStep(SW_REPORTER_REGISTRY_EXIT_CODE); | 199 ReportUmaStep(SW_REPORTER_REGISTRY_EXIT_CODE); |
| 164 ReportAndClearExitCode(exit_code); | 200 ReportAndClearExitCode(exit_code, version.GetString()); |
| 165 } | 201 } |
| 166 | 202 |
| 167 // If we can't access local state, we can't see when we last ran, so | 203 // If we can't access local state, we can't see when we last ran, so |
| 168 // just exit without running. | 204 // just exit without running. |
| 169 if (!g_browser_process || !g_browser_process->local_state()) | 205 if (!g_browser_process || !g_browser_process->local_state()) |
| 170 return; | 206 return; |
| 171 | 207 |
| 172 // Run the reporter if it hasn't been triggered in the | 208 // Run the reporter if it hasn't been triggered in the |
| 173 // kDaysBetweenSwReporterRuns days. | 209 // kDaysBetweenSwReporterRuns days. |
| 174 const base::Time last_time_triggered = base::Time::FromInternalValue( | 210 const base::Time last_time_triggered = base::Time::FromInternalValue( |
| 175 g_browser_process->local_state()->GetInt64( | 211 g_browser_process->local_state()->GetInt64( |
| 176 prefs::kSwReporterLastTimeTriggered)); | 212 prefs::kSwReporterLastTimeTriggered)); |
| 177 if ((base::Time::Now() - last_time_triggered).InDays() >= | 213 if ((base::Time::Now() - last_time_triggered).InDays() >= |
| 178 kDaysBetweenSwReporterRuns) { | 214 kDaysBetweenSwReporterRuns) { |
| 179 g_browser_process->local_state()->SetInt64( | 215 g_browser_process->local_state()->SetInt64( |
| 180 prefs::kSwReporterLastTimeTriggered, | 216 prefs::kSwReporterLastTimeTriggered, |
| 181 base::Time::Now().ToInternalValue()); | 217 base::Time::Now().ToInternalValue()); |
| 182 | 218 |
| 183 ExecuteReporter(install_dir); | 219 base::WorkerPool::PostTask( |
| 220 FROM_HERE, | |
| 221 base::Bind(&LaunchAndWaitForExit, | |
| 222 install_dir.Append(kSwReporterExeName), | |
| 223 version.GetString()), | |
| 224 true); | |
| 184 } | 225 } |
| 185 } | 226 } |
| 186 | 227 |
| 187 virtual base::FilePath GetBaseDirectory() const { return install_dir(); } | 228 virtual base::FilePath GetBaseDirectory() const { return install_dir(); } |
| 188 | 229 |
| 189 virtual void GetHash(std::vector<uint8>* hash) const { GetPkHash(hash); } | 230 virtual void GetHash(std::vector<uint8>* hash) const { GetPkHash(hash); } |
| 190 | 231 |
| 191 virtual std::string GetName() const { return "Software Reporter Tool"; } | 232 virtual std::string GetName() const { return "Software Reporter Tool"; } |
| 192 | 233 |
| 193 static base::FilePath install_dir() { | 234 static base::FilePath install_dir() { |
| (...skipping 22 matching lines...) Expand all Loading... | |
| 216 PrefService* prefs_; | 257 PrefService* prefs_; |
| 217 static wchar_t version_dir_[_MAX_PATH]; | 258 static wchar_t version_dir_[_MAX_PATH]; |
| 218 }; | 259 }; |
| 219 | 260 |
| 220 wchar_t SwReporterInstallerTraits::version_dir_[] = {}; | 261 wchar_t SwReporterInstallerTraits::version_dir_[] = {}; |
| 221 | 262 |
| 222 } // namespace | 263 } // namespace |
| 223 | 264 |
| 224 void RegisterSwReporterComponent(ComponentUpdateService* cus, | 265 void RegisterSwReporterComponent(ComponentUpdateService* cus, |
| 225 PrefService* prefs) { | 266 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. | 267 // Install the component. |
| 231 scoped_ptr<ComponentInstallerTraits> traits( | 268 scoped_ptr<ComponentInstallerTraits> traits( |
| 232 new SwReporterInstallerTraits(prefs)); | 269 new SwReporterInstallerTraits(prefs)); |
| 233 // |cus| will take ownership of |installer| during installer->Register(cus). | 270 // |cus| will take ownership of |installer| during installer->Register(cus). |
| 234 DefaultComponentInstaller* installer = | 271 DefaultComponentInstaller* installer = |
| 235 new DefaultComponentInstaller(traits.Pass()); | 272 new DefaultComponentInstaller(traits.Pass()); |
| 236 installer->Register(cus); | 273 installer->Register(cus); |
| 237 } | 274 } |
| 238 | 275 |
| 239 void RegisterPrefsForSwReporter(PrefRegistrySimple* registry) { | 276 void RegisterPrefsForSwReporter(PrefRegistrySimple* registry) { |
| 240 registry->RegisterInt64Pref(prefs::kSwReporterLastTimeTriggered, 0); | 277 registry->RegisterInt64Pref(prefs::kSwReporterLastTimeTriggered, 0); |
| 241 } | 278 } |
| 242 | 279 |
| 280 void RegisterProfilePrefsForSwReporter( | |
| 281 user_prefs::PrefRegistrySyncable* registry) { | |
| 282 registry->RegisterStringPref( | |
| 283 prefs::kSwReporterPromptState, | |
| 284 "", | |
| 285 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); | |
| 286 } | |
| 287 | |
| 243 } // namespace component_updater | 288 } // namespace component_updater |
| OLD | NEW |