OLD | NEW |
(Empty) | |
| 1 // Copyright 2017 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include "chrome/browser/safe_browsing/chrome_cleaner/chrome_cleaner_runner_win.
h" |
| 6 |
| 7 #include <utility> |
| 8 |
| 9 #include "base/base_paths.h" |
| 10 #include "base/bind.h" |
| 11 #include "base/bind_helpers.h" |
| 12 #include "base/feature_list.h" |
| 13 #include "base/location.h" |
| 14 #include "base/memory/ptr_util.h" |
| 15 #include "base/path_service.h" |
| 16 #include "base/strings/string_number_conversions.h" |
| 17 #include "base/task_scheduler/post_task.h" |
| 18 #include "base/threading/thread_task_runner_handle.h" |
| 19 #include "chrome/browser/safe_browsing/chrome_cleaner/srt_client_info_win.h" |
| 20 #include "chrome/browser/safe_browsing/chrome_cleaner/srt_field_trial_win.h" |
| 21 #include "chrome/installer/util/install_util.h" |
| 22 #include "components/chrome_cleaner/public/constants/constants.h" |
| 23 #include "components/chrome_cleaner/public/interfaces/chrome_prompt.mojom.h" |
| 24 #include "components/version_info/version_info.h" |
| 25 #include "content/public/browser/browser_thread.h" |
| 26 #include "mojo/edk/embedder/connection_params.h" |
| 27 #include "mojo/edk/embedder/embedder.h" |
| 28 #include "mojo/edk/embedder/outgoing_broker_client_invitation.h" |
| 29 #include "mojo/edk/embedder/platform_channel_pair.h" |
| 30 #include "mojo/edk/embedder/transport_protocol.h" |
| 31 #include "mojo/public/cpp/system/message_pipe.h" |
| 32 |
| 33 using chrome_cleaner::mojom::ChromePrompt; |
| 34 using chrome_cleaner::mojom::ChromePromptRequest; |
| 35 using content::BrowserThread; |
| 36 |
| 37 namespace safe_browsing { |
| 38 |
| 39 namespace { |
| 40 |
| 41 // Global delegate used to override the launching of the Cleaner process during |
| 42 // tests. |
| 43 ChromeCleanerRunnerTestDelegate* g_test_delegate = nullptr; |
| 44 |
| 45 } // namespace |
| 46 |
| 47 // static |
| 48 void ChromeCleanerRunner::RunChromeCleanerAndReplyWithExitCode( |
| 49 const base::FilePath& executable_path, |
| 50 const SwReporterInvocation& reporter_invocation, |
| 51 ChromeMetricsStatus metrics_status, |
| 52 CleanerLogsStatus cleaner_logs_status, |
| 53 ChromePromptImpl::OnPromptUser on_prompt_user, |
| 54 base::OnceClosure on_connection_closed, |
| 55 ChromeCleanerRunner::ProcessDoneCallback on_process_done) { |
| 56 auto cleaner_runner = make_scoped_refptr(new ChromeCleanerRunner( |
| 57 executable_path, reporter_invocation, metrics_status, cleaner_logs_status, |
| 58 std::move(on_prompt_user), std::move(on_connection_closed), |
| 59 std::move(on_process_done), base::ThreadTaskRunnerHandle::Get())); |
| 60 auto launch_and_wait = base::BindOnce( |
| 61 &ChromeCleanerRunner::LaunchAndWaitForExitOnBackgroundThread, |
| 62 cleaner_runner); |
| 63 auto process_done = |
| 64 base::BindOnce(&ChromeCleanerRunner::OnProcessDone, cleaner_runner); |
| 65 base::PostTaskWithTraitsAndReplyWithResult( |
| 66 FROM_HERE, |
| 67 // LaunchAndWaitForExitOnBackgroundThread creates (MayBlock()) and joins |
| 68 // (WithBaseSyncPrimitives()) a process. |
| 69 {base::MayBlock(), base::WithBaseSyncPrimitives(), |
| 70 base::TaskPriority::BACKGROUND, |
| 71 base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN}, |
| 72 std::move(launch_and_wait), std::move(process_done)); |
| 73 } |
| 74 |
| 75 ChromeCleanerRunner::ChromeCleanerRunner( |
| 76 const base::FilePath& executable_path, |
| 77 const SwReporterInvocation& reporter_invocation, |
| 78 ChromeMetricsStatus metrics_status, |
| 79 CleanerLogsStatus cleaner_logs_status, |
| 80 ChromePromptImpl::OnPromptUser on_prompt_user, |
| 81 base::OnceClosure on_connection_closed, |
| 82 ProcessDoneCallback on_process_done, |
| 83 scoped_refptr<base::SingleThreadTaskRunner> task_runner) |
| 84 : task_runner_(task_runner), |
| 85 command_line_(executable_path), |
| 86 on_prompt_user_(std::move(on_prompt_user)), |
| 87 on_connection_closed_(std::move(on_connection_closed)), |
| 88 on_process_done_(std::move(on_process_done)) { |
| 89 DCHECK(base::FeatureList::IsEnabled(kInBrowserCleanerUIFeature)); |
| 90 DCHECK(on_prompt_user_); |
| 91 DCHECK(on_connection_closed_); |
| 92 DCHECK(on_process_done_); |
| 93 DCHECK(!executable_path.empty()); |
| 94 |
| 95 if (g_test_delegate) |
| 96 command_line_ = g_test_delegate->GetTestBaseCommandLine(); |
| 97 |
| 98 // Add the non-IPC switches that should be passed to the Cleaner process. |
| 99 |
| 100 // Add switches that pass information about this Chrome installation. |
| 101 command_line_.AppendSwitchASCII(chrome_cleaner::kChromeVersionSwitch, |
| 102 version_info::GetVersionNumber()); |
| 103 command_line_.AppendSwitchASCII(chrome_cleaner::kChromeChannelSwitch, |
| 104 base::IntToString(ChannelAsInt())); |
| 105 base::FilePath chrome_exe_path; |
| 106 PathService::Get(base::FILE_EXE, &chrome_exe_path); |
| 107 command_line_.AppendSwitchPath(chrome_cleaner::kChromeExePathSwitch, |
| 108 chrome_exe_path); |
| 109 if (!InstallUtil::IsPerUserInstall()) |
| 110 command_line_.AppendSwitch(chrome_cleaner::kChromeSystemInstallSwitch); |
| 111 |
| 112 // Start the cleaner process in scanning mode. |
| 113 command_line_.AppendSwitchASCII( |
| 114 chrome_cleaner::kExecutionModeSwitch, |
| 115 base::IntToString( |
| 116 static_cast<int>(chrome_cleaner::ExecutionMode::kScanning))); |
| 117 |
| 118 // If set, forward the engine flag from the reporter. Otherwise, set the |
| 119 // engine flag explicitly to 1. |
| 120 command_line_.AppendSwitchASCII( |
| 121 chrome_cleaner::kEngineSwitch, |
| 122 reporter_invocation.command_line.HasSwitch(chrome_cleaner::kEngineSwitch) |
| 123 ? reporter_invocation.command_line.GetSwitchValueASCII( |
| 124 chrome_cleaner::kEngineSwitch) |
| 125 : base::IntToString(1)); |
| 126 |
| 127 // If metrics is enabled, we can enable crash reporting in the Chrome Cleaner |
| 128 // process. |
| 129 if (metrics_status == ChromeMetricsStatus::kEnabled) { |
| 130 command_line_.AppendSwitch(chrome_cleaner::kUmaUserSwitch); |
| 131 command_line_.AppendSwitch(chrome_cleaner::kEnableCrashReportingSwitch); |
| 132 } |
| 133 |
| 134 // Enable logs upload for users who have opted into safe browsing extended |
| 135 // reporting v2. |
| 136 if (cleaner_logs_status == CleanerLogsStatus::kUploadEnabled) |
| 137 command_line_.AppendSwitch(chrome_cleaner::kEnableCleanerLoggingSwitch); |
| 138 } |
| 139 |
| 140 ChromeCleanerRunner::LaunchStatus |
| 141 ChromeCleanerRunner::LaunchAndWaitForExitOnBackgroundThread() { |
| 142 constexpr int kBadProcessExitCode = std::numeric_limits<int>::max(); |
| 143 |
| 144 mojo::edk::OutgoingBrokerClientInvitation invitation; |
| 145 std::string mojo_pipe_token = mojo::edk::GenerateRandomToken(); |
| 146 mojo::ScopedMessagePipeHandle mojo_pipe = |
| 147 invitation.AttachMessagePipe(mojo_pipe_token); |
| 148 command_line_.AppendSwitchASCII(chrome_cleaner::kChromeMojoPipeTokenSwitch, |
| 149 mojo_pipe_token); |
| 150 |
| 151 mojo::edk::PlatformChannelPair channel; |
| 152 base::HandlesToInheritVector handles_to_inherit; |
| 153 channel.PrepareToPassClientHandleToChildProcess(&command_line_, |
| 154 &handles_to_inherit); |
| 155 base::LaunchOptions launch_options; |
| 156 launch_options.handles_to_inherit = &handles_to_inherit; |
| 157 |
| 158 base::Process cleaner_process = |
| 159 g_test_delegate |
| 160 ? g_test_delegate->LaunchTestProcess(command_line_, launch_options) |
| 161 : base::LaunchProcess(command_line_, launch_options); |
| 162 |
| 163 if (!cleaner_process.IsValid()) |
| 164 return {false, kBadProcessExitCode}; |
| 165 |
| 166 // ChromePromptImpl tasks will need to run on the IO thread. There is no |
| 167 // need to synchronize its creation, since the client end will wait for this |
| 168 // initialization to be done before sending requests. |
| 169 BrowserThread::GetTaskRunnerForThread(BrowserThread::IO) |
| 170 ->PostTask(FROM_HERE, |
| 171 base::BindOnce(&ChromeCleanerRunner::CreateChromePromptImpl, |
| 172 base::RetainedRef(this), |
| 173 chrome_cleaner::mojom::ChromePromptRequest( |
| 174 std::move(mojo_pipe)))); |
| 175 |
| 176 // TODO(alito): Consider if we need to pass in a process error callback the |
| 177 // Send() function. |
| 178 invitation.Send( |
| 179 cleaner_process.Handle(), |
| 180 mojo::edk::ConnectionParams(mojo::edk::TransportProtocol::kLegacy, |
| 181 channel.PassServerHandle())); |
| 182 |
| 183 int exit_code = kBadProcessExitCode; |
| 184 if (cleaner_process.WaitForExit(&exit_code)) |
| 185 return {true, exit_code}; |
| 186 return {false, kBadProcessExitCode}; |
| 187 } |
| 188 |
| 189 ChromeCleanerRunner::~ChromeCleanerRunner() { |
| 190 DCHECK(!chrome_prompt_impl_); |
| 191 } |
| 192 |
| 193 void ChromeCleanerRunner::CreateChromePromptImpl( |
| 194 ChromePromptRequest chrome_prompt_request) { |
| 195 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 196 DCHECK(!chrome_prompt_impl_); |
| 197 |
| 198 chrome_prompt_impl_ = base::MakeUnique<ChromePromptImpl>( |
| 199 std::move(chrome_prompt_request), |
| 200 base::Bind(&ChromeCleanerRunner::OnConnectionClosed, |
| 201 base::RetainedRef(this)), |
| 202 base::Bind(&ChromeCleanerRunner::OnPromptUser, base::RetainedRef(this))); |
| 203 // Ensure that this object is not destroyed before chrome_prompt_impl_ has |
| 204 // been released in ReleaseChromePromptImpl(). This is a bit paranoid, but |
| 205 // better safe than sorry. |
| 206 AddRef(); |
| 207 } |
| 208 |
| 209 void ChromeCleanerRunner::ReleaseChromePromptImpl() { |
| 210 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 211 DCHECK(chrome_prompt_impl_); |
| 212 chrome_prompt_impl_.release(); |
| 213 // Balanced by the call to AddRef() in CreateChromePromptImpl(). |
| 214 Release(); |
| 215 } |
| 216 |
| 217 void ChromeCleanerRunner::OnPromptUser( |
| 218 std::unique_ptr<std::set<base::FilePath>> files_to_delete, |
| 219 ChromePrompt::PromptUserCallback prompt_user_callback) { |
| 220 if (on_prompt_user_) { |
| 221 task_runner_->PostTask(FROM_HERE, |
| 222 base::BindOnce(std::move(on_prompt_user_), |
| 223 base::Passed(&files_to_delete), |
| 224 base::Passed(&prompt_user_callback))); |
| 225 } |
| 226 } |
| 227 |
| 228 void ChromeCleanerRunner::OnConnectionClosed() { |
| 229 BrowserThread::GetTaskRunnerForThread(BrowserThread::IO) |
| 230 ->PostTask(FROM_HERE, |
| 231 base::Bind(&ChromeCleanerRunner::ReleaseChromePromptImpl, |
| 232 base::RetainedRef(this))); |
| 233 |
| 234 if (on_connection_closed_) |
| 235 task_runner_->PostTask(FROM_HERE, std::move(on_connection_closed_)); |
| 236 } |
| 237 |
| 238 void ChromeCleanerRunner::OnProcessDone(LaunchStatus launch_status) { |
| 239 if (on_process_done_) { |
| 240 task_runner_->PostTask( |
| 241 FROM_HERE, base::BindOnce(std::move(on_process_done_), launch_status)); |
| 242 } |
| 243 } |
| 244 |
| 245 void SetChromeCleanerRunnerTestDelegateForTesting( |
| 246 ChromeCleanerRunnerTestDelegate* test_delegate) { |
| 247 g_test_delegate = test_delegate; |
| 248 } |
| 249 |
| 250 } // namespace safe_browsing |
OLD | NEW |