| // 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 "shell/dynamic_service_runner.h" |
| #include "shell/external_application_registrar_connection.h" |
| #include "shell/in_process_dynamic_service_runner.h" |
| #include "shell/init.h" |
| #include "url/gurl.h" |
| |
| namespace mojo { |
| |
| 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), |
| connection_(new shell::ExternalApplicationRegistrarConnection( |
| base::FilePath(command_line.GetSwitchValuePath(kShellPath)))) { |
| // 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() { |
| // TODO(vtl): We need to destroy this before calling |
| // ShutdownIPCSupportOnIOThread(). This is all quite sketchy, and we really |
| // should convert all of this to running the application on the main thread, |
| // with a separate I/O thread (and managing the lifetime of everything more |
| // carefully). |
| connection_.reset(); |
| DCHECK(!application_request_.is_pending()); |
| |
| embedder::ShutdownIPCSupportOnIOThread(); |
| } |
| |
| bool Connect() { return connection_->Connect(); } |
| |
| bool Register() { |
| base::RunLoop run_loop; |
| connection_->Register( |
| app_url_, app_args_, |
| base::Bind(&Launcher::OnRegistered, base::Unretained(this), |
| base::Unretained(&run_loop))); |
| run_loop.Run(); |
| return application_request_.is_pending(); |
| } |
| |
| void Run() { |
| DCHECK(application_request_.is_pending()); |
| shell::InProcessDynamicServiceRunner service_runner(nullptr); |
| base::RunLoop run_loop; |
| service_runner.Start(app_path_, NativeRunner::DontDeleteAppPath, |
| 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_; |
| scoped_ptr<shell::ExternalApplicationRegistrarConnection> connection_; |
| InterfaceRequest<Application> application_request_; |
| |
| DISALLOW_COPY_AND_ASSIGN(Launcher); |
| }; |
| |
| } // 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::Launcher launcher(*command_line); |
| if (!launcher.Connect()) { |
| LOG(ERROR) << "Failed to connect on socket " |
| << command_line->GetSwitchValueASCII(mojo::kShellPath); |
| return 1; |
| } |
| |
| if (!launcher.Register()) { |
| LOG(ERROR) << "Error registering " |
| << command_line->GetSwitchValueASCII(mojo::kAppURL); |
| return 1; |
| } |
| |
| launcher.Run(); |
| return 0; |
| } |