This source file includes following definitions.
- Unblock
- Block
- GetUnblocker
- controller_thread_
- Init
- io_runner
- controller_runner
- controller
- set_controller
- Init
- Shutdown
- StartApp
- channel_info_
- CreateChannel
- DidCreateChannel
- StartAppOnMainThread
- Main
#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"
#include "mojo/embedder/embedder.h"
#include "mojo/public/cpp/bindings/remote_ptr.h"
#include "mojo/public/cpp/system/core.h"
#include "mojo/shell/app_child_process.mojom.h"
namespace mojo {
namespace shell {
namespace {
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_;
};
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);
};
class AppChildControllerImpl;
class AppContext {
public:
AppContext()
: io_thread_("io_thread"),
controller_thread_("controller_thread") {}
~AppContext() {}
void Init() {
embedder::Init();
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_);
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_);
}
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:
scoped_ptr<AppChildControllerImpl> controller_;
base::Thread io_thread_;
scoped_refptr<base::SingleThreadTaskRunner> io_runner_;
base::Thread controller_thread_;
scoped_refptr<base::SingleThreadTaskRunner> controller_runner_;
DISALLOW_COPY_AND_ASSIGN(AppContext);
};
class AppChildControllerImpl : public mojo_shell::AppChildController {
public:
virtual ~AppChildControllerImpl() {
DCHECK(thread_checker_.CalledOnValidThread());
}
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());
app_context->set_controller(
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());
controller_client_->AppCompleted(MOJO_RESULT_UNIMPLEMENTED);
app_context_->set_controller(scoped_ptr<AppChildControllerImpl>());
}
virtual void StartApp(const String& app_path,
ScopedMessagePipeHandle service) OVERRIDE {
DVLOG(2) << "AppChildControllerImpl::StartApp("
<< app_path.To<std::string>() << ", ...)";
DCHECK(thread_checker_.CalledOnValidThread());
unblocker_.Unblock(base::Bind(&AppChildControllerImpl::StartAppOnMainThread,
base::FilePath::FromUTF8Unsafe(
app_path.To<std::string>()),
base::Passed(&service)));
}
private:
AppChildControllerImpl(AppContext* app_context,
const Blocker::Unblocker& unblocker)
: app_context_(app_context),
unblocker_(unblocker),
channel_info_(NULL) {
}
void CreateChannel(embedder::ScopedPlatformHandle platform_channel) {
DVLOG(2) << "AppChildControllerImpl::CreateChannel()";
DCHECK(thread_checker_.CalledOnValidThread());
ScopedMessagePipeHandle host_message_pipe(embedder::CreateChannel(
platform_channel.Pass(),
app_context_->io_runner(),
base::Bind(&AppChildControllerImpl::DidCreateChannel,
base::Unretained(this)),
base::MessageLoopProxy::current()));
controller_client_.reset(
mojo_shell::ScopedAppChildControllerClientHandle(
mojo_shell::AppChildControllerClientHandle(
host_message_pipe.release().value())), this);
}
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) {
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 {
base::NativeLibraryLoadError 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.ToString()
<< ")";
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;
}
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_;
DISALLOW_COPY_AND_ASSIGN(AppChildControllerImpl);
};
}
AppChildProcess::AppChildProcess() {
}
AppChildProcess::~AppChildProcess() {
}
void AppChildProcess::Main() {
DVLOG(2) << "AppChildProcess::Main()";
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()));
blocker.Block();
app_context.controller_runner()->PostTask(
FROM_HERE,
base::Bind(&AppChildControllerImpl::Shutdown,
base::Unretained(app_context.controller())));
}
}
}