| Index: mojo/edk/system/child_broker.cc
|
| diff --git a/mojo/edk/system/child_broker.cc b/mojo/edk/system/child_broker.cc
|
| index 85d9e5241974ad4119e607bf3dbf7bafba747576..d86f1ad44e376195d13daac06e2b63513f3099ec 100644
|
| --- a/mojo/edk/system/child_broker.cc
|
| +++ b/mojo/edk/system/child_broker.cc
|
| @@ -13,9 +13,17 @@
|
| #include "base/logging.h"
|
| #include "mojo/edk/embedder/embedder_internal.h"
|
| #include "mojo/edk/embedder/platform_channel_pair.h"
|
| +#include "mojo/edk/embedder/platform_shared_buffer.h"
|
| +#include "mojo/edk/embedder/platform_support.h"
|
| #include "mojo/edk/system/broker_messages.h"
|
| #include "mojo/edk/system/message_pipe_dispatcher.h"
|
|
|
| +#if defined(OS_POSIX)
|
| +#include <fcntl.h>
|
| +
|
| +#include "mojo/edk/embedder/platform_channel_utils_posix.h"
|
| +#endif
|
| +
|
| namespace mojo {
|
| namespace edk {
|
|
|
| @@ -26,24 +34,36 @@ ChildBroker* ChildBroker::GetInstance() {
|
|
|
| void ChildBroker::SetChildBrokerHostHandle(ScopedPlatformHandle handle) {
|
| ScopedPlatformHandle parent_async_channel_handle;
|
| + parent_sync_channel_ = std::move(handle);
|
| +
|
| +// We have two pipes to the parent. The first is for the token
|
| +// exchange for creating and passing handles on Windows, and creating shared
|
| +// buffers on POSIX, since the child needs the parent's help if it is
|
| +// sandboxed. The second is used for multiplexing related messages. We
|
| +// send the second over the first.
|
| #if defined(OS_POSIX)
|
| - parent_async_channel_handle = std::move(handle);
|
| + // Make the synchronous channel blocking.
|
| + int flags = fcntl(parent_sync_channel_.get().handle, F_GETFL, 0);
|
| + PCHECK(flags != -1);
|
| + PCHECK(fcntl(parent_sync_channel_.get().handle, F_SETFL,
|
| + flags & ~O_NONBLOCK) != -1);
|
| +
|
| + std::deque<PlatformHandle> received_handles;
|
| + char buf[1];
|
| + ssize_t result = PlatformChannelRecvmsg(parent_sync_channel_.get(), buf, 1,
|
| + &received_handles, true);
|
| + CHECK_EQ(1, result);
|
| + CHECK_EQ(1u, received_handles.size());
|
| + parent_async_channel_handle.reset(received_handles.front());
|
| #else
|
| - // On Windows we have two pipes to the parent. The first is for the token
|
| - // exchange for creating and passing handles, since the child needs the
|
| - // parent's help if it is sandboxed. The second is the same as POSIX, which is
|
| - // used for multiplexing related messages. So on Windows, we send the second
|
| - // pipe as the first string over the first one.
|
| - parent_sync_channel_ = handle.Pass();
|
| -
|
| HANDLE parent_handle = INVALID_HANDLE_VALUE;
|
| DWORD bytes_read = 0;
|
| BOOL rv = ReadFile(parent_sync_channel_.get().handle, &parent_handle,
|
| sizeof(parent_handle), &bytes_read, NULL);
|
| CHECK(rv);
|
| parent_async_channel_handle.reset(PlatformHandle(parent_handle));
|
| - sync_channel_lock_.Unlock();
|
| #endif
|
| + sync_channel_lock_.Unlock();
|
|
|
| internal::g_io_thread_task_runner->PostTask(
|
| FROM_HERE,
|
| @@ -99,6 +119,29 @@ void ChildBroker::TokenToHandle(const uint64_t* tokens,
|
| sync_channel_lock_.Unlock();
|
| }
|
| }
|
| +#else
|
| +scoped_refptr<PlatformSharedBuffer> ChildBroker::CreateSharedBuffer(
|
| + size_t num_bytes) {
|
| + sync_channel_lock_.Lock();
|
| + scoped_refptr<PlatformSharedBuffer> shared_buffer;
|
| +
|
| + BrokerMessage message;
|
| + message.size = kBrokerMessageHeaderSize + sizeof(uint32_t);
|
| + message.id = CREATE_SHARED_BUFFER;
|
| + message.shared_buffer_size = num_bytes;
|
| +
|
| + std::deque<PlatformHandle> handles;
|
| + if (WriteAndReadHandles(&message, &handles)) {
|
| + DCHECK_EQ(1u, handles.size());
|
| + PlatformHandle handle = handles.front();
|
| + if (handle.is_valid())
|
| + shared_buffer =
|
| + internal::g_platform_support->CreateSharedBufferFromHandle(
|
| + num_bytes, ScopedPlatformHandle(handles.front()));
|
| + }
|
| + sync_channel_lock_.Unlock();
|
| + return shared_buffer;
|
| +}
|
| #endif
|
|
|
| void ChildBroker::ConnectMessagePipe(uint64_t pipe_id,
|
| @@ -172,10 +215,8 @@ ChildBroker::ChildBroker()
|
| in_process_pipes_channel2_(nullptr) {
|
| DCHECK(!internal::g_broker);
|
| internal::g_broker = this;
|
| -#if defined(OS_WIN)
|
| // Block any threads from calling this until we have a pipe to the parent.
|
| sync_channel_lock_.Lock();
|
| -#endif
|
| }
|
|
|
| ChildBroker::~ChildBroker() {
|
| @@ -296,6 +337,21 @@ void ChildBroker::AttachMessagePipe(MessagePipeDispatcher* message_pipe,
|
|
|
| #if defined(OS_WIN)
|
|
|
| +void ChildBroker::CreatePlatformChannelPairNoLock(
|
| + ScopedPlatformHandle* server,
|
| + ScopedPlatformHandle* client) {
|
| + BrokerMessage message;
|
| + message.size = kBrokerMessageHeaderSize;
|
| + message.id = CREATE_PLATFORM_CHANNEL_PAIR;
|
| +
|
| + uint32_t response_size = 2 * sizeof(HANDLE);
|
| + HANDLE handles[2];
|
| + if (WriteAndReadResponse(&message, handles, response_size)) {
|
| + server->reset(PlatformHandle(handles[0]));
|
| + client->reset(PlatformHandle(handles[1]));
|
| + }
|
| +}
|
| +
|
| bool ChildBroker::WriteAndReadResponse(BrokerMessage* message,
|
| void* response,
|
| uint32_t response_size) {
|
| @@ -327,21 +383,35 @@ bool ChildBroker::WriteAndReadResponse(BrokerMessage* message,
|
|
|
| return result;
|
| }
|
| +#else
|
| +bool ChildBroker::WriteAndReadHandles(BrokerMessage* message,
|
| + std::deque<PlatformHandle>* handles) {
|
| + CHECK(parent_sync_channel_.is_valid());
|
|
|
| -void ChildBroker::CreatePlatformChannelPairNoLock(
|
| - ScopedPlatformHandle* server, ScopedPlatformHandle* client) {
|
| - BrokerMessage message;
|
| - message.size = kBrokerMessageHeaderSize;
|
| - message.id = CREATE_PLATFORM_CHANNEL_PAIR;
|
| -
|
| - uint32_t response_size = 2 * sizeof(HANDLE);
|
| - HANDLE handles[2];
|
| - if (WriteAndReadResponse(&message, handles, response_size)) {
|
| - server->reset(PlatformHandle(handles[0]));
|
| - client->reset(PlatformHandle(handles[1]));
|
| + uint32_t remaining_bytes = message->size;
|
| + while (remaining_bytes > 0) {
|
| + ssize_t bytes_written = PlatformChannelWrite(
|
| + parent_sync_channel_.get(),
|
| + reinterpret_cast<uint8_t*>(message) + (message->size - remaining_bytes),
|
| + remaining_bytes);
|
| +
|
| + if (bytes_written != -1)
|
| + remaining_bytes -= bytes_written;
|
| + else
|
| + return false;
|
| }
|
| + // Perform a blocking read (we set this fd to be blocking in
|
| + // SetChildBrokerHostHandle).
|
| + char buf[1];
|
| + ssize_t bytes_read = PlatformChannelRecvmsg(
|
| + parent_sync_channel_.get(), buf, 1, handles, true /* should_block */);
|
| + // If the other side shutdown, or there was an error, or we didn't get
|
| + // any handles.
|
| + if (bytes_read == 0 || bytes_read == -1 || handles->empty())
|
| + return false;
|
| +
|
| + return true;
|
| }
|
| -
|
| #endif
|
|
|
| } // namespace edk
|
|
|