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