blob: 4943b16bbec9a1057cc7d3214833c10ecd8b97f6 [file] [log] [blame]
// 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 "core/mojo/MojoHandle.h"
#include "bindings/core/v8/array_buffer_or_array_buffer_view.h"
#include "core/dom/ExecutionContext.h"
#include "core/mojo/MojoCreateSharedBufferResult.h"
#include "core/mojo/MojoDiscardDataOptions.h"
#include "core/mojo/MojoDuplicateBufferHandleOptions.h"
#include "core/mojo/MojoMapBufferResult.h"
#include "core/mojo/MojoReadDataOptions.h"
#include "core/mojo/MojoReadDataResult.h"
#include "core/mojo/MojoReadMessageFlags.h"
#include "core/mojo/MojoReadMessageResult.h"
#include "core/mojo/MojoWatcher.h"
#include "core/mojo/MojoWriteDataOptions.h"
#include "core/mojo/MojoWriteDataResult.h"
#include "core/typed_arrays/DOMArrayBuffer.h"
#include "core/typed_arrays/DOMArrayBufferView.h"
#include "mojo/public/cpp/system/message_pipe.h"
#include "platform/bindings/ScriptState.h"
// Mojo messages typically do not contain many handles. In fact most
// messages do not contain any handle. An inline capacity of 4 should avoid
// heap allocation in vast majority of cases.
static const size_t kHandleVectorInlineCapacity = 4;
namespace blink {
MojoHandle* MojoHandle::Create(mojo::ScopedHandle handle) {
return new MojoHandle(std::move(handle));
}
mojo::ScopedHandle MojoHandle::TakeHandle() {
return std::move(handle_);
}
MojoHandle::MojoHandle(mojo::ScopedHandle handle)
: handle_(std::move(handle)) {}
void MojoHandle::close() {
handle_.reset();
}
MojoWatcher* MojoHandle::watch(ScriptState* script_state,
const MojoHandleSignals& signals,
V8MojoWatchCallback* callback) {
return MojoWatcher::Create(handle_.get(), signals, callback,
ExecutionContext::From(script_state));
}
MojoResult MojoHandle::writeMessage(
ArrayBufferOrArrayBufferView& buffer,
const HeapVector<Member<MojoHandle>>& handles) {
// mojo::WriteMessageRaw takes ownership of the handles, so release them here.
Vector<::MojoHandle, kHandleVectorInlineCapacity> raw_handles(handles.size());
std::transform(
handles.begin(), handles.end(), raw_handles.begin(),
[](MojoHandle* handle) { return handle->handle_.release().value(); });
const void* bytes = nullptr;
uint32_t num_bytes = 0;
if (buffer.IsArrayBuffer()) {
DOMArrayBuffer* array = buffer.GetAsArrayBuffer();
bytes = array->Data();
num_bytes = array->ByteLength();
} else {
DOMArrayBufferView* view = buffer.GetAsArrayBufferView().View();
bytes = view->BaseAddress();
num_bytes = view->byteLength();
}
return mojo::WriteMessageRaw(
mojo::MessagePipeHandle(handle_->value()), bytes, num_bytes,
raw_handles.data(), raw_handles.size(), MOJO_WRITE_MESSAGE_FLAG_NONE);
}
void MojoHandle::readMessage(const MojoReadMessageFlags& flags_dict,
MojoReadMessageResult& result_dict) {
mojo::ScopedMessageHandle message;
MojoResult result =
mojo::ReadMessageNew(mojo::MessagePipeHandle(handle_->value()), &message,
MOJO_READ_MESSAGE_FLAG_NONE);
if (result != MOJO_RESULT_OK) {
result_dict.setResult(result);
return;
}
result = MojoSerializeMessage(message->value());
if (result != MOJO_RESULT_OK && result != MOJO_RESULT_FAILED_PRECONDITION) {
result_dict.setResult(MOJO_RESULT_ABORTED);
return;
}
uint32_t num_bytes = 0, num_handles = 0;
void* bytes;
Vector<::MojoHandle, kHandleVectorInlineCapacity> raw_handles;
result = MojoGetSerializedMessageContents(
message->value(), &bytes, &num_bytes, nullptr, &num_handles,
MOJO_GET_SERIALIZED_MESSAGE_CONTENTS_FLAG_NONE);
if (result == MOJO_RESULT_RESOURCE_EXHAUSTED) {
raw_handles.resize(num_handles);
result = MojoGetSerializedMessageContents(
message->value(), &bytes, &num_bytes, raw_handles.data(), &num_handles,
MOJO_GET_SERIALIZED_MESSAGE_CONTENTS_FLAG_NONE);
}
if (result != MOJO_RESULT_OK) {
result_dict.setResult(MOJO_RESULT_ABORTED);
return;
}
DOMArrayBuffer* buffer =
DOMArrayBuffer::CreateUninitializedOrNull(num_bytes, 1);
if (num_bytes) {
CHECK(buffer);
memcpy(buffer->Data(), bytes, num_bytes);
}
result_dict.setBuffer(buffer);
HeapVector<Member<MojoHandle>> handles(num_handles);
for (size_t i = 0; i < num_handles; ++i) {
handles[i] = MojoHandle::Create(
mojo::MakeScopedHandle(mojo::Handle(raw_handles[i])));
}
result_dict.setHandles(handles);
result_dict.setResult(result);
}
void MojoHandle::writeData(const ArrayBufferOrArrayBufferView& buffer,
const MojoWriteDataOptions& options_dict,
MojoWriteDataResult& result_dict) {
MojoWriteDataFlags flags = MOJO_WRITE_DATA_FLAG_NONE;
if (options_dict.allOrNone())
flags |= MOJO_WRITE_DATA_FLAG_ALL_OR_NONE;
const void* elements = nullptr;
uint32_t num_bytes = 0;
if (buffer.IsArrayBuffer()) {
DOMArrayBuffer* array = buffer.GetAsArrayBuffer();
elements = array->Data();
num_bytes = array->ByteLength();
} else {
DOMArrayBufferView* view = buffer.GetAsArrayBufferView().View();
elements = view->BaseAddress();
num_bytes = view->byteLength();
}
MojoResult result =
MojoWriteData(handle_->value(), elements, &num_bytes, flags);
result_dict.setResult(result);
result_dict.setNumBytes(result == MOJO_RESULT_OK ? num_bytes : 0);
}
void MojoHandle::queryData(MojoReadDataResult& result_dict) {
uint32_t num_bytes = 0;
MojoResult result = MojoReadData(handle_->value(), nullptr, &num_bytes,
MOJO_READ_DATA_FLAG_QUERY);
result_dict.setResult(result);
result_dict.setNumBytes(num_bytes);
}
void MojoHandle::discardData(unsigned num_bytes,
const MojoDiscardDataOptions& options_dict,
MojoReadDataResult& result_dict) {
MojoReadDataFlags flags = MOJO_READ_DATA_FLAG_DISCARD;
if (options_dict.allOrNone())
flags |= MOJO_READ_DATA_FLAG_ALL_OR_NONE;
MojoResult result =
MojoReadData(handle_->value(), nullptr, &num_bytes, flags);
result_dict.setResult(result);
result_dict.setNumBytes(result == MOJO_RESULT_OK ? num_bytes : 0);
}
void MojoHandle::readData(ArrayBufferOrArrayBufferView& buffer,
const MojoReadDataOptions& options_dict,
MojoReadDataResult& result_dict) {
MojoReadDataFlags flags = MOJO_READ_DATA_FLAG_NONE;
if (options_dict.allOrNone())
flags |= MOJO_READ_DATA_FLAG_ALL_OR_NONE;
if (options_dict.peek())
flags |= MOJO_READ_DATA_FLAG_PEEK;
void* elements = nullptr;
unsigned num_bytes = 0;
if (buffer.IsArrayBuffer()) {
DOMArrayBuffer* array = buffer.GetAsArrayBuffer();
elements = array->Data();
num_bytes = array->ByteLength();
} else {
DOMArrayBufferView* view = buffer.GetAsArrayBufferView().View();
elements = view->BaseAddress();
num_bytes = view->byteLength();
}
MojoResult result =
MojoReadData(handle_->value(), elements, &num_bytes, flags);
result_dict.setResult(result);
result_dict.setNumBytes(result == MOJO_RESULT_OK ? num_bytes : 0);
}
void MojoHandle::mapBuffer(unsigned offset,
unsigned num_bytes,
MojoMapBufferResult& result_dict) {
void* data = nullptr;
MojoResult result = MojoMapBuffer(handle_->value(), offset, num_bytes, &data,
MOJO_MAP_BUFFER_FLAG_NONE);
result_dict.setResult(result);
if (result == MOJO_RESULT_OK) {
WTF::ArrayBufferContents::DataHandle data_handle(
data, num_bytes, [](void* buffer) {
MojoResult result = MojoUnmapBuffer(buffer);
DCHECK_EQ(result, MOJO_RESULT_OK);
});
WTF::ArrayBufferContents contents(std::move(data_handle),
WTF::ArrayBufferContents::kNotShared);
result_dict.setBuffer(DOMArrayBuffer::Create(contents));
}
}
void MojoHandle::duplicateBufferHandle(
const MojoDuplicateBufferHandleOptions& options_dict,
MojoCreateSharedBufferResult& result_dict) {
::MojoDuplicateBufferHandleOptions options = {
sizeof(options), MOJO_DUPLICATE_BUFFER_HANDLE_OPTIONS_FLAG_NONE};
if (options_dict.readOnly())
options.flags |= MOJO_DUPLICATE_BUFFER_HANDLE_OPTIONS_FLAG_READ_ONLY;
mojo::Handle handle;
MojoResult result = MojoDuplicateBufferHandle(handle_->value(), &options,
handle.mutable_value());
result_dict.setResult(result);
if (result == MOJO_RESULT_OK) {
result_dict.setHandle(MojoHandle::Create(mojo::MakeScopedHandle(handle)));
}
}
} // namespace blink