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

Unified Diff: mojo/runner/child/runner_connection.cc

Issue 1419293003: Allow mojo_runner to connect to arbitrary executables. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: . Created 5 years, 2 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/runner/child/runner_connection.h ('k') | mojo/runner/child/test_native_service.mojom » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: mojo/runner/child/runner_connection.cc
diff --git a/mojo/runner/child/runner_connection.cc b/mojo/runner/child/runner_connection.cc
new file mode 100644
index 0000000000000000000000000000000000000000..c7758c41141d271f28aa5e796e7d497e07dbaeab
--- /dev/null
+++ b/mojo/runner/child/runner_connection.cc
@@ -0,0 +1,257 @@
+// Copyright 2015 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/runner/child/runner_connection.h"
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/command_line.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/thread_task_runner_handle.h"
+#include "base/threading/thread.h"
+#include "base/threading/thread_checker.h"
+#include "mojo/message_pump/message_pump_mojo.h"
+#include "mojo/public/cpp/bindings/binding.h"
+#include "mojo/runner/child/child_controller.mojom.h"
+#include "third_party/mojo/src/mojo/edk/embedder/embedder.h"
+#include "third_party/mojo/src/mojo/edk/embedder/platform_channel_pair.h"
+#include "third_party/mojo/src/mojo/edk/embedder/scoped_platform_handle.h"
+
+namespace mojo {
+namespace runner {
+namespace {
+
+// 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();
+ if (!run_after_.is_null())
+ run_after_.Run();
+ }
+
+ Unblocker GetUnblocker() { return Unblocker(this); }
+
+ private:
+ base::WaitableEvent event_;
+ base::Closure run_after_;
+
+ DISALLOW_COPY_AND_ASSIGN(Blocker);
+};
+
+using GotApplicationRequestCallback =
+ base::Callback<void(InterfaceRequest<Application>)>;
+
+void OnGotApplicationRequest(InterfaceRequest<Application>* out_request,
+ InterfaceRequest<Application> request) {
+ *out_request = request.Pass();
+}
+
+class ChildControllerImpl;
+
+class RunnerConnectionImpl : public RunnerConnection {
+ public:
+ RunnerConnectionImpl() : controller_thread_("controller_thread") {
+ StartControllerThread();
+ }
+ ~RunnerConnectionImpl() override {
+ controller_runner_->PostTask(
+ FROM_HERE, base::Bind(&RunnerConnectionImpl::ShutdownOnControllerThread,
+ base::Unretained(this)));
+ controller_thread_.Stop();
+ }
+
+ // Returns true if a connection to the runner has been established and
+ // |request| has been modified, false if no connection was established.
+ bool WaitForApplicationRequest(InterfaceRequest<Application>* request);
+
+ ChildControllerImpl* controller() const { return controller_.get(); }
+
+ void set_controller(scoped_ptr<ChildControllerImpl> controller) {
+ controller_ = controller.Pass();
+ }
+
+ private:
+ void StartControllerThread() {
+ 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_.task_runner().get();
+ CHECK(controller_runner_.get());
+ }
+
+ void ShutdownOnControllerThread() { controller_.reset(); }
+
+ base::Thread controller_thread_;
+ scoped_refptr<base::SingleThreadTaskRunner> controller_runner_;
+
+ // Accessed only on the controller thread.
+ scoped_ptr<ChildControllerImpl> controller_;
+
+ DISALLOW_COPY_AND_ASSIGN(RunnerConnectionImpl);
+};
+
+class ChildControllerImpl : public ChildController {
+ public:
+ ~ChildControllerImpl() 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 |ChildController|,
+ // etc.
+ static void Create(RunnerConnectionImpl* connection,
+ const GotApplicationRequestCallback& callback,
+ embedder::ScopedPlatformHandle platform_channel,
+ const Blocker::Unblocker& unblocker) {
+ DCHECK(connection);
+ DCHECK(platform_channel.is_valid());
+
+ DCHECK(!connection->controller());
+
+ scoped_ptr<ChildControllerImpl> impl(
+ new ChildControllerImpl(connection, callback, unblocker));
+
+ ScopedMessagePipeHandle host_message_pipe(embedder::CreateChannel(
+ platform_channel.Pass(),
+ base::Bind(&ChildControllerImpl::DidCreateChannel,
+ base::Unretained(impl.get())),
+ base::ThreadTaskRunnerHandle::Get()));
+
+ impl->Bind(host_message_pipe.Pass());
+
+ connection->set_controller(impl.Pass());
+ }
+
+ void Bind(ScopedMessagePipeHandle handle) { binding_.Bind(handle.Pass()); }
+
+ void OnConnectionError() {
+ // A connection error means the connection to the shell is lost. This is not
+ // recoverable.
+ LOG(ERROR) << "Connection error to the shell.";
+ _exit(1);
+ }
+
+ // |ChildController| methods:
+ void StartApp(InterfaceRequest<Application> application_request,
+ const StartAppCallback& on_app_complete) override {
+ DCHECK(thread_checker_.CalledOnValidThread());
+
+ on_app_complete_ = on_app_complete;
+ unblocker_.Unblock(
+ base::Bind(&ChildControllerImpl::ReturnApplicationRequestOnMainThread,
+ callback_, base::Passed(&application_request)));
+ }
+
+ void ExitNow(int32_t exit_code) override {
+ DVLOG(2) << "ChildControllerImpl::ExitNow(" << exit_code << ")";
+ _exit(exit_code);
+ }
+
+ private:
+ ChildControllerImpl(RunnerConnectionImpl* connection,
+ const GotApplicationRequestCallback& callback,
+ const Blocker::Unblocker& unblocker)
+ : connection_(connection),
+ callback_(callback),
+ unblocker_(unblocker),
+ channel_info_(nullptr),
+ binding_(this) {
+ binding_.set_connection_error_handler([this]() { OnConnectionError(); });
+ }
+
+ // Callback for |embedder::CreateChannel()|.
+ void DidCreateChannel(embedder::ChannelInfo* channel_info) {
+ DVLOG(2) << "ChildControllerImpl::DidCreateChannel()";
+ DCHECK(thread_checker_.CalledOnValidThread());
+ channel_info_ = channel_info;
+ }
+
+ static void ReturnApplicationRequestOnMainThread(
+ const GotApplicationRequestCallback& callback,
+ InterfaceRequest<Application> application_request) {
+ callback.Run(application_request.Pass());
+ }
+
+ base::ThreadChecker thread_checker_;
+ RunnerConnectionImpl* const connection_;
+ GotApplicationRequestCallback callback_;
+ Blocker::Unblocker unblocker_;
+ StartAppCallback on_app_complete_;
+
+ embedder::ChannelInfo* channel_info_;
+ Binding<ChildController> binding_;
+
+ DISALLOW_COPY_AND_ASSIGN(ChildControllerImpl);
+};
+
+bool RunnerConnectionImpl::WaitForApplicationRequest(
+ InterfaceRequest<Application>* request) {
+ embedder::ScopedPlatformHandle platform_channel =
+ embedder::PlatformChannelPair::PassClientHandleFromParentProcess(
+ *base::CommandLine::ForCurrentProcess());
+ if (!platform_channel.is_valid())
+ return false;
+
+ Blocker blocker;
+ controller_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(
+ &ChildControllerImpl::Create, base::Unretained(this),
+ base::Bind(&OnGotApplicationRequest, base::Unretained(request)),
+ base::Passed(&platform_channel), blocker.GetUnblocker()));
+ blocker.Block();
+
+ return true;
+}
+
+} // namespace
+
+RunnerConnection::~RunnerConnection() {}
+
+// static
+RunnerConnection* RunnerConnection::ConnectToRunner(
+ InterfaceRequest<Application>* request) {
+ RunnerConnectionImpl* connection = new RunnerConnectionImpl;
+ if (!connection->WaitForApplicationRequest(request)) {
+ delete connection;
+ return nullptr;
+ }
+ return connection;
+}
+
+RunnerConnection::RunnerConnection() {}
+
+} // namespace runner
+} // namespace mojo
« no previous file with comments | « mojo/runner/child/runner_connection.h ('k') | mojo/runner/child/test_native_service.mojom » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698