diff options
author | jam <jam@chromium.org> | 2015-04-06 15:30:00 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2015-04-06 22:31:05 +0000 |
commit | edc54e0f7f19fbd76a84d470fec909631740c560 (patch) | |
tree | 8eea48b9bf96670b5d9f945b01d37e502e035dad /mojo | |
parent | 7f9a9aac8a45e36e4b8d1621b9b50ffca91cf38b (diff) | |
download | chromium_src-edc54e0f7f19fbd76a84d470fec909631740c560.zip chromium_src-edc54e0f7f19fbd76a84d470fec909631740c560.tar.gz chromium_src-edc54e0f7f19fbd76a84d470fec909631740c560.tar.bz2 |
Simplify some mojo_shell code.
-make desktop/main.cc be a near empty file that calls out to separate files for main ("launcher" per naming discussions) or child process
-remove ChildProcess and derived classs; one method is enough
-remove unused mojo/shell/launcher_main.cc
-use a more reasonable size window on desktop
Review URL: https://codereview.chromium.org/1065433002
Cr-Commit-Position: refs/heads/master@{#323964}
Diffstat (limited to 'mojo')
-rw-r--r-- | mojo/services/kiosk_wm/kiosk_wm.cc | 3 | ||||
-rw-r--r-- | mojo/shell/BUILD.gn | 34 | ||||
-rw-r--r-- | mojo/shell/app_child_process.cc | 302 | ||||
-rw-r--r-- | mojo/shell/app_child_process.h | 30 | ||||
-rw-r--r-- | mojo/shell/child_process.cc | 298 | ||||
-rw-r--r-- | mojo/shell/child_process.h | 44 | ||||
-rw-r--r-- | mojo/shell/desktop/launcher_process.cc | 170 | ||||
-rw-r--r-- | mojo/shell/desktop/launcher_process.h | 17 | ||||
-rw-r--r-- | mojo/shell/desktop/main.cc | 173 | ||||
-rw-r--r-- | mojo/shell/launcher_main.cc | 116 | ||||
-rw-r--r-- | mojo/shell/shell_test_main.cc | 7 | ||||
-rw-r--r-- | mojo/shell/switches.cc | 6 | ||||
-rw-r--r-- | mojo/shell/switches.h | 1 |
13 files changed, 491 insertions, 710 deletions
diff --git a/mojo/services/kiosk_wm/kiosk_wm.cc b/mojo/services/kiosk_wm/kiosk_wm.cc index 9aa2aab..28b5b5e 100644 --- a/mojo/services/kiosk_wm/kiosk_wm.cc +++ b/mojo/services/kiosk_wm/kiosk_wm.cc @@ -55,8 +55,7 @@ void KioskWM::OnEmbed( root_ = root; root_->AddObserver(this); - // Resize to match the Nexus 5 aspect ratio: - window_manager_app_->SetViewportSize(gfx::Size(320, 640)); + window_manager_app_->SetViewportSize(gfx::Size(1280, 800)); content_ = root->view_manager()->CreateView(); content_->SetBounds(root_->bounds()); diff --git a/mojo/shell/BUILD.gn b/mojo/shell/BUILD.gn index c121d57..1dbe6ad 100644 --- a/mojo/shell/BUILD.gn +++ b/mojo/shell/BUILD.gn @@ -20,10 +20,6 @@ group("shell") { ":tests", ] - if (!is_win) { - deps += [ ":mojo_launcher" ] - } - if (is_android) { deps += [ ":mojo_shell_apk", @@ -58,7 +54,11 @@ executable("mojo_shell") { ] if (!is_android) { - sources += [ "desktop/main.cc" ] + sources += [ + "desktop/launcher_process.cc", + "desktop/launcher_process.h", + "desktop/main.cc", + ] } else { sources += [ "android/library_loader.cc", @@ -79,23 +79,6 @@ executable("mojo_shell") { } } -executable("mojo_launcher") { - sources = [ - "launcher_main.cc", - ] - - deps = [ - ":init", - ":in_process_native_runner", - "//base", - "//build/config/sanitizers:deps", - "//mojo/common", - "//third_party/mojo/src/mojo/edk/system", - "//mojo/environment:chromium", - "//url", - ] -} - source_set("init") { sources = [ "init.cc", @@ -125,8 +108,6 @@ source_set("in_process_native_runner") { source_set("lib") { sources = [ - "app_child_process.cc", - "app_child_process.h", "app_child_process_host.cc", "app_child_process_host.h", "child_process.cc", @@ -463,8 +444,9 @@ mojo_native_application("apptests") { "//third_party/mojo/src/mojo/public/cpp/bindings:callback", "//third_party/mojo/src/mojo/public/cpp/environment", "//third_party/mojo/src/mojo/public/cpp/system:system", - # "//mojo/services/http_server/public/cpp", - # "//mojo/services/http_server/public/interfaces", + + #"//mojo/services/http_server/public/cpp", + #"//mojo/services/http_server/public/interfaces", "//mojo/services/network/public/interfaces", "//mojo/shell/test:bindings", ] diff --git a/mojo/shell/app_child_process.cc b/mojo/shell/app_child_process.cc deleted file mode 100644 index 546c28c..0000000 --- a/mojo/shell/app_child_process.cc +++ /dev/null @@ -1,302 +0,0 @@ -// 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 diff --git a/mojo/shell/app_child_process.h b/mojo/shell/app_child_process.h deleted file mode 100644 index d63afda..0000000 --- a/mojo/shell/app_child_process.h +++ /dev/null @@ -1,30 +0,0 @@ -// 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. - -#ifndef SHELL_APP_CHILD_PROCESS_H_ -#define SHELL_APP_CHILD_PROCESS_H_ - -#include "base/macros.h" -#include "mojo/shell/child_process.h" - -namespace mojo { -namespace shell { - -// An implementation of |ChildProcess| for an app child process, which runs a -// single app (loaded from the file system) on its main thread. -class AppChildProcess : public ChildProcess { - public: - AppChildProcess(); - ~AppChildProcess() override; - - void Main() override; - - private: - DISALLOW_COPY_AND_ASSIGN(AppChildProcess); -}; - -} // namespace shell -} // namespace mojo - -#endif // SHELL_APP_CHILD_PROCESS_H_ diff --git a/mojo/shell/child_process.cc b/mojo/shell/child_process.cc index 1140c14..e5438b1 100644 --- a/mojo/shell/child_process.cc +++ b/mojo/shell/child_process.cc @@ -4,36 +4,302 @@ #include "mojo/shell/child_process.h" +#include "base/bind.h" +#include "base/callback_helpers.h" #include "base/command_line.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/platform_channel_pair.h" -#include "mojo/shell/app_child_process.h" +#include "mojo/edk/embedder/process_delegate.h" +#include "mojo/edk/embedder/scoped_platform_handle.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" #include "mojo/shell/switches.h" namespace mojo { namespace shell { -ChildProcess::~ChildProcess() { -} +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_; -// static -scoped_ptr<ChildProcess> ChildProcess::Create( - const base::CommandLine& command_line) { - if (!command_line.HasSwitch(switches::kChildProcess)) - return scoped_ptr<ChildProcess>(); + // Accessed only on the controller thread. + scoped_ptr<AppChildControllerImpl> controller_; - scoped_ptr<ChildProcess> rv(new AppChildProcess()); - if (!rv) - return nullptr; + // Used to unblock the main thread on shutdown. + Blocker::Unblocker shutdown_unblocker_; - rv->platform_channel_ = + 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 + +int ChildProcessMain() { + DVLOG(2) << "ChildProcessMain()"; + const base::CommandLine& command_line = + *base::CommandLine::ForCurrentProcess(); + embedder::ScopedPlatformHandle platform_channel = embedder::PlatformChannelPair::PassClientHandleFromParentProcess( command_line); - CHECK(rv->platform_channel_.is_valid()); - return rv; -} + CHECK(platform_channel.is_valid()); + + 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(); -ChildProcess::ChildProcess() { + return 0; } } // namespace shell diff --git a/mojo/shell/child_process.h b/mojo/shell/child_process.h index 3da1c8f..c0cc431 100644 --- a/mojo/shell/child_process.h +++ b/mojo/shell/child_process.h @@ -2,50 +2,16 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef SHELL_CHILD_PROCESS_H_ -#define SHELL_CHILD_PROCESS_H_ - -#include "base/macros.h" -#include "base/memory/scoped_ptr.h" -#include "mojo/edk/embedder/scoped_platform_handle.h" - -namespace base { -class CommandLine; -} +#ifndef MOJO_SHELL_CHILD_PROCESS_H_ +#define MOJO_SHELL_CHILD_PROCESS_H_ namespace mojo { namespace shell { -// A base class for child processes -- i.e., code that is actually run within -// the child process. (Instances are manufactured by |Create()|.) -class ChildProcess { - public: - virtual ~ChildProcess(); - - // Returns null if the command line doesn't indicate that this is a child - // process. |main()| should call this, and if it returns non-null it should - // call |Main()| (without a message loop on the current thread). - static scoped_ptr<ChildProcess> Create(const base::CommandLine& command_line); - - // To be implemented by subclasses. This is the "entrypoint" for a child - // process. Run with no message loop for the main thread. - virtual void Main() = 0; - - protected: - ChildProcess(); - - embedder::ScopedPlatformHandle* platform_channel() { - return &platform_channel_; - } - - private: - // Available in |Main()| (after a successful |Create()|). - embedder::ScopedPlatformHandle platform_channel_; - - DISALLOW_COPY_AND_ASSIGN(ChildProcess); -}; +// Main method for a child process. +int ChildProcessMain(); } // namespace shell } // namespace mojo -#endif // SHELL_CHILD_PROCESS_H_ +#endif // MOJO_SHELL_CHILD_PROCESS_H_ diff --git a/mojo/shell/desktop/launcher_process.cc b/mojo/shell/desktop/launcher_process.cc new file mode 100644 index 0000000..f6bb6de --- /dev/null +++ b/mojo/shell/desktop/launcher_process.cc @@ -0,0 +1,170 @@ +// Copyright 2013 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 <stdio.h> +#include <string.h> + +#include <algorithm> +#include <iostream> + +#include "base/base_switches.h" +#include "base/bind.h" +#include "base/command_line.h" +#include "base/files/file_util.h" +#include "base/message_loop/message_loop.h" +#include "base/synchronization/waitable_event.h" +#include "base/trace_event/trace_event.h" +#include "mojo/shell/command_line_util.h" +#include "mojo/shell/context.h" +#include "mojo/shell/switches.h" + +namespace mojo { +namespace shell { +namespace { + +void Usage() { + std::cerr << "Launch Mojo applications.\n"; + std::cerr + << "Usage: mojo_shell" + << " [--" << switches::kArgsFor << "=<mojo-app>]" + << " [--" << switches::kContentHandlers << "=<handlers>]" + << " [--" << switches::kDisableCache << "]" + << " [--" << switches::kEnableMultiprocess << "]" + << " [--" << switches::kOrigin << "=<url-lib-path>]" + << " [--" << switches::kTraceStartup << "]" + << " [--" << switches::kURLMappings << "=from1=to1,from2=to2]" + << " [--" << switches::kPredictableAppFilenames << "]" + << " [--" << switches::kWaitForDebugger << "]" + << " <mojo-app> ...\n\n" + << "A <mojo-app> is a Mojo URL or a Mojo URL and arguments within " + << "quotes.\n" + << "Example: mojo_shell \"mojo:js_standalone test.js\".\n" + << "<url-lib-path> is searched for shared libraries named by mojo URLs.\n" + << "The value of <handlers> is a comma separated list like:\n" + << "text/html,mojo:html_viewer," + << "application/javascript,mojo:js_content_handler\n"; +} + +// Whether we're currently tracing. +bool g_tracing = false; + +// Number of tracing blocks written. +uint32_t g_blocks = 0; + +// Trace file, if open. +FILE* g_trace_file = nullptr; + +void WriteTraceDataCollected( + base::WaitableEvent* event, + const scoped_refptr<base::RefCountedString>& events_str, + bool has_more_events) { + if (g_blocks) { + fwrite(",", 1, 1, g_trace_file); + } + + ++g_blocks; + fwrite(events_str->data().c_str(), 1, events_str->data().length(), + g_trace_file); + if (!has_more_events) { + static const char kEnd[] = "]}"; + fwrite(kEnd, 1, strlen(kEnd), g_trace_file); + PCHECK(fclose(g_trace_file) == 0); + g_trace_file = nullptr; + event->Signal(); + } +} + +void EndTraceAndFlush(base::WaitableEvent* event) { + g_trace_file = fopen("mojo_shell.trace", "w+"); + PCHECK(g_trace_file); + static const char kStart[] = "{\"traceEvents\":["; + fwrite(kStart, 1, strlen(kStart), g_trace_file); + base::trace_event::TraceLog::GetInstance()->SetDisabled(); + base::trace_event::TraceLog::GetInstance()->Flush( + base::Bind(&WriteTraceDataCollected, base::Unretained(event))); +} + +void StopTracingAndFlushToDisk() { + g_tracing = false; + base::trace_event::TraceLog::GetInstance()->SetDisabled(); + base::WaitableEvent flush_complete_event(false, false); + // TraceLog::Flush requires a message loop but we've already shut ours down. + // Spin up a new thread to flush things out. + base::Thread flush_thread("mojo_shell_trace_event_flush"); + flush_thread.Start(); + flush_thread.message_loop()->PostTask( + FROM_HERE, + base::Bind(EndTraceAndFlush, base::Unretained(&flush_complete_event))); + flush_complete_event.Wait(); +} + +} // namespace + +int LauncherProcessMain(int argc, char** argv) { + const base::CommandLine& command_line = + *base::CommandLine::ForCurrentProcess(); + + const std::set<std::string> all_switches = switches::GetAllSwitches(); + const base::CommandLine::SwitchMap switches = command_line.GetSwitches(); + bool found_unknown_switch = false; + for (const auto& s : switches) { + if (all_switches.find(s.first) == all_switches.end()) { + std::cerr << "unknown switch: " << s.first << std::endl; + found_unknown_switch = true; + } + } + + if (found_unknown_switch || command_line.HasSwitch(switches::kHelp) || + command_line.GetArgs().empty()) { + Usage(); + return 0; + } + + if (command_line.HasSwitch(switches::kTraceStartup)) { + g_tracing = true; + base::trace_event::CategoryFilter category_filter( + command_line.GetSwitchValueASCII(switches::kTraceStartup)); + base::trace_event::TraceLog::GetInstance()->SetEnabled( + category_filter, base::trace_event::TraceLog::RECORDING_MODE, + base::trace_event::TraceOptions(base::trace_event::RECORD_UNTIL_FULL)); + } + + // We want the shell::Context to outlive the MessageLoop so that pipes are + // all gracefully closed / error-out before we try to shut the Context down. + mojo::shell::Context shell_context; + { + base::MessageLoop message_loop; + if (!shell_context.Init()) { + Usage(); + return 0; + } + if (g_tracing) { + message_loop.PostDelayedTask(FROM_HERE, + base::Bind(StopTracingAndFlushToDisk), + base::TimeDelta::FromSeconds(5)); + } + + // The mojo_shell --args-for command-line switch is handled specially + // because it can appear more than once. The base::CommandLine class + // collapses multiple occurrences of the same switch. + for (int i = 1; i < argc; i++) { + ApplyApplicationArgs(&shell_context, argv[i]); + } + + message_loop.PostTask( + FROM_HERE, + base::Bind(&mojo::shell::RunCommandLineApps, &shell_context)); + message_loop.Run(); + + // Must be called before |message_loop| is destroyed. + shell_context.Shutdown(); + } + + if (g_tracing) + StopTracingAndFlushToDisk(); + return 0; +} + +} // namespace shell +} // namespace mojo diff --git a/mojo/shell/desktop/launcher_process.h b/mojo/shell/desktop/launcher_process.h new file mode 100644 index 0000000..caed878 --- /dev/null +++ b/mojo/shell/desktop/launcher_process.h @@ -0,0 +1,17 @@ +// 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. + +#ifndef MOJO_SHELL_LAUNCHER_PROCESS_H_ +#define MOJO_SHELL_LAUNCHER_PROCESS_H_ + +namespace mojo { +namespace shell { + +// Main method for the launcher process. +int LauncherProcessMain(int argc, char** argv); + +} // namespace shell +} // namespace mojo + +#endif // MOJO_SHELL_LAUNCHER_PROCESS_H_ diff --git a/mojo/shell/desktop/main.cc b/mojo/shell/desktop/main.cc index 9214985..ca89c5d 100644 --- a/mojo/shell/desktop/main.cc +++ b/mojo/shell/desktop/main.cc @@ -2,184 +2,23 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include <stdio.h> -#include <string.h> - -#include <algorithm> -#include <iostream> - #include "base/at_exit.h" -#include "base/base_switches.h" -#include "base/bind.h" #include "base/command_line.h" -#include "base/files/file_util.h" -#include "base/message_loop/message_loop.h" -#include "base/synchronization/waitable_event.h" -#include "base/trace_event/trace_event.h" #include "mojo/shell/child_process.h" -#include "mojo/shell/command_line_util.h" -#include "mojo/shell/context.h" +#include "mojo/shell/desktop/launcher_process.h" #include "mojo/shell/init.h" #include "mojo/shell/switches.h" -namespace { - -void Usage() { - std::cerr << "Launch Mojo applications.\n"; - std::cerr - << "Usage: mojo_shell" - << " [--" << switches::kArgsFor << "=<mojo-app>]" - << " [--" << switches::kContentHandlers << "=<handlers>]" - << " [--" << switches::kEnableExternalApplications << "]" - << " [--" << switches::kDisableCache << "]" - << " [--" << switches::kEnableMultiprocess << "]" - << " [--" << switches::kOrigin << "=<url-lib-path>]" - << " [--" << switches::kTraceStartup << "]" - << " [--" << switches::kURLMappings << "=from1=to1,from2=to2]" - << " [--" << switches::kPredictableAppFilenames << "]" - << " [--" << switches::kWaitForDebugger << "]" - << " <mojo-app> ...\n\n" - << "A <mojo-app> is a Mojo URL or a Mojo URL and arguments within " - << "quotes.\n" - << "Example: mojo_shell \"mojo:js_standalone test.js\".\n" - << "<url-lib-path> is searched for shared libraries named by mojo URLs.\n" - << "The value of <handlers> is a comma separated list like:\n" - << "text/html,mojo:html_viewer," - << "application/javascript,mojo:js_content_handler\n"; -} - -// Whether we're currently tracing. -bool g_tracing = false; - -// Number of tracing blocks written. -uint32_t g_blocks = 0; - -// Trace file, if open. -FILE* g_trace_file = nullptr; - -void WriteTraceDataCollected( - base::WaitableEvent* event, - const scoped_refptr<base::RefCountedString>& events_str, - bool has_more_events) { - if (g_blocks) { - fwrite(",", 1, 1, g_trace_file); - } - - ++g_blocks; - fwrite(events_str->data().c_str(), 1, events_str->data().length(), - g_trace_file); - if (!has_more_events) { - static const char kEnd[] = "]}"; - fwrite(kEnd, 1, strlen(kEnd), g_trace_file); - PCHECK(fclose(g_trace_file) == 0); - g_trace_file = nullptr; - event->Signal(); - } -} - -void EndTraceAndFlush(base::WaitableEvent* event) { - g_trace_file = fopen("mojo_shell.trace", "w+"); - PCHECK(g_trace_file); - static const char kStart[] = "{\"traceEvents\":["; - fwrite(kStart, 1, strlen(kStart), g_trace_file); - base::trace_event::TraceLog::GetInstance()->SetDisabled(); - base::trace_event::TraceLog::GetInstance()->Flush( - base::Bind(&WriteTraceDataCollected, base::Unretained(event))); -} - -void StopTracingAndFlushToDisk() { - g_tracing = false; - base::trace_event::TraceLog::GetInstance()->SetDisabled(); - base::WaitableEvent flush_complete_event(false, false); - // TraceLog::Flush requires a message loop but we've already shut ours down. - // Spin up a new thread to flush things out. - base::Thread flush_thread("mojo_shell_trace_event_flush"); - flush_thread.Start(); - flush_thread.message_loop()->PostTask( - FROM_HERE, - base::Bind(EndTraceAndFlush, base::Unretained(&flush_complete_event))); - flush_complete_event.Wait(); -} - -} // namespace - int main(int argc, char** argv) { base::AtExitManager at_exit; base::CommandLine::Init(argc, argv); mojo::shell::InitializeLogging(); - // TODO(vtl): Unify parent and child process cases to the extent possible. - if (scoped_ptr<mojo::shell::ChildProcess> child_process = - mojo::shell::ChildProcess::Create( - *base::CommandLine::ForCurrentProcess())) { - child_process->Main(); - } else { - // Only check the command line for the main process. - const base::CommandLine& command_line = - *base::CommandLine::ForCurrentProcess(); - - const std::set<std::string> all_switches = switches::GetAllSwitches(); - const base::CommandLine::SwitchMap switches = command_line.GetSwitches(); - bool found_unknown_switch = false; - for (const auto& s : switches) { - if (all_switches.find(s.first) == all_switches.end()) { - std::cerr << "unknown switch: " << s.first << std::endl; - found_unknown_switch = true; - } - } - - if (found_unknown_switch || - (!command_line.HasSwitch(switches::kEnableExternalApplications) && - (command_line.HasSwitch(switches::kHelp) || - command_line.GetArgs().empty()))) { - Usage(); - return 0; - } - - if (command_line.HasSwitch(switches::kTraceStartup)) { - g_tracing = true; - base::trace_event::CategoryFilter category_filter( - command_line.GetSwitchValueASCII(switches::kTraceStartup)); - base::trace_event::TraceLog::GetInstance()->SetEnabled( - category_filter, base::trace_event::TraceLog::RECORDING_MODE, - base::trace_event::TraceOptions( - base::trace_event::RECORD_UNTIL_FULL)); - } - - // We want the shell::Context to outlive the MessageLoop so that pipes are - // all gracefully closed / error-out before we try to shut the Context down. - mojo::shell::Context shell_context; - { - base::MessageLoop message_loop; - if (!shell_context.Init()) { - Usage(); - return 0; - } - if (g_tracing) { - message_loop.PostDelayedTask(FROM_HERE, - base::Bind(StopTracingAndFlushToDisk), - base::TimeDelta::FromSeconds(5)); - } - - // The mojo_shell --args-for command-line switch is handled specially - // because it can appear more than once. The base::CommandLine class - // collapses multiple occurrences of the same switch. - for (int i = 1; i < argc; i++) { - ApplyApplicationArgs(&shell_context, argv[i]); - } - - message_loop.PostTask( - FROM_HERE, - base::Bind(&mojo::shell::RunCommandLineApps, &shell_context)); - message_loop.Run(); - - // Must be called before |message_loop| is destroyed. - shell_context.Shutdown(); - } - } + const base::CommandLine& command_line = + *base::CommandLine::ForCurrentProcess(); + if (command_line.HasSwitch(switches::kChildProcess)) + return mojo::shell::ChildProcessMain(); - if (g_tracing) - StopTracingAndFlushToDisk(); - return 0; + return mojo::shell::LauncherProcessMain(argc, argv); } diff --git a/mojo/shell/launcher_main.cc b/mojo/shell/launcher_main.cc deleted file mode 100644 index dfe634c..0000000 --- a/mojo/shell/launcher_main.cc +++ /dev/null @@ -1,116 +0,0 @@ -// 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 "base/at_exit.h" -#include "base/bind.h" -#include "base/bind_helpers.h" -#include "base/command_line.h" -#include "base/logging.h" -#include "base/macros.h" -#include "base/memory/scoped_ptr.h" -#include "base/message_loop/message_loop.h" -#include "base/run_loop.h" -#include "base/strings/string_split.h" -#include "mojo/edk/embedder/embedder.h" -#include "mojo/edk/embedder/process_delegate.h" -#include "mojo/edk/embedder/simple_platform_support.h" -#include "mojo/shell/in_process_native_runner.h" -#include "mojo/shell/init.h" -#include "mojo/shell/native_application_support.h" -#include "url/gurl.h" - -namespace mojo { -namespace shell { - -const char kAppArgs[] = "app-args"; -const char kAppPath[] = "app-path"; -const char kAppURL[] = "app-url"; -const char kShellPath[] = "shell-path"; - -class Launcher : public embedder::ProcessDelegate { - public: - explicit Launcher(const base::CommandLine& command_line) - : app_path_(command_line.GetSwitchValuePath(kAppPath)), - app_url_(command_line.GetSwitchValueASCII(kAppURL)), - loop_(base::MessageLoop::TYPE_IO) { - // TODO(vtl): I guess this should be SLAVE, not NONE? - embedder::InitIPCSupport(embedder::ProcessType::NONE, loop_.task_runner(), - this, loop_.task_runner(), - embedder::ScopedPlatformHandle()); - - base::SplitStringAlongWhitespace(command_line.GetSwitchValueASCII(kAppArgs), - &app_args_); - } - - ~Launcher() override { - DCHECK(!application_request_.is_pending()); - - embedder::ShutdownIPCSupportOnIOThread(); - } - - bool Connect() { return false; } - - bool Register() { - return application_request_.is_pending(); - } - - void Run() { - DCHECK(application_request_.is_pending()); - InProcessNativeRunner service_runner(nullptr); - base::RunLoop run_loop; - service_runner.Start(app_path_, NativeApplicationCleanup::DONT_DELETE, - application_request_.Pass(), run_loop.QuitClosure()); - run_loop.Run(); - } - - private: - void OnRegistered(base::RunLoop* run_loop, - InterfaceRequest<Application> application_request) { - application_request_ = application_request.Pass(); - run_loop->Quit(); - } - - // embedder::ProcessDelegate implementation: - void OnShutdownComplete() override { - NOTREACHED(); // Not called since we use ShutdownIPCSupportOnIOThread(). - } - - const base::FilePath app_path_; - const GURL app_url_; - std::vector<std::string> app_args_; - base::MessageLoop loop_; - InterfaceRequest<Application> application_request_; - - DISALLOW_COPY_AND_ASSIGN(Launcher); -}; - -} // namespace shell -} // namespace mojo - -int main(int argc, char** argv) { - base::AtExitManager at_exit; - mojo::embedder::Init( - make_scoped_ptr(new mojo::embedder::SimplePlatformSupport())); - - base::CommandLine::Init(argc, argv); - const base::CommandLine* command_line = - base::CommandLine::ForCurrentProcess(); - mojo::shell::InitializeLogging(); - - mojo::shell::Launcher launcher(*command_line); - if (!launcher.Connect()) { - LOG(ERROR) << "Failed to connect on socket " - << command_line->GetSwitchValueASCII(mojo::shell::kShellPath); - return 1; - } - - if (!launcher.Register()) { - LOG(ERROR) << "Error registering " - << command_line->GetSwitchValueASCII(mojo::shell::kAppURL); - return 1; - } - - launcher.Run(); - return 0; -} diff --git a/mojo/shell/shell_test_main.cc b/mojo/shell/shell_test_main.cc index 179eb41..47b6c09 100644 --- a/mojo/shell/shell_test_main.cc +++ b/mojo/shell/shell_test_main.cc @@ -19,11 +19,8 @@ int main(int argc, char** argv) { if (command_line.HasSwitch(switches::kChildProcess)) { base::AtExitManager at_exit; - scoped_ptr<mojo::shell::ChildProcess> child_process = - mojo::shell::ChildProcess::Create(command_line); - CHECK(child_process); - child_process->Main(); - return 0; + + return mojo::shell::ChildProcessMain(); } base::TestSuite test_suite(argc, argv); diff --git a/mojo/shell/switches.cc b/mojo/shell/switches.cc index 6aa5cda..2150b19 100644 --- a/mojo/shell/switches.cc +++ b/mojo/shell/switches.cc @@ -35,11 +35,6 @@ const char kDisableCache[] = "disable-cache"; // If set apps downloaded are not deleted. const char kDontDeleteOnDownload[] = "dont-delete-on-download"; -// Allow externally-running applications to discover, connect to, and register -// themselves with the shell. -// TODO(cmasone): Work in progress. Once we're sure this works, remove. -const char kEnableExternalApplications[] = "enable-external-applications"; - // Load apps in separate processes. // TODO(vtl): Work in progress; doesn't work. Flip this to "disable" (or maybe // change it to "single-process") when it works. @@ -85,7 +80,6 @@ const char* kSwitchArray[] = {kV, kContentHandlers, kDisableCache, kDontDeleteOnDownload, - kEnableExternalApplications, kEnableMultiprocess, kForceInProcess, kHelp, diff --git a/mojo/shell/switches.h b/mojo/shell/switches.h index 5c8056f..52267fe 100644 --- a/mojo/shell/switches.h +++ b/mojo/shell/switches.h @@ -18,7 +18,6 @@ extern const char kChildProcess[]; extern const char kContentHandlers[]; extern const char kDisableCache[]; extern const char kDontDeleteOnDownload[]; -extern const char kEnableExternalApplications[]; extern const char kEnableMultiprocess[]; extern const char kForceInProcess[]; extern const char kHelp[]; |