summaryrefslogtreecommitdiffstats
path: root/mojo/shell
diff options
context:
space:
mode:
authorviettrungluu@chromium.org <viettrungluu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-03-21 12:18:52 +0000
committerviettrungluu@chromium.org <viettrungluu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-03-21 12:18:52 +0000
commitef0fe2398c9e01546223526383f1834f23ffb75a (patch)
tree0bee57f3c804cce7bcba6b98712500da8a92f81f /mojo/shell
parent90c07ab1ab976dac0ab07667224018b86d1c0f57 (diff)
downloadchromium_src-ef0fe2398c9e01546223526383f1834f23ffb75a.zip
chromium_src-ef0fe2398c9e01546223526383f1834f23ffb75a.tar.gz
chromium_src-ef0fe2398c9e01546223526383f1834f23ffb75a.tar.bz2
Mojo: Actually load/run the app in the child process.
R=sky@chromium.org Review URL: https://codereview.chromium.org/206673004 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@258543 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'mojo/shell')
-rw-r--r--mojo/shell/app_child_process.cc167
1 files changed, 134 insertions, 33 deletions
diff --git a/mojo/shell/app_child_process.cc b/mojo/shell/app_child_process.cc
index 3d07789..732f89c 100644
--- a/mojo/shell/app_child_process.cc
+++ b/mojo/shell/app_child_process.cc
@@ -5,12 +5,17 @@
#include "mojo/shell/app_child_process.h"
#include "base/bind.h"
+#include "base/callback_helpers.h"
+#include "base/file_util.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/message_loop/message_loop.h"
+#include "base/scoped_native_library.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"
@@ -24,10 +29,59 @@ namespace shell {
namespace {
-class AppChildControllerImpl;
+// 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:
+ ~Unblocker() {}
+
+ void Unblock(base::Closure run_after) {
+ DCHECK(blocker_);
+ DCHECK(blocker_->run_after_.is_null());
+ blocker_->run_after_ = run_after;
+ blocker_->event_.Signal();
+ blocker_ = NULL;
+ }
+
+ private:
+ friend class Blocker;
+ Unblocker(Blocker* blocker) : blocker_(blocker) {
+ DCHECK(blocker_);
+ }
+
+ 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:
@@ -74,15 +128,18 @@ class AppContext {
}
private:
+ // Accessed only on the controller thread.
+ // IMPORTANT: This must be BEFORE |controller_thread_|, so that the controller
+ // thread gets joined (and thus |controller_| reset) before |controller_| is
+ // destroyed.
+ scoped_ptr<AppChildControllerImpl> controller_;
+
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_;
-
DISALLOW_COPY_AND_ASSIGN(AppContext);
};
@@ -99,17 +156,27 @@ class AppChildControllerImpl : public mojo_shell::AppChildController {
static void Init(
AppContext* app_context,
embedder::ScopedPlatformHandle platform_channel,
- scoped_refptr<base::SingleThreadTaskRunner> main_thread_runner) {
+ const Blocker::Unblocker& unblocker) {
DCHECK(app_context);
DCHECK(platform_channel.is_valid());
- DCHECK(main_thread_runner);
DCHECK(!app_context->controller());
app_context->set_controller(
- make_scoped_ptr(new AppChildControllerImpl(app_context)));
- app_context->controller()->CreateChannel(platform_channel.Pass(),
- main_thread_runner);
+ make_scoped_ptr(new AppChildControllerImpl(app_context, unblocker)));
+ app_context->controller()->CreateChannel(platform_channel.Pass());
+ }
+
+ void Shutdown() {
+ DVLOG(2) << "AppChildControllerImpl::Shutdown()";
+ DCHECK(thread_checker_.CalledOnValidThread());
+
+ // TODO(vtl): Pass in the result from |MainMain()|.
+ controller_client_->AppCompleted(MOJO_RESULT_UNIMPLEMENTED);
+
+ // TODO(vtl): Drain then destroy the channel (on the I/O thread).
+ // This will destroy this object.
+ app_context_->set_controller(scoped_ptr<AppChildControllerImpl>());
}
// |AppChildController| method:
@@ -117,19 +184,23 @@ class AppChildControllerImpl : public mojo_shell::AppChildController {
ScopedMessagePipeHandle service) OVERRIDE {
DVLOG(2) << "AppChildControllerImpl::StartApp("
<< app_path.To<std::string>() << ", ...)";
+ DCHECK(thread_checker_.CalledOnValidThread());
- // TODO(vtl): Load/run app.
+ unblocker_.Unblock(base::Bind(&AppChildControllerImpl::StartAppOnMainThread,
+ base::FilePath::FromUTF8Unsafe(
+ app_path.To<std::string>()),
+ base::Passed(&service)));
}
private:
- AppChildControllerImpl(AppContext* app_context)
+ AppChildControllerImpl(AppContext* app_context,
+ const Blocker::Unblocker& unblocker)
: app_context_(app_context),
+ unblocker_(unblocker),
channel_info_(NULL) {
}
- void CreateChannel(
- embedder::ScopedPlatformHandle platform_channel,
- scoped_refptr<base::SingleThreadTaskRunner> main_thread_runner) {
+ void CreateChannel(embedder::ScopedPlatformHandle platform_channel) {
DVLOG(2) << "AppChildControllerImpl::CreateChannel()";
DCHECK(thread_checker_.CalledOnValidThread());
@@ -137,7 +208,7 @@ class AppChildControllerImpl : public mojo_shell::AppChildController {
platform_channel.Pass(),
app_context_->io_runner(),
base::Bind(&AppChildControllerImpl::DidCreateChannel,
- base::Unretained(this), main_thread_runner),
+ base::Unretained(this)),
base::MessageLoopProxy::current()));
controller_client_.reset(
mojo_shell::ScopedAppChildControllerClientHandle(
@@ -146,16 +217,49 @@ class AppChildControllerImpl : public mojo_shell::AppChildController {
}
// Callback for |embedder::CreateChannel()|.
- void DidCreateChannel(
- scoped_refptr<base::SingleThreadTaskRunner> main_thread_runner,
- embedder::ChannelInfo* channel_info) {
+ 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,
+ ScopedMessagePipeHandle service) {
+ // TODO(vtl): This is copied from in_process_dynamic_service_runner.cc.
+ DVLOG(2) << "Loading/running Mojo app from " << app_path.value()
+ << " out of process";
+
+ base::ScopedClosureRunner app_deleter(
+ base::Bind(base::IgnoreResult(&base::DeleteFile), app_path, false));
+
+ do {
+ std::string load_error;
+ base::ScopedNativeLibrary app_library(
+ base::LoadNativeLibrary(app_path, &load_error));
+ if (!app_library.is_valid()) {
+ LOG(ERROR) << "Failed to load library (error: " << load_error << ")";
+ break;
+ }
+
+ typedef MojoResult (*MojoMainFunction)(MojoHandle);
+ MojoMainFunction main_function = reinterpret_cast<MojoMainFunction>(
+ app_library.GetFunctionPointer("MojoMain"));
+ if (!main_function) {
+ LOG(ERROR) << "Entrypoint MojoMain not found";
+ break;
+ }
+
+ // TODO(vtl): Report the result back to our parent process.
+ // |MojoMain()| takes ownership of the service handle.
+ MojoResult result = main_function(service.release().value());
+ if (result < MOJO_RESULT_OK)
+ LOG(ERROR) << "MojoMain returned an error: " << result;
+ } while (false);
+ }
+
base::ThreadChecker thread_checker_;
AppContext* const app_context_;
+ Blocker::Unblocker unblocker_;
RemotePtr<mojo_shell::AppChildControllerClient> controller_client_;
embedder::ChannelInfo* channel_info_;
@@ -179,21 +283,18 @@ void AppChildProcess::Main() {
AppContext app_context;
app_context.Init();
- {
- base::MessageLoop message_loop;
-
- app_context.controller_runner()->PostTask(
- FROM_HERE,
- base::Bind(&AppChildControllerImpl::Init,
- base::Unretained(&app_context),
- base::Passed(platform_channel()),
- scoped_refptr<base::SingleThreadTaskRunner>(
- message_loop.message_loop_proxy())));
-
- // Eventually, we'll get a task posted telling us to quit this message loop,
- // which will also tell us what to do afterwards (e.g., run |MojoMain()|).
- message_loop.Run();
- }
+ 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.controller_runner()->PostTask(
+ FROM_HERE,
+ base::Bind(&AppChildControllerImpl::Shutdown,
+ base::Unretained(app_context.controller())));
}
} // namespace shell