OLD | NEW |
---|---|
1 // Copyright 2012 The Chromium Authors. All rights reserved. | 1 // Copyright 2012 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 "content/browser/child_process_launcher.h" | 5 #include "content/browser/child_process_launcher.h" |
6 | 6 |
7 #include <utility> | 7 #include <utility> |
8 | 8 |
9 #include "base/bind.h" | 9 #include "base/bind.h" |
10 #include "base/command_line.h" | 10 #include "base/command_line.h" |
(...skipping 21 matching lines...) Expand all Loading... | |
32 #include "content/browser/browser_io_surface_manager_mac.h" | 32 #include "content/browser/browser_io_surface_manager_mac.h" |
33 #include "content/browser/mach_broker_mac.h" | 33 #include "content/browser/mach_broker_mac.h" |
34 #include "sandbox/mac/bootstrap_sandbox.h" | 34 #include "sandbox/mac/bootstrap_sandbox.h" |
35 #include "sandbox/mac/pre_exec_delegate.h" | 35 #include "sandbox/mac/pre_exec_delegate.h" |
36 #elif defined(OS_ANDROID) | 36 #elif defined(OS_ANDROID) |
37 #include "base/android/jni_android.h" | 37 #include "base/android/jni_android.h" |
38 #include "content/browser/android/child_process_launcher_android.h" | 38 #include "content/browser/android/child_process_launcher_android.h" |
39 #elif defined(OS_POSIX) | 39 #elif defined(OS_POSIX) |
40 #include "base/memory/singleton.h" | 40 #include "base/memory/singleton.h" |
41 #include "content/browser/renderer_host/render_sandbox_host_linux.h" | 41 #include "content/browser/renderer_host/render_sandbox_host_linux.h" |
42 #include "content/browser/zygote_host/zygote_communication_linux.h" | |
42 #include "content/browser/zygote_host/zygote_host_impl_linux.h" | 43 #include "content/browser/zygote_host/zygote_host_impl_linux.h" |
43 #include "content/common/child_process_sandbox_support_impl_linux.h" | 44 #include "content/common/child_process_sandbox_support_impl_linux.h" |
44 #endif | 45 #endif |
45 | 46 |
46 #if defined(OS_POSIX) | 47 #if defined(OS_POSIX) |
47 #include "base/posix/global_descriptors.h" | 48 #include "base/posix/global_descriptors.h" |
48 #include "content/browser/file_descriptor_info_impl.h" | 49 #include "content/browser/file_descriptor_info_impl.h" |
49 #include "gin/v8_initializer.h" | 50 #include "gin/v8_initializer.h" |
50 #endif | 51 #endif |
51 | 52 |
52 namespace content { | 53 namespace content { |
53 | 54 |
54 namespace { | 55 namespace { |
55 | 56 |
56 typedef base::Callback<void(bool, | 57 typedef base::Callback<void(ZygoteHandle, |
57 #if defined(OS_ANDROID) | 58 #if defined(OS_ANDROID) |
58 base::ScopedFD, | 59 base::ScopedFD, |
59 #endif | 60 #endif |
60 base::Process)> NotifyCallback; | 61 base::Process)> NotifyCallback; |
61 | 62 |
62 void RecordHistogramsOnLauncherThread(base::TimeDelta launch_time) { | 63 void RecordHistogramsOnLauncherThread(base::TimeDelta launch_time) { |
63 DCHECK_CURRENTLY_ON(BrowserThread::PROCESS_LAUNCHER); | 64 DCHECK_CURRENTLY_ON(BrowserThread::PROCESS_LAUNCHER); |
64 // Log the launch time, separating out the first one (which will likely be | 65 // Log the launch time, separating out the first one (which will likely be |
65 // slower due to the rest of the browser initializing at the same time). | 66 // slower due to the rest of the browser initializing at the same time). |
66 static bool done_first_launch = false; | 67 static bool done_first_launch = false; |
(...skipping 13 matching lines...) Expand all Loading... | |
80 const base::TimeTicks begin_launch_time, | 81 const base::TimeTicks begin_launch_time, |
81 base::ScopedFD ipcfd, | 82 base::ScopedFD ipcfd, |
82 base::ProcessHandle handle) { | 83 base::ProcessHandle handle) { |
83 // This can be called on the launcher thread or UI thread. | 84 // This can be called on the launcher thread or UI thread. |
84 base::TimeDelta launch_time = base::TimeTicks::Now() - begin_launch_time; | 85 base::TimeDelta launch_time = base::TimeTicks::Now() - begin_launch_time; |
85 BrowserThread::PostTask( | 86 BrowserThread::PostTask( |
86 BrowserThread::PROCESS_LAUNCHER, FROM_HERE, | 87 BrowserThread::PROCESS_LAUNCHER, FROM_HERE, |
87 base::Bind(&RecordHistogramsOnLauncherThread, launch_time)); | 88 base::Bind(&RecordHistogramsOnLauncherThread, launch_time)); |
88 | 89 |
89 base::Closure callback_on_client_thread( | 90 base::Closure callback_on_client_thread( |
90 base::Bind(callback, false, base::Passed(&ipcfd), | 91 base::Bind(callback, ZygoteHandle(), base::Passed(&ipcfd), |
91 base::Passed(base::Process(handle)))); | 92 base::Passed(base::Process(handle)))); |
92 if (BrowserThread::CurrentlyOn(client_thread_id)) { | 93 if (BrowserThread::CurrentlyOn(client_thread_id)) { |
93 callback_on_client_thread.Run(); | 94 callback_on_client_thread.Run(); |
94 } else { | 95 } else { |
95 BrowserThread::PostTask( | 96 BrowserThread::PostTask( |
96 client_thread_id, FROM_HERE, callback_on_client_thread); | 97 client_thread_id, FROM_HERE, callback_on_client_thread); |
97 } | 98 } |
98 } | 99 } |
99 #endif | 100 #endif |
100 | 101 |
101 void LaunchOnLauncherThread(const NotifyCallback& callback, | 102 void LaunchOnLauncherThread(const NotifyCallback& callback, |
102 BrowserThread::ID client_thread_id, | 103 BrowserThread::ID client_thread_id, |
103 int child_process_id, | 104 int child_process_id, |
104 SandboxedProcessLauncherDelegate* delegate, | 105 SandboxedProcessLauncherDelegate* delegate, |
105 #if defined(OS_ANDROID) | 106 #if defined(OS_ANDROID) |
106 base::ScopedFD ipcfd, | 107 base::ScopedFD ipcfd, |
107 #endif | 108 #endif |
108 base::CommandLine* cmd_line) { | 109 base::CommandLine* cmd_line) { |
109 DCHECK_CURRENTLY_ON(BrowserThread::PROCESS_LAUNCHER); | 110 DCHECK_CURRENTLY_ON(BrowserThread::PROCESS_LAUNCHER); |
110 scoped_ptr<SandboxedProcessLauncherDelegate> delegate_deleter(delegate); | 111 scoped_ptr<SandboxedProcessLauncherDelegate> delegate_deleter(delegate); |
112 #if !defined(OS_ANDROID) | |
113 ZygoteHandle zygote; | |
114 #endif | |
111 #if defined(OS_WIN) | 115 #if defined(OS_WIN) |
112 bool use_zygote = false; | |
113 bool launch_elevated = delegate->ShouldLaunchElevated(); | 116 bool launch_elevated = delegate->ShouldLaunchElevated(); |
114 #elif defined(OS_MACOSX) | 117 #elif defined(OS_MACOSX) |
115 bool use_zygote = false; | |
116 base::EnvironmentMap env = delegate->GetEnvironment(); | 118 base::EnvironmentMap env = delegate->GetEnvironment(); |
117 base::ScopedFD ipcfd = delegate->TakeIpcFd(); | 119 base::ScopedFD ipcfd = delegate->TakeIpcFd(); |
118 #elif defined(OS_POSIX) && !defined(OS_ANDROID) | 120 #elif defined(OS_POSIX) && !defined(OS_ANDROID) |
119 bool use_zygote = delegate->ShouldUseZygote(); | |
120 base::EnvironmentMap env = delegate->GetEnvironment(); | 121 base::EnvironmentMap env = delegate->GetEnvironment(); |
121 base::ScopedFD ipcfd = delegate->TakeIpcFd(); | 122 base::ScopedFD ipcfd = delegate->TakeIpcFd(); |
122 #endif | 123 #endif |
123 scoped_ptr<base::CommandLine> cmd_line_deleter(cmd_line); | 124 scoped_ptr<base::CommandLine> cmd_line_deleter(cmd_line); |
124 base::TimeTicks begin_launch_time = base::TimeTicks::Now(); | 125 base::TimeTicks begin_launch_time = base::TimeTicks::Now(); |
125 | 126 |
126 base::Process process; | 127 base::Process process; |
127 #if defined(OS_WIN) | 128 #if defined(OS_WIN) |
128 if (launch_elevated) { | 129 if (launch_elevated) { |
129 base::LaunchOptions options; | 130 base::LaunchOptions options; |
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
192 StartChildProcess( | 193 StartChildProcess( |
193 cmd_line->argv(), child_process_id, std::move(files_to_register), regions, | 194 cmd_line->argv(), child_process_id, std::move(files_to_register), regions, |
194 base::Bind(&OnChildProcessStartedAndroid, callback, client_thread_id, | 195 base::Bind(&OnChildProcessStartedAndroid, callback, client_thread_id, |
195 begin_launch_time, base::Passed(&ipcfd))); | 196 begin_launch_time, base::Passed(&ipcfd))); |
196 | 197 |
197 #elif defined(OS_POSIX) | 198 #elif defined(OS_POSIX) |
198 // We need to close the client end of the IPC channel to reliably detect | 199 // We need to close the client end of the IPC channel to reliably detect |
199 // child termination. | 200 // child termination. |
200 | 201 |
201 #if !defined(OS_MACOSX) | 202 #if !defined(OS_MACOSX) |
202 if (use_zygote) { | 203 zygote = nullptr; |
mdempsky
2015/12/22 21:21:33
Hm, so if you use
using ZygoteHandle = std::n
Greg K
2016/01/05 21:42:13
Done.
| |
203 base::ProcessHandle handle = ZygoteHostImpl::GetInstance()->ForkRequest( | 204 ZygoteHandle* zygote_handle = delegate->GetZygote(); |
205 if (zygote_handle) { | |
206 if (*zygote_handle == nullptr) { | |
mdempsky
2015/12/22 21:21:33
I'd suggest adding a comment that mentions we're r
Greg K
2016/01/05 21:42:13
Done.
| |
207 *zygote_handle = new ZygoteCommunication(); | |
208 (*zygote_handle)->Init(); | |
209 } | |
210 zygote = *zygote_handle; | |
211 base::ProcessHandle handle = zygote->ForkRequest( | |
204 cmd_line->argv(), std::move(files_to_register), process_type); | 212 cmd_line->argv(), std::move(files_to_register), process_type); |
205 process = base::Process(handle); | 213 process = base::Process(handle); |
206 } else | 214 } else |
207 // Fall through to the normal posix case below when we're not zygoting. | 215 // Fall through to the normal posix case below when we're not zygoting. |
208 #endif // !defined(OS_MACOSX) | 216 #endif // !defined(OS_MACOSX) |
209 { | 217 { |
210 // Convert FD mapping to FileHandleMappingVector | 218 // Convert FD mapping to FileHandleMappingVector |
211 base::FileHandleMappingVector fds_to_map = | 219 base::FileHandleMappingVector fds_to_map = |
212 files_to_register->GetMappingWithIDAdjustment( | 220 files_to_register->GetMappingWithIDAdjustment( |
213 base::GlobalDescriptors::kBaseDescriptor); | 221 base::GlobalDescriptors::kBaseDescriptor); |
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
275 broker->GetLock().Release(); | 283 broker->GetLock().Release(); |
276 #endif // defined(OS_MACOSX) | 284 #endif // defined(OS_MACOSX) |
277 } | 285 } |
278 #endif // else defined(OS_POSIX) | 286 #endif // else defined(OS_POSIX) |
279 #if !defined(OS_ANDROID) | 287 #if !defined(OS_ANDROID) |
280 if (process.IsValid()) { | 288 if (process.IsValid()) { |
281 RecordHistogramsOnLauncherThread(base::TimeTicks::Now() - | 289 RecordHistogramsOnLauncherThread(base::TimeTicks::Now() - |
282 begin_launch_time); | 290 begin_launch_time); |
283 } | 291 } |
284 BrowserThread::PostTask(client_thread_id, FROM_HERE, | 292 BrowserThread::PostTask(client_thread_id, FROM_HERE, |
285 base::Bind(callback, | 293 base::Bind(callback, zygote, base::Passed(&process))); |
286 use_zygote, | |
287 base::Passed(&process))); | |
288 #endif // !defined(OS_ANDROID) | 294 #endif // !defined(OS_ANDROID) |
289 } | 295 } |
290 | 296 |
291 void TerminateOnLauncherThread(bool zygote, base::Process process) { | 297 void TerminateOnLauncherThread(ZygoteHandle zygote, base::Process process) { |
292 DCHECK_CURRENTLY_ON(BrowserThread::PROCESS_LAUNCHER); | 298 DCHECK_CURRENTLY_ON(BrowserThread::PROCESS_LAUNCHER); |
293 #if defined(OS_ANDROID) | 299 #if defined(OS_ANDROID) |
294 VLOG(1) << "ChromeProcess: Stopping process with handle " | 300 VLOG(1) << "ChromeProcess: Stopping process with handle " |
295 << process.Handle(); | 301 << process.Handle(); |
296 StopChildProcess(process.Handle()); | 302 StopChildProcess(process.Handle()); |
297 #else | 303 #else |
298 // Client has gone away, so just kill the process. Using exit code 0 | 304 // Client has gone away, so just kill the process. Using exit code 0 |
299 // means that UMA won't treat this as a crash. | 305 // means that UMA won't treat this as a crash. |
300 process.Terminate(RESULT_CODE_NORMAL_EXIT, false); | 306 process.Terminate(RESULT_CODE_NORMAL_EXIT, false); |
301 // On POSIX, we must additionally reap the child. | 307 // On POSIX, we must additionally reap the child. |
302 #if defined(OS_POSIX) | 308 #if defined(OS_POSIX) |
303 #if !defined(OS_MACOSX) | 309 #if !defined(OS_MACOSX) |
304 if (zygote) { | 310 if (zygote) { |
305 // If the renderer was created via a zygote, we have to proxy the reaping | 311 // If the renderer was created via a zygote, we have to proxy the reaping |
306 // through the zygote process. | 312 // through the zygote process. |
307 ZygoteHostImpl::GetInstance()->EnsureProcessTerminated(process.Handle()); | 313 zygote->EnsureProcessTerminated(process.Handle()); |
308 } else | 314 } else |
309 #endif // !OS_MACOSX | 315 #endif // !OS_MACOSX |
310 base::EnsureProcessTerminated(std::move(process)); | 316 base::EnsureProcessTerminated(std::move(process)); |
311 #endif // OS_POSIX | 317 #endif // OS_POSIX |
312 #endif // defined(OS_ANDROID) | 318 #endif // defined(OS_ANDROID) |
313 } | 319 } |
314 | 320 |
315 void SetProcessBackgroundedOnLauncherThread(base::Process process, | 321 void SetProcessBackgroundedOnLauncherThread(base::Process process, |
316 bool background) { | 322 bool background) { |
317 DCHECK_CURRENTLY_ON(BrowserThread::PROCESS_LAUNCHER); | 323 DCHECK_CURRENTLY_ON(BrowserThread::PROCESS_LAUNCHER); |
318 if (process.CanBackgroundProcesses()) { | 324 if (process.CanBackgroundProcesses()) { |
319 process.SetProcessBackgrounded(background); | 325 process.SetProcessBackgrounded(background); |
320 } | 326 } |
321 #if defined(OS_ANDROID) | 327 #if defined(OS_ANDROID) |
322 SetChildProcessInForeground(process.Handle(), !background); | 328 SetChildProcessInForeground(process.Handle(), !background); |
323 #endif | 329 #endif |
324 } | 330 } |
325 | 331 |
326 } // namespace | 332 } // namespace |
327 | 333 |
328 ChildProcessLauncher::ChildProcessLauncher( | 334 ChildProcessLauncher::ChildProcessLauncher( |
329 SandboxedProcessLauncherDelegate* delegate, | 335 SandboxedProcessLauncherDelegate* delegate, |
330 base::CommandLine* cmd_line, | 336 base::CommandLine* cmd_line, |
331 int child_process_id, | 337 int child_process_id, |
332 Client* client, | 338 Client* client, |
333 bool terminate_on_shutdown) | 339 bool terminate_on_shutdown) |
334 : client_(client), | 340 : client_(client), |
335 termination_status_(base::TERMINATION_STATUS_NORMAL_TERMINATION), | 341 termination_status_(base::TERMINATION_STATUS_NORMAL_TERMINATION), |
336 exit_code_(RESULT_CODE_NORMAL_EXIT), | 342 exit_code_(RESULT_CODE_NORMAL_EXIT), |
337 zygote_(false), | 343 zygote_(), |
mdempsky
2015/12/22 21:21:33
(And explicitly initialize to nullptr here if you
Greg K
2016/01/05 21:42:13
Done.
| |
338 starting_(true), | 344 starting_(true), |
339 #if defined(ADDRESS_SANITIZER) || defined(LEAK_SANITIZER) || \ | 345 #if defined(ADDRESS_SANITIZER) || defined(LEAK_SANITIZER) || \ |
340 defined(MEMORY_SANITIZER) || defined(THREAD_SANITIZER) || \ | 346 defined(MEMORY_SANITIZER) || defined(THREAD_SANITIZER) || \ |
341 defined(UNDEFINED_SANITIZER) | 347 defined(UNDEFINED_SANITIZER) |
342 terminate_child_on_shutdown_(false), | 348 terminate_child_on_shutdown_(false), |
343 #else | 349 #else |
344 terminate_child_on_shutdown_(terminate_on_shutdown), | 350 terminate_child_on_shutdown_(terminate_on_shutdown), |
345 #endif | 351 #endif |
346 weak_factory_(this) { | 352 weak_factory_(this) { |
347 DCHECK(CalledOnValidThread()); | 353 DCHECK(CalledOnValidThread()); |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
397 #if defined(OS_ANDROID) | 403 #if defined(OS_ANDROID) |
398 base::Passed(&ipcfd), | 404 base::Passed(&ipcfd), |
399 #endif | 405 #endif |
400 cmd_line)); | 406 cmd_line)); |
401 } | 407 } |
402 | 408 |
403 void ChildProcessLauncher::UpdateTerminationStatus(bool known_dead) { | 409 void ChildProcessLauncher::UpdateTerminationStatus(bool known_dead) { |
404 DCHECK(CalledOnValidThread()); | 410 DCHECK(CalledOnValidThread()); |
405 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID) | 411 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID) |
406 if (zygote_) { | 412 if (zygote_) { |
407 termination_status_ = ZygoteHostImpl::GetInstance()-> | 413 termination_status_ = zygote_->GetTerminationStatus( |
408 GetTerminationStatus(process_.Handle(), known_dead, &exit_code_); | 414 process_.Handle(), known_dead, &exit_code_); |
409 } else if (known_dead) { | 415 } else if (known_dead) { |
410 termination_status_ = | 416 termination_status_ = |
411 base::GetKnownDeadTerminationStatus(process_.Handle(), &exit_code_); | 417 base::GetKnownDeadTerminationStatus(process_.Handle(), &exit_code_); |
412 } else { | 418 } else { |
413 #elif defined(OS_MACOSX) | 419 #elif defined(OS_MACOSX) |
414 if (known_dead) { | 420 if (known_dead) { |
415 termination_status_ = | 421 termination_status_ = |
416 base::GetKnownDeadTerminationStatus(process_.Handle(), &exit_code_); | 422 base::GetKnownDeadTerminationStatus(process_.Handle(), &exit_code_); |
417 } else { | 423 } else { |
418 #elif defined(OS_ANDROID) | 424 #elif defined(OS_ANDROID) |
(...skipping 12 matching lines...) Expand all Loading... | |
431 DCHECK(CalledOnValidThread()); | 437 DCHECK(CalledOnValidThread()); |
432 base::Process to_pass = process_.Duplicate(); | 438 base::Process to_pass = process_.Duplicate(); |
433 BrowserThread::PostTask(BrowserThread::PROCESS_LAUNCHER, FROM_HERE, | 439 BrowserThread::PostTask(BrowserThread::PROCESS_LAUNCHER, FROM_HERE, |
434 base::Bind(&SetProcessBackgroundedOnLauncherThread, | 440 base::Bind(&SetProcessBackgroundedOnLauncherThread, |
435 base::Passed(&to_pass), background)); | 441 base::Passed(&to_pass), background)); |
436 } | 442 } |
437 | 443 |
438 void ChildProcessLauncher::DidLaunch( | 444 void ChildProcessLauncher::DidLaunch( |
439 base::WeakPtr<ChildProcessLauncher> instance, | 445 base::WeakPtr<ChildProcessLauncher> instance, |
440 bool terminate_on_shutdown, | 446 bool terminate_on_shutdown, |
441 bool zygote, | 447 ZygoteHandle zygote, |
442 #if defined(OS_ANDROID) | 448 #if defined(OS_ANDROID) |
443 base::ScopedFD ipcfd, | 449 base::ScopedFD ipcfd, |
444 #endif | 450 #endif |
445 base::Process process) { | 451 base::Process process) { |
446 if (!process.IsValid()) | 452 if (!process.IsValid()) |
447 LOG(ERROR) << "Failed to launch child process"; | 453 LOG(ERROR) << "Failed to launch child process"; |
448 | 454 |
449 if (instance.get()) { | 455 if (instance.get()) { |
450 instance->Notify(zygote, | 456 instance->Notify(zygote, |
451 #if defined(OS_ANDROID) | 457 #if defined(OS_ANDROID) |
452 std::move(ipcfd), | 458 std::move(ipcfd), |
453 #endif | 459 #endif |
454 std::move(process)); | 460 std::move(process)); |
455 } else { | 461 } else { |
456 if (process.IsValid() && terminate_on_shutdown) { | 462 if (process.IsValid() && terminate_on_shutdown) { |
457 // On Posix, EnsureProcessTerminated can lead to 2 seconds of sleep! So | 463 // On Posix, EnsureProcessTerminated can lead to 2 seconds of sleep! So |
458 // don't this on the UI/IO threads. | 464 // don't this on the UI/IO threads. |
459 BrowserThread::PostTask(BrowserThread::PROCESS_LAUNCHER, FROM_HERE, | 465 BrowserThread::PostTask(BrowserThread::PROCESS_LAUNCHER, FROM_HERE, |
460 base::Bind(&TerminateOnLauncherThread, zygote, | 466 base::Bind(&TerminateOnLauncherThread, zygote, |
461 base::Passed(&process))); | 467 base::Passed(&process))); |
462 } | 468 } |
463 } | 469 } |
464 } | 470 } |
465 | 471 |
466 void ChildProcessLauncher::Notify( | 472 void ChildProcessLauncher::Notify(ZygoteHandle zygote, |
467 bool zygote, | |
468 #if defined(OS_ANDROID) | 473 #if defined(OS_ANDROID) |
469 base::ScopedFD ipcfd, | 474 base::ScopedFD ipcfd, |
470 #endif | 475 #endif |
471 base::Process process) { | 476 base::Process process) { |
472 DCHECK(CalledOnValidThread()); | 477 DCHECK(CalledOnValidThread()); |
473 starting_ = false; | 478 starting_ = false; |
474 process_ = std::move(process); | 479 process_ = std::move(process); |
475 | 480 |
476 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID) | 481 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID) |
477 zygote_ = zygote; | 482 zygote_ = zygote; |
478 #endif | 483 #endif |
479 if (process_.IsValid()) { | 484 if (process_.IsValid()) { |
480 client_->OnProcessLaunched(); | 485 client_->OnProcessLaunched(); |
481 } else { | 486 } else { |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
524 } | 529 } |
525 | 530 |
526 ChildProcessLauncher::Client* ChildProcessLauncher::ReplaceClientForTest( | 531 ChildProcessLauncher::Client* ChildProcessLauncher::ReplaceClientForTest( |
527 Client* client) { | 532 Client* client) { |
528 Client* ret = client_; | 533 Client* ret = client_; |
529 client_ = client; | 534 client_ = client; |
530 return ret; | 535 return ret; |
531 } | 536 } |
532 | 537 |
533 } // namespace content | 538 } // namespace content |
OLD | NEW |