Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(192)

Unified Diff: mojo/shell/app_child_process.cc

Issue 1049993002: Get mojo_shell building inside chromium checkout. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: fix presubmit Created 5 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « mojo/shell/app_child_process.h ('k') | mojo/shell/app_child_process.mojom » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: mojo/shell/app_child_process.cc
diff --git a/mojo/shell/app_child_process.cc b/mojo/shell/app_child_process.cc
new file mode 100644
index 0000000000000000000000000000000000000000..546c28ce3e5e6d188851c08f15c74d62ec9ec6a8
--- /dev/null
+++ b/mojo/shell/app_child_process.cc
@@ -0,0 +1,302 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "mojo/shell/app_child_process.h"
+
+#include "base/bind.h"
+#include "base/callback_helpers.h"
+#include "base/files/file_path.h"
+#include "base/location.h"
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/message_loop/message_loop.h"
+#include "base/single_thread_task_runner.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/threading/thread.h"
+#include "base/threading/thread_checker.h"
+#include "mojo/common/message_pump_mojo.h"
+#include "mojo/edk/embedder/embedder.h"
+#include "mojo/edk/embedder/process_delegate.h"
+#include "mojo/edk/embedder/simple_platform_support.h"
+#include "mojo/public/cpp/system/core.h"
+#include "mojo/shell/app_child_process.mojom.h"
+#include "mojo/shell/native_application_support.h"
+
+namespace mojo {
+namespace shell {
+
+namespace {
+
+// Blocker ---------------------------------------------------------------------
+
+// Blocks a thread until another thread unblocks it, at which point it unblocks
+// and runs a closure provided by that thread.
+class Blocker {
+ public:
+ class Unblocker {
+ public:
+ explicit Unblocker(Blocker* blocker = nullptr) : blocker_(blocker) {}
+ ~Unblocker() {}
+
+ void Unblock(base::Closure run_after) {
+ DCHECK(blocker_);
+ DCHECK(blocker_->run_after_.is_null());
+ blocker_->run_after_ = run_after;
+ blocker_->event_.Signal();
+ blocker_ = nullptr;
+ }
+
+ private:
+ Blocker* blocker_;
+
+ // Copy and assign allowed.
+ };
+
+ Blocker() : event_(true, false) {}
+ ~Blocker() {}
+
+ void Block() {
+ DCHECK(run_after_.is_null());
+ event_.Wait();
+ run_after_.Run();
+ }
+
+ Unblocker GetUnblocker() { return Unblocker(this); }
+
+ private:
+ base::WaitableEvent event_;
+ base::Closure run_after_;
+
+ DISALLOW_COPY_AND_ASSIGN(Blocker);
+};
+
+// AppContext ------------------------------------------------------------------
+
+class AppChildControllerImpl;
+
+// Should be created and initialized on the main thread.
+class AppContext : public embedder::ProcessDelegate {
+ public:
+ AppContext()
+ : io_thread_("io_thread"), controller_thread_("controller_thread") {}
+ ~AppContext() override {}
+
+ void Init() {
+ // Initialize Mojo before starting any threads.
+ embedder::Init(make_scoped_ptr(new embedder::SimplePlatformSupport()));
+
+ // Create and start our I/O thread.
+ base::Thread::Options io_thread_options(base::MessageLoop::TYPE_IO, 0);
+ CHECK(io_thread_.StartWithOptions(io_thread_options));
+ io_runner_ = io_thread_.message_loop_proxy().get();
+ CHECK(io_runner_.get());
+
+ // Create and start our controller thread.
+ base::Thread::Options controller_thread_options;
+ controller_thread_options.message_loop_type =
+ base::MessageLoop::TYPE_CUSTOM;
+ controller_thread_options.message_pump_factory =
+ base::Bind(&common::MessagePumpMojo::Create);
+ CHECK(controller_thread_.StartWithOptions(controller_thread_options));
+ controller_runner_ = controller_thread_.message_loop_proxy().get();
+ CHECK(controller_runner_.get());
+
+ // TODO(vtl): This should be SLAVE, not NONE.
+ embedder::InitIPCSupport(embedder::ProcessType::NONE, controller_runner_,
+ this, io_runner_,
+ embedder::ScopedPlatformHandle());
+ }
+
+ void Shutdown() {
+ Blocker blocker;
+ shutdown_unblocker_ = blocker.GetUnblocker();
+ controller_runner_->PostTask(
+ FROM_HERE, base::Bind(&AppContext::ShutdownOnControllerThread,
+ base::Unretained(this)));
+ blocker.Block();
+ }
+
+ base::SingleThreadTaskRunner* io_runner() const { return io_runner_.get(); }
+
+ base::SingleThreadTaskRunner* controller_runner() const {
+ return controller_runner_.get();
+ }
+
+ AppChildControllerImpl* controller() const { return controller_.get(); }
+
+ void set_controller(scoped_ptr<AppChildControllerImpl> controller) {
+ controller_ = controller.Pass();
+ }
+
+ private:
+ void ShutdownOnControllerThread() {
+ // First, destroy the controller.
+ controller_.reset();
+
+ // Next shutdown IPC. We'll unblock the main thread in OnShutdownComplete().
+ embedder::ShutdownIPCSupport();
+ }
+
+ // ProcessDelegate implementation.
+ void OnShutdownComplete() override {
+ shutdown_unblocker_.Unblock(base::Closure());
+ }
+
+ base::Thread io_thread_;
+ scoped_refptr<base::SingleThreadTaskRunner> io_runner_;
+
+ base::Thread controller_thread_;
+ scoped_refptr<base::SingleThreadTaskRunner> controller_runner_;
+
+ // Accessed only on the controller thread.
+ scoped_ptr<AppChildControllerImpl> controller_;
+
+ // Used to unblock the main thread on shutdown.
+ Blocker::Unblocker shutdown_unblocker_;
+
+ DISALLOW_COPY_AND_ASSIGN(AppContext);
+};
+
+// AppChildControllerImpl ------------------------------------------------------
+
+class AppChildControllerImpl : public AppChildController, public ErrorHandler {
+ public:
+ ~AppChildControllerImpl() override {
+ DCHECK(thread_checker_.CalledOnValidThread());
+
+ // TODO(vtl): Pass in the result from |MainMain()|.
+ on_app_complete_.Run(MOJO_RESULT_UNIMPLEMENTED);
+ }
+
+ // To be executed on the controller thread. Creates the |AppChildController|,
+ // etc.
+ static void Init(AppContext* app_context,
+ embedder::ScopedPlatformHandle platform_channel,
+ const Blocker::Unblocker& unblocker) {
+ DCHECK(app_context);
+ DCHECK(platform_channel.is_valid());
+
+ DCHECK(!app_context->controller());
+
+ scoped_ptr<AppChildControllerImpl> impl(
+ new AppChildControllerImpl(app_context, unblocker));
+
+ ScopedMessagePipeHandle host_message_pipe(embedder::CreateChannel(
+ platform_channel.Pass(), app_context->io_runner(),
+ base::Bind(&AppChildControllerImpl::DidCreateChannel,
+ base::Unretained(impl.get())),
+ base::MessageLoopProxy::current()));
+
+ impl->Bind(host_message_pipe.Pass());
+
+ app_context->set_controller(impl.Pass());
+ }
+
+ void Bind(ScopedMessagePipeHandle handle) { binding_.Bind(handle.Pass()); }
+
+ // |ErrorHandler| methods:
+ void OnConnectionError() override {
+ // A connection error means the connection to the shell is lost. This is not
+ // recoverable.
+ LOG(ERROR) << "Connection error to the shell.";
+ _exit(1);
+ }
+
+ // |AppChildController| methods:
+ void StartApp(const String& app_path,
+ bool clean_app_path,
+ InterfaceRequest<Application> application_request,
+ const StartAppCallback& on_app_complete) override {
+ DVLOG(2) << "AppChildControllerImpl::StartApp(" << app_path << ", ...)";
+ DCHECK(thread_checker_.CalledOnValidThread());
+
+ on_app_complete_ = on_app_complete;
+ unblocker_.Unblock(base::Bind(&AppChildControllerImpl::StartAppOnMainThread,
+ base::FilePath::FromUTF8Unsafe(app_path),
+ clean_app_path
+ ? NativeApplicationCleanup::DELETE
+ : NativeApplicationCleanup::DONT_DELETE,
+ base::Passed(&application_request)));
+ }
+
+ void ExitNow(int32_t exit_code) override {
+ DVLOG(2) << "AppChildControllerImpl::ExitNow(" << exit_code << ")";
+ _exit(exit_code);
+ }
+
+ private:
+ AppChildControllerImpl(AppContext* app_context,
+ const Blocker::Unblocker& unblocker)
+ : app_context_(app_context),
+ unblocker_(unblocker),
+ channel_info_(nullptr),
+ binding_(this) {
+ binding_.set_error_handler(this);
+ }
+
+ // Callback for |embedder::CreateChannel()|.
+ void DidCreateChannel(embedder::ChannelInfo* channel_info) {
+ DVLOG(2) << "AppChildControllerImpl::DidCreateChannel()";
+ DCHECK(thread_checker_.CalledOnValidThread());
+ channel_info_ = channel_info;
+ }
+
+ static void StartAppOnMainThread(
+ const base::FilePath& app_path,
+ NativeApplicationCleanup cleanup,
+ InterfaceRequest<Application> application_request) {
+ // TODO(vtl): This is copied from in_process_native_runner.cc.
+ DVLOG(2) << "Loading/running Mojo app from " << app_path.value()
+ << " out of process";
+
+ // We intentionally don't unload the native library as its lifetime is the
+ // same as that of the process.
+ base::NativeLibrary app_library = LoadNativeApplication(app_path, cleanup);
+ RunNativeApplication(app_library, application_request.Pass());
+ }
+
+ base::ThreadChecker thread_checker_;
+ AppContext* const app_context_;
+ Blocker::Unblocker unblocker_;
+ StartAppCallback on_app_complete_;
+
+ embedder::ChannelInfo* channel_info_;
+ Binding<AppChildController> binding_;
+
+ DISALLOW_COPY_AND_ASSIGN(AppChildControllerImpl);
+};
+
+} // namespace
+
+// AppChildProcess -------------------------------------------------------------
+
+AppChildProcess::AppChildProcess() {
+}
+
+AppChildProcess::~AppChildProcess() {
+}
+
+void AppChildProcess::Main() {
+ DVLOG(2) << "AppChildProcess::Main()";
+
+ DCHECK(!base::MessageLoop::current());
+
+ AppContext app_context;
+ app_context.Init();
+
+ Blocker blocker;
+ app_context.controller_runner()->PostTask(
+ FROM_HERE,
+ base::Bind(&AppChildControllerImpl::Init, base::Unretained(&app_context),
+ base::Passed(platform_channel()), blocker.GetUnblocker()));
+ // This will block, then run whatever the controller wants.
+ blocker.Block();
+
+ app_context.Shutdown();
+}
+
+} // namespace shell
+} // namespace mojo
« no previous file with comments | « mojo/shell/app_child_process.h ('k') | mojo/shell/app_child_process.mojom » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698