Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(167)

Side by Side Diff: mojo/edk/system/child_broker.cc

Issue 1555273002: [mojo] Add CreateSharedBuffer method to Broker. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 4 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698