| Index: content/common/message_port.cc
|
| diff --git a/content/common/message_port.cc b/content/common/message_port.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..c89d7b5a0d0cc313290329602fedc13e6dff9150
|
| --- /dev/null
|
| +++ b/content/common/message_port.cc
|
| @@ -0,0 +1,186 @@
|
| +// Copyright 2017 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/message_port.h"
|
| +
|
| +#include "base/logging.h"
|
| +
|
| +namespace content {
|
| +
|
| +MessagePort::~MessagePort() {
|
| +}
|
| +
|
| +MessagePort::MessagePort() : state_(new State()) {
|
| +}
|
| +
|
| +MessagePort::MessagePort(const MessagePort& other) : state_(other.state_) {
|
| +}
|
| +
|
| +MessagePort& MessagePort::operator=(const MessagePort& other) {
|
| + state_ = other.state_;
|
| + return *this;
|
| +}
|
| +
|
| +MessagePort::MessagePort(mojo::ScopedMessagePipeHandle handle)
|
| + : state_(new State(std::move(handle))) {
|
| +}
|
| +
|
| +const mojo::ScopedMessagePipeHandle& MessagePort::GetHandle() const {
|
| + return state_->handle_;
|
| +}
|
| +
|
| +mojo::ScopedMessagePipeHandle MessagePort::ReleaseHandle() const {
|
| + state_->CancelWatch();
|
| + return std::move(state_->handle_);
|
| +}
|
| +
|
| +// static
|
| +std::vector<mojo::ScopedMessagePipeHandle> MessagePort::ReleaseHandles(
|
| + const std::vector<MessagePort>& ports) {
|
| + std::vector<mojo::ScopedMessagePipeHandle> handles(ports.size());
|
| + for (size_t i = 0; i < ports.size(); ++i)
|
| + handles[i] = ports[i].ReleaseHandle();
|
| + return handles;
|
| +}
|
| +
|
| +void MessagePort::PostMessage(const base::string16& encoded_message,
|
| + std::vector<MessagePort> ports) {
|
| + DCHECK(state_->handle_.is_valid());
|
| +
|
| + uint32_t num_bytes = encoded_message.size() * sizeof(base::char16);
|
| +
|
| + // NOTE: It is OK to ignore the return value of MojoWriteMessage here. HTML
|
| + // MessagePorts have no way of reporting when the peer is gone.
|
| +
|
| + if (ports.empty()) {
|
| + MojoWriteMessage(state_->handle_.get().value(),
|
| + encoded_message.data(),
|
| + num_bytes,
|
| + nullptr,
|
| + 0,
|
| + MOJO_WRITE_MESSAGE_FLAG_NONE);
|
| + } else {
|
| + uint32_t num_handles = static_cast<uint32_t>(ports.size());
|
| + std::unique_ptr<MojoHandle[]> handles(new MojoHandle[num_handles]);
|
| + for (uint32_t i = 0; i < num_handles; ++i)
|
| + handles[i] = ports[i].ReleaseHandle().release().value();
|
| + MojoWriteMessage(state_->handle_.get().value(),
|
| + encoded_message.data(),
|
| + num_bytes,
|
| + handles.get(),
|
| + num_handles,
|
| + MOJO_WRITE_MESSAGE_FLAG_NONE);
|
| + }
|
| +}
|
| +
|
| +bool MessagePort::GetMessage(base::string16* encoded_message,
|
| + std::vector<MessagePort>* ports) {
|
| + DCHECK(state_->handle_.is_valid());
|
| +
|
| + uint32_t num_bytes = 0;
|
| + uint32_t num_handles = 0;
|
| +
|
| + MojoResult rv = MojoReadMessage(state_->handle_.get().value(),
|
| + nullptr,
|
| + &num_bytes,
|
| + nullptr,
|
| + &num_handles,
|
| + MOJO_READ_MESSAGE_FLAG_NONE);
|
| + if (rv == MOJO_RESULT_OK) {
|
| + encoded_message->clear();
|
| + ports->clear();
|
| + return true;
|
| + }
|
| + if (rv != MOJO_RESULT_RESOURCE_EXHAUSTED)
|
| + return false;
|
| +
|
| + CHECK(num_bytes % 2 == 0);
|
| +
|
| + base::string16 buffer;
|
| + buffer.resize(num_bytes / sizeof(base::char16));
|
| +
|
| + std::unique_ptr<MojoHandle[]> handles;
|
| + if (num_handles)
|
| + handles.reset(new MojoHandle[num_handles]);
|
| +
|
| + rv = MojoReadMessage(state_->handle_.get().value(),
|
| + num_bytes ? &buffer[0] : nullptr,
|
| + &num_bytes,
|
| + handles.get(),
|
| + &num_handles,
|
| + MOJO_READ_MESSAGE_FLAG_NONE);
|
| + if (rv != MOJO_RESULT_OK)
|
| + return false;
|
| +
|
| + buffer.swap(*encoded_message);
|
| +
|
| + if (num_handles) {
|
| + ports->resize(static_cast<size_t>(num_handles));
|
| + for (uint32_t i = 0; i < num_handles; ++i) {
|
| + ports->at(i) = MessagePort(
|
| + mojo::ScopedMessagePipeHandle(mojo::MessagePipeHandle(handles[i])));
|
| + }
|
| + }
|
| + return true;
|
| +}
|
| +
|
| +void MessagePort::SetCallback(const base::Closure& callback) {
|
| + state_->CancelWatch();
|
| + state_->callback_ = callback;
|
| + state_->AddWatch();
|
| +}
|
| +
|
| +void MessagePort::ClearCallback() {
|
| + state_->CancelWatch();
|
| + state_->callback_.Reset();
|
| +}
|
| +
|
| +MessagePort::State::State() {
|
| +}
|
| +
|
| +MessagePort::State::State(mojo::ScopedMessagePipeHandle handle)
|
| + : handle_(std::move(handle)) {
|
| +}
|
| +
|
| +void MessagePort::State::AddWatch() {
|
| + if (!callback_)
|
| + return;
|
| +
|
| + // NOTE: An HTML MessagePort does not receive an event to tell it when the
|
| + // peer has gone away, so we only watch for readability here.
|
| + MojoResult rv = MojoWatch(handle_.get().value(),
|
| + MOJO_HANDLE_SIGNAL_READABLE,
|
| + &MessagePort::State::OnHandleReady,
|
| + reinterpret_cast<uintptr_t>(this));
|
| + if (rv != MOJO_RESULT_OK)
|
| + DVLOG(1) << this << " MojoWatch failed: " << rv;
|
| +}
|
| +
|
| +void MessagePort::State::CancelWatch() {
|
| + if (!callback_)
|
| + return;
|
| +
|
| + // NOTE: This synchronizes with the thread where OnHandleReady runs so we are
|
| + // sure to not be racing with it.
|
| + MojoCancelWatch(handle_.get().value(), reinterpret_cast<uintptr_t>(this));
|
| +}
|
| +
|
| +// static
|
| +void MessagePort::State::OnHandleReady(
|
| + uintptr_t context,
|
| + MojoResult result,
|
| + MojoHandleSignalsState signals_state,
|
| + MojoWatchNotificationFlags flags) {
|
| + if (result == MOJO_RESULT_OK) {
|
| + reinterpret_cast<MessagePort::State*>(context)->callback_.Run();
|
| + } else {
|
| + // And now his watch is ended.
|
| + }
|
| +}
|
| +
|
| +MessagePort::State::~State() {
|
| + CancelWatch();
|
| +}
|
| +
|
| +} // namespace content
|
|
|