Line data Source code
1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 : /* This Source Code Form is subject to the terms of the Mozilla Public
4 : * License, v. 2.0. If a copy of the MPL was not distributed with this
5 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 :
7 : #include "base/process_util.h"
8 : #include "base/task.h"
9 :
10 : #ifdef OS_POSIX
11 : #include <errno.h>
12 : #endif
13 :
14 : #include "mozilla/IntegerPrintfMacros.h"
15 :
16 : #include "mozilla/ipc/ProtocolUtils.h"
17 :
18 : #include "mozilla/dom/ContentParent.h"
19 : #include "mozilla/ipc/MessageChannel.h"
20 : #include "mozilla/ipc/Transport.h"
21 : #include "mozilla/StaticMutex.h"
22 : #include "mozilla/SystemGroup.h"
23 : #include "mozilla/Unused.h"
24 : #include "nsPrintfCString.h"
25 :
26 : #if defined(MOZ_SANDBOX) && defined(XP_WIN)
27 : #include "mozilla/sandboxTarget.h"
28 : #endif
29 :
30 : #if defined(XP_WIN)
31 : #include "aclapi.h"
32 : #include "sddl.h"
33 :
34 : #include "mozilla/TypeTraits.h"
35 : #endif
36 :
37 : #include "nsAutoPtr.h"
38 :
39 : using namespace IPC;
40 :
41 : using base::GetCurrentProcId;
42 : using base::ProcessHandle;
43 : using base::ProcessId;
44 :
45 : namespace mozilla {
46 :
47 : #if defined(XP_WIN)
48 : // Generate RAII classes for LPTSTR and PSECURITY_DESCRIPTOR.
49 : MOZ_TYPE_SPECIFIC_SCOPED_POINTER_TEMPLATE(ScopedLPTStr, \
50 : RemovePointer<LPTSTR>::Type, \
51 : ::LocalFree)
52 : MOZ_TYPE_SPECIFIC_SCOPED_POINTER_TEMPLATE(ScopedPSecurityDescriptor, \
53 : RemovePointer<PSECURITY_DESCRIPTOR>::Type, \
54 : ::LocalFree)
55 : #endif
56 :
57 : namespace ipc {
58 :
59 : IPCResult
60 0 : IPCResult::Fail(NotNull<IProtocol*> actor, const char* where, const char* why)
61 : {
62 : // Calls top-level protocol to handle the error.
63 0 : nsPrintfCString errorMsg("%s %s\n", where, why);
64 0 : actor->GetIPCChannel()->Listener()->ProcessingError(
65 0 : HasResultCodes::MsgProcessingError, errorMsg.get());
66 0 : return IPCResult(false);
67 : }
68 :
69 0 : class ChannelOpened : public IPC::Message
70 : {
71 : public:
72 0 : ChannelOpened(TransportDescriptor aDescriptor,
73 : ProcessId aOtherProcess,
74 : ProtocolId aProtocol,
75 : NestedLevel aNestedLevel = NOT_NESTED)
76 0 : : IPC::Message(MSG_ROUTING_CONTROL, // these only go to top-level actors
77 : CHANNEL_OPENED_MESSAGE_TYPE,
78 : 0,
79 0 : HeaderFlags(aNestedLevel))
80 : {
81 0 : IPC::WriteParam(this, aDescriptor);
82 0 : IPC::WriteParam(this, aOtherProcess);
83 0 : IPC::WriteParam(this, static_cast<uint32_t>(aProtocol));
84 0 : }
85 :
86 0 : static bool Read(const IPC::Message& aMsg,
87 : TransportDescriptor* aDescriptor,
88 : ProcessId* aOtherProcess,
89 : ProtocolId* aProtocol)
90 : {
91 0 : PickleIterator iter(aMsg);
92 0 : if (!IPC::ReadParam(&aMsg, &iter, aDescriptor) ||
93 0 : !IPC::ReadParam(&aMsg, &iter, aOtherProcess) ||
94 0 : !IPC::ReadParam(&aMsg, &iter, reinterpret_cast<uint32_t*>(aProtocol))) {
95 : return false;
96 : }
97 0 : aMsg.EndRead(iter);
98 0 : return true;
99 : }
100 : };
101 :
102 : nsresult
103 0 : Bridge(const PrivateIPDLInterface&,
104 : MessageChannel* aParentChannel, ProcessId aParentPid,
105 : MessageChannel* aChildChannel, ProcessId aChildPid,
106 : ProtocolId aProtocol, ProtocolId aChildProtocol)
107 : {
108 0 : if (!aParentPid || !aChildPid) {
109 : return NS_ERROR_INVALID_ARG;
110 : }
111 :
112 0 : TransportDescriptor parentSide, childSide;
113 : nsresult rv;
114 0 : if (NS_FAILED(rv = CreateTransport(aParentPid, &parentSide, &childSide))) {
115 : return rv;
116 : }
117 :
118 0 : if (!aParentChannel->Send(new ChannelOpened(parentSide,
119 : aChildPid,
120 : aProtocol,
121 0 : IPC::Message::NESTED_INSIDE_CPOW))) {
122 0 : CloseDescriptor(parentSide);
123 0 : CloseDescriptor(childSide);
124 0 : return NS_ERROR_BRIDGE_OPEN_PARENT;
125 : }
126 :
127 0 : if (!aChildChannel->Send(new ChannelOpened(childSide,
128 : aParentPid,
129 : aChildProtocol,
130 0 : IPC::Message::NESTED_INSIDE_CPOW))) {
131 0 : CloseDescriptor(parentSide);
132 0 : CloseDescriptor(childSide);
133 0 : return NS_ERROR_BRIDGE_OPEN_CHILD;
134 : }
135 :
136 : return NS_OK;
137 : }
138 :
139 : bool
140 0 : Open(const PrivateIPDLInterface&,
141 : MessageChannel* aOpenerChannel, ProcessId aOtherProcessId,
142 : Transport::Mode aOpenerMode,
143 : ProtocolId aProtocol, ProtocolId aChildProtocol)
144 : {
145 0 : bool isParent = (Transport::MODE_SERVER == aOpenerMode);
146 0 : ProcessId thisPid = GetCurrentProcId();
147 0 : ProcessId parentId = isParent ? thisPid : aOtherProcessId;
148 0 : ProcessId childId = !isParent ? thisPid : aOtherProcessId;
149 0 : if (!parentId || !childId) {
150 : return false;
151 : }
152 :
153 0 : TransportDescriptor parentSide, childSide;
154 0 : if (NS_FAILED(CreateTransport(parentId, &parentSide, &childSide))) {
155 : return false;
156 : }
157 :
158 0 : Message* parentMsg = new ChannelOpened(parentSide, childId, aProtocol);
159 0 : Message* childMsg = new ChannelOpened(childSide, parentId, aChildProtocol);
160 0 : nsAutoPtr<Message> messageForUs(isParent ? parentMsg : childMsg);
161 0 : nsAutoPtr<Message> messageForOtherSide(!isParent ? parentMsg : childMsg);
162 0 : if (!aOpenerChannel->Echo(messageForUs.forget()) ||
163 0 : !aOpenerChannel->Send(messageForOtherSide.forget())) {
164 0 : CloseDescriptor(parentSide);
165 0 : CloseDescriptor(childSide);
166 0 : return false;
167 : }
168 : return true;
169 : }
170 :
171 : bool
172 0 : UnpackChannelOpened(const PrivateIPDLInterface&,
173 : const Message& aMsg,
174 : TransportDescriptor* aTransport,
175 : ProcessId* aOtherProcess,
176 : ProtocolId* aProtocol)
177 : {
178 0 : return ChannelOpened::Read(aMsg, aTransport, aOtherProcess, aProtocol);
179 : }
180 :
181 : #if defined(XP_WIN)
182 : bool DuplicateHandle(HANDLE aSourceHandle,
183 : DWORD aTargetProcessId,
184 : HANDLE* aTargetHandle,
185 : DWORD aDesiredAccess,
186 : DWORD aOptions) {
187 : // If our process is the target just duplicate the handle.
188 : if (aTargetProcessId == base::GetCurrentProcId()) {
189 : return !!::DuplicateHandle(::GetCurrentProcess(), aSourceHandle,
190 : ::GetCurrentProcess(), aTargetHandle,
191 : aDesiredAccess, false, aOptions);
192 :
193 : }
194 :
195 : #if defined(MOZ_SANDBOX)
196 : // Try the broker next (will fail if not sandboxed).
197 : if (SandboxTarget::Instance()->BrokerDuplicateHandle(aSourceHandle,
198 : aTargetProcessId,
199 : aTargetHandle,
200 : aDesiredAccess,
201 : aOptions)) {
202 : return true;
203 : }
204 : #endif
205 :
206 : // Finally, see if we already have access to the process.
207 : ScopedProcessHandle targetProcess(OpenProcess(PROCESS_DUP_HANDLE,
208 : FALSE,
209 : aTargetProcessId));
210 : if (!targetProcess) {
211 : CrashReporter::AnnotateCrashReport(
212 : NS_LITERAL_CSTRING("IPCTransportFailureReason"),
213 : NS_LITERAL_CSTRING("Failed to open target process."));
214 : return false;
215 : }
216 :
217 : return !!::DuplicateHandle(::GetCurrentProcess(), aSourceHandle,
218 : targetProcess, aTargetHandle,
219 : aDesiredAccess, FALSE, aOptions);
220 : }
221 : #endif
222 :
223 : void
224 0 : AnnotateSystemError()
225 : {
226 0 : int64_t error = 0;
227 : #if defined(XP_WIN)
228 : error = ::GetLastError();
229 : #elif defined(OS_POSIX)
230 0 : error = errno;
231 : #endif
232 0 : if (error) {
233 : CrashReporter::AnnotateCrashReport(
234 0 : NS_LITERAL_CSTRING("IPCSystemError"),
235 0 : nsPrintfCString("%" PRId64, error));
236 : }
237 0 : }
238 :
239 : #if defined(XP_MACOSX)
240 : void
241 : AnnotateCrashReportWithErrno(const char* tag, int error)
242 : {
243 : CrashReporter::AnnotateCrashReport(
244 : nsCString(tag),
245 : nsPrintfCString("%d", error));
246 : }
247 : #endif
248 :
249 : void
250 0 : LogMessageForProtocol(const char* aTopLevelProtocol, base::ProcessId aOtherPid,
251 : const char* aContextDescription,
252 : uint32_t aMessageId,
253 : MessageDirection aDirection)
254 : {
255 : nsPrintfCString logMessage("[time: %" PRId64 "][%d%s%d] [%s] %s %s\n",
256 : PR_Now(), base::GetCurrentProcId(),
257 : aDirection == MessageDirection::eReceiving ? "<-" : "->",
258 : aOtherPid, aTopLevelProtocol,
259 : aContextDescription,
260 0 : StringFromIPCMessageType(aMessageId));
261 : #ifdef ANDROID
262 : __android_log_write(ANDROID_LOG_INFO, "GeckoIPC", logMessage.get());
263 : #endif
264 0 : fputs(logMessage.get(), stderr);
265 0 : }
266 :
267 : void
268 0 : ProtocolErrorBreakpoint(const char* aMsg)
269 : {
270 : // Bugs that generate these error messages can be tough to
271 : // reproduce. Log always in the hope that someone finds the error
272 : // message.
273 0 : printf_stderr("IPDL protocol error: %s\n", aMsg);
274 0 : }
275 :
276 : void
277 0 : FatalError(const char* aMsg, bool aIsParent)
278 : {
279 : #ifndef FUZZING
280 0 : ProtocolErrorBreakpoint(aMsg);
281 : #endif
282 :
283 0 : nsAutoCString formattedMessage("IPDL error: \"");
284 0 : formattedMessage.AppendASCII(aMsg);
285 0 : if (aIsParent) {
286 : // We're going to crash the parent process because at this time
287 : // there's no other really nice way of getting a minidump out of
288 : // this process if we're off the main thread.
289 0 : formattedMessage.AppendLiteral("\". Intentionally crashing.");
290 0 : NS_ERROR(formattedMessage.get());
291 0 : CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("IPCFatalErrorMsg"),
292 0 : nsDependentCString(aMsg));
293 0 : AnnotateSystemError();
294 : #ifndef FUZZING
295 0 : MOZ_CRASH("IPC FatalError in the parent process!");
296 : #endif
297 : } else {
298 0 : formattedMessage.AppendLiteral("\". abort()ing as a result.");
299 : #ifndef FUZZING
300 0 : MOZ_CRASH_UNSAFE_OOL(formattedMessage.get());
301 : #endif
302 : }
303 : }
304 :
305 : void
306 0 : LogicError(const char* aMsg)
307 : {
308 0 : MOZ_CRASH_UNSAFE_OOL(aMsg);
309 : }
310 :
311 : void
312 0 : ActorIdReadError(const char* aActorDescription)
313 : {
314 : #ifndef FUZZING
315 0 : MOZ_CRASH_UNSAFE_PRINTF("Error deserializing id for %s", aActorDescription);
316 : #endif
317 : }
318 :
319 : void
320 0 : BadActorIdError(const char* aActorDescription)
321 : {
322 0 : nsPrintfCString message("bad id for %s", aActorDescription);
323 0 : ProtocolErrorBreakpoint(message.get());
324 0 : }
325 :
326 : void
327 0 : ActorLookupError(const char* aActorDescription)
328 : {
329 0 : nsPrintfCString message("could not lookup id for %s", aActorDescription);
330 0 : ProtocolErrorBreakpoint(message.get());
331 0 : }
332 :
333 : void
334 0 : MismatchedActorTypeError(const char* aActorDescription)
335 : {
336 : nsPrintfCString message("actor that should be of type %s has different type",
337 0 : aActorDescription);
338 0 : ProtocolErrorBreakpoint(message.get());
339 0 : }
340 :
341 : void
342 0 : UnionTypeReadError(const char* aUnionName)
343 : {
344 0 : MOZ_CRASH_UNSAFE_PRINTF("error deserializing type of union %s", aUnionName);
345 : }
346 :
347 : void
348 0 : ArrayLengthReadError(const char* aElementName)
349 : {
350 0 : MOZ_CRASH_UNSAFE_PRINTF("error deserializing length of %s[]", aElementName);
351 : }
352 :
353 : void
354 0 : SentinelReadError(const char* aClassName)
355 : {
356 0 : MOZ_CRASH_UNSAFE_PRINTF("incorrect sentinel when reading %s", aClassName);
357 : }
358 :
359 : bool
360 0 : StateTransition(bool aIsDelete, State* aNext)
361 : {
362 0 : switch (*aNext) {
363 : case State::Null:
364 456 : if (aIsDelete) {
365 30 : *aNext = State::Dead;
366 : }
367 : break;
368 : case State::Dead:
369 : return false;
370 : default:
371 : return false;
372 : }
373 : return true;
374 : }
375 :
376 : bool
377 0 : ReEntrantDeleteStateTransition(bool aIsDelete,
378 : bool aIsDeleteReply,
379 : ReEntrantDeleteState* aNext)
380 : {
381 0 : switch (*aNext) {
382 : case ReEntrantDeleteState::Null:
383 0 : if (aIsDelete) {
384 0 : *aNext = ReEntrantDeleteState::Dying;
385 : }
386 : break;
387 : case ReEntrantDeleteState::Dead:
388 : return false;
389 : case ReEntrantDeleteState::Dying:
390 0 : if (aIsDeleteReply) {
391 0 : *aNext = ReEntrantDeleteState::Dead;
392 : }
393 : break;
394 : default:
395 : return false;
396 : }
397 : return true;
398 : }
399 :
400 : void
401 35 : TableToArray(const nsTHashtable<nsPtrHashKey<void>>& aTable,
402 : nsTArray<void*>& aArray)
403 : {
404 0 : uint32_t i = 0;
405 0 : void** elements = aArray.AppendElements(aTable.Count());
406 0 : for (auto iter = aTable.ConstIter(); !iter.Done(); iter.Next()) {
407 0 : elements[i] = iter.Get()->GetKey();
408 0 : ++i;
409 : }
410 35 : }
411 :
412 : Maybe<IProtocol*>
413 19 : IProtocol::ReadActor(const IPC::Message* aMessage, PickleIterator* aIter, bool aNullable,
414 : const char* aActorDescription, int32_t aProtocolTypeId)
415 : {
416 : int32_t id;
417 19 : if (!IPC::ReadParam(aMessage, aIter, &id)) {
418 0 : ActorIdReadError(aActorDescription);
419 : return Nothing();
420 : }
421 :
422 19 : if (id == 1 || (id == 0 && !aNullable)) {
423 0 : BadActorIdError(aActorDescription);
424 : return Nothing();
425 : }
426 :
427 19 : if (id == 0) {
428 0 : return Some(static_cast<IProtocol*>(nullptr));
429 : }
430 :
431 1 : IProtocol* listener = this->Lookup(id);
432 19 : if (!listener) {
433 0 : ActorLookupError(aActorDescription);
434 : return Nothing();
435 : }
436 :
437 19 : if (listener->GetProtocolTypeId() != aProtocolTypeId) {
438 0 : MismatchedActorTypeError(aActorDescription);
439 : return Nothing();
440 : }
441 :
442 : return Some(listener);
443 : }
444 :
445 : int32_t
446 0 : IProtocol::ManagedState::Register(IProtocol* aRouted)
447 : {
448 32 : return mProtocol->Manager()->Register(aRouted);
449 : }
450 :
451 : int32_t
452 0 : IProtocol::ManagedState::RegisterID(IProtocol* aRouted, int32_t aId)
453 : {
454 37 : return mProtocol->Manager()->RegisterID(aRouted, aId);
455 : }
456 :
457 : IProtocol*
458 0 : IProtocol::ManagedState::Lookup(int32_t aId)
459 : {
460 36 : return mProtocol->Manager()->Lookup(aId);
461 : }
462 :
463 : void
464 0 : IProtocol::ManagedState::Unregister(int32_t aId)
465 : {
466 57 : if (mProtocol->mId == aId) {
467 0 : mProtocol->mId = kFreedActorId;
468 : }
469 57 : mProtocol->Manager()->Unregister(aId);
470 57 : }
471 :
472 : Shmem::SharedMemory*
473 0 : IProtocol::ManagedState::CreateSharedMemory(size_t aSize,
474 : SharedMemory::SharedMemoryType aType,
475 : bool aUnsafe,
476 : int32_t* aId)
477 : {
478 0 : return mProtocol->Manager()->CreateSharedMemory(aSize, aType, aUnsafe, aId);
479 : }
480 :
481 : Shmem::SharedMemory*
482 0 : IProtocol::ManagedState::LookupSharedMemory(int32_t aId)
483 : {
484 0 : return mProtocol->Manager()->LookupSharedMemory(aId);
485 : }
486 :
487 : bool
488 0 : IProtocol::ManagedState::IsTrackingSharedMemory(Shmem::SharedMemory* aSegment)
489 : {
490 0 : return mProtocol->Manager()->IsTrackingSharedMemory(aSegment);
491 : }
492 :
493 : bool
494 0 : IProtocol::ManagedState::DestroySharedMemory(Shmem& aShmem)
495 : {
496 0 : return mProtocol->Manager()->DestroySharedMemory(aShmem);
497 : }
498 :
499 : const MessageChannel*
500 0 : IProtocol::ManagedState::GetIPCChannel() const
501 : {
502 0 : return mChannel;
503 : }
504 :
505 : MessageChannel*
506 0 : IProtocol::ManagedState::GetIPCChannel()
507 : {
508 258 : return mChannel;
509 : }
510 :
511 : ProcessId
512 0 : IProtocol::OtherPid() const
513 : {
514 37 : return Manager()->OtherPid();
515 : }
516 :
517 : void
518 0 : IProtocol::FatalError(const char* const aErrorMsg) const
519 : {
520 0 : HandleFatalError(aErrorMsg);
521 0 : }
522 :
523 : void
524 0 : IProtocol::HandleFatalError(const char* aErrorMsg) const
525 : {
526 0 : if (IProtocol* manager = Manager()) {
527 0 : manager->HandleFatalError(aErrorMsg);
528 : return;
529 : }
530 :
531 0 : mozilla::ipc::FatalError(aErrorMsg, mSide == ParentSide);
532 : }
533 :
534 : bool
535 0 : IProtocol::AllocShmem(size_t aSize,
536 : Shmem::SharedMemory::SharedMemoryType aType,
537 : Shmem* aOutMem)
538 : {
539 : Shmem::id_t id;
540 0 : Shmem::SharedMemory* rawmem(CreateSharedMemory(aSize, aType, false, &id));
541 0 : if (!rawmem) {
542 : return false;
543 : }
544 :
545 0 : *aOutMem = Shmem(Shmem::PrivateIPDLCaller(), rawmem, id);
546 0 : return true;
547 : }
548 :
549 : bool
550 0 : IProtocol::AllocUnsafeShmem(size_t aSize,
551 : Shmem::SharedMemory::SharedMemoryType aType,
552 : Shmem* aOutMem)
553 : {
554 : Shmem::id_t id;
555 0 : Shmem::SharedMemory* rawmem(CreateSharedMemory(aSize, aType, true, &id));
556 0 : if (!rawmem) {
557 : return false;
558 : }
559 :
560 0 : *aOutMem = Shmem(Shmem::PrivateIPDLCaller(), rawmem, id);
561 0 : return true;
562 : }
563 :
564 : bool
565 0 : IProtocol::DeallocShmem(Shmem& aMem)
566 : {
567 0 : bool ok = DestroySharedMemory(aMem);
568 : #ifdef DEBUG
569 0 : if (!ok) {
570 0 : if (mSide == ChildSide) {
571 0 : FatalError("bad Shmem");
572 : } else {
573 0 : NS_WARNING("bad Shmem");
574 : }
575 : return false;
576 : }
577 : #endif // DEBUG
578 0 : aMem.forget(Shmem::PrivateIPDLCaller());
579 0 : return ok;
580 : }
581 :
582 : void
583 0 : IProtocol::SetManager(IProtocol* aManager)
584 : {
585 0 : MOZ_RELEASE_ASSERT(!mManager || mManager == aManager);
586 102 : mManager = aManager;
587 102 : }
588 :
589 : void
590 44 : IProtocol::SetManagerAndRegister(IProtocol* aManager)
591 : {
592 : // Set the manager prior to registering so registering properly inherits
593 : // the manager's event target.
594 0 : SetManager(aManager);
595 :
596 0 : aManager->Register(this);
597 :
598 88 : mState->SetIPCChannel(aManager->GetIPCChannel());
599 44 : }
600 :
601 : void
602 56 : IProtocol::SetManagerAndRegister(IProtocol* aManager, int32_t aId)
603 : {
604 : // Set the manager prior to registering so registering properly inherits
605 : // the manager's event target.
606 0 : SetManager(aManager);
607 :
608 0 : aManager->RegisterID(this, aId);
609 :
610 112 : mState->SetIPCChannel(aManager->GetIPCChannel());
611 56 : }
612 :
613 : void
614 2 : IProtocol::SetEventTargetForActor(IProtocol* aActor, nsIEventTarget* aEventTarget)
615 : {
616 : // Make sure we have a manager for the internal method to access.
617 0 : aActor->SetManager(this);
618 2 : mState->SetEventTargetForActor(aActor, aEventTarget);
619 2 : }
620 :
621 : void
622 0 : IProtocol::ReplaceEventTargetForActor(IProtocol* aActor,
623 : nsIEventTarget* aEventTarget)
624 : {
625 : // Ensure the actor has been registered.
626 0 : MOZ_ASSERT(aActor->Manager());
627 0 : mState->ReplaceEventTargetForActor(aActor, aEventTarget);
628 0 : }
629 :
630 : nsIEventTarget*
631 0 : IProtocol::GetActorEventTarget()
632 : {
633 5 : return mState->GetActorEventTarget();
634 : }
635 :
636 : already_AddRefed<nsIEventTarget>
637 0 : IProtocol::GetActorEventTarget(IProtocol* aActor)
638 : {
639 8 : return mState->GetActorEventTarget(aActor);
640 : }
641 :
642 : nsIEventTarget*
643 5 : IProtocol::ManagedState::GetActorEventTarget()
644 : {
645 : // We should only call this function when this actor has been registered and
646 : // is not unregistered yet.
647 0 : MOZ_RELEASE_ASSERT(mProtocol->mId != kNullActorId && mProtocol->mId != kFreedActorId);
648 15 : RefPtr<nsIEventTarget> target = GetActorEventTarget(mProtocol);
649 10 : return target;
650 : }
651 :
652 : void
653 0 : IProtocol::ManagedState::SetEventTargetForActor(IProtocol* aActor,
654 : nsIEventTarget* aEventTarget)
655 : {
656 : // Go directly through the state so we don't try to redundantly (and
657 : // wrongly) call SetManager() on aActor.
658 0 : mProtocol->Manager()->mState->SetEventTargetForActor(aActor, aEventTarget);
659 0 : }
660 :
661 : void
662 0 : IProtocol::ManagedState::ReplaceEventTargetForActor(IProtocol* aActor,
663 : nsIEventTarget* aEventTarget)
664 : {
665 0 : mProtocol->Manager()->ReplaceEventTargetForActor(aActor, aEventTarget);
666 0 : }
667 :
668 : already_AddRefed<nsIEventTarget>
669 0 : IProtocol::ManagedState::GetActorEventTarget(IProtocol* aActor)
670 : {
671 8 : return mProtocol->Manager()->GetActorEventTarget(aActor);
672 : }
673 :
674 23 : IToplevelProtocol::IToplevelProtocol(const char* aName,
675 46 : ProtocolId aProtoId,
676 : Side aSide)
677 : : IProtocol(aSide, MakeUnique<ToplevelState>(aName, this, aSide))
678 : , mMonitor("mozilla.ipc.IToplevelProtocol.mMonitor")
679 0 : , mProtocolId(aProtoId)
680 : , mOtherPid(mozilla::ipc::kInvalidProcessId)
681 0 : , mOtherPidState(ProcessIdState::eUnstarted)
682 : , mIsMainThreadProtocol(false)
683 0 : {
684 : }
685 0 :
686 0 : IToplevelProtocol::~IToplevelProtocol()
687 0 : {
688 : if (mTrans) {
689 0 : RefPtr<DeleteTask<Transport>> task = new DeleteTask<Transport>(mTrans.release());
690 : XRE_GetIOMessageLoop()->PostTask(task.forget());
691 : }
692 0 : }
693 :
694 0 : base::ProcessId
695 37 : IToplevelProtocol::OtherPid() const
696 37 : {
697 : base::ProcessId pid = OtherPidMaybeInvalid();
698 : MOZ_RELEASE_ASSERT(pid != kInvalidProcessId);
699 : return pid;
700 0 : }
701 :
702 0 : base::ProcessId
703 : IToplevelProtocol::OtherPidMaybeInvalid() const
704 37 : {
705 : MonitorAutoLock lock(mMonitor);
706 :
707 : if (mOtherPidState == ProcessIdState::eUnstarted) {
708 : // If you're asking for the pid of a process we haven't even tried to
709 : // start, you get an invalid pid back immediately.
710 37 : return kInvalidProcessId;
711 0 : }
712 :
713 0 : while (mOtherPidState < ProcessIdState::eReady) {
714 : lock.Wait();
715 37 : }
716 : MOZ_RELEASE_ASSERT(mOtherPidState == ProcessIdState::eReady);
717 :
718 : return mOtherPid;
719 26 : }
720 :
721 : void
722 0 : IToplevelProtocol::SetOtherProcessId(base::ProcessId aOtherPid,
723 0 : ProcessIdState aState)
724 0 : {
725 26 : MonitorAutoLock lock(mMonitor);
726 26 : mOtherPid = aOtherPid;
727 : mOtherPidState = aState;
728 : lock.NotifyAll();
729 0 : }
730 :
731 0 : bool
732 0 : IToplevelProtocol::TakeMinidump(nsIFile** aDump, uint32_t* aSequence)
733 : {
734 : MOZ_RELEASE_ASSERT(GetSide() == ParentSide);
735 : return XRE_TakeMinidumpForChild(OtherPid(), aDump, aSequence);
736 6 : }
737 :
738 : bool
739 : IToplevelProtocol::Open(mozilla::ipc::Transport* aTransport,
740 : base::ProcessId aOtherPid,
741 6 : MessageLoop* aThread,
742 6 : mozilla::ipc::Side aSide)
743 : {
744 : SetOtherProcessId(aOtherPid);
745 : return GetIPCChannel()->Open(aTransport, aThread, aSide);
746 3 : }
747 :
748 : bool
749 : IToplevelProtocol::Open(MessageChannel* aChannel,
750 3 : MessageLoop* aMessageLoop,
751 3 : mozilla::ipc::Side aSide)
752 : {
753 : SetOtherProcessId(base::GetCurrentProcId());
754 : return GetIPCChannel()->Open(aChannel, aMessageLoop->SerialEventTarget(), aSide);
755 4 : }
756 :
757 : bool
758 : IToplevelProtocol::Open(MessageChannel* aChannel,
759 4 : nsIEventTarget* aEventTarget,
760 4 : mozilla::ipc::Side aSide)
761 : {
762 : SetOtherProcessId(base::GetCurrentProcId());
763 : return GetIPCChannel()->Open(aChannel, aEventTarget, aSide);
764 2 : }
765 :
766 : bool
767 : IToplevelProtocol::OpenWithAsyncPid(mozilla::ipc::Transport* aTransport,
768 2 : MessageLoop* aThread,
769 : mozilla::ipc::Side aSide)
770 : {
771 : return GetIPCChannel()->Open(aTransport, aThread, aSide);
772 0 : }
773 :
774 0 : void
775 0 : IToplevelProtocol::Close()
776 : {
777 : GetIPCChannel()->Close();
778 0 : }
779 :
780 1 : void
781 1 : IToplevelProtocol::SetReplyTimeoutMs(int32_t aTimeoutMs)
782 : {
783 : GetIPCChannel()->SetReplyTimeoutMs(aTimeoutMs);
784 0 : }
785 :
786 0 : bool
787 : IToplevelProtocol::IsOnCxxStack() const
788 : {
789 : return GetIPCChannel()->IsOnCxxStack();
790 0 : }
791 :
792 46 : int32_t
793 : IToplevelProtocol::ToplevelState::Register(IProtocol* aRouted)
794 : {
795 : if (aRouted->Id() != kNullActorId && aRouted->Id() != kFreedActorId) {
796 0 : // If there's already an ID, just return that.
797 44 : return aRouted->Id();
798 88 : }
799 : int32_t id = mProtocol->GetSide() == ParentSide ? ++mLastRouteId : --mLastRouteId;
800 : mActorMap.AddWithID(aRouted, id);
801 0 : aRouted->SetId(id);
802 0 :
803 88 : // Inherit our event target from our manager.
804 3 : if (IProtocol* manager = aRouted->Manager()) {
805 : MutexAutoLock lock(mEventTargetMutex);
806 : if (nsCOMPtr<nsIEventTarget> target = mEventTargetMap.Lookup(manager->Id())) {
807 : mEventTargetMap.AddWithID(target, id);
808 : }
809 : }
810 :
811 : return id;
812 56 : }
813 :
814 : int32_t
815 0 : IToplevelProtocol::ToplevelState::RegisterID(IProtocol* aRouted,
816 112 : int32_t aId)
817 56 : {
818 : mActorMap.AddWithID(aRouted, aId);
819 : aRouted->SetId(aId);
820 : return aId;
821 0 : }
822 :
823 175 : IProtocol*
824 : IToplevelProtocol::ToplevelState::Lookup(int32_t aId)
825 : {
826 : return mActorMap.Lookup(aId);
827 0 : }
828 :
829 0 : void
830 : IToplevelProtocol::ToplevelState::Unregister(int32_t aId)
831 0 : {
832 30 : mActorMap.Remove(aId);
833 0 :
834 : MutexAutoLock lock(mEventTargetMutex);
835 0 : mEventTargetMap.RemoveIfPresent(aId);
836 : }
837 23 :
838 : IToplevelProtocol::ToplevelState::ToplevelState(const char* aName,
839 : IToplevelProtocol* aProtocol,
840 23 : Side aSide)
841 : : ProtocolState()
842 : , mProtocol(aProtocol)
843 0 : , mLastRouteId(aSide == ParentSide ? kFreedActorId : kNullActorId)
844 : , mLastShmemId(aSide == ParentSide ? kFreedActorId : kNullActorId)
845 23 : , mEventTargetMutex("ProtocolEventTargetMutex")
846 : , mChannel(aName, aProtocol)
847 : {
848 0 : }
849 :
850 : Shmem::SharedMemory*
851 : IToplevelProtocol::ToplevelState::CreateSharedMemory(size_t aSize,
852 : Shmem::SharedMemory::SharedMemoryType aType,
853 : bool aUnsafe,
854 : Shmem::id_t* aId)
855 0 : {
856 0 : // XXX the mProtocol uses here should go away!
857 : RefPtr<Shmem::SharedMemory> segment(
858 : Shmem::Alloc(Shmem::PrivateIPDLCaller(), aSize, aType, aUnsafe));
859 0 : if (!segment) {
860 : return nullptr;
861 : }
862 : int32_t id = mProtocol->GetSide() == ParentSide ? ++mLastShmemId : --mLastShmemId;
863 0 : Shmem shmem(
864 : Shmem::PrivateIPDLCaller(),
865 : segment.get(),
866 : id);
867 :
868 : base::ProcessId pid =
869 : #ifdef ANDROID
870 : // We use OtherPidMaybeInvalid() because on Android this method is actually
871 : // called on an unconnected protocol, but Android's shared memory
872 0 : // implementation doesn't actually use the PID.
873 : mProtocol->OtherPidMaybeInvalid();
874 : #else
875 : mProtocol->OtherPid();
876 0 : #endif
877 0 :
878 : Message* descriptor = shmem.ShareTo(
879 : Shmem::PrivateIPDLCaller(), pid, MSG_ROUTING_CONTROL);
880 0 : if (!descriptor) {
881 : return nullptr;
882 0 : }
883 0 : Unused << mProtocol->GetIPCChannel()->Send(descriptor);
884 0 :
885 0 : *aId = shmem.Id(Shmem::PrivateIPDLCaller());
886 : Shmem::SharedMemory* rawSegment = segment.get();
887 : mShmemMap.AddWithID(segment.forget().take(), *aId);
888 : return rawSegment;
889 0 : }
890 :
891 1 : Shmem::SharedMemory*
892 : IToplevelProtocol::ToplevelState::LookupSharedMemory(Shmem::id_t aId)
893 : {
894 : return mShmemMap.Lookup(aId);
895 0 : }
896 :
897 0 : bool
898 : IToplevelProtocol::ToplevelState::IsTrackingSharedMemory(Shmem::SharedMemory* segment)
899 : {
900 : return mShmemMap.HasData(segment);
901 0 : }
902 :
903 0 : bool
904 0 : IToplevelProtocol::ToplevelState::DestroySharedMemory(Shmem& shmem)
905 0 : {
906 : Shmem::id_t aId = shmem.Id(Shmem::PrivateIPDLCaller());
907 : Shmem::SharedMemory* segment = LookupSharedMemory(aId);
908 : if (!segment) {
909 : return false;
910 0 : }
911 :
912 0 : Message* descriptor = shmem.UnshareFrom(
913 0 : Shmem::PrivateIPDLCaller(), MSG_ROUTING_CONTROL);
914 :
915 0 : mShmemMap.Remove(aId);
916 0 : Shmem::Dealloc(Shmem::PrivateIPDLCaller(), segment);
917 0 :
918 : MessageChannel* channel = mProtocol->GetIPCChannel();
919 : if (!channel->CanSend()) {
920 : delete descriptor;
921 0 : return true;
922 : }
923 :
924 : return descriptor && channel->Send(descriptor);
925 0 : }
926 :
927 0 : void
928 0 : IToplevelProtocol::ToplevelState::DeallocShmems()
929 : {
930 0 : for (IDMap<SharedMemory*>::const_iterator cit = mShmemMap.begin(); cit != mShmemMap.end(); ++cit) {
931 0 : Shmem::Dealloc(Shmem::PrivateIPDLCaller(), cit->second);
932 : }
933 : mShmemMap.Clear();
934 1 : }
935 :
936 : bool
937 3 : IToplevelProtocol::ToplevelState::ShmemCreated(const Message& aMsg)
938 1 : {
939 : Shmem::id_t id;
940 : RefPtr<Shmem::SharedMemory> rawmem(Shmem::OpenExisting(Shmem::PrivateIPDLCaller(), aMsg, &id, true));
941 3 : if (!rawmem) {
942 1 : return false;
943 : }
944 : mShmemMap.AddWithID(rawmem.forget().take(), id);
945 : return true;
946 0 : }
947 :
948 : bool
949 0 : IToplevelProtocol::ToplevelState::ShmemDestroyed(const Message& aMsg)
950 0 : {
951 : Shmem::id_t id;
952 : PickleIterator iter = PickleIterator(aMsg);
953 0 : if (!IPC::ReadParam(&aMsg, &iter, &id)) {
954 : return false;
955 0 : }
956 0 : aMsg.EndRead(iter);
957 0 :
958 0 : Shmem::SharedMemory* rawmem = LookupSharedMemory(id);
959 : if (rawmem) {
960 : mShmemMap.Remove(id);
961 : Shmem::Dealloc(Shmem::PrivateIPDLCaller(), rawmem);
962 : }
963 : return true;
964 0 : }
965 :
966 0 : already_AddRefed<nsIEventTarget>
967 : IToplevelProtocol::ToplevelState::GetMessageEventTarget(const Message& aMsg)
968 382 : {
969 0 : int32_t route = aMsg.routing_id();
970 :
971 0 : Maybe<MutexAutoLock> lock;
972 : lock.emplace(mEventTargetMutex);
973 0 :
974 : nsCOMPtr<nsIEventTarget> target = mEventTargetMap.Lookup(route);
975 1 :
976 56 : if (aMsg.is_constructor()) {
977 0 : ActorHandle handle;
978 : PickleIterator iter = PickleIterator(aMsg);
979 : if (!IPC::ReadParam(&aMsg, &iter, &handle)) {
980 : return nullptr;
981 : }
982 :
983 0 : // Normally a new actor inherits its event target from its manager. If the
984 112 : // manager has no event target, we give the subclass a chance to make a new
985 56 : // one.
986 : if (!target) {
987 : MutexAutoUnlock unlock(mEventTargetMutex);
988 56 : target = mProtocol->GetConstructedEventTarget(aMsg);
989 0 : }
990 :
991 0 : mEventTargetMap.AddWithID(target, handle.mId);
992 : } else if (!target) {
993 135 : // We don't need the lock after this point.
994 : lock.reset();
995 :
996 191 : target = mProtocol->GetSpecificMessageEventTarget(aMsg);
997 : }
998 :
999 : return target.forget();
1000 0 : }
1001 :
1002 0 : already_AddRefed<nsIEventTarget>
1003 : IToplevelProtocol::ToplevelState::GetActorEventTarget(IProtocol* aActor)
1004 0 : {
1005 10 : MOZ_RELEASE_ASSERT(aActor->Id() != kNullActorId && aActor->Id() != kFreedActorId);
1006 10 :
1007 : MutexAutoLock lock(mEventTargetMutex);
1008 : nsCOMPtr<nsIEventTarget> target = mEventTargetMap.Lookup(aActor->Id());
1009 : return target.forget();
1010 0 : }
1011 :
1012 : nsIEventTarget*
1013 0 : IToplevelProtocol::ToplevelState::GetActorEventTarget()
1014 : {
1015 : // The EventTarget of a ToplevelProtocol shall never be set.
1016 : return nullptr;
1017 2 : }
1018 :
1019 : void
1020 : IToplevelProtocol::ToplevelState::SetEventTargetForActor(IProtocol* aActor,
1021 2 : nsIEventTarget* aEventTarget)
1022 : {
1023 : // The EventTarget of a ToplevelProtocol shall never be set.
1024 : MOZ_RELEASE_ASSERT(aActor != mProtocol);
1025 :
1026 2 : // We should only call this function on actors that haven't been used for IPC
1027 : // code yet. Otherwise we'll be posting stuff to the wrong event target before
1028 : // we're called.
1029 : MOZ_RELEASE_ASSERT(aActor->Id() == kNullActorId || aActor->Id() == kFreedActorId);
1030 2 :
1031 0 : // Register the actor early. When it's registered again, it will keep the same
1032 : // ID.
1033 4 : int32_t id = Register(aActor);
1034 : aActor->SetId(id);
1035 :
1036 0 : MutexAutoLock lock(mEventTargetMutex);
1037 : // FIXME bug 1445121 - sometimes the id is already mapped.
1038 0 : // (IDMap debug-asserts that the existing state is as expected.)
1039 : bool replace = false;
1040 2 : #ifdef DEBUG
1041 0 : replace = mEventTargetMap.Lookup(id) != nullptr;
1042 : #endif
1043 0 : if (replace) {
1044 : mEventTargetMap.ReplaceWithID(aEventTarget, id);
1045 2 : } else {
1046 : mEventTargetMap.AddWithID(aEventTarget, id);
1047 : }
1048 0 : }
1049 :
1050 : void
1051 : IToplevelProtocol::ToplevelState::ReplaceEventTargetForActor(
1052 : IProtocol* aActor,
1053 0 : nsIEventTarget* aEventTarget)
1054 : {
1055 0 : // The EventTarget of a ToplevelProtocol shall never be set.
1056 : MOZ_RELEASE_ASSERT(aActor != mProtocol);
1057 0 :
1058 : int32_t id = aActor->Id();
1059 0 : // The ID of the actor should have existed.
1060 0 : MOZ_RELEASE_ASSERT(id!= kNullActorId && id!= kFreedActorId);
1061 0 :
1062 : MutexAutoLock lock(mEventTargetMutex);
1063 : mEventTargetMap.ReplaceWithID(aEventTarget, id);
1064 0 : }
1065 :
1066 0 : const MessageChannel*
1067 : IToplevelProtocol::ToplevelState::GetIPCChannel() const
1068 : {
1069 : return &mChannel;
1070 0 : }
1071 :
1072 : MessageChannel*
1073 : IToplevelProtocol::ToplevelState::GetIPCChannel()
1074 : {
1075 : return &mChannel;
1076 : }
1077 :
1078 : } // namespace ipc
1079 : } // namespace mozilla
|