Coverage Report

Created: 2018-09-25 14:53

/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