| Index: ipc/ipc_mojo_bootstrap.cc
|
| diff --git a/ipc/ipc_mojo_bootstrap.cc b/ipc/ipc_mojo_bootstrap.cc
|
| index ba0ea46fe5750ae93e7a0741f09f88f60a8dd04a..dc8ffdc8134dce5d8b6b962f8cadfadcd4e3dd00 100644
|
| --- a/ipc/ipc_mojo_bootstrap.cc
|
| +++ b/ipc/ipc_mojo_bootstrap.cc
|
| @@ -5,6 +5,9 @@
|
| #include "ipc/ipc_mojo_bootstrap.h"
|
|
|
| #include <stdint.h>
|
| +
|
| +#include <map>
|
| +#include <memory>
|
| #include <utility>
|
|
|
| #include "base/callback.h"
|
| @@ -12,15 +15,603 @@
|
| #include "base/macros.h"
|
| #include "base/memory/ptr_util.h"
|
| #include "base/process/process_handle.h"
|
| +#include "base/single_thread_task_runner.h"
|
| +#include "base/stl_util.h"
|
| +#include "base/synchronization/lock.h"
|
| +#include "base/threading/thread_task_runner_handle.h"
|
| #include "build/build_config.h"
|
| #include "ipc/ipc_message_utils.h"
|
| #include "ipc/ipc_platform_file.h"
|
| +#include "mojo/public/cpp/bindings/associated_group.h"
|
| +#include "mojo/public/cpp/bindings/associated_group_controller.h"
|
| #include "mojo/public/cpp/bindings/binding.h"
|
| +#include "mojo/public/cpp/bindings/connector.h"
|
| +#include "mojo/public/cpp/bindings/interface_endpoint_client.h"
|
| +#include "mojo/public/cpp/bindings/interface_endpoint_controller.h"
|
| +#include "mojo/public/cpp/bindings/interface_id.h"
|
| +#include "mojo/public/cpp/bindings/message_header_validator.h"
|
| +#include "mojo/public/cpp/bindings/pipe_control_message_handler.h"
|
| +#include "mojo/public/cpp/bindings/pipe_control_message_handler_delegate.h"
|
| +#include "mojo/public/cpp/bindings/pipe_control_message_proxy.h"
|
|
|
| namespace IPC {
|
|
|
| namespace {
|
|
|
| +class ChannelAssociatedGroupController
|
| + : public mojo::AssociatedGroupController,
|
| + public mojo::MessageReceiver,
|
| + public mojo::PipeControlMessageHandlerDelegate {
|
| + public:
|
| + ChannelAssociatedGroupController(bool set_interface_id_namespace_bit,
|
| + mojo::ScopedMessagePipeHandle handle)
|
| + : mojo::AssociatedGroupController(base::ThreadTaskRunnerHandle::Get()),
|
| + task_runner_(base::ThreadTaskRunnerHandle::Get()),
|
| + id_namespace_mask_(set_interface_id_namespace_bit ?
|
| + mojo::kInterfaceIdNamespaceMask : 0),
|
| + associated_group_(CreateAssociatedGroup()),
|
| + connector_(std::move(handle), mojo::Connector::SINGLE_THREADED_SEND,
|
| + base::ThreadTaskRunnerHandle::Get()),
|
| + header_validator_(
|
| + "IPC::mojom::Bootstrap [master] MessageHeaderValidator", this),
|
| + control_message_handler_(this),
|
| + control_message_proxy_(&connector_) {
|
| + connector_.set_incoming_receiver(&header_validator_);
|
| + connector_.set_connection_error_handler(
|
| + base::Bind(&ChannelAssociatedGroupController::OnPipeError,
|
| + base::Unretained(this)));
|
| + control_message_handler_.SetDescription(
|
| + "IPC::mojom::Bootstrap [master] PipeControlMessageHandler");
|
| + }
|
| +
|
| + mojo::AssociatedGroup* associated_group() { return associated_group_.get(); }
|
| +
|
| + void ShutDown() {
|
| + DCHECK(thread_checker_.CalledOnValidThread());
|
| + connector_.CloseMessagePipe();
|
| + OnPipeError();
|
| + associated_group_.reset();
|
| + }
|
| +
|
| + void SetProxyTaskRunner(
|
| + scoped_refptr<base::SingleThreadTaskRunner> proxy_task_runner) {
|
| + proxy_task_runner_ = proxy_task_runner;
|
| + }
|
| +
|
| + // mojo::AssociatedGroupController:
|
| + void CreateEndpointHandlePair(
|
| + mojo::ScopedInterfaceEndpointHandle* local_endpoint,
|
| + mojo::ScopedInterfaceEndpointHandle* remote_endpoint) override {
|
| + base::AutoLock locker(lock_);
|
| + uint32_t id = 0;
|
| + do {
|
| + if (next_interface_id_ >= mojo::kInterfaceIdNamespaceMask)
|
| + next_interface_id_ = 1;
|
| + id = (next_interface_id_++) | id_namespace_mask_;
|
| + } while (ContainsKey(endpoints_, id));
|
| +
|
| + Endpoint* endpoint = new Endpoint(this, id);
|
| + if (encountered_error_)
|
| + endpoint->set_peer_closed();
|
| + endpoints_.insert({ id, endpoint });
|
| +
|
| + *local_endpoint = CreateScopedInterfaceEndpointHandle(id, true);
|
| + *remote_endpoint = CreateScopedInterfaceEndpointHandle(id, false);
|
| + }
|
| +
|
| + mojo::ScopedInterfaceEndpointHandle CreateLocalEndpointHandle(
|
| + mojo::InterfaceId id) override {
|
| + if (!mojo::IsValidInterfaceId(id))
|
| + return mojo::ScopedInterfaceEndpointHandle();
|
| +
|
| + base::AutoLock locker(lock_);
|
| + bool inserted = false;
|
| + Endpoint* endpoint = FindOrInsertEndpoint(id, &inserted);
|
| + if (inserted && encountered_error_)
|
| + endpoint->set_peer_closed();
|
| +
|
| + return CreateScopedInterfaceEndpointHandle(id, true);
|
| + }
|
| +
|
| + void CloseEndpointHandle(mojo::InterfaceId id, bool is_local) override {
|
| + if (!mojo::IsValidInterfaceId(id))
|
| + return;
|
| +
|
| + base::AutoLock locker(lock_);
|
| + if (!is_local) {
|
| + DCHECK(ContainsKey(endpoints_, id));
|
| + DCHECK(!mojo::IsMasterInterfaceId(id));
|
| + control_message_proxy_.NotifyEndpointClosedBeforeSent(id);
|
| + return;
|
| + }
|
| +
|
| + DCHECK(ContainsKey(endpoints_, id));
|
| + Endpoint* endpoint = endpoints_[id].get();
|
| + DCHECK(!endpoint->client());
|
| + DCHECK(!endpoint->closed());
|
| + MarkClosedAndMaybeRemove(endpoint);
|
| +
|
| + if (!mojo::IsMasterInterfaceId(id))
|
| + control_message_proxy_.NotifyPeerEndpointClosed(id);
|
| + }
|
| +
|
| + mojo::InterfaceEndpointController* AttachEndpointClient(
|
| + const mojo::ScopedInterfaceEndpointHandle& handle,
|
| + mojo::InterfaceEndpointClient* client,
|
| + scoped_refptr<base::SingleThreadTaskRunner> runner) override {
|
| + const mojo::InterfaceId id = handle.id();
|
| +
|
| + DCHECK(mojo::IsValidInterfaceId(id));
|
| + DCHECK(client);
|
| +
|
| + base::AutoLock locker(lock_);
|
| + DCHECK(ContainsKey(endpoints_, id));
|
| +
|
| + Endpoint* endpoint = endpoints_[id].get();
|
| + endpoint->AttachClient(client, std::move(runner));
|
| +
|
| + if (endpoint->peer_closed())
|
| + NotifyEndpointOfError(endpoint, true /* force_async */);
|
| +
|
| + return endpoint;
|
| + }
|
| +
|
| + void DetachEndpointClient(
|
| + const mojo::ScopedInterfaceEndpointHandle& handle) override {
|
| + const mojo::InterfaceId id = handle.id();
|
| +
|
| + DCHECK(mojo::IsValidInterfaceId(id));
|
| +
|
| + base::AutoLock locker(lock_);
|
| + DCHECK(ContainsKey(endpoints_, id));
|
| +
|
| + Endpoint* endpoint = endpoints_[id].get();
|
| + endpoint->DetachClient();
|
| + }
|
| +
|
| + void RaiseError() override {
|
| + if (task_runner_->BelongsToCurrentThread()) {
|
| + connector_.RaiseError();
|
| + } else {
|
| + task_runner_->PostTask(
|
| + FROM_HERE,
|
| + base::Bind(&ChannelAssociatedGroupController::RaiseError, this));
|
| + }
|
| + }
|
| +
|
| + private:
|
| + class Endpoint;
|
| + friend class Endpoint;
|
| +
|
| + class Endpoint : public base::RefCountedThreadSafe<Endpoint>,
|
| + public mojo::InterfaceEndpointController {
|
| + public:
|
| + Endpoint(ChannelAssociatedGroupController* controller, mojo::InterfaceId id)
|
| + : controller_(controller), id_(id) {}
|
| +
|
| + mojo::InterfaceId id() const { return id_; }
|
| +
|
| + bool closed() const {
|
| + controller_->lock_.AssertAcquired();
|
| + return closed_;
|
| + }
|
| +
|
| + void set_closed() {
|
| + controller_->lock_.AssertAcquired();
|
| + closed_ = true;
|
| + }
|
| +
|
| + bool peer_closed() const {
|
| + controller_->lock_.AssertAcquired();
|
| + return peer_closed_;
|
| + }
|
| +
|
| + void set_peer_closed() {
|
| + controller_->lock_.AssertAcquired();
|
| + peer_closed_ = true;
|
| + }
|
| +
|
| + base::SingleThreadTaskRunner* task_runner() const {
|
| + return task_runner_.get();
|
| + }
|
| +
|
| + mojo::InterfaceEndpointClient* client() const {
|
| + controller_->lock_.AssertAcquired();
|
| + return client_;
|
| + }
|
| +
|
| + void AttachClient(mojo::InterfaceEndpointClient* client,
|
| + scoped_refptr<base::SingleThreadTaskRunner> runner) {
|
| + controller_->lock_.AssertAcquired();
|
| + DCHECK(!client_);
|
| + DCHECK(!closed_);
|
| + DCHECK(runner->BelongsToCurrentThread());
|
| +
|
| + task_runner_ = std::move(runner);
|
| + client_ = client;
|
| + }
|
| +
|
| + void DetachClient() {
|
| + controller_->lock_.AssertAcquired();
|
| + DCHECK(client_);
|
| + DCHECK(task_runner_->BelongsToCurrentThread());
|
| + DCHECK(!closed_);
|
| +
|
| + task_runner_ = nullptr;
|
| + client_ = nullptr;
|
| + }
|
| +
|
| + // mojo::InterfaceEndpointController:
|
| + bool SendMessage(mojo::Message* message) override {
|
| + DCHECK(task_runner_->BelongsToCurrentThread());
|
| + message->set_interface_id(id_);
|
| + return controller_->SendMessage(message);
|
| + }
|
| +
|
| + void AllowWokenUpBySyncWatchOnSameThread() override {
|
| + DCHECK(task_runner_->BelongsToCurrentThread());
|
| +
|
| + // TODO(rockot): Implement sync waiting.
|
| + NOTREACHED();
|
| + }
|
| +
|
| + bool SyncWatch(const bool* should_stop) override {
|
| + DCHECK(task_runner_->BelongsToCurrentThread());
|
| +
|
| + // It's not legal to make sync calls from the master endpoint's thread,
|
| + // and in fact they must only happen from the proxy task runner.
|
| + DCHECK(!controller_->task_runner_->BelongsToCurrentThread());
|
| + DCHECK(controller_->proxy_task_runner_->BelongsToCurrentThread());
|
| +
|
| + // TODO(rockot): Implement sync waiting.
|
| + NOTREACHED();
|
| + return false;
|
| + }
|
| +
|
| + private:
|
| + friend class base::RefCountedThreadSafe<Endpoint>;
|
| +
|
| + ~Endpoint() override {}
|
| +
|
| + ChannelAssociatedGroupController* const controller_;
|
| + const mojo::InterfaceId id_;
|
| +
|
| + bool closed_ = false;
|
| + bool peer_closed_ = false;
|
| + mojo::InterfaceEndpointClient* client_ = nullptr;
|
| + scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(Endpoint);
|
| + };
|
| +
|
| + ~ChannelAssociatedGroupController() override {
|
| + base::AutoLock locker(lock_);
|
| +
|
| + for (auto iter = endpoints_.begin(); iter != endpoints_.end();) {
|
| + Endpoint* endpoint = iter->second.get();
|
| + ++iter;
|
| +
|
| + DCHECK(endpoint->closed());
|
| + MarkPeerClosedAndMaybeRemove(endpoint);
|
| + }
|
| +
|
| + DCHECK(endpoints_.empty());
|
| + }
|
| +
|
| + bool SendMessage(mojo::Message* message) {
|
| + if (task_runner_->BelongsToCurrentThread()) {
|
| + DCHECK(thread_checker_.CalledOnValidThread());
|
| + return connector_.Accept(message);
|
| + } else {
|
| + // We always post tasks to the master endpoint thread when called from the
|
| + // proxy thread in order to simulate IPC::ChannelProxy::Send behavior.
|
| + DCHECK(proxy_task_runner_ &&
|
| + proxy_task_runner_->BelongsToCurrentThread());
|
| + std::unique_ptr<mojo::Message> passed_message(new mojo::Message);
|
| + message->MoveTo(passed_message.get());
|
| + task_runner_->PostTask(
|
| + FROM_HERE,
|
| + base::Bind(
|
| + &ChannelAssociatedGroupController::SendMessageOnMasterThread,
|
| + this, base::Passed(&passed_message)));
|
| + return true;
|
| + }
|
| + }
|
| +
|
| + void SendMessageOnMasterThread(std::unique_ptr<mojo::Message> message) {
|
| + DCHECK(thread_checker_.CalledOnValidThread());
|
| + if (!SendMessage(message.get()))
|
| + RaiseError();
|
| + }
|
| +
|
| + void OnPipeError() {
|
| + DCHECK(thread_checker_.CalledOnValidThread());
|
| +
|
| + // We keep |this| alive here because it's possible for the notifications
|
| + // below to release all other references.
|
| + scoped_refptr<ChannelAssociatedGroupController> keepalive(this);
|
| +
|
| + base::AutoLock locker(lock_);
|
| + encountered_error_ = true;
|
| +
|
| + std::vector<scoped_refptr<Endpoint>> endpoints_to_notify;
|
| + for (auto iter = endpoints_.begin(); iter != endpoints_.end();) {
|
| + Endpoint* endpoint = iter->second.get();
|
| + ++iter;
|
| +
|
| + if (endpoint->client())
|
| + endpoints_to_notify.push_back(endpoint);
|
| +
|
| + MarkPeerClosedAndMaybeRemove(endpoint);
|
| + }
|
| +
|
| + for (auto& endpoint : endpoints_to_notify) {
|
| + // Because an notification may in turn detach any endpoint, we have to
|
| + // check each client again here.
|
| + if (endpoint->client())
|
| + NotifyEndpointOfError(endpoint.get(), false /* force_async */);
|
| + }
|
| + }
|
| +
|
| + void NotifyEndpointOfError(Endpoint* endpoint, bool force_async) {
|
| + lock_.AssertAcquired();
|
| + DCHECK(endpoint->task_runner() && endpoint->client());
|
| + if (endpoint->task_runner()->BelongsToCurrentThread() && !force_async) {
|
| + mojo::InterfaceEndpointClient* client = endpoint->client();
|
| +
|
| + base::AutoUnlock unlocker(lock_);
|
| + client->NotifyError();
|
| + } else {
|
| + endpoint->task_runner()->PostTask(
|
| + FROM_HERE,
|
| + base::Bind(&ChannelAssociatedGroupController
|
| + ::NotifyEndpointOfErrorOnEndpointThread, this,
|
| + make_scoped_refptr(endpoint)));
|
| + }
|
| + }
|
| +
|
| + void NotifyEndpointOfErrorOnEndpointThread(scoped_refptr<Endpoint> endpoint) {
|
| + base::AutoLock locker(lock_);
|
| + if (!endpoint->client())
|
| + return;
|
| + DCHECK(endpoint->task_runner()->BelongsToCurrentThread());
|
| + NotifyEndpointOfError(endpoint.get(), false /* force_async */);
|
| + }
|
| +
|
| + void MarkClosedAndMaybeRemove(Endpoint* endpoint) {
|
| + lock_.AssertAcquired();
|
| + endpoint->set_closed();
|
| + if (endpoint->closed() && endpoint->peer_closed())
|
| + endpoints_.erase(endpoint->id());
|
| + }
|
| +
|
| + void MarkPeerClosedAndMaybeRemove(Endpoint* endpoint) {
|
| + lock_.AssertAcquired();
|
| + endpoint->set_peer_closed();
|
| + if (endpoint->closed() && endpoint->peer_closed())
|
| + endpoints_.erase(endpoint->id());
|
| + }
|
| +
|
| + Endpoint* FindOrInsertEndpoint(mojo::InterfaceId id, bool* inserted) {
|
| + lock_.AssertAcquired();
|
| + DCHECK(!inserted || !*inserted);
|
| +
|
| + auto iter = endpoints_.find(id);
|
| + if (iter != endpoints_.end())
|
| + return iter->second.get();
|
| +
|
| + Endpoint* endpoint = new Endpoint(this, id);
|
| + endpoints_.insert({ id, endpoint });
|
| + if (inserted)
|
| + *inserted = true;
|
| + return endpoint;
|
| + }
|
| +
|
| + // mojo::MessageReceiver:
|
| + bool Accept(mojo::Message* message) override {
|
| + DCHECK(thread_checker_.CalledOnValidThread());
|
| +
|
| + if (mojo::PipeControlMessageHandler::IsPipeControlMessage(message)) {
|
| + if (!control_message_handler_.Accept(message))
|
| + RaiseError();
|
| + return true;
|
| + }
|
| +
|
| + mojo::InterfaceId id = message->interface_id();
|
| + DCHECK(mojo::IsValidInterfaceId(id));
|
| +
|
| + base::AutoLock locker(lock_);
|
| + bool inserted = false;
|
| + Endpoint* endpoint = FindOrInsertEndpoint(id, &inserted);
|
| + if (inserted) {
|
| + MarkClosedAndMaybeRemove(endpoint);
|
| + if (!mojo::IsMasterInterfaceId(id))
|
| + control_message_proxy_.NotifyPeerEndpointClosed(id);
|
| + return true;
|
| + }
|
| +
|
| + if (endpoint->closed())
|
| + return true;
|
| +
|
| + mojo::InterfaceEndpointClient* client = endpoint->client();
|
| + if (!client || !endpoint->task_runner()->BelongsToCurrentThread()) {
|
| + // No client has been bound yet or the client runs tasks on another
|
| + // thread. We assume the other thread must always be the one on which
|
| + // |proxy_task_runner_| runs tasks, since that's the only valid scenario.
|
| + //
|
| + // If the client is not yet bound, it must be bound by the time this task
|
| + // runs or else it's programmer error.
|
| + DCHECK(proxy_task_runner_);
|
| + CHECK(false);
|
| + std::unique_ptr<mojo::Message> passed_message(new mojo::Message);
|
| + message->MoveTo(passed_message.get());
|
| + proxy_task_runner_->PostTask(
|
| + FROM_HERE,
|
| + base::Bind(&ChannelAssociatedGroupController::AcceptOnProxyThread,
|
| + this, base::Passed(&passed_message)));
|
| + return true;
|
| + }
|
| +
|
| + // We do not expect to receive sync responses on the master endpoint thread.
|
| + // If it's happening, it's a bug.
|
| + DCHECK(!message->has_flag(mojo::Message::kFlagIsSync));
|
| +
|
| + bool result = false;
|
| + {
|
| + base::AutoUnlock unlocker(lock_);
|
| + result = client->HandleIncomingMessage(message);
|
| + }
|
| +
|
| + if (!result)
|
| + RaiseError();
|
| +
|
| + return true;
|
| + }
|
| +
|
| + void AcceptOnProxyThread(std::unique_ptr<mojo::Message> message) {
|
| + DCHECK(proxy_task_runner_->BelongsToCurrentThread());
|
| +
|
| + // TODO(rockot): Implement this.
|
| + NOTREACHED();
|
| + }
|
| +
|
| + // mojo::PipeControlMessageHandlerDelegate:
|
| + bool OnPeerAssociatedEndpointClosed(mojo::InterfaceId id) override {
|
| + DCHECK(thread_checker_.CalledOnValidThread());
|
| +
|
| + if (mojo::IsMasterInterfaceId(id))
|
| + return false;
|
| +
|
| + base::AutoLock locker(lock_);
|
| + scoped_refptr<Endpoint> endpoint = FindOrInsertEndpoint(id, nullptr);
|
| + if (!endpoint->peer_closed()) {
|
| + if (endpoint->client())
|
| + NotifyEndpointOfError(endpoint.get(), false /* force_async */);
|
| + MarkPeerClosedAndMaybeRemove(endpoint.get());
|
| + }
|
| +
|
| + return true;
|
| + }
|
| +
|
| + bool OnAssociatedEndpointClosedBeforeSent(mojo::InterfaceId id) override {
|
| + DCHECK(thread_checker_.CalledOnValidThread());
|
| +
|
| + if (mojo::IsMasterInterfaceId(id))
|
| + return false;
|
| +
|
| + base::AutoLock locker(lock_);
|
| + Endpoint* endpoint = FindOrInsertEndpoint(id, nullptr);
|
| + DCHECK(!endpoint->closed());
|
| + MarkClosedAndMaybeRemove(endpoint);
|
| + control_message_proxy_.NotifyPeerEndpointClosed(id);
|
| + return true;
|
| + }
|
| +
|
| + // Checked in places which must be run on the master endpoint's thread.
|
| + base::ThreadChecker thread_checker_;
|
| +
|
| + scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
|
| + scoped_refptr<base::SingleThreadTaskRunner> proxy_task_runner_;
|
| + const uint32_t id_namespace_mask_;
|
| + std::unique_ptr<mojo::AssociatedGroup> associated_group_;
|
| + mojo::Connector connector_;
|
| + mojo::MessageHeaderValidator header_validator_;
|
| + mojo::PipeControlMessageHandler control_message_handler_;
|
| +
|
| + // Guards the fields below for thread-safe access.
|
| + base::Lock lock_;
|
| +
|
| + bool encountered_error_ = false;
|
| + uint32_t next_interface_id_ = 1;
|
| + std::map<uint32_t, scoped_refptr<Endpoint>> endpoints_;
|
| + mojo::PipeControlMessageProxy control_message_proxy_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(ChannelAssociatedGroupController);
|
| +};
|
| +
|
| +class BootstrapMasterProxy {
|
| + public:
|
| + BootstrapMasterProxy() {}
|
| + ~BootstrapMasterProxy() {
|
| + endpoint_client_.reset();
|
| + proxy_.reset();
|
| + if (controller_)
|
| + controller_->ShutDown();
|
| + }
|
| +
|
| + void Bind(mojo::ScopedMessagePipeHandle handle) {
|
| + DCHECK(!controller_);
|
| + controller_ = new ChannelAssociatedGroupController(true, std::move(handle));
|
| + endpoint_client_.reset(new mojo::InterfaceEndpointClient(
|
| + controller_->CreateLocalEndpointHandle(mojo::kMasterInterfaceId),
|
| + nullptr,
|
| + base::MakeUnique<typename mojom::Bootstrap::ResponseValidator_>(),
|
| + false, base::ThreadTaskRunnerHandle::Get()));
|
| + proxy_.reset(new mojom::BootstrapProxy(endpoint_client_.get()));
|
| + proxy_->serialization_context()->group_controller = controller_;
|
| + }
|
| +
|
| + void set_connection_error_handler(const base::Closure& handler) {
|
| + DCHECK(endpoint_client_);
|
| + endpoint_client_->set_connection_error_handler(handler);
|
| + }
|
| +
|
| + mojo::AssociatedGroup* associated_group() {
|
| + DCHECK(controller_);
|
| + return controller_->associated_group();
|
| + }
|
| +
|
| + mojom::Bootstrap* operator->() {
|
| + DCHECK(proxy_);
|
| + return proxy_.get();
|
| + }
|
| +
|
| + private:
|
| + std::unique_ptr<mojom::BootstrapProxy> proxy_;
|
| + scoped_refptr<ChannelAssociatedGroupController> controller_;
|
| + std::unique_ptr<mojo::InterfaceEndpointClient> endpoint_client_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(BootstrapMasterProxy);
|
| +};
|
| +
|
| +class BootstrapMasterBinding {
|
| + public:
|
| + explicit BootstrapMasterBinding(mojom::Bootstrap* impl) {
|
| + stub_.set_sink(impl);
|
| + }
|
| +
|
| + ~BootstrapMasterBinding() {
|
| + endpoint_client_.reset();
|
| + if (controller_)
|
| + controller_->ShutDown();
|
| + }
|
| +
|
| + void set_connection_error_handler(const base::Closure& handler) {
|
| + DCHECK(endpoint_client_);
|
| + endpoint_client_->set_connection_error_handler(handler);
|
| + }
|
| +
|
| + void Bind(mojo::ScopedMessagePipeHandle handle) {
|
| + DCHECK(!controller_);
|
| + controller_ =
|
| + new ChannelAssociatedGroupController(false, std::move(handle));
|
| + stub_.serialization_context()->group_controller = controller_;
|
| +
|
| + endpoint_client_.reset(new mojo::InterfaceEndpointClient(
|
| + controller_->CreateLocalEndpointHandle(mojo::kMasterInterfaceId),
|
| + &stub_,
|
| + base::MakeUnique<typename mojom::Bootstrap::RequestValidator_>(),
|
| + false, base::ThreadTaskRunnerHandle::Get()));
|
| + }
|
| +
|
| + private:
|
| + mojom::BootstrapStub stub_;
|
| + scoped_refptr<ChannelAssociatedGroupController> controller_;
|
| + std::unique_ptr<mojo::InterfaceEndpointClient> endpoint_client_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(BootstrapMasterBinding);
|
| +};
|
| +
|
| // MojoBootstrap for the server process. You should create the instance
|
| // using MojoBootstrap::Create().
|
| class MojoServerBootstrap : public MojoBootstrap {
|
| @@ -33,7 +624,7 @@ class MojoServerBootstrap : public MojoBootstrap {
|
|
|
| void OnInitDone(int32_t peer_pid);
|
|
|
| - mojom::BootstrapPtr bootstrap_;
|
| + BootstrapMasterProxy bootstrap_;
|
| IPC::mojom::ChannelAssociatedPtrInfo send_channel_;
|
| IPC::mojom::ChannelAssociatedRequest receive_channel_request_;
|
|
|
| @@ -45,7 +636,7 @@ MojoServerBootstrap::MojoServerBootstrap() = default;
|
| void MojoServerBootstrap::Connect() {
|
| DCHECK_EQ(state(), STATE_INITIALIZED);
|
|
|
| - bootstrap_.Bind(mojom::BootstrapPtrInfo(TakeHandle(), 0));
|
| + bootstrap_.Bind(TakeHandle());
|
| bootstrap_.set_connection_error_handler(
|
| base::Bind(&MojoServerBootstrap::Fail, base::Unretained(this)));
|
|
|
| @@ -96,7 +687,7 @@ class MojoClientBootstrap : public MojoBootstrap, public mojom::Bootstrap {
|
| int32_t peer_pid,
|
| const InitCallback& callback) override;
|
|
|
| - mojo::Binding<mojom::Bootstrap> binding_;
|
| + BootstrapMasterBinding binding_;
|
|
|
| DISALLOW_COPY_AND_ASSIGN(MojoClientBootstrap);
|
| };
|
|
|