Chromium Code Reviews| 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" | |
| 16 #include "mojo/edk/system/broker_messages.h" | 18 #include "mojo/edk/system/broker_messages.h" |
| 17 #include "mojo/edk/system/message_pipe_dispatcher.h" | 19 #include "mojo/edk/system/message_pipe_dispatcher.h" |
| 18 | 20 |
| 21 #if defined(OS_POSIX) | |
| 22 #include "mojo/edk/embedder/platform_channel_utils_posix.h" | |
| 23 #endif | |
| 24 | |
| 19 namespace mojo { | 25 namespace mojo { |
| 20 namespace edk { | 26 namespace edk { |
| 21 | 27 |
| 22 ChildBroker* ChildBroker::GetInstance() { | 28 ChildBroker* ChildBroker::GetInstance() { |
| 23 return base::Singleton< | 29 return base::Singleton< |
| 24 ChildBroker, base::LeakySingletonTraits<ChildBroker>>::get(); | 30 ChildBroker, base::LeakySingletonTraits<ChildBroker>>::get(); |
| 25 } | 31 } |
| 26 | 32 |
| 27 void ChildBroker::SetChildBrokerHostHandle(ScopedPlatformHandle handle) { | 33 void ChildBroker::SetChildBrokerHostHandle(ScopedPlatformHandle handle) { |
| 28 ScopedPlatformHandle parent_async_channel_handle; | 34 ScopedPlatformHandle parent_async_channel_handle; |
| 35 parent_sync_channel_ = std::move(handle); | |
| 36 | |
| 37 // We have two pipes to the parent. The first is for the token | |
| 38 // exchange for creating and passing handles on Windows, and creating shared | |
| 39 // buffers on POSIX, since the child needs the parent's help if it is | |
| 40 // sandboxed. The second is used for multiplexing related messages. We | |
| 41 // send the second over the first. | |
| 29 #if defined(OS_POSIX) | 42 #if defined(OS_POSIX) |
| 30 parent_async_channel_handle = std::move(handle); | 43 std::deque<PlatformHandle> received_handles; |
| 44 char buf[1]; | |
| 45 ssize_t result = PlatformChannelRecvmsg(parent_sync_channel_.get(), buf, 1, | |
|
Eliot Courtney
2016/01/05 04:45:47
Does this need to be queried in a loop since it wo
jam
2016/01/06 02:58:16
ReadFile below specifies the number of bytes to re
Eliot Courtney
2016/01/07 02:26:09
Thanks! I've done this, although made it not tempo
jam
2016/01/08 22:37:40
great, i had some more statements in this comment
| |
| 46 &received_handles); | |
| 47 CHECK_EQ(1, result); | |
| 48 CHECK_EQ(1u, received_handles.size()); | |
| 49 parent_async_channel_handle.reset(received_handles.front()); | |
| 31 #else | 50 #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_ = handle.Pass(); | |
| 38 | |
| 39 HANDLE parent_handle = INVALID_HANDLE_VALUE; | 51 HANDLE parent_handle = INVALID_HANDLE_VALUE; |
| 40 DWORD bytes_read = 0; | 52 DWORD bytes_read = 0; |
| 41 BOOL rv = ReadFile(parent_sync_channel_.get().handle, &parent_handle, | 53 BOOL rv = ReadFile(parent_sync_channel_.get().handle, &parent_handle, |
| 42 sizeof(parent_handle), &bytes_read, NULL); | 54 sizeof(parent_handle), &bytes_read, NULL); |
| 43 CHECK(rv); | 55 CHECK(rv); |
| 44 parent_async_channel_handle.reset(PlatformHandle(parent_handle)); | 56 parent_async_channel_handle.reset(PlatformHandle(parent_handle)); |
| 57 #endif | |
| 45 sync_channel_lock_.Unlock(); | 58 sync_channel_lock_.Unlock(); |
| 46 #endif | |
| 47 | 59 |
| 48 internal::g_io_thread_task_runner->PostTask( | 60 internal::g_io_thread_task_runner->PostTask( |
| 49 FROM_HERE, | 61 FROM_HERE, |
| 50 base::Bind(&ChildBroker::InitAsyncChannel, base::Unretained(this), | 62 base::Bind(&ChildBroker::InitAsyncChannel, base::Unretained(this), |
| 51 base::Passed(&parent_async_channel_handle))); | 63 base::Passed(&parent_async_channel_handle))); |
| 52 } | 64 } |
| 53 | 65 |
| 54 #if defined(OS_WIN) | 66 #if defined(OS_WIN) |
| 55 void ChildBroker::CreatePlatformChannelPair( | 67 void ChildBroker::CreatePlatformChannelPair( |
| 56 ScopedPlatformHandle* server, ScopedPlatformHandle* client) { | 68 ScopedPlatformHandle* server, ScopedPlatformHandle* client) { |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 92 std::vector<HANDLE> handles_temp(count); | 104 std::vector<HANDLE> handles_temp(count); |
| 93 uint32_t response_size = | 105 uint32_t response_size = |
| 94 static_cast<uint32_t>(handles_temp.size()) * sizeof(HANDLE); | 106 static_cast<uint32_t>(handles_temp.size()) * sizeof(HANDLE); |
| 95 sync_channel_lock_.Lock(); | 107 sync_channel_lock_.Lock(); |
| 96 if (WriteAndReadResponse(message, &handles_temp[0], response_size)) { | 108 if (WriteAndReadResponse(message, &handles_temp[0], response_size)) { |
| 97 for (uint32_t i = 0; i < count; ++i) | 109 for (uint32_t i = 0; i < count; ++i) |
| 98 handles[i].handle = handles_temp[i]; | 110 handles[i].handle = handles_temp[i]; |
| 99 sync_channel_lock_.Unlock(); | 111 sync_channel_lock_.Unlock(); |
| 100 } | 112 } |
| 101 } | 113 } |
| 114 #else | |
| 115 scoped_refptr<PlatformSharedBuffer> ChildBroker::CreateSharedBuffer( | |
| 116 size_t num_bytes) { | |
| 117 sync_channel_lock_.Lock(); | |
| 118 scoped_refptr<PlatformSharedBuffer> shared_buffer = | |
| 119 CreateSharedBufferNoLock(num_bytes); | |
|
jam
2016/01/06 02:58:16
no need to have two methods for this. you can inli
Eliot Courtney
2016/01/07 02:26:09
Done.
| |
| 120 sync_channel_lock_.Unlock(); | |
| 121 | |
| 122 return shared_buffer; | |
| 123 } | |
| 102 #endif | 124 #endif |
| 103 | 125 |
| 104 void ChildBroker::ConnectMessagePipe(uint64_t pipe_id, | 126 void ChildBroker::ConnectMessagePipe(uint64_t pipe_id, |
| 105 MessagePipeDispatcher* message_pipe) { | 127 MessagePipeDispatcher* message_pipe) { |
| 106 DCHECK(internal::g_io_thread_task_runner->RunsTasksOnCurrentThread()); | 128 DCHECK(internal::g_io_thread_task_runner->RunsTasksOnCurrentThread()); |
| 107 | 129 |
| 108 ConnectMessagePipeMessage data; | 130 ConnectMessagePipeMessage data; |
| 109 memset(&data, 0, sizeof(data)); | 131 memset(&data, 0, sizeof(data)); |
| 110 data.pipe_id = pipe_id; | 132 data.pipe_id = pipe_id; |
| 111 if (pending_connects_.find(pipe_id) != pending_connects_.end()) { | 133 if (pending_connects_.find(pipe_id) != pending_connects_.end()) { |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 165 connected_pipes_[message_pipe]->RemoveRoute(pipe_id); | 187 connected_pipes_[message_pipe]->RemoveRoute(pipe_id); |
| 166 connected_pipes_.erase(message_pipe); | 188 connected_pipes_.erase(message_pipe); |
| 167 } | 189 } |
| 168 | 190 |
| 169 ChildBroker::ChildBroker() | 191 ChildBroker::ChildBroker() |
| 170 : parent_async_channel_(nullptr), | 192 : parent_async_channel_(nullptr), |
| 171 in_process_pipes_channel1_(nullptr), | 193 in_process_pipes_channel1_(nullptr), |
| 172 in_process_pipes_channel2_(nullptr) { | 194 in_process_pipes_channel2_(nullptr) { |
| 173 DCHECK(!internal::g_broker); | 195 DCHECK(!internal::g_broker); |
| 174 internal::g_broker = this; | 196 internal::g_broker = this; |
| 175 #if defined(OS_WIN) | |
| 176 // Block any threads from calling this until we have a pipe to the parent. | 197 // Block any threads from calling this until we have a pipe to the parent. |
| 177 sync_channel_lock_.Lock(); | 198 sync_channel_lock_.Lock(); |
| 178 #endif | |
| 179 } | 199 } |
| 180 | 200 |
| 181 ChildBroker::~ChildBroker() { | 201 ChildBroker::~ChildBroker() { |
| 182 } | 202 } |
| 183 | 203 |
| 184 void ChildBroker::OnReadMessage( | 204 void ChildBroker::OnReadMessage( |
| 185 const MessageInTransit::View& message_view, | 205 const MessageInTransit::View& message_view, |
| 186 ScopedPlatformHandleVectorPtr platform_handles) { | 206 ScopedPlatformHandleVectorPtr platform_handles) { |
| 187 DCHECK(internal::g_io_thread_task_runner->RunsTasksOnCurrentThread()); | 207 DCHECK(internal::g_io_thread_task_runner->RunsTasksOnCurrentThread()); |
| 188 MultiplexMessages type = | 208 MultiplexMessages type = |
| (...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 278 // then when it's read it returns no messages because it doesn't have the | 298 // then when it's read it returns no messages because it doesn't have the |
| 279 // channel yet. | 299 // channel yet. |
| 280 message_pipe->GotNonTransferableChannel(raw_channel->channel()); | 300 message_pipe->GotNonTransferableChannel(raw_channel->channel()); |
| 281 // The above call could have caused |CloseMessagePipe| to be called. | 301 // The above call could have caused |CloseMessagePipe| to be called. |
| 282 if (connected_pipes_.find(message_pipe) != connected_pipes_.end()) | 302 if (connected_pipes_.find(message_pipe) != connected_pipes_.end()) |
| 283 raw_channel->AddRoute(pipe_id, message_pipe); | 303 raw_channel->AddRoute(pipe_id, message_pipe); |
| 284 } | 304 } |
| 285 | 305 |
| 286 #if defined(OS_WIN) | 306 #if defined(OS_WIN) |
| 287 | 307 |
| 308 void ChildBroker::CreatePlatformChannelPairNoLock( | |
| 309 ScopedPlatformHandle* server, | |
| 310 ScopedPlatformHandle* client) { | |
| 311 BrokerMessage message; | |
| 312 message.size = kBrokerMessageHeaderSize; | |
| 313 message.id = CREATE_PLATFORM_CHANNEL_PAIR; | |
| 314 | |
| 315 uint32_t response_size = 2 * sizeof(HANDLE); | |
| 316 HANDLE handles[2]; | |
| 317 if (WriteAndReadResponse(&message, handles, response_size)) { | |
| 318 server->reset(PlatformHandle(handles[0])); | |
| 319 client->reset(PlatformHandle(handles[1])); | |
| 320 } | |
| 321 } | |
| 322 | |
| 288 bool ChildBroker::WriteAndReadResponse(BrokerMessage* message, | 323 bool ChildBroker::WriteAndReadResponse(BrokerMessage* message, |
| 289 void* response, | 324 void* response, |
| 290 uint32_t response_size) { | 325 uint32_t response_size) { |
| 291 CHECK(parent_sync_channel_.is_valid()); | 326 CHECK(parent_sync_channel_.is_valid()); |
| 292 | 327 |
| 293 bool result = true; | 328 bool result = true; |
| 329 | |
|
jam
2016/01/06 02:58:16
nit: no need to change
Eliot Courtney
2016/01/07 02:26:09
Done.
| |
| 294 DWORD bytes_written = 0; | 330 DWORD bytes_written = 0; |
| 295 // This will always write in one chunk per | 331 // This will always write in one chunk per |
| 296 // https://msdn.microsoft.com/en-us/library/windows/desktop/aa365150.aspx. | 332 // https://msdn.microsoft.com/en-us/library/windows/desktop/aa365150.aspx. |
| 297 BOOL rv = WriteFile(parent_sync_channel_.get().handle, message, message->size, | 333 BOOL rv = WriteFile(parent_sync_channel_.get().handle, message, message->size, |
| 298 &bytes_written, NULL); | 334 &bytes_written, NULL); |
| 299 if (!rv || bytes_written != message->size) { | 335 if (!rv || bytes_written != message->size) { |
| 300 LOG(ERROR) << "Child token serializer couldn't write message."; | 336 LOG(ERROR) << "Child token serializer couldn't write message."; |
| 301 result = false; | 337 result = false; |
| 302 } else { | 338 } else { |
| 303 while (response_size) { | 339 while (response_size) { |
| 304 DWORD bytes_read = 0; | 340 DWORD bytes_read = 0; |
| 305 rv = ReadFile(parent_sync_channel_.get().handle, response, response_size, | 341 rv = ReadFile(parent_sync_channel_.get().handle, response, response_size, |
| 306 &bytes_read, NULL); | 342 &bytes_read, NULL); |
| 307 if (!rv) { | 343 if (!rv) { |
| 308 LOG(ERROR) << "Child token serializer couldn't read result."; | 344 LOG(ERROR) << "Child token serializer couldn't read result."; |
| 309 result = false; | 345 result = false; |
| 310 break; | 346 break; |
| 311 } | 347 } |
| 312 response_size -= bytes_read; | 348 response_size -= bytes_read; |
| 313 response = static_cast<char*>(response) + bytes_read; | 349 response = static_cast<char*>(response) + bytes_read; |
| 314 } | 350 } |
| 315 } | 351 } |
| 316 | 352 |
| 317 return result; | 353 return result; |
| 318 } | 354 } |
| 355 #else | |
| 356 scoped_refptr<PlatformSharedBuffer> ChildBroker::CreateSharedBufferNoLock( | |
| 357 size_t num_bytes) { | |
| 358 BrokerMessage message; | |
| 359 message.size = kBrokerMessageHeaderSize + sizeof(uint32_t); | |
| 360 message.id = CREATE_SHARED_BUFFER; | |
| 361 message.num_bytes = num_bytes; | |
| 319 | 362 |
| 320 void ChildBroker::CreatePlatformChannelPairNoLock( | 363 std::deque<PlatformHandle> handles; |
| 321 ScopedPlatformHandle* server, ScopedPlatformHandle* client) { | 364 if (WriteAndReadHandles(&message, &handles)) { |
| 322 BrokerMessage message; | 365 DCHECK_EQ(1u, handles.size()); |
| 323 message.size = kBrokerMessageHeaderSize; | 366 if (handles.empty()) { |
| 324 message.id = CREATE_PLATFORM_CHANNEL_PAIR; | 367 LOG(ERROR) |
| 368 << "ChildBroker did not receive handle when creating shared buffer"; | |
| 369 return nullptr; | |
| 370 } | |
| 325 | 371 |
| 326 uint32_t response_size = 2 * sizeof(HANDLE); | 372 PlatformHandle handle = handles.front(); |
| 327 HANDLE handles[2]; | 373 if (handle.is_valid()) |
| 328 if (WriteAndReadResponse(&message, handles, response_size)) { | 374 return internal::g_platform_support->CreateSharedBufferFromHandle( |
| 329 server->reset(PlatformHandle(handles[0])); | 375 num_bytes, ScopedPlatformHandle(handles.front())); |
| 330 client->reset(PlatformHandle(handles[1])); | 376 else |
| 377 return nullptr; | |
| 331 } | 378 } |
| 379 | |
| 380 return nullptr; | |
| 332 } | 381 } |
| 333 | 382 |
| 383 bool ChildBroker::WriteAndReadHandles(BrokerMessage* message, | |
| 384 std::deque<PlatformHandle>* handles) { | |
| 385 CHECK(parent_sync_channel_.is_valid()); | |
| 386 | |
| 387 uint32_t remaining_bytes = message->size; | |
| 388 while (remaining_bytes > 0) { | |
| 389 ssize_t bytes_written = PlatformChannelWrite( | |
|
Eliot Courtney
2016/01/05 04:45:47
This loop is on top of a non-blocking function (Pl
jam
2016/01/06 02:58:16
i don't see how it would ever block in practice, b
Eliot Courtney
2016/01/07 02:26:09
I removed the O_NONBLOCK using fcntl like you sugg
| |
| 390 parent_sync_channel_.get(), | |
| 391 reinterpret_cast<uint8_t*>(message) + (message->size - remaining_bytes), | |
| 392 remaining_bytes); | |
| 393 | |
| 394 if (bytes_written == -1 && errno != EAGAIN && errno != EWOULDBLOCK) | |
| 395 return false; | |
| 396 | |
| 397 if (bytes_written != -1) | |
| 398 remaining_bytes -= bytes_written; | |
| 399 } | |
| 400 | |
| 401 while (1) { | |
|
jam
2016/01/06 02:58:16
same as first comment in this file, why not make r
Eliot Courtney
2016/01/07 02:26:09
Done.
| |
| 402 char buf[1]; | |
| 403 ssize_t bytes_read = | |
| 404 PlatformChannelRecvmsg(parent_sync_channel_.get(), buf, 1, handles); | |
|
Eliot Courtney
2016/01/05 04:45:47
Same comment as above.
Eliot Courtney
2016/01/07 02:26:08
Done.
| |
| 405 if (bytes_read == 0 || | |
| 406 (bytes_read == -1 && errno != EAGAIN && errno != EWOULDBLOCK)) | |
| 407 return false; | |
| 408 | |
| 409 if (handles->size() >= 1) | |
| 410 break; | |
| 411 } | |
| 412 return true; | |
| 413 } | |
| 334 #endif | 414 #endif |
| 335 | 415 |
| 336 } // namespace edk | 416 } // namespace edk |
| 337 } // namespace mojo | 417 } // namespace mojo |
| OLD | NEW |