Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 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 "mojo/shell/runner/host/child_process_host.h" | 5 #include "mojo/shell/runner/host/child_process_host.h" |
| 6 | 6 |
| 7 #include <stdint.h> | 7 #include <stdint.h> |
| 8 | 8 |
| 9 #include <utility> | 9 #include <utility> |
| 10 | 10 |
| 11 #include "base/bind.h" | 11 #include "base/bind.h" |
| 12 #include "base/command_line.h" | 12 #include "base/command_line.h" |
| 13 #include "base/location.h" | 13 #include "base/location.h" |
| 14 #include "base/logging.h" | 14 #include "base/logging.h" |
| 15 #include "base/macros.h" | 15 #include "base/macros.h" |
| 16 #include "base/message_loop/message_loop.h" | 16 #include "base/message_loop/message_loop.h" |
| 17 #include "base/process/kill.h" | 17 #include "base/process/kill.h" |
| 18 #include "base/process/launch.h" | 18 #include "base/process/launch.h" |
| 19 #include "base/task_runner.h" | 19 #include "base/task_runner.h" |
| 20 #include "base/thread_task_runner_handle.h" | 20 #include "base/thread_task_runner_handle.h" |
| 21 #include "mojo/edk/embedder/embedder.h" | 21 #include "mojo/edk/embedder/embedder.h" |
| 22 #include "mojo/public/cpp/bindings/interface_ptr_info.h" | 22 #include "mojo/public/cpp/bindings/interface_ptr_info.h" |
| 23 #include "mojo/public/cpp/system/core.h" | 23 #include "mojo/public/cpp/system/core.h" |
| 24 #include "mojo/shell/runner/common/switches.h" | 24 #include "mojo/shell/runner/common/switches.h" |
| 25 #include "third_party/mojo/src/mojo/edk/embedder/embedder.h" | |
| 26 | 25 |
| 27 #if defined(OS_LINUX) && !defined(OS_ANDROID) | 26 #if defined(OS_LINUX) && !defined(OS_ANDROID) |
| 28 #include "sandbox/linux/services/namespace_sandbox.h" | 27 #include "sandbox/linux/services/namespace_sandbox.h" |
| 29 #endif | 28 #endif |
| 30 | 29 |
| 31 #if defined(OS_WIN) | 30 #if defined(OS_WIN) |
| 32 #include "base/win/windows_version.h" | 31 #include "base/win/windows_version.h" |
| 33 #endif | 32 #endif |
| 34 | 33 |
| 35 namespace mojo { | 34 namespace mojo { |
| (...skipping 21 matching lines...) Expand all Loading... | |
| 57 } | 56 } |
| 58 | 57 |
| 59 ChildProcessHost::PipeHolder::~PipeHolder() {} | 58 ChildProcessHost::PipeHolder::~PipeHolder() {} |
| 60 | 59 |
| 61 ChildProcessHost::ChildProcessHost(base::TaskRunner* launch_process_runner, | 60 ChildProcessHost::ChildProcessHost(base::TaskRunner* launch_process_runner, |
| 62 bool start_sandboxed, | 61 bool start_sandboxed, |
| 63 const base::FilePath& app_path) | 62 const base::FilePath& app_path) |
| 64 : launch_process_runner_(launch_process_runner), | 63 : launch_process_runner_(launch_process_runner), |
| 65 start_sandboxed_(start_sandboxed), | 64 start_sandboxed_(start_sandboxed), |
| 66 app_path_(app_path), | 65 app_path_(app_path), |
| 67 channel_info_(nullptr), | |
| 68 start_child_process_event_(false, false), | 66 start_child_process_event_(false, false), |
| 69 weak_factory_(this) { | 67 weak_factory_(this) { |
| 70 pipe_holder_ = new PipeHolder(); | 68 pipe_holder_ = new PipeHolder(); |
| 71 if (base::CommandLine::ForCurrentProcess()->HasSwitch("use-new-edk")) { | 69 node_channel_.reset(new edk::PlatformChannelPair); |
| 72 node_channel_.reset(new edk::PlatformChannelPair); | 70 primordial_pipe_token_ = edk::GenerateRandomToken(); |
| 73 primordial_pipe_token_ = edk::GenerateRandomToken(); | |
| 74 } else { | |
| 75 pipe_holder_->SetPipe(embedder::CreateChannel( | |
| 76 platform_channel_pair_.PassServerHandle(), | |
| 77 base::Bind(&ChildProcessHost::DidCreateChannel, base::Unretained(this)), | |
| 78 base::ThreadTaskRunnerHandle::Get())); | |
| 79 OnMessagePipeCreated(); | |
| 80 } | |
| 81 } | 71 } |
| 82 | 72 |
| 83 ChildProcessHost::ChildProcessHost(ScopedHandle channel) | 73 ChildProcessHost::ChildProcessHost(ScopedHandle channel) |
| 84 : launch_process_runner_(nullptr), | 74 : launch_process_runner_(nullptr), |
| 85 start_sandboxed_(false), | 75 start_sandboxed_(false), |
| 86 channel_info_(nullptr), | |
| 87 start_child_process_event_(false, false), | 76 start_child_process_event_(false, false), |
| 88 weak_factory_(this) { | 77 weak_factory_(this) { |
| 89 CHECK(channel.is_valid()); | 78 CHECK(channel.is_valid()); |
| 90 ScopedMessagePipeHandle handle(MessagePipeHandle(channel.release().value())); | 79 ScopedMessagePipeHandle handle(MessagePipeHandle(channel.release().value())); |
| 91 controller_.Bind( | 80 controller_.Bind( |
| 92 InterfacePtrInfo<mojom::ChildController>(std::move(handle), 0u)); | 81 InterfacePtrInfo<mojom::ChildController>(std::move(handle), 0u)); |
| 93 } | 82 } |
| 94 | 83 |
| 95 ChildProcessHost::~ChildProcessHost() { | 84 ChildProcessHost::~ChildProcessHost() { |
| 96 if (!app_path_.empty()) | 85 if (!app_path_.empty()) |
| 97 CHECK(!controller_) << "Destroying ChildProcessHost before calling Join"; | 86 CHECK(!controller_) << "Destroying ChildProcessHost before calling Join"; |
| 98 } | 87 } |
| 99 | 88 |
| 100 void ChildProcessHost::Start(const ProcessReadyCallback& callback) { | 89 void ChildProcessHost::Start(const ProcessReadyCallback& callback) { |
| 101 DCHECK(!child_process_.IsValid()); | 90 DCHECK(!child_process_.IsValid()); |
| 102 DCHECK(process_ready_callback_.is_null()); | 91 DCHECK(process_ready_callback_.is_null()); |
| 103 | 92 |
| 104 process_ready_callback_ = callback; | 93 process_ready_callback_ = callback; |
| 105 if (base::CommandLine::ForCurrentProcess()->HasSwitch("use-new-edk")) { | 94 // With the new EDK, bootstrap message pipes are created asynchronously. |
|
jam
2016/02/08 17:32:12
nit: remove new edk since there's only one now?
Ken Rockot(use gerrit already)
2016/02/08 17:51:18
Done
| |
| 106 // With the new EDK, bootstrap message pipes are created asynchronously. | 95 // We recieve the bound pipe (if successful) on an arbitrary thread, |
| 107 // We recieve the bound pipe (if successful) on an arbitrary thread, | 96 // stash it in the thread-safe |pipe_holder_|, and then try to call |
| 108 // stash it in the thread-safe |pipe_holder_|, and then try to call | 97 // OnMessagePipeCreated() on the host's main thread. |
| 109 // OnMessagePipeCreated() on the host's main thread. | 98 // |
| 110 // | 99 // Because of the way the launcher process shuts down, it's possible for |
| 111 // Because of the way the launcher process shuts down, it's possible for | 100 // the main thread's MessageLoop to stop running (but not yet be destroyed!) |
| 112 // the main thread's MessageLoop to stop running (but not yet be destroyed!) | 101 // while this boostrap is pending, resulting in OnMessagePipeCreated() never |
| 113 // while this boostrap is pending, resulting in OnMessagePipeCreated() never | 102 // being called. |
| 114 // being called. | 103 // |
| 115 // | 104 // A typical child process (i.e. one using ApplicationImpl to bind the other |
| 116 // A typical child process (i.e. one using ApplicationImpl to bind the other | 105 // end of this pipe) may hang forever waiting for an Initialize() message |
| 117 // end of this pipe) may hang forever waiting for an Initialize() message | 106 // unless the pipe is closed. This in turn means that Join() could hang |
| 118 // unless the pipe is closed. This in turn means that Join() could hang | 107 // waiting for the process to exit. Deadlock! |
| 119 // waiting for the process to exit. Deadlock! | 108 // |
| 120 // | 109 // |pipe_holder_| exists for this reason. If it's still holding onto the |
| 121 // |pipe_holder_| exists for this reason. If it's still holding onto the | 110 // pipe when Join() is called, the pipe will be closed. |
| 122 // pipe when Join() is called, the pipe will be closed. | 111 DCHECK(!primordial_pipe_token_.empty()); |
| 123 DCHECK(!primordial_pipe_token_.empty()); | 112 edk::CreateParentMessagePipe( |
| 124 edk::CreateParentMessagePipe( | 113 primordial_pipe_token_, |
| 125 primordial_pipe_token_, | 114 base::Bind(&OnParentMessagePipeCreated, pipe_holder_, |
| 126 base::Bind(&OnParentMessagePipeCreated, pipe_holder_, | 115 base::ThreadTaskRunnerHandle::Get(), |
| 127 base::ThreadTaskRunnerHandle::Get(), | 116 base::Bind(&ChildProcessHost::OnMessagePipeCreated, |
| 128 base::Bind(&ChildProcessHost::OnMessagePipeCreated, | 117 weak_factory_.GetWeakPtr()))); |
| 129 weak_factory_.GetWeakPtr()))); | |
| 130 } | |
| 131 | 118 |
| 132 launch_process_runner_->PostTaskAndReply( | 119 launch_process_runner_->PostTaskAndReply( |
| 133 FROM_HERE, | 120 FROM_HERE, |
| 134 base::Bind(&ChildProcessHost::DoLaunch, base::Unretained(this)), | 121 base::Bind(&ChildProcessHost::DoLaunch, base::Unretained(this)), |
| 135 base::Bind(&ChildProcessHost::DidStart, weak_factory_.GetWeakPtr())); | 122 base::Bind(&ChildProcessHost::DidStart, weak_factory_.GetWeakPtr())); |
| 136 } | 123 } |
| 137 | 124 |
| 138 int ChildProcessHost::Join() { | 125 int ChildProcessHost::Join() { |
| 139 if (controller_) // We use this as a signal that Start was called. | 126 if (controller_) // We use this as a signal that Start was called. |
| 140 start_child_process_event_.Wait(); | 127 start_child_process_event_.Wait(); |
| (...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 254 << " support."; | 241 << " support."; |
| 255 } | 242 } |
| 256 } else | 243 } else |
| 257 #endif | 244 #endif |
| 258 child_process_ = base::LaunchProcess(child_command_line, options); | 245 child_process_ = base::LaunchProcess(child_command_line, options); |
| 259 | 246 |
| 260 if (child_process_.IsValid()) { | 247 if (child_process_.IsValid()) { |
| 261 platform_channel_pair_.ChildProcessLaunched(); | 248 platform_channel_pair_.ChildProcessLaunched(); |
| 262 if (node_channel_.get()) { | 249 if (node_channel_.get()) { |
| 263 node_channel_->ChildProcessLaunched(); | 250 node_channel_->ChildProcessLaunched(); |
| 264 mojo::embedder::ChildProcessLaunched( | 251 mojo::edk::ChildProcessLaunched( |
| 265 child_process_.Handle(), | 252 child_process_.Handle(), |
| 266 mojo::embedder::ScopedPlatformHandle(mojo::embedder::PlatformHandle( | 253 mojo::edk::ScopedPlatformHandle(mojo::edk::PlatformHandle( |
| 267 node_channel_->PassServerHandle().release().handle))); | 254 node_channel_->PassServerHandle().release().handle))); |
| 268 } | 255 } |
| 269 } | 256 } |
| 270 start_child_process_event_.Signal(); | 257 start_child_process_event_.Signal(); |
| 271 } | 258 } |
| 272 | 259 |
| 273 void ChildProcessHost::AppCompleted(int32_t result) { | 260 void ChildProcessHost::AppCompleted(int32_t result) { |
| 274 if (!on_app_complete_.is_null()) { | 261 if (!on_app_complete_.is_null()) { |
| 275 auto on_app_complete = on_app_complete_; | 262 auto on_app_complete = on_app_complete_; |
| 276 on_app_complete_.reset(); | 263 on_app_complete_.reset(); |
| 277 on_app_complete.Run(result); | 264 on_app_complete.Run(result); |
| 278 } | 265 } |
| 279 } | 266 } |
| 280 | 267 |
| 281 void ChildProcessHost::DidCreateChannel(embedder::ChannelInfo* channel_info) { | |
| 282 DVLOG(2) << "AppChildProcessHost::DidCreateChannel()"; | |
| 283 | |
| 284 DCHECK(channel_info || | |
| 285 base::CommandLine::ForCurrentProcess()->HasSwitch("use-new-edk")); | |
| 286 channel_info_ = channel_info; | |
| 287 } | |
| 288 | |
| 289 void ChildProcessHost::OnMessagePipeCreated() { | 268 void ChildProcessHost::OnMessagePipeCreated() { |
| 290 controller_.Bind( | 269 controller_.Bind( |
| 291 InterfacePtrInfo<mojom::ChildController>(pipe_holder_->PassPipe(), 0u)); | 270 InterfacePtrInfo<mojom::ChildController>(pipe_holder_->PassPipe(), 0u)); |
| 292 MaybeNotifyProcessReady(); | 271 MaybeNotifyProcessReady(); |
| 293 } | 272 } |
| 294 | 273 |
| 295 void ChildProcessHost::MaybeNotifyProcessReady() { | 274 void ChildProcessHost::MaybeNotifyProcessReady() { |
| 296 if (controller_.is_bound() && child_process_.IsValid()) | 275 if (controller_.is_bound() && child_process_.IsValid()) |
| 297 process_ready_callback_.Run(child_process_.Pid()); | 276 process_ready_callback_.Run(child_process_.Pid()); |
| 298 } | 277 } |
| 299 | 278 |
| 300 // static | 279 // static |
| 301 void ChildProcessHost::OnParentMessagePipeCreated( | 280 void ChildProcessHost::OnParentMessagePipeCreated( |
| 302 scoped_refptr<PipeHolder> holder, | 281 scoped_refptr<PipeHolder> holder, |
| 303 scoped_refptr<base::TaskRunner> callback_task_runner, | 282 scoped_refptr<base::TaskRunner> callback_task_runner, |
| 304 const base::Closure& callback, | 283 const base::Closure& callback, |
| 305 ScopedMessagePipeHandle pipe) { | 284 ScopedMessagePipeHandle pipe) { |
| 306 holder->SetPipe(std::move(pipe)); | 285 holder->SetPipe(std::move(pipe)); |
| 307 callback_task_runner->PostTask(FROM_HERE, callback); | 286 callback_task_runner->PostTask(FROM_HERE, callback); |
| 308 } | 287 } |
| 309 | 288 |
| 310 } // namespace shell | 289 } // namespace shell |
| 311 } // namespace mojo | 290 } // namespace mojo |
| OLD | NEW |