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