// Copyright 2016 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 "mojo/edk/system/broker_host.h" #include <utility> #include "base/logging.h" #include "base/memory/ref_counted.h" #include "base/message_loop/message_loop.h" #include "base/threading/thread_task_runner_handle.h" #include "mojo/edk/embedder/named_platform_channel_pair.h" #include "mojo/edk/embedder/named_platform_handle.h" #include "mojo/edk/embedder/platform_handle_vector.h" #include "mojo/edk/embedder/platform_shared_buffer.h" #include "mojo/edk/system/broker_messages.h" namespace mojo { namespace edk { BrokerHost::BrokerHost(base::ProcessHandle client_process, ScopedPlatformHandle platform_handle) #if defined(OS_WIN) : client_process_(client_process) #endif { CHECK(platform_handle.is_valid()); base::MessageLoop::current()->AddDestructionObserver(this); channel_ = Channel::Create(this, ConnectionParams(std::move(platform_handle)), base::ThreadTaskRunnerHandle::Get()); channel_->Start(); } BrokerHost::~BrokerHost() { // We're always destroyed on the creation thread, which is the IO thread. base::MessageLoop::current()->RemoveDestructionObserver(this); if (channel_) channel_->ShutDown(); } bool BrokerHost::PrepareHandlesForClient(PlatformHandleVector* handles) { #if defined(OS_WIN) if (!Channel::Message::RewriteHandles( base::GetCurrentProcessHandle(), client_process_, handles)) { // NOTE: We only log an error here. We do not signal a logical error or // prevent any message from being sent. The client should handle unexpected // invalid handles appropriately. DLOG(ERROR) << "Failed to rewrite one or more handles to broker client."; return false; } #endif return true; } bool BrokerHost::SendChannel(ScopedPlatformHandle handle) { CHECK(handle.is_valid()); CHECK(channel_); #if defined(OS_WIN) InitData* data; Channel::MessagePtr message = CreateBrokerMessage(BrokerMessageType::INIT, 1, 0, &data); data->pipe_name_length = 0; #else Channel::MessagePtr message = CreateBrokerMessage(BrokerMessageType::INIT, 1, nullptr); #endif ScopedPlatformHandleVectorPtr handles; handles.reset(new PlatformHandleVector(1)); handles->at(0) = handle.release(); // This may legitimately fail on Windows if the client process is in another // session, e.g., is an elevated process. if (!PrepareHandlesForClient(handles.get())) return false; message->SetHandles(std::move(handles)); channel_->Write(std::move(message)); return true; } #if defined(OS_WIN) void BrokerHost::SendNamedChannel(const base::StringPiece16& pipe_name) { InitData* data; base::char16* name_data; Channel::MessagePtr message = CreateBrokerMessage( BrokerMessageType::INIT, 0, sizeof(*name_data) * pipe_name.length(), &data, reinterpret_cast<void**>(&name_data)); data->pipe_name_length = static_cast<uint32_t>(pipe_name.length()); std::copy(pipe_name.begin(), pipe_name.end(), name_data); channel_->Write(std::move(message)); } #endif // defined(OS_WIN) void BrokerHost::OnBufferRequest(uint32_t num_bytes) { scoped_refptr<PlatformSharedBuffer> read_only_buffer; scoped_refptr<PlatformSharedBuffer> buffer = PlatformSharedBuffer::Create(num_bytes); if (buffer) read_only_buffer = buffer->CreateReadOnlyDuplicate(); if (!read_only_buffer) buffer = nullptr; Channel::MessagePtr message = CreateBrokerMessage( BrokerMessageType::BUFFER_RESPONSE, buffer ? 2 : 0, nullptr); if (buffer) { ScopedPlatformHandleVectorPtr handles; handles.reset(new PlatformHandleVector(2)); handles->at(0) = buffer->PassPlatformHandle().release(); handles->at(1) = read_only_buffer->PassPlatformHandle().release(); PrepareHandlesForClient(handles.get()); message->SetHandles(std::move(handles)); } channel_->Write(std::move(message)); } void BrokerHost::OnChannelMessage(const void* payload, size_t payload_size, ScopedPlatformHandleVectorPtr handles) { if (payload_size < sizeof(BrokerMessageHeader)) return; const BrokerMessageHeader* header = static_cast<const BrokerMessageHeader*>(payload); switch (header->type) { case BrokerMessageType::BUFFER_REQUEST: if (payload_size == sizeof(BrokerMessageHeader) + sizeof(BufferRequestData)) { const BufferRequestData* request = reinterpret_cast<const BufferRequestData*>(header + 1); OnBufferRequest(request->size); } break; default: LOG(ERROR) << "Unexpected broker message type: " << header->type; break; } } void BrokerHost::OnChannelError() { delete this; } void BrokerHost::WillDestroyCurrentMessageLoop() { delete this; } } // namespace edk } // namespace mojo