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 |