1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "mojo/core/core.h"
6
7 #include <string.h>
8
9 #include <algorithm>
10 #include <utility>
11
12 #include "base/bind.h"
13 #include "base/containers/stack_container.h"
14 #include "base/location.h"
15 #include "base/logging.h"
16 #include "base/macros.h"
17 #include "base/memory/ptr_util.h"
18 #include "base/memory/writable_shared_memory_region.h"
19 #include "base/rand_util.h"
20 #include "base/strings/string_number_conversions.h"
21 #include "base/strings/string_piece.h"
22 #include "base/threading/thread_task_runner_handle.h"
23 #include "base/time/time.h"
24 // #include "base/trace_event/memory_dump_manager.h"
25 #include "build/build_config.h"
26 #include "mojo/core/channel.h"
27 #include "mojo/core/configuration.h"
28 #include "mojo/core/data_pipe_consumer_dispatcher.h"
29 #include "mojo/core/data_pipe_producer_dispatcher.h"
30 #include "mojo/core/embedder/process_error_callback.h"
31 #include "mojo/core/handle_signals_state.h"
32 #include "mojo/core/invitation_dispatcher.h"
33 #include "mojo/core/message_pipe_dispatcher.h"
34 #include "mojo/core/platform_handle_dispatcher.h"
35 #include "mojo/core/platform_handle_utils.h"
36 #include "mojo/core/platform_shared_memory_mapping.h"
37 #include "mojo/core/ports/event.h"
38 #include "mojo/core/ports/name.h"
39 #include "mojo/core/ports/node.h"
40 #include "mojo/core/request_context.h"
41 #include "mojo/core/shared_buffer_dispatcher.h"
42 #include "mojo/core/user_message_impl.h"
43 #include "mojo/core/watcher_dispatcher.h"
44
45 namespace mojo {
46 namespace core {
47
48 namespace {
49
50 // This is an unnecessarily large limit that is relatively easy to enforce.
51 const uint32_t kMaxHandlesPerMessage = 1024 * 1024;
52
53 // TODO(rockot): Maybe we could negotiate a debugging pipe ID for cross-process
54 // pipes too; for now we just use a constant. This only affects bootstrap pipes.
55 const uint64_t kUnknownPipeIdForDebug = 0x7f7f7f7f7f7f7f7fUL;
56
57 // The pipe name which must be used for the sole pipe attachment on any isolated
58 // invitation.
59 constexpr base::StringPiece kIsolatedInvitationPipeName = {"\0\0\0\0", 4};
60
InvokeProcessErrorCallbackOnTaskRunner(scoped_refptr<base::TaskRunner> task_runner,MojoProcessErrorHandler handler,uintptr_t context,const std::string & error,MojoProcessErrorFlags flags)61 void InvokeProcessErrorCallbackOnTaskRunner(
62 scoped_refptr<base::TaskRunner> task_runner,
63 MojoProcessErrorHandler handler,
64 uintptr_t context,
65 const std::string& error,
66 MojoProcessErrorFlags flags) {
67 // We always run the handler asynchronously to ensure no Mojo core reentrancy.
68 task_runner->PostTask(
69 FROM_HERE,
70 base::BindOnce(
71 [](MojoProcessErrorHandler handler, uintptr_t context,
72 const std::string& error, MojoProcessErrorFlags flags) {
73 MojoProcessErrorDetails details;
74 details.struct_size = sizeof(details);
75 DCHECK(base::IsValueInRangeForNumericType<uint32_t>(error.size()));
76 details.error_message_length = static_cast<uint32_t>(error.size());
77 if (!error.empty())
78 details.error_message = error.data();
79 else
80 details.error_message = nullptr;
81 details.flags = flags;
82 handler(context, &details);
83 },
84 handler, context, error, flags));
85 }
86
87 // Helper class which is bound to the lifetime of a
88 // ProcessErrorCallback generated by the |MojoSendInvitation()|
89 // API. When the last reference to the error callback is lost within the EDK,
90 // which will happen shortly after a connection to the process is lost, that
91 // obviously guarantees that no more invocations of the callback will occur. At
92 // that point, the corresponding instance of this object (owned by the callback
93 // -- see Core::SendInvitation) will be destroyed.
94 class ProcessDisconnectHandler {
95 public:
ProcessDisconnectHandler(scoped_refptr<base::TaskRunner> task_runner,MojoProcessErrorHandler handler,uintptr_t context)96 ProcessDisconnectHandler(scoped_refptr<base::TaskRunner> task_runner,
97 MojoProcessErrorHandler handler,
98 uintptr_t context)
99 : task_runner_(std::move(task_runner)),
100 handler_(handler),
101 context_(context) {}
102
~ProcessDisconnectHandler()103 ~ProcessDisconnectHandler() {
104 InvokeProcessErrorCallbackOnTaskRunner(
105 task_runner_, handler_, context_, std::string(),
106 MOJO_PROCESS_ERROR_FLAG_DISCONNECTED);
107 }
108
109 private:
110 const scoped_refptr<base::TaskRunner> task_runner_;
111 const MojoProcessErrorHandler handler_;
112 const uintptr_t context_;
113
114 DISALLOW_COPY_AND_ASSIGN(ProcessDisconnectHandler);
115 };
116
RunMojoProcessErrorHandler(ProcessDisconnectHandler * disconnect_handler,scoped_refptr<base::TaskRunner> task_runner,MojoProcessErrorHandler handler,uintptr_t context,const std::string & error)117 void RunMojoProcessErrorHandler(ProcessDisconnectHandler* disconnect_handler,
118 scoped_refptr<base::TaskRunner> task_runner,
119 MojoProcessErrorHandler handler,
120 uintptr_t context,
121 const std::string& error) {
122 InvokeProcessErrorCallbackOnTaskRunner(task_runner, handler, context, error,
123 MOJO_PROCESS_ERROR_FLAG_NONE);
124 }
125
126 } // namespace
127
Core()128 Core::Core() {
129 handles_.reset(new HandleTable);
130 // base::trace_event::MemoryDumpManager::GetInstance()->RegisterDumpProvider(
131 // handles_.get(), "MojoHandleTable", nullptr);
132 }
133
~Core()134 Core::~Core() {
135 if (node_controller_ && node_controller_->io_task_runner()) {
136 // If this races with IO thread shutdown the callback will be dropped and
137 // the NodeController will be shutdown on this thread anyway, which is also
138 // just fine.
139 scoped_refptr<base::TaskRunner> io_task_runner =
140 node_controller_->io_task_runner();
141 io_task_runner->PostTask(FROM_HERE,
142 base::BindOnce(&Core::PassNodeControllerToIOThread,
143 base::Passed(&node_controller_)));
144 }
145 // base::trace_event::MemoryDumpManager::GetInstance()
146 // ->UnregisterAndDeleteDumpProviderSoon(std::move(handles_));
147 }
148
SetIOTaskRunner(scoped_refptr<base::TaskRunner> io_task_runner)149 void Core::SetIOTaskRunner(scoped_refptr<base::TaskRunner> io_task_runner) {
150 GetNodeController()->SetIOTaskRunner(io_task_runner);
151 }
152
GetNodeController()153 NodeController* Core::GetNodeController() {
154 base::AutoLock lock(node_controller_lock_);
155 if (!node_controller_)
156 node_controller_.reset(new NodeController(this));
157 return node_controller_.get();
158 }
159
GetDispatcher(MojoHandle handle)160 scoped_refptr<Dispatcher> Core::GetDispatcher(MojoHandle handle) {
161 base::AutoLock lock(handles_->GetLock());
162 return handles_->GetDispatcher(handle);
163 }
164
GetAndRemoveDispatcher(MojoHandle handle)165 scoped_refptr<Dispatcher> Core::GetAndRemoveDispatcher(MojoHandle handle) {
166 scoped_refptr<Dispatcher> dispatcher;
167 base::AutoLock lock(handles_->GetLock());
168 handles_->GetAndRemoveDispatcher(handle, &dispatcher);
169 return dispatcher;
170 }
171
SetDefaultProcessErrorCallback(const ProcessErrorCallback & callback)172 void Core::SetDefaultProcessErrorCallback(
173 const ProcessErrorCallback& callback) {
174 default_process_error_callback_ = callback;
175 }
176
CreatePartialMessagePipe(ports::PortRef * peer)177 MojoHandle Core::CreatePartialMessagePipe(ports::PortRef* peer) {
178 RequestContext request_context;
179 ports::PortRef local_port;
180 GetNodeController()->node()->CreatePortPair(&local_port, peer);
181 return AddDispatcher(new MessagePipeDispatcher(
182 GetNodeController(), local_port, kUnknownPipeIdForDebug, 0));
183 }
184
CreatePartialMessagePipe(const ports::PortRef & port)185 MojoHandle Core::CreatePartialMessagePipe(const ports::PortRef& port) {
186 RequestContext request_context;
187 return AddDispatcher(new MessagePipeDispatcher(GetNodeController(), port,
188 kUnknownPipeIdForDebug, 1));
189 }
190
SendBrokerClientInvitation(base::ProcessHandle target_process,ConnectionParams connection_params,const std::vector<std::pair<std::string,ports::PortRef>> & attached_ports,const ProcessErrorCallback & process_error_callback)191 void Core::SendBrokerClientInvitation(
192 base::ProcessHandle target_process,
193 ConnectionParams connection_params,
194 const std::vector<std::pair<std::string, ports::PortRef>>& attached_ports,
195 const ProcessErrorCallback& process_error_callback) {
196 RequestContext request_context;
197 GetNodeController()->SendBrokerClientInvitation(
198 target_process, std::move(connection_params), attached_ports,
199 process_error_callback);
200 }
201
AcceptBrokerClientInvitation(ConnectionParams connection_params)202 void Core::AcceptBrokerClientInvitation(ConnectionParams connection_params) {
203 RequestContext request_context;
204 GetNodeController()->AcceptBrokerClientInvitation(
205 std::move(connection_params));
206 }
207
ConnectIsolated(ConnectionParams connection_params,const ports::PortRef & port,base::StringPiece connection_name)208 void Core::ConnectIsolated(ConnectionParams connection_params,
209 const ports::PortRef& port,
210 base::StringPiece connection_name) {
211 RequestContext request_context;
212 GetNodeController()->ConnectIsolated(std::move(connection_params), port,
213 connection_name);
214 }
215
SetMachPortProvider(base::PortProvider * port_provider)216 void Core::SetMachPortProvider(base::PortProvider* port_provider) {
217 #if defined(OS_MACOSX) && !defined(OS_IOS)
218 GetNodeController()->CreateMachPortRelay(port_provider);
219 #endif
220 }
221
222 #if defined(OS_MACOSX) && !defined(OS_IOS)
GetMachPortRelay()223 MachPortRelay* Core::GetMachPortRelay() {
224 return GetNodeController()->GetMachPortRelay();
225 }
226 #endif
227
AddDispatcher(scoped_refptr<Dispatcher> dispatcher)228 MojoHandle Core::AddDispatcher(scoped_refptr<Dispatcher> dispatcher) {
229 base::AutoLock lock(handles_->GetLock());
230 return handles_->AddDispatcher(dispatcher);
231 }
232
AddDispatchersFromTransit(const std::vector<Dispatcher::DispatcherInTransit> & dispatchers,MojoHandle * handles)233 bool Core::AddDispatchersFromTransit(
234 const std::vector<Dispatcher::DispatcherInTransit>& dispatchers,
235 MojoHandle* handles) {
236 bool failed = false;
237 {
238 base::AutoLock lock(handles_->GetLock());
239 if (!handles_->AddDispatchersFromTransit(dispatchers, handles))
240 failed = true;
241 }
242 if (failed) {
243 for (auto d : dispatchers) {
244 if (d.dispatcher)
245 d.dispatcher->Close();
246 }
247 return false;
248 }
249 return true;
250 }
251
AcquireDispatchersForTransit(const MojoHandle * handles,size_t num_handles,std::vector<Dispatcher::DispatcherInTransit> * dispatchers)252 MojoResult Core::AcquireDispatchersForTransit(
253 const MojoHandle* handles,
254 size_t num_handles,
255 std::vector<Dispatcher::DispatcherInTransit>* dispatchers) {
256 base::AutoLock lock(handles_->GetLock());
257 MojoResult rv = handles_->BeginTransit(handles, num_handles, dispatchers);
258 if (rv != MOJO_RESULT_OK)
259 handles_->CancelTransit(*dispatchers);
260 return rv;
261 }
262
ReleaseDispatchersForTransit(const std::vector<Dispatcher::DispatcherInTransit> & dispatchers,bool in_transit)263 void Core::ReleaseDispatchersForTransit(
264 const std::vector<Dispatcher::DispatcherInTransit>& dispatchers,
265 bool in_transit) {
266 base::AutoLock lock(handles_->GetLock());
267 if (in_transit)
268 handles_->CompleteTransitAndClose(dispatchers);
269 else
270 handles_->CancelTransit(dispatchers);
271 }
272
RequestShutdown(const base::Closure & callback)273 void Core::RequestShutdown(const base::Closure& callback) {
274 GetNodeController()->RequestShutdown(callback);
275 }
276
ExtractMessagePipeFromInvitation(const std::string & name)277 MojoHandle Core::ExtractMessagePipeFromInvitation(const std::string& name) {
278 RequestContext request_context;
279 ports::PortRef port0, port1;
280 GetNodeController()->node()->CreatePortPair(&port0, &port1);
281 MojoHandle handle = AddDispatcher(new MessagePipeDispatcher(
282 GetNodeController(), port0, kUnknownPipeIdForDebug, 1));
283 GetNodeController()->MergePortIntoInviter(name, port1);
284 return handle;
285 }
286
GetTimeTicksNow()287 MojoTimeTicks Core::GetTimeTicksNow() {
288 return base::TimeTicks::Now().ToInternalValue();
289 }
290
Close(MojoHandle handle)291 MojoResult Core::Close(MojoHandle handle) {
292 RequestContext request_context;
293 scoped_refptr<Dispatcher> dispatcher;
294 {
295 base::AutoLock lock(handles_->GetLock());
296 MojoResult rv = handles_->GetAndRemoveDispatcher(handle, &dispatcher);
297 if (rv != MOJO_RESULT_OK)
298 return rv;
299 }
300 dispatcher->Close();
301 return MOJO_RESULT_OK;
302 }
303
QueryHandleSignalsState(MojoHandle handle,MojoHandleSignalsState * signals_state)304 MojoResult Core::QueryHandleSignalsState(
305 MojoHandle handle,
306 MojoHandleSignalsState* signals_state) {
307 RequestContext request_context;
308 scoped_refptr<Dispatcher> dispatcher = GetDispatcher(handle);
309 if (!dispatcher || !signals_state)
310 return MOJO_RESULT_INVALID_ARGUMENT;
311 *signals_state = dispatcher->GetHandleSignalsState();
312 return MOJO_RESULT_OK;
313 }
314
CreateTrap(MojoTrapEventHandler handler,const MojoCreateTrapOptions * options,MojoHandle * trap_handle)315 MojoResult Core::CreateTrap(MojoTrapEventHandler handler,
316 const MojoCreateTrapOptions* options,
317 MojoHandle* trap_handle) {
318 if (options && options->struct_size < sizeof(*options))
319 return MOJO_RESULT_INVALID_ARGUMENT;
320
321 RequestContext request_context;
322 if (!trap_handle)
323 return MOJO_RESULT_INVALID_ARGUMENT;
324 *trap_handle = AddDispatcher(new WatcherDispatcher(handler));
325 if (*trap_handle == MOJO_HANDLE_INVALID)
326 return MOJO_RESULT_RESOURCE_EXHAUSTED;
327 return MOJO_RESULT_OK;
328 }
329
AddTrigger(MojoHandle trap_handle,MojoHandle handle,MojoHandleSignals signals,MojoTriggerCondition condition,uintptr_t context,const MojoAddTriggerOptions * options)330 MojoResult Core::AddTrigger(MojoHandle trap_handle,
331 MojoHandle handle,
332 MojoHandleSignals signals,
333 MojoTriggerCondition condition,
334 uintptr_t context,
335 const MojoAddTriggerOptions* options) {
336 if (options && options->struct_size < sizeof(*options))
337 return MOJO_RESULT_INVALID_ARGUMENT;
338
339 RequestContext request_context;
340 scoped_refptr<Dispatcher> watcher = GetDispatcher(trap_handle);
341 if (!watcher || watcher->GetType() != Dispatcher::Type::WATCHER)
342 return MOJO_RESULT_INVALID_ARGUMENT;
343
344 scoped_refptr<Dispatcher> dispatcher = GetDispatcher(handle);
345 if (!dispatcher)
346 return MOJO_RESULT_INVALID_ARGUMENT;
347
348 return watcher->WatchDispatcher(std::move(dispatcher), signals, condition,
349 context);
350 }
351
RemoveTrigger(MojoHandle trap_handle,uintptr_t context,const MojoRemoveTriggerOptions * options)352 MojoResult Core::RemoveTrigger(MojoHandle trap_handle,
353 uintptr_t context,
354 const MojoRemoveTriggerOptions* options) {
355 if (options && options->struct_size < sizeof(*options))
356 return MOJO_RESULT_INVALID_ARGUMENT;
357
358 RequestContext request_context;
359 scoped_refptr<Dispatcher> watcher = GetDispatcher(trap_handle);
360 if (!watcher || watcher->GetType() != Dispatcher::Type::WATCHER)
361 return MOJO_RESULT_INVALID_ARGUMENT;
362 return watcher->CancelWatch(context);
363 }
364
ArmTrap(MojoHandle trap_handle,const MojoArmTrapOptions * options,uint32_t * num_blocking_events,MojoTrapEvent * blocking_events)365 MojoResult Core::ArmTrap(MojoHandle trap_handle,
366 const MojoArmTrapOptions* options,
367 uint32_t* num_blocking_events,
368 MojoTrapEvent* blocking_events) {
369 if (options && options->struct_size < sizeof(*options))
370 return MOJO_RESULT_INVALID_ARGUMENT;
371
372 RequestContext request_context;
373 scoped_refptr<Dispatcher> watcher = GetDispatcher(trap_handle);
374 if (!watcher || watcher->GetType() != Dispatcher::Type::WATCHER)
375 return MOJO_RESULT_INVALID_ARGUMENT;
376 return watcher->Arm(num_blocking_events, blocking_events);
377 }
378
CreateMessage(const MojoCreateMessageOptions * options,MojoMessageHandle * message_handle)379 MojoResult Core::CreateMessage(const MojoCreateMessageOptions* options,
380 MojoMessageHandle* message_handle) {
381 if (!message_handle)
382 return MOJO_RESULT_INVALID_ARGUMENT;
383 if (options && options->struct_size < sizeof(*options))
384 return MOJO_RESULT_INVALID_ARGUMENT;
385 *message_handle = reinterpret_cast<MojoMessageHandle>(
386 UserMessageImpl::CreateEventForNewMessage().release());
387 return MOJO_RESULT_OK;
388 }
389
DestroyMessage(MojoMessageHandle message_handle)390 MojoResult Core::DestroyMessage(MojoMessageHandle message_handle) {
391 if (!message_handle)
392 return MOJO_RESULT_INVALID_ARGUMENT;
393
394 RequestContext request_context;
395 delete reinterpret_cast<ports::UserMessageEvent*>(message_handle);
396 return MOJO_RESULT_OK;
397 }
398
SerializeMessage(MojoMessageHandle message_handle,const MojoSerializeMessageOptions * options)399 MojoResult Core::SerializeMessage(MojoMessageHandle message_handle,
400 const MojoSerializeMessageOptions* options) {
401 if (!message_handle)
402 return MOJO_RESULT_INVALID_ARGUMENT;
403 if (options && options->struct_size < sizeof(*options))
404 return MOJO_RESULT_INVALID_ARGUMENT;
405 RequestContext request_context;
406 return reinterpret_cast<ports::UserMessageEvent*>(message_handle)
407 ->GetMessage<UserMessageImpl>()
408 ->SerializeIfNecessary();
409 }
410
AppendMessageData(MojoMessageHandle message_handle,uint32_t additional_payload_size,const MojoHandle * handles,uint32_t num_handles,const MojoAppendMessageDataOptions * options,void ** buffer,uint32_t * buffer_size)411 MojoResult Core::AppendMessageData(MojoMessageHandle message_handle,
412 uint32_t additional_payload_size,
413 const MojoHandle* handles,
414 uint32_t num_handles,
415 const MojoAppendMessageDataOptions* options,
416 void** buffer,
417 uint32_t* buffer_size) {
418 if (!message_handle || (num_handles && !handles))
419 return MOJO_RESULT_INVALID_ARGUMENT;
420 if (options && options->struct_size < sizeof(*options))
421 return MOJO_RESULT_INVALID_ARGUMENT;
422
423 RequestContext request_context;
424 auto* message = reinterpret_cast<ports::UserMessageEvent*>(message_handle)
425 ->GetMessage<UserMessageImpl>();
426 MojoResult rv =
427 message->AppendData(additional_payload_size, handles, num_handles);
428 if (rv != MOJO_RESULT_OK)
429 return rv;
430
431 if (options && (options->flags & MOJO_APPEND_MESSAGE_DATA_FLAG_COMMIT_SIZE)) {
432 RequestContext request_context;
433 message->CommitSize();
434 }
435
436 if (buffer)
437 *buffer = message->user_payload();
438 if (buffer_size) {
439 *buffer_size =
440 base::checked_cast<uint32_t>(message->user_payload_capacity());
441 }
442 return MOJO_RESULT_OK;
443 }
444
GetMessageData(MojoMessageHandle message_handle,const MojoGetMessageDataOptions * options,void ** buffer,uint32_t * num_bytes,MojoHandle * handles,uint32_t * num_handles)445 MojoResult Core::GetMessageData(MojoMessageHandle message_handle,
446 const MojoGetMessageDataOptions* options,
447 void** buffer,
448 uint32_t* num_bytes,
449 MojoHandle* handles,
450 uint32_t* num_handles) {
451 if (!message_handle || (num_handles && *num_handles && !handles))
452 return MOJO_RESULT_INVALID_ARGUMENT;
453 if (options && options->struct_size < sizeof(*options))
454 return MOJO_RESULT_INVALID_ARGUMENT;
455
456 auto* message = reinterpret_cast<ports::UserMessageEvent*>(message_handle)
457 ->GetMessage<UserMessageImpl>();
458 if (!message->IsSerialized() || !message->IsTransmittable())
459 return MOJO_RESULT_FAILED_PRECONDITION;
460
461 if (num_bytes) {
462 base::CheckedNumeric<uint32_t> payload_size = message->user_payload_size();
463 *num_bytes = payload_size.ValueOrDie();
464 }
465
466 if (message->user_payload_size() > 0) {
467 if (!num_bytes || !buffer)
468 return MOJO_RESULT_RESOURCE_EXHAUSTED;
469
470 *buffer = message->user_payload();
471 } else if (buffer) {
472 *buffer = nullptr;
473 }
474
475 if (options && (options->flags & MOJO_GET_MESSAGE_DATA_FLAG_IGNORE_HANDLES))
476 return MOJO_RESULT_OK;
477
478 uint32_t max_num_handles = 0;
479 if (num_handles) {
480 max_num_handles = *num_handles;
481 *num_handles = static_cast<uint32_t>(message->num_handles());
482 }
483
484 if (message->num_handles() > max_num_handles ||
485 message->num_handles() > kMaxHandlesPerMessage) {
486 return MOJO_RESULT_RESOURCE_EXHAUSTED;
487 }
488
489 RequestContext request_context;
490 return message->ExtractSerializedHandles(
491 UserMessageImpl::ExtractBadHandlePolicy::kAbort, handles);
492 }
493
SetMessageContext(MojoMessageHandle message_handle,uintptr_t context,MojoMessageContextSerializer serializer,MojoMessageContextDestructor destructor,const MojoSetMessageContextOptions * options)494 MojoResult Core::SetMessageContext(
495 MojoMessageHandle message_handle,
496 uintptr_t context,
497 MojoMessageContextSerializer serializer,
498 MojoMessageContextDestructor destructor,
499 const MojoSetMessageContextOptions* options) {
500 if (!message_handle)
501 return MOJO_RESULT_INVALID_ARGUMENT;
502 if (options && options->struct_size < sizeof(*options))
503 return MOJO_RESULT_INVALID_ARGUMENT;
504 auto* message = reinterpret_cast<ports::UserMessageEvent*>(message_handle)
505 ->GetMessage<UserMessageImpl>();
506 return message->SetContext(context, serializer, destructor);
507 }
508
GetMessageContext(MojoMessageHandle message_handle,const MojoGetMessageContextOptions * options,uintptr_t * context)509 MojoResult Core::GetMessageContext(MojoMessageHandle message_handle,
510 const MojoGetMessageContextOptions* options,
511 uintptr_t* context) {
512 if (!message_handle)
513 return MOJO_RESULT_INVALID_ARGUMENT;
514 if (options && options->struct_size < sizeof(*options))
515 return MOJO_RESULT_INVALID_ARGUMENT;
516
517 auto* message = reinterpret_cast<ports::UserMessageEvent*>(message_handle)
518 ->GetMessage<UserMessageImpl>();
519 if (!message->HasContext())
520 return MOJO_RESULT_NOT_FOUND;
521
522 *context = message->context();
523 return MOJO_RESULT_OK;
524 }
525
CreateMessagePipe(const MojoCreateMessagePipeOptions * options,MojoHandle * message_pipe_handle0,MojoHandle * message_pipe_handle1)526 MojoResult Core::CreateMessagePipe(const MojoCreateMessagePipeOptions* options,
527 MojoHandle* message_pipe_handle0,
528 MojoHandle* message_pipe_handle1) {
529 RequestContext request_context;
530 ports::PortRef port0, port1;
531 GetNodeController()->node()->CreatePortPair(&port0, &port1);
532
533 DCHECK(message_pipe_handle0);
534 DCHECK(message_pipe_handle1);
535
536 uint64_t pipe_id = base::RandUint64();
537
538 *message_pipe_handle0 = AddDispatcher(
539 new MessagePipeDispatcher(GetNodeController(), port0, pipe_id, 0));
540 if (*message_pipe_handle0 == MOJO_HANDLE_INVALID)
541 return MOJO_RESULT_RESOURCE_EXHAUSTED;
542
543 *message_pipe_handle1 = AddDispatcher(
544 new MessagePipeDispatcher(GetNodeController(), port1, pipe_id, 1));
545 if (*message_pipe_handle1 == MOJO_HANDLE_INVALID) {
546 scoped_refptr<Dispatcher> dispatcher0;
547 {
548 base::AutoLock lock(handles_->GetLock());
549 handles_->GetAndRemoveDispatcher(*message_pipe_handle0, &dispatcher0);
550 }
551 dispatcher0->Close();
552 return MOJO_RESULT_RESOURCE_EXHAUSTED;
553 }
554
555 return MOJO_RESULT_OK;
556 }
557
WriteMessage(MojoHandle message_pipe_handle,MojoMessageHandle message_handle,const MojoWriteMessageOptions * options)558 MojoResult Core::WriteMessage(MojoHandle message_pipe_handle,
559 MojoMessageHandle message_handle,
560 const MojoWriteMessageOptions* options) {
561 RequestContext request_context;
562 if (!message_handle)
563 return MOJO_RESULT_INVALID_ARGUMENT;
564 auto message_event = base::WrapUnique(
565 reinterpret_cast<ports::UserMessageEvent*>(message_handle));
566 auto* message = message_event->GetMessage<UserMessageImpl>();
567 if (!message || !message->IsTransmittable())
568 return MOJO_RESULT_INVALID_ARGUMENT;
569 auto dispatcher = GetDispatcher(message_pipe_handle);
570 if (!dispatcher)
571 return MOJO_RESULT_INVALID_ARGUMENT;
572 return dispatcher->WriteMessage(std::move(message_event));
573 }
574
ReadMessage(MojoHandle message_pipe_handle,const MojoReadMessageOptions * options,MojoMessageHandle * message_handle)575 MojoResult Core::ReadMessage(MojoHandle message_pipe_handle,
576 const MojoReadMessageOptions* options,
577 MojoMessageHandle* message_handle) {
578 RequestContext request_context;
579 auto dispatcher = GetDispatcher(message_pipe_handle);
580 if (!dispatcher || !message_handle)
581 return MOJO_RESULT_INVALID_ARGUMENT;
582
583 std::unique_ptr<ports::UserMessageEvent> message_event;
584 MojoResult rv = dispatcher->ReadMessage(&message_event);
585 if (rv != MOJO_RESULT_OK)
586 return rv;
587
588 *message_handle =
589 reinterpret_cast<MojoMessageHandle>(message_event.release());
590 return MOJO_RESULT_OK;
591 }
592
FuseMessagePipes(MojoHandle handle0,MojoHandle handle1,const MojoFuseMessagePipesOptions * options)593 MojoResult Core::FuseMessagePipes(MojoHandle handle0,
594 MojoHandle handle1,
595 const MojoFuseMessagePipesOptions* options) {
596 RequestContext request_context;
597 scoped_refptr<Dispatcher> dispatcher0;
598 scoped_refptr<Dispatcher> dispatcher1;
599
600 bool valid_handles = true;
601 {
602 base::AutoLock lock(handles_->GetLock());
603 MojoResult result0 =
604 handles_->GetAndRemoveDispatcher(handle0, &dispatcher0);
605 MojoResult result1 =
606 handles_->GetAndRemoveDispatcher(handle1, &dispatcher1);
607 if (result0 != MOJO_RESULT_OK || result1 != MOJO_RESULT_OK ||
608 dispatcher0->GetType() != Dispatcher::Type::MESSAGE_PIPE ||
609 dispatcher1->GetType() != Dispatcher::Type::MESSAGE_PIPE)
610 valid_handles = false;
611 }
612
613 if (!valid_handles) {
614 if (dispatcher0)
615 dispatcher0->Close();
616 if (dispatcher1)
617 dispatcher1->Close();
618 return MOJO_RESULT_INVALID_ARGUMENT;
619 }
620
621 MessagePipeDispatcher* mpd0 =
622 static_cast<MessagePipeDispatcher*>(dispatcher0.get());
623 MessagePipeDispatcher* mpd1 =
624 static_cast<MessagePipeDispatcher*>(dispatcher1.get());
625
626 if (!mpd0->Fuse(mpd1))
627 return MOJO_RESULT_FAILED_PRECONDITION;
628
629 return MOJO_RESULT_OK;
630 }
631
NotifyBadMessage(MojoMessageHandle message_handle,const char * error,size_t error_num_bytes,const MojoNotifyBadMessageOptions * options)632 MojoResult Core::NotifyBadMessage(MojoMessageHandle message_handle,
633 const char* error,
634 size_t error_num_bytes,
635 const MojoNotifyBadMessageOptions* options) {
636 if (!message_handle)
637 return MOJO_RESULT_INVALID_ARGUMENT;
638
639 auto* message_event =
640 reinterpret_cast<ports::UserMessageEvent*>(message_handle);
641 auto* message = message_event->GetMessage<UserMessageImpl>();
642 if (message->source_node() == ports::kInvalidNodeName) {
643 DVLOG(1) << "Received invalid message from unknown node.";
644 if (!default_process_error_callback_.is_null())
645 default_process_error_callback_.Run(std::string(error, error_num_bytes));
646 return MOJO_RESULT_OK;
647 }
648
649 GetNodeController()->NotifyBadMessageFrom(
650 message->source_node(), std::string(error, error_num_bytes));
651 return MOJO_RESULT_OK;
652 }
653
CreateDataPipe(const MojoCreateDataPipeOptions * options,MojoHandle * data_pipe_producer_handle,MojoHandle * data_pipe_consumer_handle)654 MojoResult Core::CreateDataPipe(const MojoCreateDataPipeOptions* options,
655 MojoHandle* data_pipe_producer_handle,
656 MojoHandle* data_pipe_consumer_handle) {
657 RequestContext request_context;
658 if (options && options->struct_size < sizeof(MojoCreateDataPipeOptions))
659 return MOJO_RESULT_INVALID_ARGUMENT;
660
661 MojoCreateDataPipeOptions create_options;
662 create_options.struct_size = sizeof(MojoCreateDataPipeOptions);
663 create_options.flags = options ? options->flags : 0;
664 create_options.element_num_bytes = options ? options->element_num_bytes : 1;
665 // TODO(rockot): Use Configuration to get default data pipe capacity.
666 create_options.capacity_num_bytes = options && options->capacity_num_bytes
667 ? options->capacity_num_bytes
668 : 64 * 1024;
669 if (!create_options.element_num_bytes || !create_options.capacity_num_bytes ||
670 create_options.capacity_num_bytes < create_options.element_num_bytes) {
671 return MOJO_RESULT_INVALID_ARGUMENT;
672 }
673
674 base::subtle::PlatformSharedMemoryRegion ring_buffer_region =
675 base::WritableSharedMemoryRegion::TakeHandleForSerialization(
676 GetNodeController()->CreateSharedBuffer(
677 create_options.capacity_num_bytes));
678
679 // NOTE: We demote the writable region to an unsafe region so that the
680 // producer handle can be transferred freely. There is no compelling reason
681 // to restrict access rights of consumers since they are the exclusive
682 // consumer of this pipe, and it would be impossible to support such access
683 // control on Android anyway.
684 auto writable_region_handle = ring_buffer_region.PassPlatformHandle();
685 #if defined(OS_POSIX) && !defined(OS_ANDROID) && \
686 (!defined(OS_MACOSX) || defined(OS_IOS))
687 // This isn't strictly necessary, but it does make the handle configuration
688 // consistent with regular UnsafeSharedMemoryRegions.
689 writable_region_handle.readonly_fd.reset();
690 #endif
691 base::UnsafeSharedMemoryRegion producer_region =
692 base::UnsafeSharedMemoryRegion::Deserialize(
693 base::subtle::PlatformSharedMemoryRegion::Take(
694 std::move(writable_region_handle),
695 base::subtle::PlatformSharedMemoryRegion::Mode::kUnsafe,
696 create_options.capacity_num_bytes, ring_buffer_region.GetGUID()));
697 if (!producer_region.IsValid())
698 return MOJO_RESULT_RESOURCE_EXHAUSTED;
699
700 ports::PortRef port0, port1;
701 GetNodeController()->node()->CreatePortPair(&port0, &port1);
702
703 DCHECK(data_pipe_producer_handle);
704 DCHECK(data_pipe_consumer_handle);
705
706 base::UnsafeSharedMemoryRegion consumer_region = producer_region.Duplicate();
707 uint64_t pipe_id = base::RandUint64();
708 scoped_refptr<Dispatcher> producer = DataPipeProducerDispatcher::Create(
709 GetNodeController(), port0, std::move(producer_region), create_options,
710 pipe_id);
711 if (!producer)
712 return MOJO_RESULT_RESOURCE_EXHAUSTED;
713
714 scoped_refptr<Dispatcher> consumer = DataPipeConsumerDispatcher::Create(
715 GetNodeController(), port1, std::move(consumer_region), create_options,
716 pipe_id);
717 if (!consumer) {
718 producer->Close();
719 return MOJO_RESULT_RESOURCE_EXHAUSTED;
720 }
721
722 *data_pipe_producer_handle = AddDispatcher(producer);
723 *data_pipe_consumer_handle = AddDispatcher(consumer);
724 if (*data_pipe_producer_handle == MOJO_HANDLE_INVALID ||
725 *data_pipe_consumer_handle == MOJO_HANDLE_INVALID) {
726 if (*data_pipe_producer_handle != MOJO_HANDLE_INVALID) {
727 scoped_refptr<Dispatcher> unused;
728 base::AutoLock lock(handles_->GetLock());
729 handles_->GetAndRemoveDispatcher(*data_pipe_producer_handle, &unused);
730 }
731 producer->Close();
732 consumer->Close();
733 return MOJO_RESULT_RESOURCE_EXHAUSTED;
734 }
735
736 return MOJO_RESULT_OK;
737 }
738
WriteData(MojoHandle data_pipe_producer_handle,const void * elements,uint32_t * num_bytes,const MojoWriteDataOptions * options)739 MojoResult Core::WriteData(MojoHandle data_pipe_producer_handle,
740 const void* elements,
741 uint32_t* num_bytes,
742 const MojoWriteDataOptions* options) {
743 RequestContext request_context;
744 scoped_refptr<Dispatcher> dispatcher(
745 GetDispatcher(data_pipe_producer_handle));
746 if (!dispatcher)
747 return MOJO_RESULT_INVALID_ARGUMENT;
748
749 MojoWriteDataOptions validated_options;
750 if (options) {
751 if (options->struct_size < sizeof(*options))
752 return MOJO_RESULT_INVALID_ARGUMENT;
753
754 constexpr MojoWriteDataFlags kSupportedFlags =
755 MOJO_WRITE_DATA_FLAG_NONE | MOJO_WRITE_DATA_FLAG_ALL_OR_NONE;
756 if (options->flags & ~kSupportedFlags)
757 return MOJO_RESULT_UNIMPLEMENTED;
758 validated_options.flags = options->flags;
759 } else {
760 validated_options.flags = MOJO_WRITE_DATA_FLAG_NONE;
761 }
762 return dispatcher->WriteData(elements, num_bytes, validated_options);
763 }
764
BeginWriteData(MojoHandle data_pipe_producer_handle,const MojoBeginWriteDataOptions * options,void ** buffer,uint32_t * buffer_num_bytes)765 MojoResult Core::BeginWriteData(MojoHandle data_pipe_producer_handle,
766 const MojoBeginWriteDataOptions* options,
767 void** buffer,
768 uint32_t* buffer_num_bytes) {
769 RequestContext request_context;
770 scoped_refptr<Dispatcher> dispatcher(
771 GetDispatcher(data_pipe_producer_handle));
772 if (!dispatcher)
773 return MOJO_RESULT_INVALID_ARGUMENT;
774 if (options) {
775 if (options->struct_size < sizeof(*options))
776 return MOJO_RESULT_INVALID_ARGUMENT;
777 if (options->flags != MOJO_BEGIN_WRITE_DATA_FLAG_NONE)
778 return MOJO_RESULT_UNIMPLEMENTED;
779 }
780 return dispatcher->BeginWriteData(buffer, buffer_num_bytes);
781 }
782
EndWriteData(MojoHandle data_pipe_producer_handle,uint32_t num_bytes_written,const MojoEndWriteDataOptions * options)783 MojoResult Core::EndWriteData(MojoHandle data_pipe_producer_handle,
784 uint32_t num_bytes_written,
785 const MojoEndWriteDataOptions* options) {
786 RequestContext request_context;
787 scoped_refptr<Dispatcher> dispatcher(
788 GetDispatcher(data_pipe_producer_handle));
789 if (!dispatcher)
790 return MOJO_RESULT_INVALID_ARGUMENT;
791 if (options) {
792 if (options->struct_size < sizeof(*options))
793 return MOJO_RESULT_INVALID_ARGUMENT;
794 if (options->flags != MOJO_END_WRITE_DATA_FLAG_NONE)
795 return MOJO_RESULT_UNIMPLEMENTED;
796 }
797 return dispatcher->EndWriteData(num_bytes_written);
798 }
799
ReadData(MojoHandle data_pipe_consumer_handle,const MojoReadDataOptions * options,void * elements,uint32_t * num_bytes)800 MojoResult Core::ReadData(MojoHandle data_pipe_consumer_handle,
801 const MojoReadDataOptions* options,
802 void* elements,
803 uint32_t* num_bytes) {
804 RequestContext request_context;
805 scoped_refptr<Dispatcher> dispatcher(
806 GetDispatcher(data_pipe_consumer_handle));
807 if (!dispatcher)
808 return MOJO_RESULT_INVALID_ARGUMENT;
809
810 MojoReadDataOptions validated_options;
811 if (options) {
812 if (options->struct_size < sizeof(*options))
813 return MOJO_RESULT_INVALID_ARGUMENT;
814
815 constexpr MojoReadDataFlags kSupportedFlags =
816 MOJO_READ_DATA_FLAG_NONE | MOJO_READ_DATA_FLAG_ALL_OR_NONE |
817 MOJO_READ_DATA_FLAG_DISCARD | MOJO_READ_DATA_FLAG_QUERY |
818 MOJO_READ_DATA_FLAG_PEEK;
819 if (options->flags & ~kSupportedFlags)
820 return MOJO_RESULT_UNIMPLEMENTED;
821 validated_options.flags = options->flags;
822 } else {
823 validated_options.flags = MOJO_WRITE_DATA_FLAG_NONE;
824 }
825 return dispatcher->ReadData(validated_options, elements, num_bytes);
826 }
827
BeginReadData(MojoHandle data_pipe_consumer_handle,const MojoBeginReadDataOptions * options,const void ** buffer,uint32_t * buffer_num_bytes)828 MojoResult Core::BeginReadData(MojoHandle data_pipe_consumer_handle,
829 const MojoBeginReadDataOptions* options,
830 const void** buffer,
831 uint32_t* buffer_num_bytes) {
832 RequestContext request_context;
833 scoped_refptr<Dispatcher> dispatcher(
834 GetDispatcher(data_pipe_consumer_handle));
835 if (!dispatcher)
836 return MOJO_RESULT_INVALID_ARGUMENT;
837
838 if (options) {
839 if (options->struct_size < sizeof(*options))
840 return MOJO_RESULT_INVALID_ARGUMENT;
841 if (options->flags != MOJO_BEGIN_READ_DATA_FLAG_NONE)
842 return MOJO_RESULT_UNIMPLEMENTED;
843 }
844 return dispatcher->BeginReadData(buffer, buffer_num_bytes);
845 }
846
EndReadData(MojoHandle data_pipe_consumer_handle,uint32_t num_bytes_read,const MojoEndReadDataOptions * options)847 MojoResult Core::EndReadData(MojoHandle data_pipe_consumer_handle,
848 uint32_t num_bytes_read,
849 const MojoEndReadDataOptions* options) {
850 RequestContext request_context;
851 scoped_refptr<Dispatcher> dispatcher(
852 GetDispatcher(data_pipe_consumer_handle));
853 if (!dispatcher)
854 return MOJO_RESULT_INVALID_ARGUMENT;
855 if (options) {
856 if (options->struct_size < sizeof(*options))
857 return MOJO_RESULT_INVALID_ARGUMENT;
858 if (options->flags != MOJO_END_READ_DATA_FLAG_NONE)
859 return MOJO_RESULT_UNIMPLEMENTED;
860 }
861 return dispatcher->EndReadData(num_bytes_read);
862 }
863
CreateSharedBuffer(uint64_t num_bytes,const MojoCreateSharedBufferOptions * options,MojoHandle * shared_buffer_handle)864 MojoResult Core::CreateSharedBuffer(
865 uint64_t num_bytes,
866 const MojoCreateSharedBufferOptions* options,
867 MojoHandle* shared_buffer_handle) {
868 RequestContext request_context;
869 MojoCreateSharedBufferOptions validated_options = {};
870 MojoResult result = SharedBufferDispatcher::ValidateCreateOptions(
871 options, &validated_options);
872 if (result != MOJO_RESULT_OK)
873 return result;
874
875 scoped_refptr<SharedBufferDispatcher> dispatcher;
876 result = SharedBufferDispatcher::Create(
877 validated_options, GetNodeController(), num_bytes, &dispatcher);
878 if (result != MOJO_RESULT_OK) {
879 DCHECK(!dispatcher);
880 return result;
881 }
882
883 *shared_buffer_handle = AddDispatcher(dispatcher);
884 if (*shared_buffer_handle == MOJO_HANDLE_INVALID) {
885 LOG(ERROR) << "Handle table full";
886 dispatcher->Close();
887 return MOJO_RESULT_RESOURCE_EXHAUSTED;
888 }
889
890 return MOJO_RESULT_OK;
891 }
892
DuplicateBufferHandle(MojoHandle buffer_handle,const MojoDuplicateBufferHandleOptions * options,MojoHandle * new_buffer_handle)893 MojoResult Core::DuplicateBufferHandle(
894 MojoHandle buffer_handle,
895 const MojoDuplicateBufferHandleOptions* options,
896 MojoHandle* new_buffer_handle) {
897 RequestContext request_context;
898 scoped_refptr<Dispatcher> dispatcher(GetDispatcher(buffer_handle));
899 if (!dispatcher)
900 return MOJO_RESULT_INVALID_ARGUMENT;
901
902 // Don't verify |options| here; that's the dispatcher's job.
903 scoped_refptr<Dispatcher> new_dispatcher;
904 MojoResult result =
905 dispatcher->DuplicateBufferHandle(options, &new_dispatcher);
906 if (result != MOJO_RESULT_OK)
907 return result;
908
909 *new_buffer_handle = AddDispatcher(new_dispatcher);
910 if (*new_buffer_handle == MOJO_HANDLE_INVALID) {
911 LOG(ERROR) << "Handle table full";
912 new_dispatcher->Close();
913 return MOJO_RESULT_RESOURCE_EXHAUSTED;
914 }
915
916 return MOJO_RESULT_OK;
917 }
918
MapBuffer(MojoHandle buffer_handle,uint64_t offset,uint64_t num_bytes,const MojoMapBufferOptions * options,void ** buffer)919 MojoResult Core::MapBuffer(MojoHandle buffer_handle,
920 uint64_t offset,
921 uint64_t num_bytes,
922 const MojoMapBufferOptions* options,
923 void** buffer) {
924 scoped_refptr<Dispatcher> dispatcher(GetDispatcher(buffer_handle));
925 if (!dispatcher)
926 return MOJO_RESULT_INVALID_ARGUMENT;
927 if (options) {
928 if (options->struct_size < sizeof(*options))
929 return MOJO_RESULT_INVALID_ARGUMENT;
930 if (options->flags != MOJO_MAP_BUFFER_FLAG_NONE)
931 return MOJO_RESULT_UNIMPLEMENTED;
932 }
933
934 std::unique_ptr<PlatformSharedMemoryMapping> mapping;
935 MojoResult result = dispatcher->MapBuffer(offset, num_bytes, &mapping);
936 if (result != MOJO_RESULT_OK)
937 return result;
938
939 DCHECK(mapping);
940 void* address = mapping->GetBase();
941 {
942 base::AutoLock locker(mapping_table_lock_);
943 if (mapping_table_.size() >= GetConfiguration().max_mapping_table_size)
944 return MOJO_RESULT_RESOURCE_EXHAUSTED;
945 auto emplace_result = mapping_table_.emplace(address, std::move(mapping));
946 DCHECK(emplace_result.second);
947 }
948
949 *buffer = address;
950 return MOJO_RESULT_OK;
951 }
952
UnmapBuffer(void * buffer)953 MojoResult Core::UnmapBuffer(void* buffer) {
954 std::unique_ptr<PlatformSharedMemoryMapping> mapping;
955 // Destroy |mapping| while not holding the lock.
956 {
957 base::AutoLock lock(mapping_table_lock_);
958 auto iter = mapping_table_.find(buffer);
959 if (iter == mapping_table_.end())
960 return MOJO_RESULT_INVALID_ARGUMENT;
961
962 // Grab a reference so that it gets unmapped outside of this lock.
963 mapping = std::move(iter->second);
964 mapping_table_.erase(iter);
965 }
966 return MOJO_RESULT_OK;
967 }
968
GetBufferInfo(MojoHandle buffer_handle,const MojoGetBufferInfoOptions * options,MojoSharedBufferInfo * info)969 MojoResult Core::GetBufferInfo(MojoHandle buffer_handle,
970 const MojoGetBufferInfoOptions* options,
971 MojoSharedBufferInfo* info) {
972 if (options) {
973 if (options->struct_size < sizeof(*options))
974 return MOJO_RESULT_INVALID_ARGUMENT;
975 if (options->flags != MOJO_GET_BUFFER_INFO_FLAG_NONE)
976 return MOJO_RESULT_UNIMPLEMENTED;
977 }
978 if (!info || info->struct_size < sizeof(MojoSharedBufferInfo))
979 return MOJO_RESULT_INVALID_ARGUMENT;
980
981 scoped_refptr<Dispatcher> dispatcher(GetDispatcher(buffer_handle));
982 if (!dispatcher)
983 return MOJO_RESULT_INVALID_ARGUMENT;
984
985 return dispatcher->GetBufferInfo(info);
986 }
987
WrapPlatformHandle(const MojoPlatformHandle * platform_handle,const MojoWrapPlatformHandleOptions * options,MojoHandle * mojo_handle)988 MojoResult Core::WrapPlatformHandle(
989 const MojoPlatformHandle* platform_handle,
990 const MojoWrapPlatformHandleOptions* options,
991 MojoHandle* mojo_handle) {
992 if (!platform_handle ||
993 platform_handle->struct_size < sizeof(*platform_handle)) {
994 return MOJO_RESULT_INVALID_ARGUMENT;
995 }
996
997 auto handle = PlatformHandle::FromMojoPlatformHandle(platform_handle);
998 MojoHandle h =
999 AddDispatcher(PlatformHandleDispatcher::Create(std::move(handle)));
1000 if (h == MOJO_HANDLE_INVALID)
1001 return MOJO_RESULT_RESOURCE_EXHAUSTED;
1002
1003 *mojo_handle = h;
1004 return MOJO_RESULT_OK;
1005 }
1006
UnwrapPlatformHandle(MojoHandle mojo_handle,const MojoUnwrapPlatformHandleOptions * options,MojoPlatformHandle * platform_handle)1007 MojoResult Core::UnwrapPlatformHandle(
1008 MojoHandle mojo_handle,
1009 const MojoUnwrapPlatformHandleOptions* options,
1010 MojoPlatformHandle* platform_handle) {
1011 if (!platform_handle ||
1012 platform_handle->struct_size < sizeof(*platform_handle)) {
1013 return MOJO_RESULT_INVALID_ARGUMENT;
1014 }
1015
1016 scoped_refptr<Dispatcher> dispatcher;
1017 {
1018 base::AutoLock lock(handles_->GetLock());
1019 dispatcher = handles_->GetDispatcher(mojo_handle);
1020 if (dispatcher->GetType() != Dispatcher::Type::PLATFORM_HANDLE)
1021 return MOJO_RESULT_INVALID_ARGUMENT;
1022
1023 MojoResult result =
1024 handles_->GetAndRemoveDispatcher(mojo_handle, &dispatcher);
1025 if (result != MOJO_RESULT_OK)
1026 return result;
1027 }
1028
1029 PlatformHandleDispatcher* phd =
1030 static_cast<PlatformHandleDispatcher*>(dispatcher.get());
1031 PlatformHandle handle = phd->TakePlatformHandle();
1032 phd->Close();
1033
1034 PlatformHandle::ToMojoPlatformHandle(std::move(handle), platform_handle);
1035 return MOJO_RESULT_OK;
1036 }
1037
WrapPlatformSharedMemoryRegion(const MojoPlatformHandle * platform_handles,uint32_t num_platform_handles,uint64_t size,const MojoSharedBufferGuid * guid,MojoPlatformSharedMemoryRegionAccessMode access_mode,const MojoWrapPlatformSharedMemoryRegionOptions * options,MojoHandle * mojo_handle)1038 MojoResult Core::WrapPlatformSharedMemoryRegion(
1039 const MojoPlatformHandle* platform_handles,
1040 uint32_t num_platform_handles,
1041 uint64_t size,
1042 const MojoSharedBufferGuid* guid,
1043 MojoPlatformSharedMemoryRegionAccessMode access_mode,
1044 const MojoWrapPlatformSharedMemoryRegionOptions* options,
1045 MojoHandle* mojo_handle) {
1046 DCHECK(size);
1047
1048 #if defined(OS_POSIX) && !defined(OS_ANDROID) && \
1049 (!defined(OS_MACOSX) || defined(OS_IOS))
1050 if (access_mode == MOJO_PLATFORM_SHARED_MEMORY_REGION_ACCESS_MODE_WRITABLE) {
1051 if (num_platform_handles != 2)
1052 return MOJO_RESULT_INVALID_ARGUMENT;
1053 }
1054 #else
1055 if (num_platform_handles != 1)
1056 return MOJO_RESULT_INVALID_ARGUMENT;
1057 #endif
1058
1059 PlatformHandle handles[2];
1060 bool handles_ok = true;
1061 for (size_t i = 0; i < num_platform_handles; ++i) {
1062 handles[i] = PlatformHandle::FromMojoPlatformHandle(&platform_handles[i]);
1063 if (!handles[i].is_valid())
1064 handles_ok = false;
1065 }
1066 if (!handles_ok)
1067 return MOJO_RESULT_INVALID_ARGUMENT;
1068
1069 base::UnguessableToken token =
1070 base::UnguessableToken::Deserialize(guid->high, guid->low);
1071
1072 base::subtle::PlatformSharedMemoryRegion::Mode mode;
1073 switch (access_mode) {
1074 case MOJO_PLATFORM_SHARED_MEMORY_REGION_ACCESS_MODE_READ_ONLY:
1075 mode = base::subtle::PlatformSharedMemoryRegion::Mode::kReadOnly;
1076 break;
1077 case MOJO_PLATFORM_SHARED_MEMORY_REGION_ACCESS_MODE_WRITABLE:
1078 mode = base::subtle::PlatformSharedMemoryRegion::Mode::kWritable;
1079 break;
1080 case MOJO_PLATFORM_SHARED_MEMORY_REGION_ACCESS_MODE_UNSAFE:
1081 mode = base::subtle::PlatformSharedMemoryRegion::Mode::kUnsafe;
1082 break;
1083 default:
1084 return MOJO_RESULT_INVALID_ARGUMENT;
1085 }
1086
1087 base::subtle::PlatformSharedMemoryRegion region =
1088 base::subtle::PlatformSharedMemoryRegion::Take(
1089 CreateSharedMemoryRegionHandleFromPlatformHandles(
1090 std::move(handles[0]), std::move(handles[1])),
1091 mode, size, token);
1092 if (!region.IsValid())
1093 return MOJO_RESULT_UNKNOWN;
1094
1095 scoped_refptr<SharedBufferDispatcher> dispatcher;
1096 MojoResult result =
1097 SharedBufferDispatcher::CreateFromPlatformSharedMemoryRegion(
1098 std::move(region), &dispatcher);
1099 if (result != MOJO_RESULT_OK)
1100 return result;
1101
1102 MojoHandle h = AddDispatcher(dispatcher);
1103 if (h == MOJO_HANDLE_INVALID) {
1104 dispatcher->Close();
1105 return MOJO_RESULT_RESOURCE_EXHAUSTED;
1106 }
1107
1108 *mojo_handle = h;
1109 return MOJO_RESULT_OK;
1110 }
1111
UnwrapPlatformSharedMemoryRegion(MojoHandle mojo_handle,const MojoUnwrapPlatformSharedMemoryRegionOptions * options,MojoPlatformHandle * platform_handles,uint32_t * num_platform_handles,uint64_t * size,MojoSharedBufferGuid * guid,MojoPlatformSharedMemoryRegionAccessMode * access_mode)1112 MojoResult Core::UnwrapPlatformSharedMemoryRegion(
1113 MojoHandle mojo_handle,
1114 const MojoUnwrapPlatformSharedMemoryRegionOptions* options,
1115 MojoPlatformHandle* platform_handles,
1116 uint32_t* num_platform_handles,
1117 uint64_t* size,
1118 MojoSharedBufferGuid* guid,
1119 MojoPlatformSharedMemoryRegionAccessMode* access_mode) {
1120 scoped_refptr<Dispatcher> dispatcher;
1121 MojoResult result = MOJO_RESULT_OK;
1122 {
1123 base::AutoLock lock(handles_->GetLock());
1124 result = handles_->GetAndRemoveDispatcher(mojo_handle, &dispatcher);
1125 if (result != MOJO_RESULT_OK)
1126 return result;
1127 }
1128
1129 if (dispatcher->GetType() != Dispatcher::Type::SHARED_BUFFER) {
1130 dispatcher->Close();
1131 return MOJO_RESULT_INVALID_ARGUMENT;
1132 }
1133
1134 SharedBufferDispatcher* shm_dispatcher =
1135 static_cast<SharedBufferDispatcher*>(dispatcher.get());
1136 base::subtle::PlatformSharedMemoryRegion region =
1137 shm_dispatcher->PassPlatformSharedMemoryRegion();
1138 DCHECK(region.IsValid());
1139 DCHECK(size);
1140 *size = region.GetSize();
1141
1142 base::UnguessableToken token = region.GetGUID();
1143 guid->high = token.GetHighForSerialization();
1144 guid->low = token.GetLowForSerialization();
1145
1146 DCHECK(access_mode);
1147 switch (region.GetMode()) {
1148 case base::subtle::PlatformSharedMemoryRegion::Mode::kReadOnly:
1149 *access_mode = MOJO_PLATFORM_SHARED_MEMORY_REGION_ACCESS_MODE_READ_ONLY;
1150 break;
1151 case base::subtle::PlatformSharedMemoryRegion::Mode::kWritable:
1152 *access_mode = MOJO_PLATFORM_SHARED_MEMORY_REGION_ACCESS_MODE_WRITABLE;
1153 break;
1154 case base::subtle::PlatformSharedMemoryRegion::Mode::kUnsafe:
1155 *access_mode = MOJO_PLATFORM_SHARED_MEMORY_REGION_ACCESS_MODE_UNSAFE;
1156 break;
1157 default:
1158 return MOJO_RESULT_INVALID_ARGUMENT;
1159 }
1160
1161 PlatformHandle handle;
1162 PlatformHandle read_only_handle;
1163 ExtractPlatformHandlesFromSharedMemoryRegionHandle(
1164 region.PassPlatformHandle(), &handle, &read_only_handle);
1165
1166 const uint32_t available_handle_storage_slots = *num_platform_handles;
1167 if (available_handle_storage_slots < 1)
1168 return MOJO_RESULT_RESOURCE_EXHAUSTED;
1169 *num_platform_handles = 1;
1170 #if defined(OS_POSIX) && !defined(OS_ANDROID) && \
1171 (!defined(OS_MACOSX) || defined(OS_IOS))
1172 if (region.GetMode() ==
1173 base::subtle::PlatformSharedMemoryRegion::Mode::kWritable) {
1174 if (available_handle_storage_slots < 2)
1175 return MOJO_RESULT_INVALID_ARGUMENT;
1176 PlatformHandle::ToMojoPlatformHandle(std::move(read_only_handle),
1177 &platform_handles[1]);
1178 if (platform_handles[1].type == MOJO_PLATFORM_HANDLE_TYPE_INVALID)
1179 return MOJO_RESULT_INVALID_ARGUMENT;
1180 *num_platform_handles = 2;
1181 }
1182 #endif
1183
1184 PlatformHandle::ToMojoPlatformHandle(std::move(handle), &platform_handles[0]);
1185 if (platform_handles[0].type == MOJO_PLATFORM_HANDLE_TYPE_INVALID)
1186 return MOJO_RESULT_INVALID_ARGUMENT;
1187
1188 return MOJO_RESULT_OK;
1189 }
1190
CreateInvitation(const MojoCreateInvitationOptions * options,MojoHandle * invitation_handle)1191 MojoResult Core::CreateInvitation(const MojoCreateInvitationOptions* options,
1192 MojoHandle* invitation_handle) {
1193 if (options && options->struct_size < sizeof(*options))
1194 return MOJO_RESULT_INVALID_ARGUMENT;
1195 if (!invitation_handle)
1196 return MOJO_RESULT_INVALID_ARGUMENT;
1197
1198 *invitation_handle = AddDispatcher(new InvitationDispatcher);
1199 if (*invitation_handle == MOJO_HANDLE_INVALID)
1200 return MOJO_RESULT_RESOURCE_EXHAUSTED;
1201
1202 return MOJO_RESULT_OK;
1203 }
1204
AttachMessagePipeToInvitation(MojoHandle invitation_handle,const void * name,uint32_t name_num_bytes,const MojoAttachMessagePipeToInvitationOptions * options,MojoHandle * message_pipe_handle)1205 MojoResult Core::AttachMessagePipeToInvitation(
1206 MojoHandle invitation_handle,
1207 const void* name,
1208 uint32_t name_num_bytes,
1209 const MojoAttachMessagePipeToInvitationOptions* options,
1210 MojoHandle* message_pipe_handle) {
1211 if (options && options->struct_size < sizeof(*options))
1212 return MOJO_RESULT_INVALID_ARGUMENT;
1213 if (!message_pipe_handle)
1214 return MOJO_RESULT_INVALID_ARGUMENT;
1215 if (name_num_bytes == 0)
1216 return MOJO_RESULT_INVALID_ARGUMENT;
1217
1218 scoped_refptr<Dispatcher> dispatcher = GetDispatcher(invitation_handle);
1219 if (!dispatcher || dispatcher->GetType() != Dispatcher::Type::INVITATION)
1220 return MOJO_RESULT_INVALID_ARGUMENT;
1221 auto* invitation_dispatcher =
1222 static_cast<InvitationDispatcher*>(dispatcher.get());
1223
1224 RequestContext request_context;
1225
1226 ports::PortRef remote_peer_port;
1227 MojoHandle local_handle = CreatePartialMessagePipe(&remote_peer_port);
1228 if (local_handle == MOJO_HANDLE_INVALID)
1229 return MOJO_RESULT_RESOURCE_EXHAUSTED;
1230
1231 MojoResult result = invitation_dispatcher->AttachMessagePipe(
1232 base::StringPiece(static_cast<const char*>(name), name_num_bytes),
1233 std::move(remote_peer_port));
1234 if (result != MOJO_RESULT_OK) {
1235 Close(local_handle);
1236 return result;
1237 }
1238
1239 *message_pipe_handle = local_handle;
1240 return MOJO_RESULT_OK;
1241 }
1242
ExtractMessagePipeFromInvitation(MojoHandle invitation_handle,const void * name,uint32_t name_num_bytes,const MojoExtractMessagePipeFromInvitationOptions * options,MojoHandle * message_pipe_handle)1243 MojoResult Core::ExtractMessagePipeFromInvitation(
1244 MojoHandle invitation_handle,
1245 const void* name,
1246 uint32_t name_num_bytes,
1247 const MojoExtractMessagePipeFromInvitationOptions* options,
1248 MojoHandle* message_pipe_handle) {
1249 if (options && options->struct_size < sizeof(*options))
1250 return MOJO_RESULT_INVALID_ARGUMENT;
1251 if (!message_pipe_handle)
1252 return MOJO_RESULT_INVALID_ARGUMENT;
1253 if (name_num_bytes == 0)
1254 return MOJO_RESULT_INVALID_ARGUMENT;
1255
1256 RequestContext request_context;
1257
1258 base::StringPiece name_string(static_cast<const char*>(name), name_num_bytes);
1259 scoped_refptr<Dispatcher> dispatcher = GetDispatcher(invitation_handle);
1260 if (!dispatcher || dispatcher->GetType() != Dispatcher::Type::INVITATION)
1261 return MOJO_RESULT_INVALID_ARGUMENT;
1262 auto* invitation_dispatcher =
1263 static_cast<InvitationDispatcher*>(dispatcher.get());
1264 // First attempt to extract from the invitation object itself. This is for
1265 // cases where this invitation was created in-process or is an accepted
1266 // isolated invitation.
1267 MojoResult extract_result = invitation_dispatcher->ExtractMessagePipe(
1268 name_string, message_pipe_handle);
1269 if (extract_result == MOJO_RESULT_OK ||
1270 extract_result == MOJO_RESULT_RESOURCE_EXHAUSTED) {
1271 return extract_result;
1272 }
1273
1274 *message_pipe_handle =
1275 ExtractMessagePipeFromInvitation(name_string.as_string());
1276 if (*message_pipe_handle == MOJO_HANDLE_INVALID)
1277 return MOJO_RESULT_RESOURCE_EXHAUSTED;
1278 return MOJO_RESULT_OK;
1279 }
1280
SendInvitation(MojoHandle invitation_handle,const MojoPlatformProcessHandle * process_handle,const MojoInvitationTransportEndpoint * transport_endpoint,MojoProcessErrorHandler error_handler,uintptr_t error_handler_context,const MojoSendInvitationOptions * options)1281 MojoResult Core::SendInvitation(
1282 MojoHandle invitation_handle,
1283 const MojoPlatformProcessHandle* process_handle,
1284 const MojoInvitationTransportEndpoint* transport_endpoint,
1285 MojoProcessErrorHandler error_handler,
1286 uintptr_t error_handler_context,
1287 const MojoSendInvitationOptions* options) {
1288 if (options && options->struct_size < sizeof(*options))
1289 return MOJO_RESULT_INVALID_ARGUMENT;
1290
1291 base::ProcessHandle target_process = base::kNullProcessHandle;
1292 if (process_handle) {
1293 if (process_handle->struct_size < sizeof(*process_handle))
1294 return MOJO_RESULT_INVALID_ARGUMENT;
1295 #if defined(OS_WIN)
1296 target_process = reinterpret_cast<base::ProcessHandle>(
1297 static_cast<uintptr_t>(process_handle->value));
1298 #else
1299 target_process = static_cast<base::ProcessHandle>(process_handle->value);
1300 #endif
1301 }
1302
1303 ProcessErrorCallback process_error_callback;
1304 if (error_handler) {
1305 auto error_handler_task_runner = GetNodeController()->io_task_runner();
1306 process_error_callback = base::BindRepeating(
1307 &RunMojoProcessErrorHandler,
1308 base::Owned(new ProcessDisconnectHandler(
1309 error_handler_task_runner, error_handler, error_handler_context)),
1310 error_handler_task_runner, error_handler, error_handler_context);
1311 } else if (default_process_error_callback_) {
1312 process_error_callback = default_process_error_callback_;
1313 }
1314
1315 if (!transport_endpoint)
1316 return MOJO_RESULT_INVALID_ARGUMENT;
1317 if (transport_endpoint->struct_size < sizeof(*transport_endpoint))
1318 return MOJO_RESULT_INVALID_ARGUMENT;
1319 if (transport_endpoint->num_platform_handles == 0)
1320 return MOJO_RESULT_INVALID_ARGUMENT;
1321 if (!transport_endpoint->platform_handles)
1322 return MOJO_RESULT_INVALID_ARGUMENT;
1323 if (transport_endpoint->type != MOJO_INVITATION_TRANSPORT_TYPE_CHANNEL &&
1324 transport_endpoint->type !=
1325 MOJO_INVITATION_TRANSPORT_TYPE_CHANNEL_SERVER) {
1326 return MOJO_RESULT_UNIMPLEMENTED;
1327 }
1328
1329 scoped_refptr<Dispatcher> dispatcher = GetDispatcher(invitation_handle);
1330 if (!dispatcher || dispatcher->GetType() != Dispatcher::Type::INVITATION)
1331 return MOJO_RESULT_INVALID_ARGUMENT;
1332 auto* invitation_dispatcher =
1333 static_cast<InvitationDispatcher*>(dispatcher.get());
1334
1335 auto endpoint = PlatformHandle::FromMojoPlatformHandle(
1336 &transport_endpoint->platform_handles[0]);
1337 if (!endpoint.is_valid())
1338 return MOJO_RESULT_INVALID_ARGUMENT;
1339
1340 ConnectionParams connection_params;
1341 #if defined(OS_WIN) || defined(OS_POSIX)
1342 if (transport_endpoint->type ==
1343 MOJO_INVITATION_TRANSPORT_TYPE_CHANNEL_SERVER) {
1344 connection_params =
1345 ConnectionParams(PlatformChannelServerEndpoint(std::move(endpoint)));
1346 }
1347 #endif
1348 if (!connection_params.server_endpoint().is_valid()) {
1349 connection_params =
1350 ConnectionParams(PlatformChannelEndpoint(std::move(endpoint)));
1351 }
1352
1353 // At this point everything else has been validated, so we can take ownership
1354 // of the dispatcher.
1355 {
1356 base::AutoLock lock(handles_->GetLock());
1357 scoped_refptr<Dispatcher> removed_dispatcher;
1358 MojoResult result = handles_->GetAndRemoveDispatcher(invitation_handle,
1359 &removed_dispatcher);
1360 if (result != MOJO_RESULT_OK) {
1361 // Release ownership of the endpoint platform handle, per the API
1362 // contract. The caller retains ownership on failure.
1363 connection_params.TakeEndpoint().TakePlatformHandle().release();
1364 connection_params.TakeServerEndpoint().TakePlatformHandle().release();
1365 return result;
1366 }
1367 DCHECK_EQ(removed_dispatcher.get(), invitation_dispatcher);
1368 }
1369
1370 std::vector<std::pair<std::string, ports::PortRef>> attached_ports;
1371 InvitationDispatcher::PortMapping attached_port_map =
1372 invitation_dispatcher->TakeAttachedPorts();
1373 invitation_dispatcher->Close();
1374 for (auto& entry : attached_port_map)
1375 attached_ports.emplace_back(entry.first, std::move(entry.second));
1376
1377 bool is_isolated =
1378 options && (options->flags & MOJO_SEND_INVITATION_FLAG_ISOLATED);
1379 RequestContext request_context;
1380 if (is_isolated) {
1381 DCHECK_EQ(attached_ports.size(), 1u);
1382 DCHECK_EQ(attached_ports[0].first, kIsolatedInvitationPipeName);
1383 base::StringPiece connection_name(options->isolated_connection_name,
1384 options->isolated_connection_name_length);
1385 GetNodeController()->ConnectIsolated(std::move(connection_params),
1386 attached_ports[0].second,
1387 connection_name);
1388 } else {
1389 GetNodeController()->SendBrokerClientInvitation(
1390 target_process, std::move(connection_params), attached_ports,
1391 process_error_callback);
1392 }
1393
1394 return MOJO_RESULT_OK;
1395 }
1396
AcceptInvitation(const MojoInvitationTransportEndpoint * transport_endpoint,const MojoAcceptInvitationOptions * options,MojoHandle * invitation_handle)1397 MojoResult Core::AcceptInvitation(
1398 const MojoInvitationTransportEndpoint* transport_endpoint,
1399 const MojoAcceptInvitationOptions* options,
1400 MojoHandle* invitation_handle) {
1401 if (options && options->struct_size < sizeof(*options))
1402 return MOJO_RESULT_INVALID_ARGUMENT;
1403
1404 if (!transport_endpoint)
1405 return MOJO_RESULT_INVALID_ARGUMENT;
1406 if (transport_endpoint->struct_size < sizeof(*transport_endpoint))
1407 return MOJO_RESULT_INVALID_ARGUMENT;
1408 if (transport_endpoint->num_platform_handles == 0)
1409 return MOJO_RESULT_INVALID_ARGUMENT;
1410 if (!transport_endpoint->platform_handles)
1411 return MOJO_RESULT_INVALID_ARGUMENT;
1412 if (transport_endpoint->type != MOJO_INVITATION_TRANSPORT_TYPE_CHANNEL &&
1413 transport_endpoint->type !=
1414 MOJO_INVITATION_TRANSPORT_TYPE_CHANNEL_SERVER) {
1415 return MOJO_RESULT_UNIMPLEMENTED;
1416 }
1417
1418 if (!invitation_handle)
1419 return MOJO_RESULT_INVALID_ARGUMENT;
1420 auto dispatcher = base::MakeRefCounted<InvitationDispatcher>();
1421 *invitation_handle = AddDispatcher(dispatcher);
1422 if (*invitation_handle == MOJO_HANDLE_INVALID)
1423 return MOJO_RESULT_RESOURCE_EXHAUSTED;
1424
1425 auto endpoint = PlatformHandle::FromMojoPlatformHandle(
1426 &transport_endpoint->platform_handles[0]);
1427 if (!endpoint.is_valid()) {
1428 Close(*invitation_handle);
1429 *invitation_handle = MOJO_HANDLE_INVALID;
1430 return MOJO_RESULT_INVALID_ARGUMENT;
1431 }
1432
1433 ConnectionParams connection_params;
1434 #if defined(OS_WIN) || defined(OS_POSIX)
1435 if (transport_endpoint->type ==
1436 MOJO_INVITATION_TRANSPORT_TYPE_CHANNEL_SERVER) {
1437 connection_params =
1438 ConnectionParams(PlatformChannelServerEndpoint(std::move(endpoint)));
1439 }
1440 #endif
1441 if (!connection_params.server_endpoint().is_valid()) {
1442 connection_params =
1443 ConnectionParams(PlatformChannelEndpoint(std::move(endpoint)));
1444 }
1445
1446 bool is_isolated =
1447 options && (options->flags & MOJO_ACCEPT_INVITATION_FLAG_ISOLATED);
1448 NodeController* const node_controller = GetNodeController();
1449 RequestContext request_context;
1450 if (is_isolated) {
1451 // For an isolated invitation, we simply mint a new port pair here and send
1452 // one name to the remote endpoint while stashing the other in the accepted
1453 // invitation object for later extraction.
1454 ports::PortRef local_port;
1455 ports::PortRef remote_port;
1456 node_controller->node()->CreatePortPair(&local_port, &remote_port);
1457 node_controller->ConnectIsolated(std::move(connection_params), remote_port,
1458 base::StringPiece());
1459 MojoResult result =
1460 dispatcher->AttachMessagePipe(kIsolatedInvitationPipeName, local_port);
1461 DCHECK_EQ(MOJO_RESULT_OK, result);
1462 } else {
1463 node_controller->AcceptBrokerClientInvitation(std::move(connection_params));
1464 }
1465
1466 return MOJO_RESULT_OK;
1467 }
1468
SetQuota(MojoHandle handle,MojoQuotaType type,uint64_t limit,const MojoSetQuotaOptions * options)1469 MojoResult Core::SetQuota(MojoHandle handle,
1470 MojoQuotaType type,
1471 uint64_t limit,
1472 const MojoSetQuotaOptions* options) {
1473 RequestContext request_context;
1474 if (options && options->struct_size < sizeof(*options))
1475 return MOJO_RESULT_INVALID_ARGUMENT;
1476 auto dispatcher = GetDispatcher(handle);
1477 if (!dispatcher)
1478 return MOJO_RESULT_INVALID_ARGUMENT;
1479
1480 return dispatcher->SetQuota(type, limit);
1481 }
1482
QueryQuota(MojoHandle handle,MojoQuotaType type,const MojoQueryQuotaOptions * options,uint64_t * limit,uint64_t * usage)1483 MojoResult Core::QueryQuota(MojoHandle handle,
1484 MojoQuotaType type,
1485 const MojoQueryQuotaOptions* options,
1486 uint64_t* limit,
1487 uint64_t* usage) {
1488 RequestContext request_context;
1489 if (options && options->struct_size < sizeof(*options))
1490 return MOJO_RESULT_INVALID_ARGUMENT;
1491 auto dispatcher = GetDispatcher(handle);
1492 if (!dispatcher)
1493 return MOJO_RESULT_INVALID_ARGUMENT;
1494 return dispatcher->QueryQuota(type, limit, usage);
1495 }
1496
GetActiveHandlesForTest(std::vector<MojoHandle> * handles)1497 void Core::GetActiveHandlesForTest(std::vector<MojoHandle>* handles) {
1498 base::AutoLock lock(handles_->GetLock());
1499 handles_->GetActiveHandlesForTest(handles);
1500 }
1501
1502 // static
PassNodeControllerToIOThread(std::unique_ptr<NodeController> node_controller)1503 void Core::PassNodeControllerToIOThread(
1504 std::unique_ptr<NodeController> node_controller) {
1505 // It's OK to leak this reference. At this point we know the IO loop is still
1506 // running, and we know the NodeController will observe its eventual
1507 // destruction. This tells the NodeController to delete itself when that
1508 // happens.
1509 node_controller.release()->DestroyOnIOThreadShutdown();
1510 }
1511
1512 } // namespace core
1513 } // namespace mojo
1514