| // 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 <stdint.h> |
| |
| #include "base/macros.h" |
| #include "base/strings/stringprintf.h" |
| #include "base/thread_task_runner_handle.h" |
| #include "build/build_config.h" |
| #include "content/browser/mojo/mojo_shell_client_host.h" |
| #include "content/common/mojo/mojo_messages.h" |
| #include "content/public/browser/browser_thread.h" |
| #include "content/public/browser/render_process_host.h" |
| #include "content/public/common/mojo_shell_connection.h" |
| #include "ipc/ipc_sender.h" |
| #include "mojo/application/public/cpp/application_impl.h" |
| #include "mojo/application/public/interfaces/application_manager.mojom.h" |
| #include "mojo/converters/network/network_type_converters.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 content { |
| namespace { |
| |
| const char kMojoShellInstanceURL[] = "mojo_shell_instance_url"; |
| const char kMojoPlatformFile[] = "mojo_platform_file"; |
| |
| void DidCreateChannel(mojo::embedder::ChannelInfo* info) {} |
| |
| base::PlatformFile PlatformFileFromScopedPlatformHandle( |
| mojo::embedder::ScopedPlatformHandle handle) { |
| #if defined(OS_POSIX) |
| return handle.release().fd; |
| #elif defined(OS_WIN) |
| return handle.release().handle; |
| #endif |
| } |
| |
| class InstanceURL : public base::SupportsUserData::Data { |
| public: |
| InstanceURL(const std::string& instance_url) : instance_url_(instance_url) {} |
| ~InstanceURL() override {} |
| |
| std::string get() const { return instance_url_; } |
| |
| private: |
| std::string instance_url_; |
| |
| DISALLOW_COPY_AND_ASSIGN(InstanceURL); |
| }; |
| |
| class InstanceShellHandle : public base::SupportsUserData::Data { |
| public: |
| InstanceShellHandle(base::PlatformFile shell_handle) |
| : shell_handle_(shell_handle) {} |
| ~InstanceShellHandle() override {} |
| |
| base::PlatformFile get() const { return shell_handle_; } |
| |
| private: |
| base::PlatformFile shell_handle_; |
| |
| DISALLOW_COPY_AND_ASSIGN(InstanceShellHandle); |
| }; |
| |
| void SetMojoApplicationInstanceURL(RenderProcessHost* render_process_host, |
| const std::string& instance_url) { |
| render_process_host->SetUserData(kMojoShellInstanceURL, |
| new InstanceURL(instance_url)); |
| } |
| |
| void SetMojoPlatformFile(RenderProcessHost* render_process_host, |
| base::PlatformFile platform_file) { |
| render_process_host->SetUserData(kMojoPlatformFile, |
| new InstanceShellHandle(platform_file)); |
| } |
| |
| void CallRegisterProcessWithBroker(base::ProcessId pid, |
| MojoHandle client_pipe) { |
| mojo::shell::mojom::ApplicationManagerPtr application_manager; |
| MojoShellConnection::Get()->GetApplication()->ConnectToService( |
| "mojo:shell", &application_manager); |
| application_manager->RegisterProcessWithBroker( |
| static_cast<uint32_t>(pid), |
| mojo::ScopedHandle(mojo::Handle(client_pipe))); |
| } |
| |
| } // namespace |
| |
| void RegisterChildWithExternalShell(int child_process_id, |
| RenderProcessHost* render_process_host) { |
| // Some process types get created before the main message loop. |
| if (!MojoShellConnection::Get()) |
| return; |
| |
| // Create the channel to be shared with the target process. |
| mojo::embedder::HandlePassingInformation handle_passing_info; |
| mojo::embedder::PlatformChannelPair platform_channel_pair; |
| |
| // Give one end to the shell so that it can create an instance. |
| mojo::embedder::ScopedPlatformHandle platform_channel = |
| platform_channel_pair.PassServerHandle(); |
| mojo::ScopedMessagePipeHandle handle(mojo::embedder::CreateChannel( |
| platform_channel.Pass(), base::Bind(&DidCreateChannel), |
| base::ThreadTaskRunnerHandle::Get())); |
| mojo::shell::mojom::ApplicationManagerPtr application_manager; |
| MojoShellConnection::Get()->GetApplication()->ConnectToService( |
| "mojo:shell", &application_manager); |
| // The content of the URL/qualifier we pass is actually meaningless, it's only |
| // important that they're unique per process. |
| // TODO(beng): We need to specify a restrictive CapabilityFilter here that |
| // matches the needs of the target process. Figure out where that |
| // specification is best determined (not here, this is a common |
| // chokepoint for all process types) and how to wire it through. |
| // http://crbug.com/555393 |
| std::string url = |
| base::StringPrintf("exe:chrome_renderer%d", child_process_id); |
| |
| application_manager->CreateInstanceForHandle( |
| mojo::ScopedHandle(mojo::Handle(handle.release().value())), |
| url, |
| CreateCapabilityFilterForRenderer()); |
| |
| // Send the other end to the child via Chrome IPC. |
| base::PlatformFile client_file = PlatformFileFromScopedPlatformHandle( |
| platform_channel_pair.PassClientHandle()); |
| SetMojoPlatformFile(render_process_host, client_file); |
| |
| // Store the URL on the RPH so client code can access it later via |
| // GetMojoApplicationInstanceURL(). |
| SetMojoApplicationInstanceURL(render_process_host, url); |
| } |
| |
| std::string GetMojoApplicationInstanceURL( |
| RenderProcessHost* render_process_host) { |
| InstanceURL* instance_url = static_cast<InstanceURL*>( |
| render_process_host->GetUserData(kMojoShellInstanceURL)); |
| return instance_url ? instance_url->get() : std::string(); |
| } |
| |
| void SendExternalMojoShellHandleToChild( |
| base::ProcessHandle process_handle, |
| RenderProcessHost* render_process_host) { |
| InstanceShellHandle* client_file = static_cast<InstanceShellHandle*>( |
| render_process_host->GetUserData(kMojoPlatformFile)); |
| if (!client_file) |
| return; |
| render_process_host->Send(new MojoMsg_BindExternalMojoShellHandle( |
| IPC::GetFileHandleForProcess(client_file->get(), process_handle, true))); |
| } |
| |
| mojo::embedder::ScopedPlatformHandle RegisterProcessWithBroker( |
| base::ProcessId pid) { |
| mojo::embedder::PlatformChannelPair platform_channel_pair; |
| |
| MojoHandle platform_handle_wrapper; |
| MojoResult rv = mojo::embedder::CreatePlatformHandleWrapper( |
| platform_channel_pair.PassServerHandle(), &platform_handle_wrapper); |
| CHECK_EQ(rv, MOJO_RESULT_OK); |
| |
| if (BrowserThread::CurrentlyOn(BrowserThread::UI)) { |
| CallRegisterProcessWithBroker(pid, platform_handle_wrapper); |
| } else { |
| BrowserThread::PostTask( |
| BrowserThread::UI, |
| FROM_HERE, |
| base::Bind(CallRegisterProcessWithBroker, pid, |
| platform_handle_wrapper)); |
| } |
| |
| return platform_channel_pair.PassClientHandle(); |
| } |
| |
| } // namespace content |