| 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 | 8 |
| 9 #include <algorithm> | 9 #include <algorithm> |
| 10 #include <map> | 10 #include <map> |
| (...skipping 29 matching lines...) Expand all Loading... |
| 40 #include "components/prefs/pref_registry_simple.h" | 40 #include "components/prefs/pref_registry_simple.h" |
| 41 #include "components/update_client/update_client.h" | 41 #include "components/update_client/update_client.h" |
| 42 #include "components/update_client/utils.h" | 42 #include "components/update_client/utils.h" |
| 43 #include "components/variations/variations_associated_data.h" | 43 #include "components/variations/variations_associated_data.h" |
| 44 #include "content/public/browser/browser_thread.h" | 44 #include "content/public/browser/browser_thread.h" |
| 45 | 45 |
| 46 namespace component_updater { | 46 namespace component_updater { |
| 47 | 47 |
| 48 namespace { | 48 namespace { |
| 49 | 49 |
| 50 using safe_browsing::SwReporterInvocation; |
| 51 |
| 50 // These values are used to send UMA information and are replicated in the | 52 // These values are used to send UMA information and are replicated in the |
| 51 // histograms.xml file, so the order MUST NOT CHANGE. | 53 // histograms.xml file, so the order MUST NOT CHANGE. |
| 52 enum SRTCompleted { | 54 enum SRTCompleted { |
| 53 SRT_COMPLETED_NOT_YET = 0, | 55 SRT_COMPLETED_NOT_YET = 0, |
| 54 SRT_COMPLETED_YES = 1, | 56 SRT_COMPLETED_YES = 1, |
| 55 SRT_COMPLETED_LATER = 2, | 57 SRT_COMPLETED_LATER = 2, |
| 56 SRT_COMPLETED_MAX, | 58 SRT_COMPLETED_MAX, |
| 57 }; | 59 }; |
| 58 | 60 |
| 59 // CRX hash. The extension id is: gkmgaooipdjhmangpemjhigmamcehddo. The hash was | 61 // CRX hash. The extension id is: gkmgaooipdjhmangpemjhigmamcehddo. The hash was |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 114 | 116 |
| 115 void ReportExperimentError(SwReporterExperimentError error) { | 117 void ReportExperimentError(SwReporterExperimentError error) { |
| 116 UMA_HISTOGRAM_ENUMERATION("SoftwareReporter.ExperimentErrors", error, | 118 UMA_HISTOGRAM_ENUMERATION("SoftwareReporter.ExperimentErrors", error, |
| 117 SW_REPORTER_EXPERIMENT_ERROR_MAX); | 119 SW_REPORTER_EXPERIMENT_ERROR_MAX); |
| 118 } | 120 } |
| 119 | 121 |
| 120 // Run the software reporter on the next Chrome startup after it's downloaded. | 122 // Run the software reporter on the next Chrome startup after it's downloaded. |
| 121 // (This is the default |reporter_runner| function passed to the | 123 // (This is the default |reporter_runner| function passed to the |
| 122 // |SwReporterInstallerTraits| constructor in |RegisterSwReporterComponent| | 124 // |SwReporterInstallerTraits| constructor in |RegisterSwReporterComponent| |
| 123 // below.) | 125 // below.) |
| 124 void RunSwReporterAfterStartup( | 126 void RunSwReportersAfterStartup( |
| 125 const safe_browsing::SwReporterInvocation& invocation, | 127 const safe_browsing::SwReporterQueue& invocations, |
| 126 const base::Version& version) { | 128 const base::Version& version) { |
| 127 content::BrowserThread::PostAfterStartupTask( | 129 content::BrowserThread::PostAfterStartupTask( |
| 128 FROM_HERE, base::ThreadTaskRunnerHandle::Get(), | 130 FROM_HERE, base::ThreadTaskRunnerHandle::Get(), |
| 129 base::Bind(&safe_browsing::RunSwReporter, invocation, version, | 131 base::Bind(&safe_browsing::RunSwReporters, invocations, version, |
| 130 base::ThreadTaskRunnerHandle::Get(), | 132 base::ThreadTaskRunnerHandle::Get(), |
| 131 base::WorkerPool::GetTaskRunner(true))); | 133 base::WorkerPool::GetTaskRunner(true))); |
| 132 } | 134 } |
| 133 | 135 |
| 134 // Ensures |str| contains only alphanumeric characters and characters from | 136 // Ensures |str| contains only alphanumeric characters and characters from |
| 135 // |extras|, and is not longer than |max_length|. | 137 // |extras|, and is not longer than |max_length|. |
| 136 bool ValidateString(const std::string& str, | 138 bool ValidateString(const std::string& str, |
| 137 const std::string& extras, | 139 const std::string& extras, |
| 138 size_t max_length) { | 140 size_t max_length) { |
| 139 return str.size() <= max_length && | 141 return str.size() <= max_length && |
| 140 std::all_of(str.cbegin(), str.cend(), [&extras](char c) { | 142 std::all_of(str.cbegin(), str.cend(), [&extras](char c) { |
| 141 return base::IsAsciiAlpha(c) || base::IsAsciiDigit(c) || | 143 return base::IsAsciiAlpha(c) || base::IsAsciiDigit(c) || |
| 142 extras.find(c) != std::string::npos; | 144 extras.find(c) != std::string::npos; |
| 143 }); | 145 }); |
| 144 } | 146 } |
| 145 | 147 |
| 146 // Reads the command-line params and an UMA histogram suffix from the manifest, | 148 // Reads the command-line params and an UMA histogram suffix from the manifest, |
| 147 // and launch the SwReporter with those parameters. If anything goes wrong the | 149 // and launch the SwReporter with those parameters. If anything goes wrong the |
| 148 // SwReporter should not be run at all, instead of falling back to the default. | 150 // SwReporter should not be run at all. |
| 149 void RunExperimentalSwReporter(const base::FilePath& exe_path, | 151 void RunExperimentalSwReporter(const base::FilePath& exe_path, |
| 150 const base::Version& version, | 152 const base::Version& version, |
| 151 std::unique_ptr<base::DictionaryValue> manifest, | 153 std::unique_ptr<base::DictionaryValue> manifest, |
| 152 const SwReporterRunner& reporter_runner) { | 154 const SwReporterRunner& reporter_runner) { |
| 153 // The experiment requires launch_params so if they aren't present just | 155 // The experiment requires launch_params so if they aren't present just |
| 154 // return. This isn't an error because the user could get into the experiment | 156 // return. This isn't an error because the user could get into the experiment |
| 155 // group before they've downloaded the experiment component. | 157 // group before they've downloaded the experiment component. |
| 156 base::Value* launch_params = nullptr; | 158 base::Value* launch_params = nullptr; |
| 157 if (!manifest->Get("launch_params", &launch_params)) | 159 if (!manifest->Get("launch_params", &launch_params)) |
| 158 return; | 160 return; |
| 159 | 161 |
| 160 const base::ListValue* parameter_list = nullptr; | 162 const base::ListValue* parameter_list = nullptr; |
| 161 if (!launch_params->GetAsList(¶meter_list) || parameter_list->empty() || | 163 if (!launch_params->GetAsList(¶meter_list) || parameter_list->empty()) { |
| 162 // For future expansion, the manifest takes a list of invocation | |
| 163 // parameters, but currently we only support a single invocation. | |
| 164 parameter_list->GetSize() > 1) { | |
| 165 ReportExperimentError(SW_REPORTER_EXPERIMENT_ERROR_BAD_PARAMS); | 164 ReportExperimentError(SW_REPORTER_EXPERIMENT_ERROR_BAD_PARAMS); |
| 166 return; | 165 return; |
| 167 } | 166 } |
| 168 | 167 |
| 169 const base::DictionaryValue* invocation_params = nullptr; | 168 safe_browsing::SwReporterQueue invocations; |
| 170 if (!parameter_list->GetDictionary(0, &invocation_params)) { | 169 for (const auto& iter : *parameter_list) { |
| 171 ReportExperimentError(SW_REPORTER_EXPERIMENT_ERROR_BAD_PARAMS); | 170 const base::DictionaryValue* invocation_params = nullptr; |
| 172 return; | 171 if (!iter->GetAsDictionary(&invocation_params)) { |
| 173 } | |
| 174 | |
| 175 // Max length of the registry and histogram suffix. Fairly arbitrary: the | |
| 176 // Windows registry accepts much longer keys, but we need to display this | |
| 177 // string in histograms as well. | |
| 178 constexpr size_t kMaxSuffixLength = 80; | |
| 179 | |
| 180 // The suffix must be an alphanumeric string. (Empty is fine as long as the | |
| 181 // "suffix" key is present.) | |
| 182 std::string suffix; | |
| 183 const base::Value* suffix_value = nullptr; | |
| 184 if (!invocation_params->Get("suffix", &suffix_value) || | |
| 185 !suffix_value->GetAsString(&suffix) || | |
| 186 (!suffix.empty() && | |
| 187 !ValidateString(suffix, std::string(), kMaxSuffixLength))) { | |
| 188 ReportExperimentError(SW_REPORTER_EXPERIMENT_ERROR_BAD_PARAMS); | |
| 189 return; | |
| 190 } | |
| 191 | |
| 192 // Build a command line for the reporter out of the executable path and the | |
| 193 // arguments from the manifest. (The "arguments" key must be present, but | |
| 194 // it's ok if it's an empty list or a list of empty strings.) | |
| 195 std::vector<base::string16> argv = {exe_path.value()}; | |
| 196 const base::Value* arguments_value = nullptr; | |
| 197 const base::ListValue* arguments = nullptr; | |
| 198 if (!invocation_params->Get("arguments", &arguments_value) || | |
| 199 !arguments_value->GetAsList(&arguments)) { | |
| 200 ReportExperimentError(SW_REPORTER_EXPERIMENT_ERROR_BAD_PARAMS); | |
| 201 return; | |
| 202 } | |
| 203 | |
| 204 for (const auto& value : *arguments) { | |
| 205 base::string16 argument; | |
| 206 if (!value->GetAsString(&argument)) { | |
| 207 ReportExperimentError(SW_REPORTER_EXPERIMENT_ERROR_BAD_PARAMS); | 172 ReportExperimentError(SW_REPORTER_EXPERIMENT_ERROR_BAD_PARAMS); |
| 208 return; | 173 return; |
| 209 } | 174 } |
| 210 if (!argument.empty()) | 175 |
| 211 argv.push_back(argument); | 176 // Max length of the registry and histogram suffix. Fairly arbitrary: the |
| 177 // Windows registry accepts much longer keys, but we need to display this |
| 178 // string in histograms as well. |
| 179 constexpr size_t kMaxSuffixLength = 80; |
| 180 |
| 181 // The suffix must be an alphanumeric string. (Empty is fine as long as the |
| 182 // "suffix" key is present.) |
| 183 std::string suffix; |
| 184 if (!invocation_params->GetString("suffix", &suffix) || |
| 185 !ValidateString(suffix, std::string(), kMaxSuffixLength)) { |
| 186 ReportExperimentError(SW_REPORTER_EXPERIMENT_ERROR_BAD_PARAMS); |
| 187 return; |
| 188 } |
| 189 |
| 190 // Build a command line for the reporter out of the executable path and the |
| 191 // arguments from the manifest. (The "arguments" key must be present, but |
| 192 // it's ok if it's an empty list or a list of empty strings.) |
| 193 const base::ListValue* arguments = nullptr; |
| 194 if (!invocation_params->GetList("arguments", &arguments)) { |
| 195 ReportExperimentError(SW_REPORTER_EXPERIMENT_ERROR_BAD_PARAMS); |
| 196 return; |
| 197 } |
| 198 |
| 199 std::vector<base::string16> argv = {exe_path.value()}; |
| 200 for (const auto& value : *arguments) { |
| 201 base::string16 argument; |
| 202 if (!value->GetAsString(&argument)) { |
| 203 ReportExperimentError(SW_REPORTER_EXPERIMENT_ERROR_BAD_PARAMS); |
| 204 return; |
| 205 } |
| 206 if (!argument.empty()) |
| 207 argv.push_back(argument); |
| 208 } |
| 209 |
| 210 base::CommandLine command_line(argv); |
| 211 |
| 212 // Add the histogram suffix to the command-line as well, so that the |
| 213 // reporter will add the same suffix to registry keys where it writes |
| 214 // metrics. |
| 215 if (!suffix.empty()) |
| 216 command_line.AppendSwitchASCII("registry-suffix", suffix); |
| 217 |
| 218 // "prompt" is optional, but if present must be a boolean. |
| 219 SwReporterInvocation::Flags flags = 0; |
| 220 const base::Value* prompt_value = nullptr; |
| 221 if (invocation_params->Get("prompt", &prompt_value)) { |
| 222 bool prompt = false; |
| 223 if (!prompt_value->GetAsBoolean(&prompt)) { |
| 224 ReportExperimentError(SW_REPORTER_EXPERIMENT_ERROR_BAD_PARAMS); |
| 225 return; |
| 226 } |
| 227 if (prompt) |
| 228 flags |= SwReporterInvocation::FLAG_TRIGGER_PROMPT; |
| 229 } |
| 230 |
| 231 auto invocation = SwReporterInvocation::FromCommandLine(command_line); |
| 232 invocation.suffix = suffix; |
| 233 invocation.flags = flags; |
| 234 invocations.push(invocation); |
| 212 } | 235 } |
| 213 | 236 |
| 214 base::CommandLine command_line(argv); | 237 DCHECK(!invocations.empty()); |
| 215 | 238 reporter_runner.Run(invocations, version); |
| 216 // Add the histogram suffix to the command-line as well, so that the | |
| 217 // reporter will add the same suffix to registry keys where it writes | |
| 218 // metrics. | |
| 219 if (!suffix.empty()) | |
| 220 command_line.AppendSwitchASCII("registry-suffix", suffix); | |
| 221 | |
| 222 auto invocation = | |
| 223 safe_browsing::SwReporterInvocation::FromCommandLine(command_line); | |
| 224 invocation.suffix = suffix; | |
| 225 invocation.is_experimental = true; | |
| 226 | |
| 227 reporter_runner.Run(invocation, version); | |
| 228 } | 239 } |
| 229 | 240 |
| 230 } // namespace | 241 } // namespace |
| 231 | 242 |
| 232 SwReporterInstallerTraits::SwReporterInstallerTraits( | 243 SwReporterInstallerTraits::SwReporterInstallerTraits( |
| 233 const SwReporterRunner& reporter_runner, | 244 const SwReporterRunner& reporter_runner, |
| 234 bool is_experimental_engine_supported) | 245 bool is_experimental_engine_supported) |
| 235 : reporter_runner_(reporter_runner), | 246 : reporter_runner_(reporter_runner), |
| 236 is_experimental_engine_supported_(is_experimental_engine_supported) {} | 247 is_experimental_engine_supported_(is_experimental_engine_supported) {} |
| 237 | 248 |
| (...skipping 23 matching lines...) Expand all Loading... |
| 261 void SwReporterInstallerTraits::ComponentReady( | 272 void SwReporterInstallerTraits::ComponentReady( |
| 262 const base::Version& version, | 273 const base::Version& version, |
| 263 const base::FilePath& install_dir, | 274 const base::FilePath& install_dir, |
| 264 std::unique_ptr<base::DictionaryValue> manifest) { | 275 std::unique_ptr<base::DictionaryValue> manifest) { |
| 265 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); | 276 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
| 266 const base::FilePath exe_path(install_dir.Append(kSwReporterExeName)); | 277 const base::FilePath exe_path(install_dir.Append(kSwReporterExeName)); |
| 267 if (IsExperimentalEngineEnabled()) { | 278 if (IsExperimentalEngineEnabled()) { |
| 268 RunExperimentalSwReporter(exe_path, version, std::move(manifest), | 279 RunExperimentalSwReporter(exe_path, version, std::move(manifest), |
| 269 reporter_runner_); | 280 reporter_runner_); |
| 270 } else { | 281 } else { |
| 271 reporter_runner_.Run( | 282 auto invocation = SwReporterInvocation::FromFilePath(exe_path); |
| 272 safe_browsing::SwReporterInvocation::FromFilePath(exe_path), version); | 283 invocation.flags = SwReporterInvocation::FLAG_LOG_TO_RAPPOR | |
| 284 SwReporterInvocation::FLAG_LOG_EXIT_CODE_TO_PREFS | |
| 285 SwReporterInvocation::FLAG_TRIGGER_PROMPT | |
| 286 SwReporterInvocation::FLAG_SEND_REPORTER_LOGS; |
| 287 |
| 288 safe_browsing::SwReporterQueue invocations; |
| 289 invocations.push(invocation); |
| 290 reporter_runner_.Run(invocations, version); |
| 273 } | 291 } |
| 274 } | 292 } |
| 275 | 293 |
| 276 base::FilePath SwReporterInstallerTraits::GetRelativeInstallDir() const { | 294 base::FilePath SwReporterInstallerTraits::GetRelativeInstallDir() const { |
| 277 return base::FilePath(FILE_PATH_LITERAL("SwReporter")); | 295 return base::FilePath(FILE_PATH_LITERAL("SwReporter")); |
| 278 } | 296 } |
| 279 | 297 |
| 280 void SwReporterInstallerTraits::GetHash(std::vector<uint8_t>* hash) const { | 298 void SwReporterInstallerTraits::GetHash(std::vector<uint8_t>* hash) const { |
| 281 DCHECK(hash); | 299 DCHECK(hash); |
| 282 hash->assign(kSha256Hash, kSha256Hash + sizeof(kSha256Hash)); | 300 hash->assign(kSha256Hash, kSha256Hash + sizeof(kSha256Hash)); |
| (...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 398 } | 416 } |
| 399 | 417 |
| 400 // The experiment is only enabled on x86. There's no way to check this in the | 418 // The experiment is only enabled on x86. There's no way to check this in the |
| 401 // variations config so we'll hard-code it. | 419 // variations config so we'll hard-code it. |
| 402 const bool is_experimental_engine_supported = | 420 const bool is_experimental_engine_supported = |
| 403 base::win::OSInfo::GetInstance()->architecture() == | 421 base::win::OSInfo::GetInstance()->architecture() == |
| 404 base::win::OSInfo::X86_ARCHITECTURE; | 422 base::win::OSInfo::X86_ARCHITECTURE; |
| 405 | 423 |
| 406 // Install the component. | 424 // Install the component. |
| 407 std::unique_ptr<ComponentInstallerTraits> traits( | 425 std::unique_ptr<ComponentInstallerTraits> traits( |
| 408 new SwReporterInstallerTraits(base::Bind(&RunSwReporterAfterStartup), | 426 new SwReporterInstallerTraits(base::Bind(&RunSwReportersAfterStartup), |
| 409 is_experimental_engine_supported)); | 427 is_experimental_engine_supported)); |
| 410 // |cus| will take ownership of |installer| during installer->Register(cus). | 428 // |cus| will take ownership of |installer| during installer->Register(cus). |
| 411 DefaultComponentInstaller* installer = | 429 DefaultComponentInstaller* installer = |
| 412 new DefaultComponentInstaller(std::move(traits)); | 430 new DefaultComponentInstaller(std::move(traits)); |
| 413 installer->Register(cus, base::Closure()); | 431 installer->Register(cus, base::Closure()); |
| 414 } | 432 } |
| 415 | 433 |
| 416 void RegisterPrefsForSwReporter(PrefRegistrySimple* registry) { | 434 void RegisterPrefsForSwReporter(PrefRegistrySimple* registry) { |
| 417 registry->RegisterInt64Pref(prefs::kSwReporterLastTimeTriggered, 0); | 435 registry->RegisterInt64Pref(prefs::kSwReporterLastTimeTriggered, 0); |
| 418 registry->RegisterIntegerPref(prefs::kSwReporterLastExitCode, -1); | 436 registry->RegisterIntegerPref(prefs::kSwReporterLastExitCode, -1); |
| 419 registry->RegisterBooleanPref(prefs::kSwReporterPendingPrompt, false); | 437 registry->RegisterBooleanPref(prefs::kSwReporterPendingPrompt, false); |
| 420 registry->RegisterInt64Pref(prefs::kSwReporterLastTimeSentReport, 0); | 438 registry->RegisterInt64Pref(prefs::kSwReporterLastTimeSentReport, 0); |
| 421 } | 439 } |
| 422 | 440 |
| 423 void RegisterProfilePrefsForSwReporter( | 441 void RegisterProfilePrefsForSwReporter( |
| 424 user_prefs::PrefRegistrySyncable* registry) { | 442 user_prefs::PrefRegistrySyncable* registry) { |
| 425 registry->RegisterStringPref(prefs::kSwReporterPromptVersion, ""); | 443 registry->RegisterStringPref(prefs::kSwReporterPromptVersion, ""); |
| 426 | 444 |
| 427 registry->RegisterStringPref(prefs::kSwReporterPromptSeed, ""); | 445 registry->RegisterStringPref(prefs::kSwReporterPromptSeed, ""); |
| 428 } | 446 } |
| 429 | 447 |
| 430 } // namespace component_updater | 448 } // namespace component_updater |
| OLD | NEW |