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 <fcntl.h> | |
23 | |
24 #include "mojo/edk/embedder/platform_channel_utils_posix.h" | |
25 #endif | |
26 | |
19 namespace mojo { | 27 namespace mojo { |
20 namespace edk { | 28 namespace edk { |
21 | 29 |
22 ChildBroker* ChildBroker::GetInstance() { | 30 ChildBroker* ChildBroker::GetInstance() { |
23 return base::Singleton< | 31 return base::Singleton< |
24 ChildBroker, base::LeakySingletonTraits<ChildBroker>>::get(); | 32 ChildBroker, base::LeakySingletonTraits<ChildBroker>>::get(); |
25 } | 33 } |
26 | 34 |
27 void ChildBroker::SetChildBrokerHostHandle(ScopedPlatformHandle handle) { | 35 void ChildBroker::SetChildBrokerHostHandle(ScopedPlatformHandle handle) { |
28 ScopedPlatformHandle parent_async_channel_handle; | 36 ScopedPlatformHandle parent_async_channel_handle; |
37 parent_sync_channel_ = std::move(handle); | |
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. | |
29 #if defined(OS_POSIX) | 44 #if defined(OS_POSIX) |
30 parent_async_channel_handle = std::move(handle); | 45 // Make the synchronous channel blocking. |
46 fcntl(parent_sync_channel_.get().handle, F_SETFL, | |
Anand Mistry (off Chromium)
2016/01/07 04:36:33
Since you rely on the channels becoming blocking,
Eliot Courtney
2016/01/07 05:01:30
Done.
| |
47 fcntl(parent_sync_channel_.get().handle, F_GETFL, 0) & ~O_NONBLOCK); | |
48 | |
49 std::deque<PlatformHandle> received_handles; | |
50 char buf[1]; | |
51 ssize_t result = PlatformChannelRecvmsg(parent_sync_channel_.get(), buf, 1, | |
52 &received_handles); | |
53 CHECK_EQ(1, result); | |
54 CHECK_EQ(1u, received_handles.size()); | |
55 parent_async_channel_handle.reset(received_handles.front()); | |
31 #else | 56 #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; | 57 HANDLE parent_handle = INVALID_HANDLE_VALUE; |
40 DWORD bytes_read = 0; | 58 DWORD bytes_read = 0; |
41 BOOL rv = ReadFile(parent_sync_channel_.get().handle, &parent_handle, | 59 BOOL rv = ReadFile(parent_sync_channel_.get().handle, &parent_handle, |
42 sizeof(parent_handle), &bytes_read, NULL); | 60 sizeof(parent_handle), &bytes_read, NULL); |
43 CHECK(rv); | 61 CHECK(rv); |
44 parent_async_channel_handle.reset(PlatformHandle(parent_handle)); | 62 parent_async_channel_handle.reset(PlatformHandle(parent_handle)); |
63 #endif | |
45 sync_channel_lock_.Unlock(); | 64 sync_channel_lock_.Unlock(); |
46 #endif | |
47 | 65 |
48 internal::g_io_thread_task_runner->PostTask( | 66 internal::g_io_thread_task_runner->PostTask( |
49 FROM_HERE, | 67 FROM_HERE, |
50 base::Bind(&ChildBroker::InitAsyncChannel, base::Unretained(this), | 68 base::Bind(&ChildBroker::InitAsyncChannel, base::Unretained(this), |
51 base::Passed(&parent_async_channel_handle))); | 69 base::Passed(&parent_async_channel_handle))); |
52 } | 70 } |
53 | 71 |
54 #if defined(OS_WIN) | 72 #if defined(OS_WIN) |
55 void ChildBroker::CreatePlatformChannelPair( | 73 void ChildBroker::CreatePlatformChannelPair( |
56 ScopedPlatformHandle* server, ScopedPlatformHandle* client) { | 74 ScopedPlatformHandle* server, ScopedPlatformHandle* client) { |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
92 std::vector<HANDLE> handles_temp(count); | 110 std::vector<HANDLE> handles_temp(count); |
93 uint32_t response_size = | 111 uint32_t response_size = |
94 static_cast<uint32_t>(handles_temp.size()) * sizeof(HANDLE); | 112 static_cast<uint32_t>(handles_temp.size()) * sizeof(HANDLE); |
95 sync_channel_lock_.Lock(); | 113 sync_channel_lock_.Lock(); |
96 if (WriteAndReadResponse(message, &handles_temp[0], response_size)) { | 114 if (WriteAndReadResponse(message, &handles_temp[0], response_size)) { |
97 for (uint32_t i = 0; i < count; ++i) | 115 for (uint32_t i = 0; i < count; ++i) |
98 handles[i].handle = handles_temp[i]; | 116 handles[i].handle = handles_temp[i]; |
99 sync_channel_lock_.Unlock(); | 117 sync_channel_lock_.Unlock(); |
100 } | 118 } |
101 } | 119 } |
120 #else | |
121 scoped_refptr<PlatformSharedBuffer> ChildBroker::CreateSharedBuffer( | |
122 size_t num_bytes) { | |
123 sync_channel_lock_.Lock(); | |
Anand Mistry (off Chromium)
2016/01/07 04:36:33
Why aren't you using AutoLock?
Eliot Courtney
2016/01/07 05:01:30
This lock is actually a LockImpl, see comment: htt
| |
124 scoped_refptr<PlatformSharedBuffer> shared_buffer; | |
125 | |
126 BrokerMessage message; | |
127 message.size = kBrokerMessageHeaderSize + sizeof(uint32_t); | |
128 message.id = CREATE_SHARED_BUFFER; | |
129 message.num_bytes = num_bytes; | |
130 | |
131 std::deque<PlatformHandle> handles; | |
132 if (WriteAndReadHandles(&message, &handles)) { | |
133 DCHECK_EQ(1u, handles.size()); | |
134 PlatformHandle handle = handles.front(); | |
135 if (handle.is_valid()) | |
136 shared_buffer = | |
137 internal::g_platform_support->CreateSharedBufferFromHandle( | |
138 num_bytes, ScopedPlatformHandle(handles.front())); | |
139 } | |
140 | |
141 sync_channel_lock_.Unlock(); | |
142 return shared_buffer; | |
143 } | |
102 #endif | 144 #endif |
103 | 145 |
104 void ChildBroker::ConnectMessagePipe(uint64_t pipe_id, | 146 void ChildBroker::ConnectMessagePipe(uint64_t pipe_id, |
105 MessagePipeDispatcher* message_pipe) { | 147 MessagePipeDispatcher* message_pipe) { |
106 DCHECK(internal::g_io_thread_task_runner->RunsTasksOnCurrentThread()); | 148 DCHECK(internal::g_io_thread_task_runner->RunsTasksOnCurrentThread()); |
107 | 149 |
108 ConnectMessagePipeMessage data; | 150 ConnectMessagePipeMessage data; |
109 memset(&data, 0, sizeof(data)); | 151 memset(&data, 0, sizeof(data)); |
110 data.pipe_id = pipe_id; | 152 data.pipe_id = pipe_id; |
111 if (pending_connects_.find(pipe_id) != pending_connects_.end()) { | 153 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); | 207 connected_pipes_[message_pipe]->RemoveRoute(pipe_id); |
166 connected_pipes_.erase(message_pipe); | 208 connected_pipes_.erase(message_pipe); |
167 } | 209 } |
168 | 210 |
169 ChildBroker::ChildBroker() | 211 ChildBroker::ChildBroker() |
170 : parent_async_channel_(nullptr), | 212 : parent_async_channel_(nullptr), |
171 in_process_pipes_channel1_(nullptr), | 213 in_process_pipes_channel1_(nullptr), |
172 in_process_pipes_channel2_(nullptr) { | 214 in_process_pipes_channel2_(nullptr) { |
173 DCHECK(!internal::g_broker); | 215 DCHECK(!internal::g_broker); |
174 internal::g_broker = this; | 216 internal::g_broker = this; |
175 #if defined(OS_WIN) | |
176 // Block any threads from calling this until we have a pipe to the parent. | 217 // Block any threads from calling this until we have a pipe to the parent. |
177 sync_channel_lock_.Lock(); | 218 sync_channel_lock_.Lock(); |
178 #endif | |
179 } | 219 } |
180 | 220 |
181 ChildBroker::~ChildBroker() { | 221 ChildBroker::~ChildBroker() { |
182 } | 222 } |
183 | 223 |
184 void ChildBroker::OnReadMessage( | 224 void ChildBroker::OnReadMessage( |
185 const MessageInTransit::View& message_view, | 225 const MessageInTransit::View& message_view, |
186 ScopedPlatformHandleVectorPtr platform_handles) { | 226 ScopedPlatformHandleVectorPtr platform_handles) { |
187 DCHECK(internal::g_io_thread_task_runner->RunsTasksOnCurrentThread()); | 227 DCHECK(internal::g_io_thread_task_runner->RunsTasksOnCurrentThread()); |
188 MultiplexMessages type = | 228 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 | 318 // then when it's read it returns no messages because it doesn't have the |
279 // channel yet. | 319 // channel yet. |
280 message_pipe->GotNonTransferableChannel(raw_channel->channel()); | 320 message_pipe->GotNonTransferableChannel(raw_channel->channel()); |
281 // The above call could have caused |CloseMessagePipe| to be called. | 321 // The above call could have caused |CloseMessagePipe| to be called. |
282 if (connected_pipes_.find(message_pipe) != connected_pipes_.end()) | 322 if (connected_pipes_.find(message_pipe) != connected_pipes_.end()) |
283 raw_channel->AddRoute(pipe_id, message_pipe); | 323 raw_channel->AddRoute(pipe_id, message_pipe); |
284 } | 324 } |
285 | 325 |
286 #if defined(OS_WIN) | 326 #if defined(OS_WIN) |
287 | 327 |
328 void ChildBroker::CreatePlatformChannelPairNoLock( | |
329 ScopedPlatformHandle* server, | |
330 ScopedPlatformHandle* client) { | |
331 BrokerMessage message; | |
332 message.size = kBrokerMessageHeaderSize; | |
333 message.id = CREATE_PLATFORM_CHANNEL_PAIR; | |
334 | |
335 uint32_t response_size = 2 * sizeof(HANDLE); | |
336 HANDLE handles[2]; | |
337 if (WriteAndReadResponse(&message, handles, response_size)) { | |
338 server->reset(PlatformHandle(handles[0])); | |
339 client->reset(PlatformHandle(handles[1])); | |
340 } | |
341 } | |
342 | |
288 bool ChildBroker::WriteAndReadResponse(BrokerMessage* message, | 343 bool ChildBroker::WriteAndReadResponse(BrokerMessage* message, |
289 void* response, | 344 void* response, |
290 uint32_t response_size) { | 345 uint32_t response_size) { |
291 CHECK(parent_sync_channel_.is_valid()); | 346 CHECK(parent_sync_channel_.is_valid()); |
292 | 347 |
293 bool result = true; | 348 bool result = true; |
294 DWORD bytes_written = 0; | 349 DWORD bytes_written = 0; |
295 // This will always write in one chunk per | 350 // This will always write in one chunk per |
296 // https://msdn.microsoft.com/en-us/library/windows/desktop/aa365150.aspx. | 351 // https://msdn.microsoft.com/en-us/library/windows/desktop/aa365150.aspx. |
297 BOOL rv = WriteFile(parent_sync_channel_.get().handle, message, message->size, | 352 BOOL rv = WriteFile(parent_sync_channel_.get().handle, message, message->size, |
(...skipping 11 matching lines...) Expand all Loading... | |
309 result = false; | 364 result = false; |
310 break; | 365 break; |
311 } | 366 } |
312 response_size -= bytes_read; | 367 response_size -= bytes_read; |
313 response = static_cast<char*>(response) + bytes_read; | 368 response = static_cast<char*>(response) + bytes_read; |
314 } | 369 } |
315 } | 370 } |
316 | 371 |
317 return result; | 372 return result; |
318 } | 373 } |
374 #else | |
375 bool ChildBroker::WriteAndReadHandles(BrokerMessage* message, | |
376 std::deque<PlatformHandle>* handles) { | |
377 DCHECK_EQ(0, | |
378 fcntl(parent_sync_channel_.get().handle, F_GETFL, 0) & O_NONBLOCK); | |
379 CHECK(parent_sync_channel_.is_valid()); | |
319 | 380 |
320 void ChildBroker::CreatePlatformChannelPairNoLock( | 381 uint32_t remaining_bytes = message->size; |
321 ScopedPlatformHandle* server, ScopedPlatformHandle* client) { | 382 while (remaining_bytes > 0) { |
322 BrokerMessage message; | 383 ssize_t bytes_written = PlatformChannelWrite( |
323 message.size = kBrokerMessageHeaderSize; | 384 parent_sync_channel_.get(), |
324 message.id = CREATE_PLATFORM_CHANNEL_PAIR; | 385 reinterpret_cast<uint8_t*>(message) + (message->size - remaining_bytes), |
386 remaining_bytes); | |
325 | 387 |
326 uint32_t response_size = 2 * sizeof(HANDLE); | 388 if (bytes_written != -1) |
327 HANDLE handles[2]; | 389 remaining_bytes -= bytes_written; |
328 if (WriteAndReadResponse(&message, handles, response_size)) { | 390 else |
329 server->reset(PlatformHandle(handles[0])); | 391 return false; |
330 client->reset(PlatformHandle(handles[1])); | |
331 } | 392 } |
393 | |
394 // Perform a blocking read (we set this fd to be blocking in | |
395 // SetChildBrokerHostHandle). | |
396 char buf[1]; | |
397 ssize_t bytes_read = | |
398 PlatformChannelRecvmsg(parent_sync_channel_.get(), buf, 1, handles); | |
399 // If the other side shutdown, or there was an error, or we didn't get | |
400 // any handles. | |
401 if (bytes_read == 0 || bytes_read == -1 || handles->empty()) | |
402 return false; | |
403 | |
404 return true; | |
332 } | 405 } |
333 | |
334 #endif | 406 #endif |
335 | 407 |
336 } // namespace edk | 408 } // namespace edk |
337 } // namespace mojo | 409 } // namespace mojo |
OLD | NEW |