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