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/runner/child_process.h" | 5 #include "mojo/runner/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/location.h" | 12 #include "base/location.h" |
| 13 #include "base/logging.h" | 13 #include "base/logging.h" |
| 14 #include "base/macros.h" | 14 #include "base/macros.h" |
| 15 #include "base/memory/ref_counted.h" | 15 #include "base/memory/ref_counted.h" |
| 16 #include "base/memory/scoped_ptr.h" | 16 #include "base/memory/scoped_ptr.h" |
| 17 #include "base/message_loop/message_loop.h" | 17 #include "base/message_loop/message_loop.h" |
| 18 #include "base/single_thread_task_runner.h" | 18 #include "base/single_thread_task_runner.h" |
| 19 #include "base/synchronization/waitable_event.h" | 19 #include "base/synchronization/waitable_event.h" |
| 20 #include "base/thread_task_runner_handle.h" | 20 #include "base/thread_task_runner_handle.h" |
| 21 #include "base/threading/thread.h" | 21 #include "base/threading/thread.h" |
| 22 #include "base/threading/thread_checker.h" | 22 #include "base/threading/thread_checker.h" |
| 23 #include "base/thread_task_runner_handle.h" | |
| 24 #include "mojo/common/message_pump_mojo.h" | 23 #include "mojo/common/message_pump_mojo.h" |
| 25 #include "mojo/edk/embedder/embedder.h" | 24 #include "mojo/edk/embedder/embedder.h" |
| 26 #include "mojo/edk/embedder/platform_channel_pair.h" | 25 #include "mojo/edk/embedder/platform_channel_pair.h" |
| 27 #include "mojo/edk/embedder/process_delegate.h" | 26 #include "mojo/edk/embedder/process_delegate.h" |
| 28 #include "mojo/edk/embedder/scoped_platform_handle.h" | 27 #include "mojo/edk/embedder/scoped_platform_handle.h" |
| 29 #include "mojo/edk/embedder/simple_platform_support.h" | 28 #include "mojo/edk/embedder/simple_platform_support.h" |
| 30 #include "mojo/public/cpp/system/core.h" | 29 #include "mojo/public/cpp/system/core.h" |
| 31 #include "mojo/runner/child_process.mojom.h" | 30 #include "mojo/runner/child_process.mojom.h" |
| 32 #include "mojo/runner/native_application_support.h" | 31 #include "mojo/runner/native_application_support.h" |
| 33 #include "mojo/runner/switches.h" | 32 #include "mojo/runner/switches.h" |
| 34 | 33 |
| 34 #if defined(OS_LINUX) && !defined(OS_ANDROID) | |
| 35 #include "base/rand_util.h" | |
| 36 #include "base/sys_info.h" | |
| 37 #include "mojo/runner/linux_sandbox.h" | |
| 38 #endif | |
| 39 | |
| 35 namespace mojo { | 40 namespace mojo { |
| 36 namespace runner { | 41 namespace runner { |
| 37 | 42 |
| 38 namespace { | 43 namespace { |
| 39 | 44 |
| 40 // Blocker --------------------------------------------------------------------- | 45 // Blocker --------------------------------------------------------------------- |
| 41 | 46 |
| 42 // Blocks a thread until another thread unblocks it, at which point it unblocks | 47 // Blocks a thread until another thread unblocks it, at which point it unblocks |
| 43 // and runs a closure provided by that thread. | 48 // and runs a closure provided by that thread. |
| 44 class Blocker { | 49 class Blocker { |
| (...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 175 ~ChildControllerImpl() override { | 180 ~ChildControllerImpl() override { |
| 176 DCHECK(thread_checker_.CalledOnValidThread()); | 181 DCHECK(thread_checker_.CalledOnValidThread()); |
| 177 | 182 |
| 178 // TODO(vtl): Pass in the result from |MainMain()|. | 183 // TODO(vtl): Pass in the result from |MainMain()|. |
| 179 on_app_complete_.Run(MOJO_RESULT_UNIMPLEMENTED); | 184 on_app_complete_.Run(MOJO_RESULT_UNIMPLEMENTED); |
| 180 } | 185 } |
| 181 | 186 |
| 182 // To be executed on the controller thread. Creates the |ChildController|, | 187 // To be executed on the controller thread. Creates the |ChildController|, |
| 183 // etc. | 188 // etc. |
| 184 static void Init(AppContext* app_context, | 189 static void Init(AppContext* app_context, |
| 190 base::NativeLibrary app_library, | |
| 185 embedder::ScopedPlatformHandle platform_channel, | 191 embedder::ScopedPlatformHandle platform_channel, |
| 186 const Blocker::Unblocker& unblocker) { | 192 const Blocker::Unblocker& unblocker) { |
| 187 DCHECK(app_context); | 193 DCHECK(app_context); |
| 188 DCHECK(platform_channel.is_valid()); | 194 DCHECK(platform_channel.is_valid()); |
| 189 | 195 |
| 190 DCHECK(!app_context->controller()); | 196 DCHECK(!app_context->controller()); |
| 191 | 197 |
| 192 scoped_ptr<ChildControllerImpl> impl( | 198 scoped_ptr<ChildControllerImpl> impl( |
| 193 new ChildControllerImpl(app_context, unblocker)); | 199 new ChildControllerImpl(app_context, app_library, unblocker)); |
| 194 | 200 |
| 195 ScopedMessagePipeHandle host_message_pipe(embedder::CreateChannel( | 201 ScopedMessagePipeHandle host_message_pipe(embedder::CreateChannel( |
| 196 platform_channel.Pass(), | 202 platform_channel.Pass(), |
| 197 base::Bind(&ChildControllerImpl::DidCreateChannel, | 203 base::Bind(&ChildControllerImpl::DidCreateChannel, |
| 198 base::Unretained(impl.get())), | 204 base::Unretained(impl.get())), |
| 199 base::ThreadTaskRunnerHandle::Get())); | 205 base::ThreadTaskRunnerHandle::Get())); |
| 200 | 206 |
| 201 impl->Bind(host_message_pipe.Pass()); | 207 impl->Bind(host_message_pipe.Pass()); |
| 202 | 208 |
| 203 app_context->set_controller(impl.Pass()); | 209 app_context->set_controller(impl.Pass()); |
| 204 } | 210 } |
| 205 | 211 |
| 206 void Bind(ScopedMessagePipeHandle handle) { binding_.Bind(handle.Pass()); } | 212 void Bind(ScopedMessagePipeHandle handle) { binding_.Bind(handle.Pass()); } |
| 207 | 213 |
| 208 void OnConnectionError() { | 214 void OnConnectionError() { |
| 209 // A connection error means the connection to the shell is lost. This is not | 215 // A connection error means the connection to the shell is lost. This is not |
| 210 // recoverable. | 216 // recoverable. |
| 211 LOG(ERROR) << "Connection error to the shell."; | 217 LOG(ERROR) << "Connection error to the shell."; |
| 212 _exit(1); | 218 _exit(1); |
| 213 } | 219 } |
| 214 | 220 |
| 215 // |ChildController| methods: | 221 // |ChildController| methods: |
| 216 void StartApp(const String& app_path, | 222 void StartApp(InterfaceRequest<Application> application_request, |
| 217 bool clean_app_path, | |
| 218 InterfaceRequest<Application> application_request, | |
| 219 const StartAppCallback& on_app_complete) override { | 223 const StartAppCallback& on_app_complete) override { |
| 220 DVLOG(2) << "ChildControllerImpl::StartApp(" << app_path << ", ...)"; | |
| 221 DCHECK(thread_checker_.CalledOnValidThread()); | 224 DCHECK(thread_checker_.CalledOnValidThread()); |
| 222 | 225 |
| 223 on_app_complete_ = on_app_complete; | 226 on_app_complete_ = on_app_complete; |
| 224 unblocker_.Unblock(base::Bind( | 227 unblocker_.Unblock(base::Bind(&ChildControllerImpl::StartAppOnMainThread, |
| 225 &ChildControllerImpl::StartAppOnMainThread, | 228 base::Unretained(app_library_), |
| 226 base::FilePath::FromUTF8Unsafe(app_path), | 229 base::Passed(&application_request))); |
| 227 clean_app_path ? shell::NativeApplicationCleanup::DELETE | |
| 228 : shell::NativeApplicationCleanup::DONT_DELETE, | |
| 229 base::Passed(&application_request))); | |
| 230 } | 230 } |
| 231 | 231 |
| 232 void ExitNow(int32_t exit_code) override { | 232 void ExitNow(int32_t exit_code) override { |
| 233 DVLOG(2) << "ChildControllerImpl::ExitNow(" << exit_code << ")"; | 233 DVLOG(2) << "ChildControllerImpl::ExitNow(" << exit_code << ")"; |
| 234 _exit(exit_code); | 234 _exit(exit_code); |
| 235 } | 235 } |
| 236 | 236 |
| 237 private: | 237 private: |
| 238 ChildControllerImpl(AppContext* app_context, | 238 ChildControllerImpl(AppContext* app_context, |
| 239 base::NativeLibrary app_library, | |
| 239 const Blocker::Unblocker& unblocker) | 240 const Blocker::Unblocker& unblocker) |
| 240 : app_context_(app_context), | 241 : app_context_(app_context), |
| 242 app_library_(app_library), | |
| 241 unblocker_(unblocker), | 243 unblocker_(unblocker), |
| 242 channel_info_(nullptr), | 244 channel_info_(nullptr), |
| 243 binding_(this) { | 245 binding_(this) { |
| 244 binding_.set_connection_error_handler([this]() { OnConnectionError(); }); | 246 binding_.set_connection_error_handler([this]() { OnConnectionError(); }); |
| 245 } | 247 } |
| 246 | 248 |
| 247 // Callback for |embedder::CreateChannel()|. | 249 // Callback for |embedder::CreateChannel()|. |
| 248 void DidCreateChannel(embedder::ChannelInfo* channel_info) { | 250 void DidCreateChannel(embedder::ChannelInfo* channel_info) { |
| 249 DVLOG(2) << "ChildControllerImpl::DidCreateChannel()"; | 251 DVLOG(2) << "ChildControllerImpl::DidCreateChannel()"; |
| 250 DCHECK(thread_checker_.CalledOnValidThread()); | 252 DCHECK(thread_checker_.CalledOnValidThread()); |
| 251 channel_info_ = channel_info; | 253 channel_info_ = channel_info; |
| 252 } | 254 } |
| 253 | 255 |
| 254 static void StartAppOnMainThread( | 256 static void StartAppOnMainThread( |
| 255 const base::FilePath& app_path, | 257 base::NativeLibrary app_library, |
| 256 shell::NativeApplicationCleanup cleanup, | |
| 257 InterfaceRequest<Application> application_request) { | 258 InterfaceRequest<Application> application_request) { |
| 258 // TODO(vtl): This is copied from in_process_native_runner.cc. | 259 if (!RunNativeApplication(app_library, application_request.Pass())) { |
| 259 DVLOG(2) << "Loading/running Mojo app from " << app_path.value() | 260 LOG(ERROR) << "Failure to RunNativeApplication()"; |
| 260 << " out of process"; | 261 } |
| 261 | |
| 262 // We intentionally don't unload the native library as its lifetime is the | |
| 263 // same as that of the process. | |
| 264 base::NativeLibrary app_library = LoadNativeApplication(app_path, cleanup); | |
| 265 RunNativeApplication(app_library, application_request.Pass()); | |
| 266 } | 262 } |
| 267 | 263 |
| 268 base::ThreadChecker thread_checker_; | 264 base::ThreadChecker thread_checker_; |
| 269 AppContext* const app_context_; | 265 AppContext* const app_context_; |
| 266 base::NativeLibrary app_library_; | |
| 270 Blocker::Unblocker unblocker_; | 267 Blocker::Unblocker unblocker_; |
| 271 StartAppCallback on_app_complete_; | 268 StartAppCallback on_app_complete_; |
| 272 | 269 |
| 273 embedder::ChannelInfo* channel_info_; | 270 embedder::ChannelInfo* channel_info_; |
| 274 Binding<ChildController> binding_; | 271 Binding<ChildController> binding_; |
| 275 | 272 |
| 276 DISALLOW_COPY_AND_ASSIGN(ChildControllerImpl); | 273 DISALLOW_COPY_AND_ASSIGN(ChildControllerImpl); |
| 277 }; | 274 }; |
| 278 | 275 |
| 279 } // namespace | 276 } // namespace |
| 280 | 277 |
| 281 int ChildProcessMain() { | 278 int ChildProcessMain() { |
| 282 DVLOG(2) << "ChildProcessMain()"; | 279 DVLOG(2) << "ChildProcessMain()"; |
| 283 const base::CommandLine& command_line = | 280 const base::CommandLine& command_line = |
| 284 *base::CommandLine::ForCurrentProcess(); | 281 *base::CommandLine::ForCurrentProcess(); |
| 282 | |
| 283 #if defined(OS_LINUX) && !defined(OS_ANDROID) | |
| 284 using sandbox::syscall_broker::BrokerFilePermission; | |
| 285 scoped_ptr<mandoline::LinuxSandbox> sandbox; | |
| 286 #endif | |
| 287 base::NativeLibrary app_library = 0; | |
| 288 if (command_line.HasSwitch(switches::kChildProcess)) { | |
| 289 // Load the application library before we engage the sandbox. | |
| 290 mojo::shell::NativeApplicationCleanup cleanup = | |
| 291 command_line.HasSwitch(switches::kDeleteAfterLoad) | |
| 292 ? mojo::shell::NativeApplicationCleanup::DELETE | |
| 293 : mojo::shell::NativeApplicationCleanup::DONT_DELETE; | |
| 294 app_library = mojo::runner::LoadNativeApplication( | |
| 295 command_line.GetSwitchValuePath(switches::kChildProcess), cleanup); | |
| 296 | |
| 297 #if defined(OS_LINUX) && !defined(OS_ANDROID) | |
| 298 using sandbox::syscall_broker::BrokerFilePermission; | |
| 299 scoped_ptr<mandoline::LinuxSandbox> sandbox; | |
| 300 if (command_line.HasSwitch(switches::kEnableSandbox)) { | |
| 301 // Warm parts of base. | |
| 302 base::RandUint64(); | |
| 303 base::SysInfo::AmountOfPhysicalMemory(); | |
| 304 base::SysInfo::MaxSharedMemorySize(); | |
| 305 base::SysInfo::NumberOfProcessors(); | |
| 306 | |
| 307 // Do whatever warming that the mojo application wants. | |
| 308 typedef void (*SandboxWarmFunction)(); | |
| 309 SandboxWarmFunction sandbox_warm = reinterpret_cast<SandboxWarmFunction>( | |
| 310 base::GetFunctionPointerFromNativeLibrary(app_library, | |
| 311 "MojoSandboxWarm")); | |
| 312 if (sandbox_warm) | |
| 313 sandbox_warm(); | |
| 314 | |
|
jln (very slow on Chromium)
2015/07/29 20:28:04
The contract for "MojoSanboxWarm" should be:
1. D
Elliot Glaysher
2015/07/29 21:08:32
I have added the checks to LinuxSandbox::Warmup().
| |
| 315 std::vector<BrokerFilePermission> permissions; | |
| 316 sandbox.reset(new mandoline::LinuxSandbox(permissions)); | |
| 317 sandbox->Warmup(); | |
| 318 sandbox->EngageNamespaceSandbox(); | |
| 319 sandbox->EngageSeccompSandbox(); | |
| 320 sandbox->Seal(); | |
| 321 } | |
| 322 #endif | |
| 323 } | |
| 324 | |
| 285 embedder::ScopedPlatformHandle platform_channel = | 325 embedder::ScopedPlatformHandle platform_channel = |
| 286 embedder::PlatformChannelPair::PassClientHandleFromParentProcess( | 326 embedder::PlatformChannelPair::PassClientHandleFromParentProcess( |
| 287 command_line); | 327 command_line); |
| 288 CHECK(platform_channel.is_valid()); | 328 CHECK(platform_channel.is_valid()); |
| 289 | 329 |
| 290 DCHECK(!base::MessageLoop::current()); | 330 DCHECK(!base::MessageLoop::current()); |
| 291 | 331 |
| 292 AppContext app_context; | 332 AppContext app_context; |
| 293 app_context.Init(); | 333 app_context.Init(); |
| 294 | 334 |
| 295 Blocker blocker; | 335 Blocker blocker; |
| 296 app_context.controller_runner()->PostTask( | 336 app_context.controller_runner()->PostTask( |
| 297 FROM_HERE, | 337 FROM_HERE, |
| 298 base::Bind(&ChildControllerImpl::Init, base::Unretained(&app_context), | 338 base::Bind(&ChildControllerImpl::Init, base::Unretained(&app_context), |
| 299 base::Passed(&platform_channel), blocker.GetUnblocker())); | 339 base::Unretained(app_library), base::Passed(&platform_channel), |
| 340 blocker.GetUnblocker())); | |
| 300 // This will block, then run whatever the controller wants. | 341 // This will block, then run whatever the controller wants. |
| 301 blocker.Block(); | 342 blocker.Block(); |
| 302 | 343 |
| 303 app_context.Shutdown(); | 344 app_context.Shutdown(); |
| 304 | 345 |
| 305 return 0; | 346 return 0; |
| 306 } | 347 } |
| 307 | 348 |
| 308 } // namespace runner | 349 } // namespace runner |
| 309 } // namespace mojo | 350 } // namespace mojo |
| OLD | NEW |