| 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/runner/host/child_process.h" | 5 #include "mojo/runner/host/child_process.h" |
| 6 | 6 |
| 7 #include "base/base_switches.h" | 7 #include "base/base_switches.h" |
| 8 #include "base/bind.h" | 8 #include "base/bind.h" |
| 9 #include "base/callback_helpers.h" | 9 #include "base/callback_helpers.h" |
| 10 #include "base/command_line.h" | 10 #include "base/command_line.h" |
| 11 #include "base/files/file_path.h" | 11 #include "base/files/file_path.h" |
| 12 #include "base/i18n/icu_util.h" | 12 #include "base/i18n/icu_util.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/memory/ref_counted.h" | 16 #include "base/memory/ref_counted.h" |
| 17 #include "base/memory/scoped_ptr.h" | 17 #include "base/memory/scoped_ptr.h" |
| 18 #include "base/message_loop/message_loop.h" | 18 #include "base/message_loop/message_loop.h" |
| 19 #include "base/single_thread_task_runner.h" | 19 #include "base/single_thread_task_runner.h" |
| 20 #include "base/synchronization/waitable_event.h" | 20 #include "base/synchronization/waitable_event.h" |
| 21 #include "base/thread_task_runner_handle.h" | 21 #include "base/thread_task_runner_handle.h" |
| 22 #include "base/threading/thread.h" | 22 #include "base/threading/thread.h" |
| 23 #include "base/threading/thread_checker.h" | 23 #include "base/threading/thread_checker.h" |
| 24 #include "mojo/edk/embedder/embedder.h" |
| 25 #include "mojo/edk/embedder/platform_channel_pair.h" |
| 24 #include "mojo/message_pump/message_pump_mojo.h" | 26 #include "mojo/message_pump/message_pump_mojo.h" |
| 25 #include "mojo/public/cpp/bindings/binding.h" | 27 #include "mojo/public/cpp/bindings/binding.h" |
| 26 #include "mojo/public/cpp/system/core.h" | 28 #include "mojo/public/cpp/system/core.h" |
| 27 #include "mojo/runner/child/child_controller.mojom.h" | 29 #include "mojo/runner/child/child_controller.mojom.h" |
| 28 #include "mojo/runner/host/native_application_support.h" | 30 #include "mojo/runner/host/native_application_support.h" |
| 29 #include "mojo/runner/host/switches.h" | 31 #include "mojo/runner/host/switches.h" |
| 30 #include "mojo/runner/init.h" | 32 #include "mojo/runner/init.h" |
| 31 #include "third_party/mojo/src/mojo/edk/embedder/embedder.h" | 33 #include "third_party/mojo/src/mojo/edk/embedder/embedder.h" |
| 32 #include "third_party/mojo/src/mojo/edk/embedder/platform_channel_pair.h" | 34 #include "third_party/mojo/src/mojo/edk/embedder/platform_channel_pair.h" |
| 33 #include "third_party/mojo/src/mojo/edk/embedder/process_delegate.h" | 35 #include "third_party/mojo/src/mojo/edk/embedder/process_delegate.h" |
| 34 #include "third_party/mojo/src/mojo/edk/embedder/scoped_platform_handle.h" | 36 #include "third_party/mojo/src/mojo/edk/embedder/scoped_platform_handle.h" |
| 35 | 37 |
| 36 #if defined(OS_LINUX) && !defined(OS_ANDROID) | 38 #if defined(OS_LINUX) && !defined(OS_ANDROID) |
| 37 #include "base/rand_util.h" | 39 #include "base/rand_util.h" |
| 38 #include "base/sys_info.h" | 40 #include "base/sys_info.h" |
| 39 #include "mojo/runner/host/linux_sandbox.h" | 41 #include "mojo/runner/host/linux_sandbox.h" |
| 40 #endif | 42 #endif |
| 41 | 43 |
| 42 namespace mojo { | 44 namespace mojo { |
| 43 namespace runner { | 45 namespace runner { |
| 44 | 46 |
| 45 namespace { | 47 namespace { |
| 46 | 48 |
| 49 void DidCreateChannel(embedder::ChannelInfo* channel_info) { |
| 50 DVLOG(2) << "ChildControllerImpl::DidCreateChannel()"; |
| 51 } |
| 52 |
| 47 // Blocker --------------------------------------------------------------------- | 53 // Blocker --------------------------------------------------------------------- |
| 48 | 54 |
| 49 // Blocks a thread until another thread unblocks it, at which point it unblocks | 55 // Blocks a thread until another thread unblocks it, at which point it unblocks |
| 50 // and runs a closure provided by that thread. | 56 // and runs a closure provided by that thread. |
| 51 class Blocker { | 57 class Blocker { |
| 52 public: | 58 public: |
| 53 class Unblocker { | 59 class Unblocker { |
| 54 public: | 60 public: |
| 55 explicit Unblocker(Blocker* blocker = nullptr) : blocker_(blocker) {} | 61 explicit Unblocker(Blocker* blocker = nullptr) : blocker_(blocker) {} |
| 56 ~Unblocker() {} | 62 ~Unblocker() {} |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 95 // Should be created and initialized on the main thread. | 101 // Should be created and initialized on the main thread. |
| 96 // TODO(use_chrome_edk) | 102 // TODO(use_chrome_edk) |
| 97 // class AppContext : public edk::ProcessDelegate { | 103 // class AppContext : public edk::ProcessDelegate { |
| 98 class AppContext : public embedder::ProcessDelegate { | 104 class AppContext : public embedder::ProcessDelegate { |
| 99 public: | 105 public: |
| 100 AppContext() | 106 AppContext() |
| 101 : io_thread_("io_thread"), controller_thread_("controller_thread") {} | 107 : io_thread_("io_thread"), controller_thread_("controller_thread") {} |
| 102 ~AppContext() override {} | 108 ~AppContext() override {} |
| 103 | 109 |
| 104 void Init() { | 110 void Init() { |
| 111 #if defined(OS_WIN) |
| 112 embedder::PreInitializeChildProcess(); |
| 113 #endif |
| 114 |
| 105 // Initialize Mojo before starting any threads. | 115 // Initialize Mojo before starting any threads. |
| 106 embedder::Init(); | 116 embedder::Init(); |
| 107 | 117 |
| 108 // Create and start our I/O thread. | 118 // Create and start our I/O thread. |
| 109 base::Thread::Options io_thread_options(base::MessageLoop::TYPE_IO, 0); | 119 base::Thread::Options io_thread_options(base::MessageLoop::TYPE_IO, 0); |
| 110 CHECK(io_thread_.StartWithOptions(io_thread_options)); | 120 CHECK(io_thread_.StartWithOptions(io_thread_options)); |
| 111 io_runner_ = io_thread_.task_runner().get(); | 121 io_runner_ = io_thread_.task_runner().get(); |
| 112 CHECK(io_runner_.get()); | 122 CHECK(io_runner_.get()); |
| 113 | 123 |
| 114 // TODO(vtl): This should be SLAVE, not NONE. | 124 // TODO(vtl): This should be SLAVE, not NONE. |
| (...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 186 DCHECK(thread_checker_.CalledOnValidThread()); | 196 DCHECK(thread_checker_.CalledOnValidThread()); |
| 187 | 197 |
| 188 // TODO(vtl): Pass in the result from |MainMain()|. | 198 // TODO(vtl): Pass in the result from |MainMain()|. |
| 189 on_app_complete_.Run(MOJO_RESULT_UNIMPLEMENTED); | 199 on_app_complete_.Run(MOJO_RESULT_UNIMPLEMENTED); |
| 190 } | 200 } |
| 191 | 201 |
| 192 // To be executed on the controller thread. Creates the |ChildController|, | 202 // To be executed on the controller thread. Creates the |ChildController|, |
| 193 // etc. | 203 // etc. |
| 194 static void Init(AppContext* app_context, | 204 static void Init(AppContext* app_context, |
| 195 base::NativeLibrary app_library, | 205 base::NativeLibrary app_library, |
| 196 embedder::ScopedPlatformHandle platform_channel, | 206 ScopedMessagePipeHandle host_message_pipe, |
| 197 const Blocker::Unblocker& unblocker) { | 207 const Blocker::Unblocker& unblocker) { |
| 198 DCHECK(app_context); | 208 DCHECK(app_context); |
| 199 DCHECK(platform_channel.is_valid()); | 209 DCHECK(host_message_pipe.is_valid()); |
| 200 | 210 |
| 201 DCHECK(!app_context->controller()); | 211 DCHECK(!app_context->controller()); |
| 202 | 212 |
| 203 scoped_ptr<ChildControllerImpl> impl( | 213 scoped_ptr<ChildControllerImpl> impl( |
| 204 new ChildControllerImpl(app_context, app_library, unblocker)); | 214 new ChildControllerImpl(app_context, app_library, unblocker)); |
| 205 | 215 |
| 206 ScopedMessagePipeHandle host_message_pipe(embedder::CreateChannel( | |
| 207 platform_channel.Pass(), | |
| 208 base::Bind(&ChildControllerImpl::DidCreateChannel, | |
| 209 base::Unretained(impl.get())), | |
| 210 base::ThreadTaskRunnerHandle::Get())); | |
| 211 | |
| 212 impl->Bind(host_message_pipe.Pass()); | 216 impl->Bind(host_message_pipe.Pass()); |
| 213 | 217 |
| 214 app_context->set_controller(impl.Pass()); | 218 app_context->set_controller(impl.Pass()); |
| 215 } | 219 } |
| 216 | 220 |
| 217 void Bind(ScopedMessagePipeHandle handle) { binding_.Bind(handle.Pass()); } | 221 void Bind(ScopedMessagePipeHandle handle) { binding_.Bind(handle.Pass()); } |
| 218 | 222 |
| 219 void OnConnectionError() { | 223 void OnConnectionError() { |
| 220 // A connection error means the connection to the shell is lost. This is not | 224 // A connection error means the connection to the shell is lost. This is not |
| 221 // recoverable. | 225 // recoverable. |
| (...skipping 22 matching lines...) Expand all Loading... |
| 244 base::NativeLibrary app_library, | 248 base::NativeLibrary app_library, |
| 245 const Blocker::Unblocker& unblocker) | 249 const Blocker::Unblocker& unblocker) |
| 246 : app_context_(app_context), | 250 : app_context_(app_context), |
| 247 app_library_(app_library), | 251 app_library_(app_library), |
| 248 unblocker_(unblocker), | 252 unblocker_(unblocker), |
| 249 channel_info_(nullptr), | 253 channel_info_(nullptr), |
| 250 binding_(this) { | 254 binding_(this) { |
| 251 binding_.set_connection_error_handler([this]() { OnConnectionError(); }); | 255 binding_.set_connection_error_handler([this]() { OnConnectionError(); }); |
| 252 } | 256 } |
| 253 | 257 |
| 254 // Callback for |embedder::CreateChannel()|. | |
| 255 void DidCreateChannel(embedder::ChannelInfo* channel_info) { | |
| 256 DVLOG(2) << "ChildControllerImpl::DidCreateChannel()"; | |
| 257 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 258 channel_info_ = channel_info; | |
| 259 } | |
| 260 | |
| 261 static void StartAppOnMainThread( | 258 static void StartAppOnMainThread( |
| 262 base::NativeLibrary app_library, | 259 base::NativeLibrary app_library, |
| 263 InterfaceRequest<Application> application_request) { | 260 InterfaceRequest<Application> application_request) { |
| 264 if (!RunNativeApplication(app_library, application_request.Pass())) { | 261 if (!RunNativeApplication(app_library, application_request.Pass())) { |
| 265 LOG(ERROR) << "Failure to RunNativeApplication()"; | 262 LOG(ERROR) << "Failure to RunNativeApplication()"; |
| 266 } | 263 } |
| 267 } | 264 } |
| 268 | 265 |
| 269 base::ThreadChecker thread_checker_; | 266 base::ThreadChecker thread_checker_; |
| 270 AppContext* const app_context_; | 267 AppContext* const app_context_; |
| 271 base::NativeLibrary app_library_; | 268 base::NativeLibrary app_library_; |
| 272 Blocker::Unblocker unblocker_; | 269 Blocker::Unblocker unblocker_; |
| 273 StartAppCallback on_app_complete_; | 270 StartAppCallback on_app_complete_; |
| 274 | 271 |
| 275 embedder::ChannelInfo* channel_info_; | 272 embedder::ChannelInfo* channel_info_; |
| 276 Binding<ChildController> binding_; | 273 Binding<ChildController> binding_; |
| 277 | 274 |
| 278 DISALLOW_COPY_AND_ASSIGN(ChildControllerImpl); | 275 DISALLOW_COPY_AND_ASSIGN(ChildControllerImpl); |
| 279 }; | 276 }; |
| 280 | 277 |
| 278 #if defined(OS_LINUX) && !defined(OS_ANDROID) |
| 279 scoped_ptr<mojo::runner::LinuxSandbox> InitializeSandbox() { |
| 280 using sandbox::syscall_broker::BrokerFilePermission; |
| 281 // Warm parts of base in the copy of base in the mojo runner. |
| 282 base::RandUint64(); |
| 283 base::SysInfo::AmountOfPhysicalMemory(); |
| 284 base::SysInfo::MaxSharedMemorySize(); |
| 285 base::SysInfo::NumberOfProcessors(); |
| 286 |
| 287 // TODO(erg,jln): Allowing access to all of /dev/shm/ makes it easy to |
| 288 // spy on other shared memory using processes. This is a temporary hack |
| 289 // so that we have some sandbox until we have proper shared memory |
| 290 // support integrated into mojo. |
| 291 std::vector<BrokerFilePermission> permissions; |
| 292 permissions.push_back( |
| 293 BrokerFilePermission::ReadWriteCreateUnlinkRecursive("/dev/shm/")); |
| 294 scoped_ptr<mojo::runner::LinuxSandbox> sandbox( |
| 295 new mojo::runner::LinuxSandbox(permissions)); |
| 296 sandbox->Warmup(); |
| 297 sandbox->EngageNamespaceSandbox(); |
| 298 sandbox->EngageSeccompSandbox(); |
| 299 sandbox->Seal(); |
| 300 return sandbox.Pass(); |
| 301 } |
| 302 #endif |
| 303 |
| 304 ScopedMessagePipeHandle InitializeHostMessagePipe( |
| 305 embedder::ScopedPlatformHandle platform_channel, |
| 306 scoped_refptr<base::TaskRunner> io_task_runner) { |
| 307 ScopedMessagePipeHandle host_message_pipe(embedder::CreateChannel( |
| 308 platform_channel.Pass(), base::Bind(&DidCreateChannel), io_task_runner)); |
| 309 |
| 310 #if defined(OS_WIN) |
| 311 if (base::CommandLine::ForCurrentProcess()->HasSwitch("use-new-edk")) { |
| 312 // When using the new Mojo EDK, each message pipe is backed by a platform |
| 313 // handle. The one platform handle that comes on the command line is used |
| 314 // to bind to the ChildController interface. However we also want a |
| 315 // platform handle to setup the communication channel by which we exchange |
| 316 // handles to/from tokens, which is needed for sandboxed Windows |
| 317 // processes. |
| 318 char token_serializer_handle[10]; |
| 319 MojoHandleSignalsState state; |
| 320 MojoResult rv = |
| 321 MojoWait(host_message_pipe.get().value(), MOJO_HANDLE_SIGNAL_READABLE, |
| 322 MOJO_DEADLINE_INDEFINITE, &state); |
| 323 CHECK_EQ(MOJO_RESULT_OK, rv); |
| 324 uint32_t num_bytes = arraysize(token_serializer_handle); |
| 325 rv = MojoReadMessage(host_message_pipe.get().value(), |
| 326 token_serializer_handle, &num_bytes, nullptr, 0, |
| 327 MOJO_READ_MESSAGE_FLAG_NONE); |
| 328 CHECK_EQ(MOJO_RESULT_OK, rv); |
| 329 |
| 330 edk::ScopedPlatformHandle token_serializer_channel = |
| 331 edk::PlatformChannelPair::PassClientHandleFromParentProcessFromString( |
| 332 std::string(token_serializer_handle, num_bytes)); |
| 333 CHECK(token_serializer_channel.is_valid()); |
| 334 embedder::SetParentPipeHandle(token_serializer_channel.release().handle); |
| 335 } |
| 336 #endif |
| 337 |
| 338 return host_message_pipe.Pass(); |
| 339 } |
| 340 |
| 281 } // namespace | 341 } // namespace |
| 282 | 342 |
| 283 int ChildProcessMain() { | 343 int ChildProcessMain() { |
| 284 DVLOG(2) << "ChildProcessMain()"; | 344 DVLOG(2) << "ChildProcessMain()"; |
| 285 const base::CommandLine& command_line = | 345 const base::CommandLine& command_line = |
| 286 *base::CommandLine::ForCurrentProcess(); | 346 *base::CommandLine::ForCurrentProcess(); |
| 287 | 347 |
| 288 #if defined(OS_LINUX) && !defined(OS_ANDROID) | 348 #if defined(OS_LINUX) && !defined(OS_ANDROID) |
| 289 using sandbox::syscall_broker::BrokerFilePermission; | |
| 290 scoped_ptr<mojo::runner::LinuxSandbox> sandbox; | 349 scoped_ptr<mojo::runner::LinuxSandbox> sandbox; |
| 291 #endif | 350 #endif |
| 292 base::NativeLibrary app_library = 0; | 351 base::NativeLibrary app_library = 0; |
| 293 if (command_line.HasSwitch(switches::kChildProcess)) { | 352 // Load the application library before we engage the sandbox. |
| 294 // Load the application library before we engage the sandbox. | 353 app_library = mojo::runner::LoadNativeApplication( |
| 295 app_library = mojo::runner::LoadNativeApplication( | 354 command_line.GetSwitchValuePath(switches::kChildProcess)); |
| 296 command_line.GetSwitchValuePath(switches::kChildProcess)); | |
| 297 | 355 |
| 298 base::i18n::InitializeICU(); | 356 base::i18n::InitializeICU(); |
| 299 CallLibraryEarlyInitialization(app_library); | 357 CallLibraryEarlyInitialization(app_library); |
| 300 | |
| 301 #if defined(OS_LINUX) && !defined(OS_ANDROID) | 358 #if defined(OS_LINUX) && !defined(OS_ANDROID) |
| 302 if (command_line.HasSwitch(switches::kEnableSandbox)) { | 359 if (command_line.HasSwitch(switches::kEnableSandbox)) |
| 303 // Warm parts of base in the copy of base in the mojo runner. | 360 sandbox = InitializeSandbox(); |
| 304 base::RandUint64(); | |
| 305 base::SysInfo::AmountOfPhysicalMemory(); | |
| 306 base::SysInfo::MaxSharedMemorySize(); | |
| 307 base::SysInfo::NumberOfProcessors(); | |
| 308 | |
| 309 // TODO(erg,jln): Allowing access to all of /dev/shm/ makes it easy to | |
| 310 // spy on other shared memory using processes. This is a temporary hack | |
| 311 // so that we have some sandbox until we have proper shared memory | |
| 312 // support integrated into mojo. | |
| 313 std::vector<BrokerFilePermission> permissions; | |
| 314 permissions.push_back( | |
| 315 BrokerFilePermission::ReadWriteCreateUnlinkRecursive("/dev/shm/")); | |
| 316 sandbox.reset(new mojo::runner::LinuxSandbox(permissions)); | |
| 317 sandbox->Warmup(); | |
| 318 sandbox->EngageNamespaceSandbox(); | |
| 319 sandbox->EngageSeccompSandbox(); | |
| 320 sandbox->Seal(); | |
| 321 } | |
| 322 #endif | 361 #endif |
| 323 } | |
| 324 | 362 |
| 325 embedder::ScopedPlatformHandle platform_channel = | 363 embedder::ScopedPlatformHandle platform_channel = |
| 326 embedder::PlatformChannelPair::PassClientHandleFromParentProcess( | 364 embedder::PlatformChannelPair::PassClientHandleFromParentProcess( |
| 327 command_line); | 365 command_line); |
| 328 CHECK(platform_channel.is_valid()); | 366 CHECK(platform_channel.is_valid()); |
| 329 | 367 |
| 330 DCHECK(!base::MessageLoop::current()); | 368 DCHECK(!base::MessageLoop::current()); |
| 331 | 369 |
| 332 AppContext app_context; | 370 AppContext app_context; |
| 333 app_context.Init(); | 371 app_context.Init(); |
| 372 ScopedMessagePipeHandle host_message_pipe = InitializeHostMessagePipe( |
| 373 platform_channel.Pass(), app_context.io_runner()); |
| 334 Blocker blocker; | 374 Blocker blocker; |
| 335 app_context.controller_runner()->PostTask( | 375 app_context.controller_runner()->PostTask( |
| 336 FROM_HERE, | 376 FROM_HERE, |
| 337 base::Bind(&ChildControllerImpl::Init, base::Unretained(&app_context), | 377 base::Bind(&ChildControllerImpl::Init, base::Unretained(&app_context), |
| 338 base::Unretained(app_library), base::Passed(&platform_channel), | 378 base::Unretained(app_library), |
| 339 blocker.GetUnblocker())); | 379 base::Passed(&host_message_pipe), blocker.GetUnblocker())); |
| 340 // This will block, then run whatever the controller wants. | 380 // This will block, then run whatever the controller wants. |
| 341 blocker.Block(); | 381 blocker.Block(); |
| 342 | 382 |
| 343 app_context.Shutdown(); | 383 app_context.Shutdown(); |
| 344 | 384 |
| 345 return 0; | 385 return 0; |
| 346 } | 386 } |
| 347 | 387 |
| 348 } // namespace runner | 388 } // namespace runner |
| 349 } // namespace mojo | 389 } // namespace mojo |
| OLD | NEW |