| OLD | NEW |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "mojo/edk/system/child_broker.h" | 5 #include "mojo/edk/system/child_broker.h" |
| 6 | 6 |
| 7 #include <stddef.h> | 7 #include <stddef.h> |
| 8 #include <stdint.h> | 8 #include <stdint.h> |
| 9 | 9 |
| 10 #include <utility> | 10 #include <utility> |
| 11 | 11 |
| 12 #include "base/bind.h" | 12 #include "base/bind.h" |
| 13 #include "base/logging.h" | 13 #include "base/logging.h" |
| 14 #include "mojo/edk/embedder/embedder_internal.h" | 14 #include "mojo/edk/embedder/embedder_internal.h" |
| 15 #include "mojo/edk/embedder/platform_channel_pair.h" | 15 #include "mojo/edk/embedder/platform_channel_pair.h" |
| 16 #include "mojo/edk/embedder/platform_shared_buffer.h" | |
| 17 #include "mojo/edk/embedder/platform_support.h" | |
| 18 #include "mojo/edk/system/broker_messages.h" | 16 #include "mojo/edk/system/broker_messages.h" |
| 19 #include "mojo/edk/system/message_pipe_dispatcher.h" | 17 #include "mojo/edk/system/message_pipe_dispatcher.h" |
| 20 | 18 |
| 21 #if defined(OS_POSIX) | |
| 22 #include <fcntl.h> | |
| 23 | |
| 24 #include "mojo/edk/embedder/platform_channel_utils_posix.h" | |
| 25 #endif | |
| 26 | |
| 27 namespace mojo { | 19 namespace mojo { |
| 28 namespace edk { | 20 namespace edk { |
| 29 | 21 |
| 30 ChildBroker* ChildBroker::GetInstance() { | 22 ChildBroker* ChildBroker::GetInstance() { |
| 31 return base::Singleton< | 23 return base::Singleton< |
| 32 ChildBroker, base::LeakySingletonTraits<ChildBroker>>::get(); | 24 ChildBroker, base::LeakySingletonTraits<ChildBroker>>::get(); |
| 33 } | 25 } |
| 34 | 26 |
| 35 void ChildBroker::SetChildBrokerHostHandle(ScopedPlatformHandle handle) { | 27 void ChildBroker::SetChildBrokerHostHandle(ScopedPlatformHandle handle) { |
| 36 ScopedPlatformHandle parent_async_channel_handle; | 28 ScopedPlatformHandle parent_async_channel_handle; |
| 29 #if defined(OS_POSIX) |
| 30 parent_async_channel_handle = std::move(handle); |
| 31 #else |
| 32 // On Windows we have two pipes to the parent. The first is for the token |
| 33 // exchange for creating and passing handles, since the child needs the |
| 34 // parent's help if it is sandboxed. The second is the same as POSIX, which is |
| 35 // used for multiplexing related messages. So on Windows, we send the second |
| 36 // pipe as the first string over the first one. |
| 37 parent_sync_channel_ = std::move(handle); | 37 parent_sync_channel_ = std::move(handle); |
| 38 | 38 |
| 39 // We have two pipes to the parent. The first is for the token | |
| 40 // exchange for creating and passing handles on Windows, and creating shared | |
| 41 // buffers on POSIX, since the child needs the parent's help if it is | |
| 42 // sandboxed. The second is used for multiplexing related messages. We | |
| 43 // send the second over the first. | |
| 44 #if defined(OS_POSIX) | |
| 45 // Make the synchronous channel blocking. | |
| 46 int flags = fcntl(parent_sync_channel_.get().handle, F_GETFL, 0); | |
| 47 PCHECK(flags != -1); | |
| 48 PCHECK(fcntl(parent_sync_channel_.get().handle, F_SETFL, | |
| 49 flags & ~O_NONBLOCK) != -1); | |
| 50 | |
| 51 std::deque<PlatformHandle> received_handles; | |
| 52 char buf[1]; | |
| 53 ssize_t result = PlatformChannelRecvmsg(parent_sync_channel_.get(), buf, 1, | |
| 54 &received_handles, true); | |
| 55 CHECK_EQ(1, result); | |
| 56 CHECK_EQ(1u, received_handles.size()); | |
| 57 parent_async_channel_handle.reset(received_handles.front()); | |
| 58 #else | |
| 59 HANDLE parent_handle = INVALID_HANDLE_VALUE; | 39 HANDLE parent_handle = INVALID_HANDLE_VALUE; |
| 60 DWORD bytes_read = 0; | 40 DWORD bytes_read = 0; |
| 61 BOOL rv = ReadFile(parent_sync_channel_.get().handle, &parent_handle, | 41 BOOL rv = ReadFile(parent_sync_channel_.get().handle, &parent_handle, |
| 62 sizeof(parent_handle), &bytes_read, NULL); | 42 sizeof(parent_handle), &bytes_read, NULL); |
| 63 CHECK(rv); | 43 CHECK(rv); |
| 64 parent_async_channel_handle.reset(PlatformHandle(parent_handle)); | 44 parent_async_channel_handle.reset(PlatformHandle(parent_handle)); |
| 45 sync_channel_lock_.Unlock(); |
| 65 #endif | 46 #endif |
| 66 sync_channel_lock_.Unlock(); | |
| 67 | 47 |
| 68 internal::g_io_thread_task_runner->PostTask( | 48 internal::g_io_thread_task_runner->PostTask( |
| 69 FROM_HERE, | 49 FROM_HERE, |
| 70 base::Bind(&ChildBroker::InitAsyncChannel, base::Unretained(this), | 50 base::Bind(&ChildBroker::InitAsyncChannel, base::Unretained(this), |
| 71 base::Passed(&parent_async_channel_handle))); | 51 base::Passed(&parent_async_channel_handle))); |
| 72 } | 52 } |
| 73 | 53 |
| 74 #if defined(OS_WIN) | 54 #if defined(OS_WIN) |
| 75 void ChildBroker::CreatePlatformChannelPair( | 55 void ChildBroker::CreatePlatformChannelPair( |
| 76 ScopedPlatformHandle* server, ScopedPlatformHandle* client) { | 56 ScopedPlatformHandle* server, ScopedPlatformHandle* client) { |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 112 std::vector<HANDLE> handles_temp(count); | 92 std::vector<HANDLE> handles_temp(count); |
| 113 uint32_t response_size = | 93 uint32_t response_size = |
| 114 static_cast<uint32_t>(handles_temp.size()) * sizeof(HANDLE); | 94 static_cast<uint32_t>(handles_temp.size()) * sizeof(HANDLE); |
| 115 sync_channel_lock_.Lock(); | 95 sync_channel_lock_.Lock(); |
| 116 if (WriteAndReadResponse(message, &handles_temp[0], response_size)) { | 96 if (WriteAndReadResponse(message, &handles_temp[0], response_size)) { |
| 117 for (uint32_t i = 0; i < count; ++i) | 97 for (uint32_t i = 0; i < count; ++i) |
| 118 handles[i].handle = handles_temp[i]; | 98 handles[i].handle = handles_temp[i]; |
| 119 sync_channel_lock_.Unlock(); | 99 sync_channel_lock_.Unlock(); |
| 120 } | 100 } |
| 121 } | 101 } |
| 122 #else | |
| 123 scoped_refptr<PlatformSharedBuffer> ChildBroker::CreateSharedBuffer( | |
| 124 size_t num_bytes) { | |
| 125 sync_channel_lock_.Lock(); | |
| 126 scoped_refptr<PlatformSharedBuffer> shared_buffer; | |
| 127 | |
| 128 BrokerMessage message; | |
| 129 message.size = kBrokerMessageHeaderSize + sizeof(uint32_t); | |
| 130 message.id = CREATE_SHARED_BUFFER; | |
| 131 message.shared_buffer_size = num_bytes; | |
| 132 | |
| 133 std::deque<PlatformHandle> handles; | |
| 134 if (WriteAndReadHandles(&message, &handles)) { | |
| 135 DCHECK_EQ(1u, handles.size()); | |
| 136 PlatformHandle handle = handles.front(); | |
| 137 if (handle.is_valid()) | |
| 138 shared_buffer = | |
| 139 internal::g_platform_support->CreateSharedBufferFromHandle( | |
| 140 num_bytes, ScopedPlatformHandle(handles.front())); | |
| 141 } | |
| 142 sync_channel_lock_.Unlock(); | |
| 143 return shared_buffer; | |
| 144 } | |
| 145 #endif | 102 #endif |
| 146 | 103 |
| 147 void ChildBroker::ConnectMessagePipe(uint64_t pipe_id, | 104 void ChildBroker::ConnectMessagePipe(uint64_t pipe_id, |
| 148 MessagePipeDispatcher* message_pipe) { | 105 MessagePipeDispatcher* message_pipe) { |
| 149 DCHECK(internal::g_io_thread_task_runner->RunsTasksOnCurrentThread()); | 106 DCHECK(internal::g_io_thread_task_runner->RunsTasksOnCurrentThread()); |
| 150 | 107 |
| 151 ConnectMessagePipeMessage data; | 108 ConnectMessagePipeMessage data; |
| 152 memset(&data, 0, sizeof(data)); | 109 memset(&data, 0, sizeof(data)); |
| 153 data.pipe_id = pipe_id; | 110 data.pipe_id = pipe_id; |
| 154 if (pending_connects_.find(pipe_id) != pending_connects_.end()) { | 111 if (pending_connects_.find(pipe_id) != pending_connects_.end()) { |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 208 connected_pipes_[message_pipe]->RemoveRoute(pipe_id); | 165 connected_pipes_[message_pipe]->RemoveRoute(pipe_id); |
| 209 connected_pipes_.erase(message_pipe); | 166 connected_pipes_.erase(message_pipe); |
| 210 } | 167 } |
| 211 | 168 |
| 212 ChildBroker::ChildBroker() | 169 ChildBroker::ChildBroker() |
| 213 : parent_async_channel_(nullptr), | 170 : parent_async_channel_(nullptr), |
| 214 in_process_pipes_channel1_(nullptr), | 171 in_process_pipes_channel1_(nullptr), |
| 215 in_process_pipes_channel2_(nullptr) { | 172 in_process_pipes_channel2_(nullptr) { |
| 216 DCHECK(!internal::g_broker); | 173 DCHECK(!internal::g_broker); |
| 217 internal::g_broker = this; | 174 internal::g_broker = this; |
| 175 #if defined(OS_WIN) |
| 218 // Block any threads from calling this until we have a pipe to the parent. | 176 // Block any threads from calling this until we have a pipe to the parent. |
| 219 sync_channel_lock_.Lock(); | 177 sync_channel_lock_.Lock(); |
| 178 #endif |
| 220 } | 179 } |
| 221 | 180 |
| 222 ChildBroker::~ChildBroker() { | 181 ChildBroker::~ChildBroker() { |
| 223 } | 182 } |
| 224 | 183 |
| 225 void ChildBroker::OnReadMessage( | 184 void ChildBroker::OnReadMessage( |
| 226 const MessageInTransit::View& message_view, | 185 const MessageInTransit::View& message_view, |
| 227 ScopedPlatformHandleVectorPtr platform_handles) { | 186 ScopedPlatformHandleVectorPtr platform_handles) { |
| 228 DCHECK(internal::g_io_thread_task_runner->RunsTasksOnCurrentThread()); | 187 DCHECK(internal::g_io_thread_task_runner->RunsTasksOnCurrentThread()); |
| 229 MultiplexMessages type = | 188 MultiplexMessages type = |
| (...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 330 // then when it's read it returns no messages because it doesn't have the | 289 // then when it's read it returns no messages because it doesn't have the |
| 331 // channel yet. | 290 // channel yet. |
| 332 message_pipe->GotNonTransferableChannel(raw_channel->channel()); | 291 message_pipe->GotNonTransferableChannel(raw_channel->channel()); |
| 333 // The above call could have caused |CloseMessagePipe| to be called. | 292 // The above call could have caused |CloseMessagePipe| to be called. |
| 334 if (connected_pipes_.find(message_pipe) != connected_pipes_.end()) | 293 if (connected_pipes_.find(message_pipe) != connected_pipes_.end()) |
| 335 raw_channel->AddRoute(pipe_id, message_pipe); | 294 raw_channel->AddRoute(pipe_id, message_pipe); |
| 336 } | 295 } |
| 337 | 296 |
| 338 #if defined(OS_WIN) | 297 #if defined(OS_WIN) |
| 339 | 298 |
| 340 void ChildBroker::CreatePlatformChannelPairNoLock( | |
| 341 ScopedPlatformHandle* server, | |
| 342 ScopedPlatformHandle* client) { | |
| 343 BrokerMessage message; | |
| 344 message.size = kBrokerMessageHeaderSize; | |
| 345 message.id = CREATE_PLATFORM_CHANNEL_PAIR; | |
| 346 | |
| 347 uint32_t response_size = 2 * sizeof(HANDLE); | |
| 348 HANDLE handles[2]; | |
| 349 if (WriteAndReadResponse(&message, handles, response_size)) { | |
| 350 server->reset(PlatformHandle(handles[0])); | |
| 351 client->reset(PlatformHandle(handles[1])); | |
| 352 } | |
| 353 } | |
| 354 | |
| 355 bool ChildBroker::WriteAndReadResponse(BrokerMessage* message, | 299 bool ChildBroker::WriteAndReadResponse(BrokerMessage* message, |
| 356 void* response, | 300 void* response, |
| 357 uint32_t response_size) { | 301 uint32_t response_size) { |
| 358 CHECK(parent_sync_channel_.is_valid()); | 302 CHECK(parent_sync_channel_.is_valid()); |
| 359 | 303 |
| 360 bool result = true; | 304 bool result = true; |
| 361 DWORD bytes_written = 0; | 305 DWORD bytes_written = 0; |
| 362 // This will always write in one chunk per | 306 // This will always write in one chunk per |
| 363 // https://msdn.microsoft.com/en-us/library/windows/desktop/aa365150.aspx. | 307 // https://msdn.microsoft.com/en-us/library/windows/desktop/aa365150.aspx. |
| 364 BOOL rv = WriteFile(parent_sync_channel_.get().handle, message, message->size, | 308 BOOL rv = WriteFile(parent_sync_channel_.get().handle, message, message->size, |
| (...skipping 11 matching lines...) Expand all Loading... |
| 376 result = false; | 320 result = false; |
| 377 break; | 321 break; |
| 378 } | 322 } |
| 379 response_size -= bytes_read; | 323 response_size -= bytes_read; |
| 380 response = static_cast<char*>(response) + bytes_read; | 324 response = static_cast<char*>(response) + bytes_read; |
| 381 } | 325 } |
| 382 } | 326 } |
| 383 | 327 |
| 384 return result; | 328 return result; |
| 385 } | 329 } |
| 386 #else | |
| 387 bool ChildBroker::WriteAndReadHandles(BrokerMessage* message, | |
| 388 std::deque<PlatformHandle>* handles) { | |
| 389 CHECK(parent_sync_channel_.is_valid()); | |
| 390 | 330 |
| 391 uint32_t remaining_bytes = message->size; | 331 void ChildBroker::CreatePlatformChannelPairNoLock( |
| 392 while (remaining_bytes > 0) { | 332 ScopedPlatformHandle* server, ScopedPlatformHandle* client) { |
| 393 ssize_t bytes_written = PlatformChannelWrite( | 333 BrokerMessage message; |
| 394 parent_sync_channel_.get(), | 334 message.size = kBrokerMessageHeaderSize; |
| 395 reinterpret_cast<uint8_t*>(message) + (message->size - remaining_bytes), | 335 message.id = CREATE_PLATFORM_CHANNEL_PAIR; |
| 396 remaining_bytes); | |
| 397 | 336 |
| 398 if (bytes_written != -1) | 337 uint32_t response_size = 2 * sizeof(HANDLE); |
| 399 remaining_bytes -= bytes_written; | 338 HANDLE handles[2]; |
| 400 else | 339 if (WriteAndReadResponse(&message, handles, response_size)) { |
| 401 return false; | 340 server->reset(PlatformHandle(handles[0])); |
| 341 client->reset(PlatformHandle(handles[1])); |
| 402 } | 342 } |
| 403 // Perform a blocking read (we set this fd to be blocking in | 343 } |
| 404 // SetChildBrokerHostHandle). | |
| 405 char buf[1]; | |
| 406 ssize_t bytes_read = PlatformChannelRecvmsg( | |
| 407 parent_sync_channel_.get(), buf, 1, handles, true /* should_block */); | |
| 408 // If the other side shutdown, or there was an error, or we didn't get | |
| 409 // any handles. | |
| 410 if (bytes_read == 0 || bytes_read == -1 || handles->empty()) | |
| 411 return false; | |
| 412 | 344 |
| 413 return true; | |
| 414 } | |
| 415 #endif | 345 #endif |
| 416 | 346 |
| 417 } // namespace edk | 347 } // namespace edk |
| 418 } // namespace mojo | 348 } // namespace mojo |
| OLD | NEW |