| // 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 "content/common/service_manager/child_connection.h" |
| |
| #include <stdint.h> |
| #include <utility> |
| |
| #include "base/bind.h" |
| #include "base/macros.h" |
| #include "base/process/process.h" |
| #include "base/rand_util.h" |
| #include "base/strings/string_number_conversions.h" |
| #include "content/common/child.mojom.h" |
| #include "content/public/common/service_manager_connection.h" |
| #include "mojo/public/cpp/system/message_pipe.h" |
| #include "services/service_manager/public/cpp/connector.h" |
| #include "services/service_manager/public/cpp/identity.h" |
| #include "services/service_manager/public/mojom/service.mojom.h" |
| |
| namespace content { |
| |
| class ChildConnection::IOThreadContext |
| : public base::RefCountedThreadSafe<IOThreadContext> { |
| public: |
| IOThreadContext() {} |
| |
| void Initialize(const service_manager::Identity& child_identity, |
| service_manager::Connector* connector, |
| mojo::ScopedMessagePipeHandle service_pipe, |
| scoped_refptr<base::SequencedTaskRunner> io_task_runner) { |
| DCHECK(!io_task_runner_); |
| io_task_runner_ = io_task_runner; |
| std::unique_ptr<service_manager::Connector> io_thread_connector; |
| if (connector) |
| connector_ = connector->Clone(); |
| child_identity_ = child_identity; |
| io_task_runner_->PostTask( |
| FROM_HERE, base::BindOnce(&IOThreadContext::InitializeOnIOThread, this, |
| child_identity, std::move(service_pipe))); |
| } |
| |
| void BindInterface(const std::string& interface_name, |
| mojo::ScopedMessagePipeHandle interface_pipe) { |
| io_task_runner_->PostTask( |
| FROM_HERE, |
| base::BindOnce(&IOThreadContext::BindInterfaceOnIOThread, this, |
| interface_name, std::move(interface_pipe))); |
| } |
| |
| void ShutDown() { |
| if (!io_task_runner_) |
| return; |
| bool posted = io_task_runner_->PostTask( |
| FROM_HERE, base::BindOnce(&IOThreadContext::ShutDownOnIOThread, this)); |
| DCHECK(posted); |
| } |
| |
| void BindInterfaceOnIOThread(const std::string& interface_name, |
| mojo::ScopedMessagePipeHandle request_handle) { |
| if (connector_) { |
| connector_->BindInterface(child_identity_, interface_name, |
| std::move(request_handle)); |
| } |
| } |
| |
| void SetProcess(base::Process process) { |
| DCHECK(io_task_runner_); |
| io_task_runner_->PostTask( |
| FROM_HERE, base::BindOnce(&IOThreadContext::SetProcessOnIOThread, this, |
| std::move(process))); |
| } |
| |
| void ForceCrash() { |
| DCHECK(io_task_runner_); |
| io_task_runner_->PostTask( |
| FROM_HERE, |
| base::BindOnce(&IOThreadContext::ForceCrashOnIOThread, this)); |
| } |
| |
| private: |
| friend class base::RefCountedThreadSafe<IOThreadContext>; |
| |
| virtual ~IOThreadContext() {} |
| |
| void InitializeOnIOThread( |
| const service_manager::Identity& child_identity, |
| mojo::ScopedMessagePipeHandle service_pipe) { |
| service_manager::mojom::ServicePtr service; |
| service.Bind(mojo::InterfacePtrInfo<service_manager::mojom::Service>( |
| std::move(service_pipe), 0u)); |
| auto pid_receiver_request = mojo::MakeRequest(&pid_receiver_); |
| |
| if (connector_) { |
| connector_->RegisterServiceInstance(child_identity, std::move(service), |
| std::move(pid_receiver_request)); |
| connector_->BindInterface(child_identity, &child_); |
| } |
| } |
| |
| void ShutDownOnIOThread() { |
| connector_.reset(); |
| pid_receiver_.reset(); |
| } |
| |
| void SetProcessOnIOThread(base::Process process) { |
| DCHECK(pid_receiver_.is_bound()); |
| pid_receiver_->SetPID(process.Pid()); |
| pid_receiver_.reset(); |
| process_ = std::move(process); |
| } |
| |
| void ForceCrashOnIOThread() { child_->CrashHungProcess(); } |
| |
| scoped_refptr<base::SequencedTaskRunner> io_task_runner_; |
| // Usable from the IO thread only. |
| std::unique_ptr<service_manager::Connector> connector_; |
| service_manager::Identity child_identity_; |
| // ServiceManagerConnection in the child monitors the lifetime of this pipe. |
| mojom::ChildPtr child_; |
| service_manager::mojom::PIDReceiverPtr pid_receiver_; |
| // Hold onto the process, and thus its process handle, so that the pid will |
| // remain valid. |
| base::Process process_; |
| |
| DISALLOW_COPY_AND_ASSIGN(IOThreadContext); |
| }; |
| |
| ChildConnection::ChildConnection( |
| const service_manager::Identity& child_identity, |
| mojo::OutgoingInvitation* invitation, |
| service_manager::Connector* connector, |
| scoped_refptr<base::SequencedTaskRunner> io_task_runner) |
| : context_(new IOThreadContext), |
| child_identity_(child_identity), |
| weak_factory_(this) { |
| service_token_ = base::NumberToString(base::RandUint64()); |
| context_->Initialize(child_identity_, connector, |
| invitation->AttachMessagePipe(service_token_), |
| io_task_runner); |
| } |
| |
| ChildConnection::~ChildConnection() { |
| context_->ShutDown(); |
| } |
| |
| void ChildConnection::BindInterface( |
| const std::string& interface_name, |
| mojo::ScopedMessagePipeHandle interface_pipe) { |
| context_->BindInterface(interface_name, std::move(interface_pipe)); |
| } |
| |
| void ChildConnection::SetProcess(base::Process process) { |
| context_->SetProcess(std::move(process)); |
| } |
| |
| void ChildConnection::ForceCrash() { |
| context_->ForceCrash(); |
| } |
| |
| } // namespace content |