Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/ipc/glue/ProtocolUtils.h
Line
Count
Source (jump to first uncovered line)
1
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2
 * vim: sw=4 ts=4 et :
3
 */
4
/* This Source Code Form is subject to the terms of the Mozilla Public
5
 * License, v. 2.0. If a copy of the MPL was not distributed with this
6
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7
8
#ifndef mozilla_ipc_ProtocolUtils_h
9
#define mozilla_ipc_ProtocolUtils_h 1
10
11
#include "base/id_map.h"
12
#include "base/process.h"
13
#include "base/process_util.h"
14
#include "chrome/common/ipc_message_utils.h"
15
16
#include "prenv.h"
17
18
#include "IPCMessageStart.h"
19
#include "mozilla/AlreadyAddRefed.h"
20
#include "mozilla/Attributes.h"
21
#include "mozilla/ipc/ByteBuf.h"
22
#include "mozilla/ipc/FileDescriptor.h"
23
#include "mozilla/ipc/MessageChannel.h"
24
#include "mozilla/ipc/Shmem.h"
25
#include "mozilla/ipc/Transport.h"
26
#include "mozilla/ipc/MessageLink.h"
27
#include "mozilla/recordreplay/ChildIPC.h"
28
#include "mozilla/LinkedList.h"
29
#include "mozilla/Maybe.h"
30
#include "mozilla/MozPromise.h"
31
#include "mozilla/Mutex.h"
32
#include "mozilla/NotNull.h"
33
#include "mozilla/Scoped.h"
34
#include "mozilla/UniquePtr.h"
35
#include "MainThreadUtils.h"
36
#include "nsICrashReporter.h"
37
#include "nsILabelableRunnable.h"
38
39
#if defined(ANDROID) && defined(DEBUG)
40
#include <android/log.h>
41
#endif
42
43
template<typename T> class nsTHashtable;
44
template<typename T> class nsPtrHashKey;
45
46
// WARNING: this takes into account the private, special-message-type
47
// enum in ipc_channel.h.  They need to be kept in sync.
48
namespace {
49
// XXX the max message ID is actually kuint32max now ... when this
50
// changed, the assumptions of the special message IDs changed in that
51
// they're not carving out messages from likely-unallocated space, but
52
// rather carving out messages from the end of space allocated to
53
// protocol 0.  Oops!  We can get away with this until protocol 0
54
// starts approaching its 65,536th message.
55
enum {
56
    BUILD_IDS_MATCH_MESSAGE_TYPE   = kuint16max - 8,
57
    BUILD_ID_MESSAGE_TYPE          = kuint16max - 7, // unused
58
    CHANNEL_OPENED_MESSAGE_TYPE    = kuint16max - 6,
59
    SHMEM_DESTROYED_MESSAGE_TYPE   = kuint16max - 5,
60
    SHMEM_CREATED_MESSAGE_TYPE     = kuint16max - 4,
61
    GOODBYE_MESSAGE_TYPE           = kuint16max - 3,
62
    CANCEL_MESSAGE_TYPE            = kuint16max - 2,
63
64
    // kuint16max - 1 is used by ipc_channel.h.
65
};
66
67
} // namespace
68
69
class nsIEventTarget;
70
71
namespace mozilla {
72
class SchedulerGroup;
73
74
namespace dom {
75
class ContentParent;
76
} // namespace dom
77
78
namespace net {
79
class NeckoParent;
80
} // namespace net
81
82
namespace ipc {
83
84
#ifdef FUZZING
85
class ProtocolFuzzerHelper;
86
#endif
87
88
class MessageChannel;
89
90
#ifdef XP_WIN
91
const base::ProcessHandle kInvalidProcessHandle = INVALID_HANDLE_VALUE;
92
93
// In theory, on Windows, this is a valid process ID, but in practice they are
94
// currently divisible by four. Process IDs share the kernel handle allocation
95
// code and they are guaranteed to be divisible by four.
96
// As this could change for process IDs we shouldn't generally rely on this
97
// property, however even if that were to change, it seems safe to rely on this
98
// particular value never being used.
99
const base::ProcessId kInvalidProcessId = kuint32max;
100
#else
101
const base::ProcessHandle kInvalidProcessHandle = -1;
102
const base::ProcessId kInvalidProcessId = -1;
103
#endif
104
105
// Scoped base::ProcessHandle to ensure base::CloseProcessHandle is called.
106
struct ScopedProcessHandleTraits
107
{
108
  typedef base::ProcessHandle type;
109
110
  static type empty()
111
  {
112
    return kInvalidProcessHandle;
113
  }
114
115
  static void release(type aProcessHandle)
116
  {
117
    if (aProcessHandle && aProcessHandle != kInvalidProcessHandle) {
118
      base::CloseProcessHandle(aProcessHandle);
119
    }
120
  }
121
};
122
typedef mozilla::Scoped<ScopedProcessHandleTraits> ScopedProcessHandle;
123
124
class ProtocolFdMapping;
125
class ProtocolCloneContext;
126
127
// Used to pass references to protocol actors across the wire.
128
// Actors created on the parent-side have a positive ID, and actors
129
// allocated on the child side have a negative ID.
130
struct ActorHandle
131
{
132
    int mId;
133
};
134
135
// What happens if Interrupt calls race?
136
enum RacyInterruptPolicy {
137
    RIPError,
138
    RIPChildWins,
139
    RIPParentWins
140
};
141
142
143
class IToplevelProtocol;
144
145
class IProtocol : public HasResultCodes
146
{
147
#ifdef FUZZING
148
  friend class mozilla::ipc::ProtocolFuzzerHelper;
149
#endif
150
151
public:
152
    enum ActorDestroyReason {
153
        FailedConstructor,
154
        Deletion,
155
        AncestorDeletion,
156
        NormalShutdown,
157
        AbnormalShutdown
158
    };
159
160
    // A lot of the functionality of IProtocol only differs between toplevel
161
    // protocols (IToplevelProtocol) and managed protocols (everything else).
162
    // If we put such functionality in IProtocol via virtual methods, that
163
    // means that *every* protocol inherits that functionality through said
164
    // virtual methods, then every protocol needs a (largely redundant)
165
    // entry in its vtable.  That redundancy adds up quickly with several
166
    // hundred protocols.
167
    //
168
    // This class (and its two subclasses) ensure that we don't have a bunch
169
    // of redundant entries in protocol vtables: we have a single vtable per
170
    // subclass, and then each protocol has its own instance of one of the
171
    // subclasses.  This setup makes things a bit slower, but the space
172
    // savings are worth it.
173
    class ProtocolState
174
    {
175
    public:
176
0
        ProtocolState() : mChannel(nullptr) {}
177
0
        virtual ~ProtocolState() = default;
178
179
        // Shared memory functions.
180
        virtual Shmem::SharedMemory* CreateSharedMemory(
181
            size_t, SharedMemory::SharedMemoryType, bool, int32_t*) = 0;
182
        virtual Shmem::SharedMemory* LookupSharedMemory(int32_t) = 0;
183
        virtual bool IsTrackingSharedMemory(Shmem::SharedMemory*) = 0;
184
        virtual bool DestroySharedMemory(Shmem&) = 0;
185
186
        // Protocol management functions.
187
        virtual int32_t Register(IProtocol*) = 0;
188
        virtual int32_t RegisterID(IProtocol*, int32_t) = 0;
189
        virtual IProtocol* Lookup(int32_t) = 0;
190
        virtual void Unregister(int32_t) = 0;
191
192
        // Returns the event target set by SetEventTargetForActor() if available.
193
        virtual nsIEventTarget* GetActorEventTarget() = 0;
194
195
        virtual void SetEventTargetForActor(IProtocol* aActor, nsIEventTarget* aEventTarget) = 0;
196
        virtual void ReplaceEventTargetForActor(IProtocol* aActor, nsIEventTarget* aEventTarget) = 0;
197
198
        virtual already_AddRefed<nsIEventTarget>
199
        GetActorEventTarget(IProtocol* aActor) = 0;
200
201
        virtual const MessageChannel* GetIPCChannel() const = 0;
202
        virtual MessageChannel* GetIPCChannel() = 0;
203
204
        // XXX we have this weird setup where ProtocolState has an mChannel
205
        // member, but it (probably?) only gets set for protocols that have
206
        // a manager.  That is, for toplevel protocols, this member is dead
207
        // weight and should be removed, since toplevel protocols maintain
208
        // their own channel.
209
0
        void SetIPCChannel(MessageChannel* aChannel) { mChannel = aChannel; }
210
211
    protected:
212
        MessageChannel* mChannel;
213
    };
214
215
    // Managed protocols just forward all of their operations to the topmost
216
    // managing protocol.
217
    class ManagedState final : public ProtocolState
218
    {
219
    public:
220
        explicit ManagedState(IProtocol* aProtocol)
221
            : ProtocolState()
222
            , mProtocol(aProtocol)
223
        {}
224
225
        Shmem::SharedMemory* CreateSharedMemory(
226
            size_t, SharedMemory::SharedMemoryType, bool, int32_t*) override;
227
        Shmem::SharedMemory* LookupSharedMemory(int32_t) override;
228
        bool IsTrackingSharedMemory(Shmem::SharedMemory*) override;
229
        bool DestroySharedMemory(Shmem&) override;
230
231
        int32_t Register(IProtocol*) override;
232
        int32_t RegisterID(IProtocol*, int32_t) override;
233
        IProtocol* Lookup(int32_t) override;
234
        void Unregister(int32_t) override;
235
236
        nsIEventTarget* GetActorEventTarget() override;
237
        void SetEventTargetForActor(IProtocol* aActor, nsIEventTarget* aEventTarget) override;
238
        void ReplaceEventTargetForActor(IProtocol* aActor, nsIEventTarget* aEventTarget) override;
239
        already_AddRefed<nsIEventTarget> GetActorEventTarget(IProtocol* aActor) override;
240
241
        const MessageChannel* GetIPCChannel() const override;
242
        MessageChannel* GetIPCChannel() override;
243
244
    private:
245
        IProtocol* const mProtocol;
246
    };
247
248
    typedef base::ProcessId ProcessId;
249
    typedef IPC::Message Message;
250
    typedef IPC::MessageInfo MessageInfo;
251
252
    explicit IProtocol(Side aSide)
253
        : IProtocol(aSide, MakeUnique<ManagedState>(this))
254
    {}
255
256
    int32_t Register(IProtocol* aRouted)
257
0
    {
258
0
        return mState->Register(aRouted);
259
0
    }
260
    int32_t RegisterID(IProtocol* aRouted, int32_t aId)
261
0
    {
262
0
        return mState->RegisterID(aRouted, aId);
263
0
    }
264
    IProtocol* Lookup(int32_t aId)
265
0
    {
266
0
        return mState->Lookup(aId);
267
0
    }
268
    void Unregister(int32_t aId)
269
0
    {
270
0
        return mState->Unregister(aId);
271
0
    }
272
273
    virtual void RemoveManagee(int32_t, IProtocol*) = 0;
274
275
    Shmem::SharedMemory* CreateSharedMemory(
276
        size_t aSize, SharedMemory::SharedMemoryType aType, bool aUnsafe, int32_t* aId)
277
0
    {
278
0
        return mState->CreateSharedMemory(aSize, aType, aUnsafe, aId);
279
0
    }
280
    Shmem::SharedMemory* LookupSharedMemory(int32_t aId)
281
0
    {
282
0
        return mState->LookupSharedMemory(aId);
283
0
    }
284
    bool IsTrackingSharedMemory(Shmem::SharedMemory* aSegment)
285
0
    {
286
0
        return mState->IsTrackingSharedMemory(aSegment);
287
0
    }
288
    bool DestroySharedMemory(Shmem& aShmem)
289
0
    {
290
0
        return mState->DestroySharedMemory(aShmem);
291
0
    }
292
293
    MessageChannel* GetIPCChannel()
294
0
    {
295
0
        return mState->GetIPCChannel();
296
0
    }
297
    const MessageChannel* GetIPCChannel() const
298
0
    {
299
0
        return mState->GetIPCChannel();
300
0
    }
301
    void SetMiddlemanIPCChannel(MessageChannel* aChannel)
302
    {
303
        // Middleman processes sometimes need to change the channel used by a
304
        // protocol.
305
        MOZ_RELEASE_ASSERT(recordreplay::IsMiddleman());
306
        mState->SetIPCChannel(aChannel);
307
    }
308
309
    // XXX odd ducks, acknowledged
310
    virtual ProcessId OtherPid() const;
311
0
    Side GetSide() const { return mSide; }
312
313
    void FatalError(const char* const aErrorMsg) const;
314
    virtual void HandleFatalError(const char* aErrorMsg) const;
315
316
    Maybe<IProtocol*> ReadActor(const IPC::Message* aMessage, PickleIterator* aIter, bool aNullable,
317
                                const char* aActorDescription, int32_t aProtocolTypeId);
318
319
    virtual Result OnMessageReceived(const Message& aMessage) = 0;
320
    virtual Result OnMessageReceived(const Message& aMessage, Message *& aReply) = 0;
321
    virtual Result OnCallReceived(const Message& aMessage, Message *& aReply) = 0;
322
323
    virtual int32_t GetProtocolTypeId() = 0;
324
325
0
    int32_t Id() const { return mId; }
326
0
    IProtocol* Manager() const { return mManager; }
327
328
    bool AllocShmem(size_t aSize, Shmem::SharedMemory::SharedMemoryType aType, Shmem* aOutMem);
329
    bool AllocUnsafeShmem(size_t aSize, Shmem::SharedMemory::SharedMemoryType aType, Shmem* aOutMem);
330
    bool DeallocShmem(Shmem& aMem);
331
332
    // Sets an event target to which all messages for aActor will be
333
    // dispatched. This method must be called before right before the SendPFoo
334
    // message for aActor is sent. And SendPFoo *must* be called if
335
    // SetEventTargetForActor is called. The receiver when calling
336
    // SetEventTargetForActor must be the actor that will be the manager for
337
    // aActor.
338
    void SetEventTargetForActor(IProtocol* aActor, nsIEventTarget* aEventTarget);
339
340
    // Replace the event target for the messages of aActor. There must not be
341
    // any messages of aActor in the task queue, or we might run into some
342
    // unexpected behavior.
343
    void ReplaceEventTargetForActor(IProtocol* aActor,
344
                                    nsIEventTarget* aEventTarget);
345
346
    nsIEventTarget* GetActorEventTarget();
347
    already_AddRefed<nsIEventTarget> GetActorEventTarget(IProtocol* aActor);
348
349
protected:
350
    IProtocol(Side aSide, UniquePtr<ProtocolState> aState)
351
        : mId(0)
352
        , mSide(aSide)
353
        , mManager(nullptr)
354
        , mState(std::move(aState))
355
0
    {}
356
357
    friend class IToplevelProtocol;
358
359
0
    void SetId(int32_t aId) { mId = aId; }
360
    void ResetManager() { mManager = nullptr; }
361
    // We have separate functions because the accessibility code manually
362
    // calls SetManager.
363
    void SetManager(IProtocol* aManager);
364
365
    // Sets the manager for the protocol and registers the protocol with
366
    // its manager, setting up channels for the protocol as well.  Not
367
    // for use outside of IPDL.
368
    void SetManagerAndRegister(IProtocol* aManager);
369
    void SetManagerAndRegister(IProtocol* aManager, int32_t aId);
370
371
    static const int32_t kNullActorId = 0;
372
    static const int32_t kFreedActorId = 1;
373
374
private:
375
    int32_t mId;
376
    Side mSide;
377
    IProtocol* mManager;
378
    UniquePtr<ProtocolState> mState;
379
};
380
381
typedef IPCMessageStart ProtocolId;
382
383
0
#define IPC_OK() mozilla::ipc::IPCResult::Ok()
384
#define IPC_FAIL(actor, why) mozilla::ipc::IPCResult::Fail(WrapNotNull(actor), __func__, (why))
385
#define IPC_FAIL_NO_REASON(actor) mozilla::ipc::IPCResult::Fail(WrapNotNull(actor), __func__)
386
387
/**
388
 * All message deserializer and message handler should return this
389
 * type via above macros. We use a less generic name here to avoid
390
 * conflict with mozilla::Result because we have quite a few using
391
 * namespace mozilla::ipc; in the code base.
392
 */
393
class IPCResult {
394
public:
395
    static IPCResult Ok() { return IPCResult(true); }
396
    static IPCResult Fail(NotNull<IProtocol*> aActor, const char* aWhere, const char* aWhy = "");
397
    MOZ_IMPLICIT operator bool() const { return mSuccess; }
398
private:
399
    explicit IPCResult(bool aResult) : mSuccess(aResult) {}
400
    bool mSuccess;
401
};
402
403
template<class PFooSide>
404
class Endpoint;
405
406
/**
407
 * All top-level protocols should inherit this class.
408
 *
409
 * IToplevelProtocol tracks all top-level protocol actors created from
410
 * this protocol actor.
411
 */
412
class IToplevelProtocol : public IProtocol
413
{
414
    template<class PFooSide> friend class Endpoint;
415
416
protected:
417
    explicit IToplevelProtocol(const char* aName, ProtocolId aProtoId,
418
                               Side aSide);
419
    ~IToplevelProtocol();
420
421
public:
422
    enum ProcessIdState {
423
        eUnstarted,
424
        ePending,
425
        eReady,
426
        eError
427
    };
428
429
    class ToplevelState final : public ProtocolState
430
    {
431
#ifdef FUZZING
432
      friend class mozilla::ipc::ProtocolFuzzerHelper;
433
#endif
434
435
    public:
436
        ToplevelState(const char* aName, IToplevelProtocol* aProtocol, Side aSide);
437
438
        Shmem::SharedMemory* CreateSharedMemory(
439
            size_t, SharedMemory::SharedMemoryType, bool, int32_t*) override;
440
        Shmem::SharedMemory* LookupSharedMemory(int32_t) override;
441
        bool IsTrackingSharedMemory(Shmem::SharedMemory*) override;
442
        bool DestroySharedMemory(Shmem&) override;
443
444
        void DeallocShmems();
445
446
        bool ShmemCreated(const Message& aMsg);
447
        bool ShmemDestroyed(const Message& aMsg);
448
449
        int32_t Register(IProtocol*) override;
450
        int32_t RegisterID(IProtocol*, int32_t) override;
451
        IProtocol* Lookup(int32_t) override;
452
        void Unregister(int32_t) override;
453
454
        nsIEventTarget* GetActorEventTarget() override;
455
        void SetEventTargetForActor(IProtocol* aActor, nsIEventTarget* aEventTarget) override;
456
        void ReplaceEventTargetForActor(IProtocol* aActor, nsIEventTarget* aEventTarget) override;
457
        already_AddRefed<nsIEventTarget> GetActorEventTarget(IProtocol* aActor) override;
458
459
        virtual already_AddRefed<nsIEventTarget>
460
        GetMessageEventTarget(const Message& aMsg);
461
462
        const MessageChannel* GetIPCChannel() const override;
463
        MessageChannel* GetIPCChannel() override;
464
465
    private:
466
        IToplevelProtocol* const mProtocol;
467
        IDMap<IProtocol*> mActorMap;
468
        int32_t mLastRouteId;
469
        IDMap<Shmem::SharedMemory*> mShmemMap;
470
        Shmem::id_t mLastShmemId;
471
472
        Mutex mEventTargetMutex;
473
        IDMap<nsCOMPtr<nsIEventTarget>> mEventTargetMap;
474
475
        MessageChannel mChannel;
476
    };
477
478
    using SchedulerGroupSet = nsILabelableRunnable::SchedulerGroupSet;
479
480
    void SetTransport(UniquePtr<Transport> aTrans)
481
0
    {
482
0
        mTrans = std::move(aTrans);
483
0
    }
484
485
    Transport* GetTransport() const { return mTrans.get(); }
486
487
    ProtocolId GetProtocolId() const { return mProtocolId; }
488
489
    base::ProcessId OtherPid() const final;
490
    void SetOtherProcessId(base::ProcessId aOtherPid,
491
                           ProcessIdState aState = ProcessIdState::eReady);
492
493
    bool TakeMinidump(nsIFile** aDump, uint32_t* aSequence);
494
495
    virtual void OnChannelClose() = 0;
496
    virtual void OnChannelError() = 0;
497
0
    virtual void ProcessingError(Result aError, const char* aMsgName) {}
498
    virtual void OnChannelConnected(int32_t peer_pid) {}
499
500
    bool Open(mozilla::ipc::Transport* aTransport,
501
              base::ProcessId aOtherPid,
502
              MessageLoop* aThread = nullptr,
503
              mozilla::ipc::Side aSide = mozilla::ipc::UnknownSide);
504
505
    bool Open(MessageChannel* aChannel,
506
              MessageLoop* aMessageLoop,
507
              mozilla::ipc::Side aSide = mozilla::ipc::UnknownSide);
508
509
    bool Open(MessageChannel* aChannel,
510
              nsIEventTarget* aEventTarget,
511
              mozilla::ipc::Side aSide = mozilla::ipc::UnknownSide);
512
513
    bool OpenWithAsyncPid(mozilla::ipc::Transport* aTransport,
514
                          MessageLoop* aThread = nullptr,
515
                          mozilla::ipc::Side aSide = mozilla::ipc::UnknownSide);
516
517
    void Close();
518
519
    void SetReplyTimeoutMs(int32_t aTimeoutMs);
520
521
    void DeallocShmems() { DowncastState()->DeallocShmems(); }
522
523
    bool ShmemCreated(const Message& aMsg) { return DowncastState()->ShmemCreated(aMsg); }
524
    bool ShmemDestroyed(const Message& aMsg) { return DowncastState()->ShmemDestroyed(aMsg); }
525
526
0
    virtual bool ShouldContinueFromReplyTimeout() {
527
0
        return false;
528
0
    }
529
530
    // WARNING: This function is called with the MessageChannel monitor held.
531
    virtual void IntentionalCrash() {
532
        MOZ_CRASH("Intentional IPDL crash");
533
    }
534
535
    // The code here is only useful for fuzzing. It should not be used for any
536
    // other purpose.
537
#ifdef DEBUG
538
    // Returns true if we should simulate a timeout.
539
    // WARNING: This is a testing-only function that is called with the
540
    // MessageChannel monitor held. Don't do anything fancy here or we could
541
    // deadlock.
542
    virtual bool ArtificialTimeout() {
543
        return false;
544
    }
545
546
    // Returns true if we want to cause the worker thread to sleep with the
547
    // monitor unlocked.
548
    virtual bool NeedArtificialSleep() {
549
        return false;
550
    }
551
552
    // This function should be implemented to sleep for some amount of time on
553
    // the worker thread. Will only be called if NeedArtificialSleep() returns
554
    // true.
555
    virtual void ArtificialSleep() {}
556
#else
557
    bool ArtificialTimeout() { return false; }
558
0
    bool NeedArtificialSleep() { return false; }
559
0
    void ArtificialSleep() {}
560
#endif
561
562
0
    virtual void EnteredCxxStack() {}
563
0
    virtual void ExitedCxxStack() {}
564
0
    virtual void EnteredCall() {}
565
0
    virtual void ExitedCall() {}
566
567
    bool IsOnCxxStack() const;
568
569
    virtual RacyInterruptPolicy MediateInterruptRace(const MessageInfo& parent,
570
                                                     const MessageInfo& child)
571
    {
572
        return RIPChildWins;
573
    }
574
575
    /**
576
     * Return true if windows messages can be handled while waiting for a reply
577
     * to a sync IPDL message.
578
     */
579
    virtual bool HandleWindowsMessages(const Message& aMsg) const { return true; }
580
581
    virtual void OnEnteredSyncSend() {
582
    }
583
    virtual void OnExitedSyncSend() {
584
    }
585
586
    virtual void ProcessRemoteNativeEventsInInterruptCall() {
587
    }
588
589
    // Override this method in top-level protocols to change the SchedulerGroups
590
    // that a message might affect. This should be used only as a last resort
591
    // when it's difficult to determine an EventTarget ahead of time. See the
592
    // comment in nsILabelableRunnable.h for more information.
593
    virtual bool
594
    GetMessageSchedulerGroups(const Message& aMsg, SchedulerGroupSet& aGroups)
595
    {
596
        return false;
597
    }
598
599
    // This method is only used for collecting telemetry bits in various places,
600
    // and we shouldn't pay the overhead of having it in protocol vtables when
601
    // it's not being used.
602
#ifdef EARLY_BETA_OR_EARLIER
603
    virtual void OnChannelReceivedMessage(const Message& aMsg) {}
604
#endif
605
606
    bool IsMainThreadProtocol() const { return mIsMainThreadProtocol; }
607
0
    void SetIsMainThreadProtocol() { mIsMainThreadProtocol = NS_IsMainThread(); }
608
609
    already_AddRefed<nsIEventTarget>
610
    GetMessageEventTarget(const Message& aMsg)
611
0
    {
612
0
        return DowncastState()->GetMessageEventTarget(aMsg);
613
0
    }
614
615
protected:
616
    ToplevelState* DowncastState() const
617
0
    {
618
0
        return static_cast<ToplevelState*>(mState.get());
619
0
    }
620
621
    // Override this method in top-level protocols to change the event target
622
    // for a new actor (and its sub-actors).
623
    virtual already_AddRefed<nsIEventTarget>
624
    GetConstructedEventTarget(const Message& aMsg) { return nullptr; }
625
626
    // Override this method in top-level protocols to change the event target
627
    // for specific messages.
628
    virtual already_AddRefed<nsIEventTarget>
629
    GetSpecificMessageEventTarget(const Message& aMsg) { return nullptr; }
630
631
    // This monitor protects mOtherPid and mOtherPidState. All other fields
632
    // should only be accessed on the worker thread.
633
    mutable mozilla::Monitor mMonitor;
634
  private:
635
    base::ProcessId OtherPidMaybeInvalid() const;
636
637
    ProtocolId mProtocolId;
638
    UniquePtr<Transport> mTrans;
639
    base::ProcessId mOtherPid;
640
    ProcessIdState mOtherPidState;
641
    bool mIsMainThreadProtocol;
642
};
643
644
class IShmemAllocator
645
{
646
public:
647
  virtual bool AllocShmem(size_t aSize,
648
                          mozilla::ipc::SharedMemory::SharedMemoryType aShmType,
649
                          mozilla::ipc::Shmem* aShmem) = 0;
650
  virtual bool AllocUnsafeShmem(size_t aSize,
651
                                mozilla::ipc::SharedMemory::SharedMemoryType aShmType,
652
                                mozilla::ipc::Shmem* aShmem) = 0;
653
  virtual bool DeallocShmem(mozilla::ipc::Shmem& aShmem) = 0;
654
};
655
656
#define FORWARD_SHMEM_ALLOCATOR_TO(aImplClass) \
657
  virtual bool AllocShmem(size_t aSize, \
658
                          mozilla::ipc::SharedMemory::SharedMemoryType aShmType, \
659
                          mozilla::ipc::Shmem* aShmem) override \
660
  { return aImplClass::AllocShmem(aSize, aShmType, aShmem); } \
661
  virtual bool AllocUnsafeShmem(size_t aSize, \
662
                                mozilla::ipc::SharedMemory::SharedMemoryType aShmType, \
663
                                mozilla::ipc::Shmem* aShmem) override \
664
  { return aImplClass::AllocUnsafeShmem(aSize, aShmType, aShmem); } \
665
  virtual bool DeallocShmem(mozilla::ipc::Shmem& aShmem) override \
666
  { return aImplClass::DeallocShmem(aShmem); }
667
668
inline bool
669
LoggingEnabled()
670
{
671
#if defined(DEBUG) || defined(FUZZING)
672
    return !!PR_GetEnv("MOZ_IPC_MESSAGE_LOG");
673
#else
674
    return false;
675
#endif
676
}
677
678
inline bool
679
LoggingEnabledFor(const char *aTopLevelProtocol)
680
{
681
#if defined(DEBUG) || defined(FUZZING)
682
    const char *filter = PR_GetEnv("MOZ_IPC_MESSAGE_LOG");
683
    if (!filter) {
684
        return false;
685
    }
686
    return strcmp(filter, "1") == 0 || strcmp(filter, aTopLevelProtocol) == 0;
687
#else
688
    return false;
689
#endif
690
}
691
692
enum class MessageDirection {
693
    eSending,
694
    eReceiving,
695
};
696
697
MOZ_NEVER_INLINE void
698
LogMessageForProtocol(const char* aTopLevelProtocol, base::ProcessId aOtherPid,
699
                      const char* aContextDescription,
700
                      uint32_t aMessageId,
701
                      MessageDirection aDirection);
702
703
MOZ_NEVER_INLINE void
704
ProtocolErrorBreakpoint(const char* aMsg);
705
706
// The code generator calls this function for errors which come from the
707
// methods of protocols.  Doing this saves codesize by making the error
708
// cases significantly smaller.
709
MOZ_NEVER_INLINE void
710
FatalError(const char* aMsg, bool aIsParent);
711
712
// The code generator calls this function for errors which are not
713
// protocol-specific: errors in generated struct methods or errors in
714
// transition functions, for instance.  Doing this saves codesize by
715
// by making the error cases significantly smaller.
716
MOZ_NEVER_INLINE void
717
LogicError(const char* aMsg);
718
719
MOZ_NEVER_INLINE void
720
ActorIdReadError(const char* aActorDescription);
721
722
MOZ_NEVER_INLINE void
723
BadActorIdError(const char* aActorDescription);
724
725
MOZ_NEVER_INLINE void
726
ActorLookupError(const char* aActorDescription);
727
728
MOZ_NEVER_INLINE void
729
MismatchedActorTypeError(const char* aActorDescription);
730
731
MOZ_NEVER_INLINE void
732
UnionTypeReadError(const char* aUnionName);
733
734
MOZ_NEVER_INLINE void
735
ArrayLengthReadError(const char* aElementName);
736
737
MOZ_NEVER_INLINE void
738
SentinelReadError(const char* aElementName);
739
740
struct PrivateIPDLInterface {};
741
742
nsresult
743
Bridge(const PrivateIPDLInterface&,
744
       MessageChannel*, base::ProcessId, MessageChannel*, base::ProcessId,
745
       ProtocolId, ProtocolId);
746
747
bool
748
Open(const PrivateIPDLInterface&,
749
     MessageChannel*, base::ProcessId, Transport::Mode,
750
     ProtocolId, ProtocolId);
751
752
bool
753
UnpackChannelOpened(const PrivateIPDLInterface&,
754
                    const IPC::Message&,
755
                    TransportDescriptor*, base::ProcessId*, ProtocolId*);
756
757
#if defined(XP_WIN)
758
// This is a restricted version of Windows' DuplicateHandle() function
759
// that works inside the sandbox and can send handles but not retrieve
760
// them.  Unlike DuplicateHandle(), it takes a process ID rather than
761
// a process handle.  It returns true on success, false otherwise.
762
bool
763
DuplicateHandle(HANDLE aSourceHandle,
764
                DWORD aTargetProcessId,
765
                HANDLE* aTargetHandle,
766
                DWORD aDesiredAccess,
767
                DWORD aOptions);
768
#endif
769
770
/**
771
 * Annotate the crash reporter with the error code from the most recent system
772
 * call. Returns the system error.
773
 */
774
void AnnotateSystemError();
775
776
enum class LivenessState
777
{
778
  Dead,
779
  Null,
780
  Start = Null
781
};
782
783
bool
784
StateTransition(bool aIsDelete, LivenessState* aNext);
785
786
enum class ReEntrantDeleteLivenessState
787
{
788
  Dead,
789
  Null,
790
  Dying,
791
  Start = Null,
792
};
793
794
bool
795
ReEntrantDeleteStateTransition(bool aIsDelete,
796
                               bool aIsDeleteReply,
797
                               ReEntrantDeleteLivenessState* aNext);
798
799
/**
800
 * An endpoint represents one end of a partially initialized IPDL channel. To
801
 * set up a new top-level protocol:
802
 *
803
 * Endpoint<PFooParent> parentEp;
804
 * Endpoint<PFooChild> childEp;
805
 * nsresult rv;
806
 * rv = PFoo::CreateEndpoints(parentPid, childPid, &parentEp, &childEp);
807
 *
808
 * You're required to pass in parentPid and childPid, which are the pids of the
809
 * processes in which the parent and child endpoints will be used.
810
 *
811
 * Endpoints can be passed in IPDL messages or sent to other threads using
812
 * PostTask. Once an Endpoint has arrived at its destination process and thread,
813
 * you need to create the top-level actor and bind it to the endpoint:
814
 *
815
 * FooParent* parent = new FooParent();
816
 * bool rv1 = parentEp.Bind(parent, processActor);
817
 * bool rv2 = parent->SendBar(...);
818
 *
819
 * (See Bind below for an explanation of processActor.) Once the actor is bound
820
 * to the endpoint, it can send and receive messages.
821
 */
822
template<class PFooSide>
823
class Endpoint
824
{
825
public:
826
    typedef base::ProcessId ProcessId;
827
828
    Endpoint()
829
      : mValid(false)
830
      , mMode(static_cast<mozilla::ipc::Transport::Mode>(0))
831
      , mMyPid(0)
832
      , mOtherPid(0)
833
0
    {
834
0
    }
Unexecuted instantiation: mozilla::ipc::Endpoint<mozilla::ipc::PBackgroundParent>::Endpoint()
Unexecuted instantiation: mozilla::ipc::Endpoint<mozilla::ipc::PBackgroundChild>::Endpoint()
835
836
    Endpoint(const PrivateIPDLInterface&,
837
             mozilla::ipc::Transport::Mode aMode,
838
             TransportDescriptor aTransport,
839
             ProcessId aMyPid,
840
             ProcessId aOtherPid)
841
      : mValid(true)
842
      , mMode(aMode)
843
      , mTransport(aTransport)
844
      , mMyPid(aMyPid)
845
      , mOtherPid(aOtherPid)
846
    {}
847
848
    Endpoint(Endpoint&& aOther)
849
      : mValid(aOther.mValid)
850
      , mTransport(aOther.mTransport)
851
      , mMyPid(aOther.mMyPid)
852
      , mOtherPid(aOther.mOtherPid)
853
0
    {
854
0
        if (aOther.mValid) {
855
0
            mMode = aOther.mMode;
856
0
        }
857
0
        aOther.mValid = false;
858
0
    }
859
860
    Endpoint& operator=(Endpoint&& aOther)
861
    {
862
        mValid = aOther.mValid;
863
        if (aOther.mValid) {
864
            mMode = aOther.mMode;
865
        }
866
        mTransport = aOther.mTransport;
867
        mMyPid = aOther.mMyPid;
868
        mOtherPid = aOther.mOtherPid;
869
870
        aOther.mValid = false;
871
        return *this;
872
    }
873
874
0
    ~Endpoint() {
875
0
        if (mValid) {
876
0
            CloseDescriptor(mTransport);
877
0
        }
878
0
    }
Unexecuted instantiation: mozilla::ipc::Endpoint<mozilla::ipc::PBackgroundParent>::~Endpoint()
Unexecuted instantiation: mozilla::ipc::Endpoint<mozilla::ipc::PBackgroundChild>::~Endpoint()
879
880
    ProcessId OtherPid() const {
881
        return mOtherPid;
882
    }
883
884
    // This method binds aActor to this endpoint. After this call, the actor can
885
    // be used to send and receive messages. The endpoint becomes invalid.
886
    bool Bind(PFooSide* aActor)
887
0
    {
888
0
        MOZ_RELEASE_ASSERT(mValid);
889
0
        if (mMyPid != base::GetCurrentProcId()) {
890
0
            // These pids must match, unless we are recording or replaying, in
891
0
            // which case the parent process will have supplied the pid for the
892
0
            // middleman process instead. Fix this here. If we're replaying
893
0
            // we'll see the pid of the middleman used while recording.
894
0
            MOZ_RELEASE_ASSERT(recordreplay::IsRecordingOrReplaying());
895
0
            MOZ_RELEASE_ASSERT(recordreplay::IsReplaying() ||
896
0
                               mMyPid == recordreplay::child::MiddlemanProcessId());
897
0
            mMyPid = base::GetCurrentProcId();
898
0
        }
899
0
900
0
        UniquePtr<Transport> t = mozilla::ipc::OpenDescriptor(mTransport, mMode);
901
0
        if (!t) {
902
0
            return false;
903
0
        }
904
0
        if (!aActor->Open(t.get(), mOtherPid, XRE_GetIOMessageLoop(),
905
0
                          mMode == Transport::MODE_SERVER ? ParentSide : ChildSide)) {
906
0
            return false;
907
0
        }
908
0
        mValid = false;
909
0
        aActor->SetTransport(std::move(t));
910
0
        return true;
911
0
    }
Unexecuted instantiation: mozilla::ipc::Endpoint<mozilla::ipc::PBackgroundParent>::Bind(mozilla::ipc::PBackgroundParent*)
Unexecuted instantiation: mozilla::ipc::Endpoint<mozilla::ipc::PBackgroundChild>::Bind(mozilla::ipc::PBackgroundChild*)
912
913
    bool IsValid() const {
914
        return mValid;
915
    }
916
917
private:
918
    friend struct IPC::ParamTraits<Endpoint<PFooSide>>;
919
920
    Endpoint(const Endpoint&) = delete;
921
    Endpoint& operator=(const Endpoint&) = delete;
922
923
    bool mValid;
924
    mozilla::ipc::Transport::Mode mMode;
925
    TransportDescriptor mTransport;
926
    ProcessId mMyPid, mOtherPid;
927
};
928
929
#if defined(XP_MACOSX)
930
void AnnotateCrashReportWithErrno(CrashReporter::Annotation tag, int error);
931
#else
932
static inline void AnnotateCrashReportWithErrno(CrashReporter::Annotation tag, int error)
933
0
{}
Unexecuted instantiation: Unified_cpp_ipc_glue0.cpp:mozilla::ipc::AnnotateCrashReportWithErrno(CrashReporter::Annotation, int)
Unexecuted instantiation: Unified_cpp_ipc_glue1.cpp:mozilla::ipc::AnnotateCrashReportWithErrno(CrashReporter::Annotation, int)
934
#endif
935
936
// This function is used internally to create a pair of Endpoints. See the
937
// comment above Endpoint for a description of how it might be used.
938
template<class PFooParent, class PFooChild>
939
nsresult
940
CreateEndpoints(const PrivateIPDLInterface& aPrivate,
941
                base::ProcessId aParentDestPid,
942
                base::ProcessId aChildDestPid,
943
                Endpoint<PFooParent>* aParentEndpoint,
944
                Endpoint<PFooChild>* aChildEndpoint)
945
{
946
  MOZ_RELEASE_ASSERT(aParentDestPid);
947
  MOZ_RELEASE_ASSERT(aChildDestPid);
948
949
  TransportDescriptor parentTransport, childTransport;
950
  nsresult rv;
951
  if (NS_FAILED(rv = CreateTransport(aParentDestPid, &parentTransport, &childTransport))) {
952
    AnnotateCrashReportWithErrno(
953
      CrashReporter::Annotation::IpcCreateEndpointsNsresult, int(rv));
954
    return rv;
955
  }
956
957
  *aParentEndpoint = Endpoint<PFooParent>(aPrivate, mozilla::ipc::Transport::MODE_SERVER,
958
                                          parentTransport, aParentDestPid, aChildDestPid);
959
960
  *aChildEndpoint = Endpoint<PFooChild>(aPrivate, mozilla::ipc::Transport::MODE_CLIENT,
961
                                        childTransport, aChildDestPid, aParentDestPid);
962
963
  return NS_OK;
964
}
965
966
void
967
TableToArray(const nsTHashtable<nsPtrHashKey<void>>& aTable,
968
             nsTArray<void*>& aArray);
969
970
} // namespace ipc
971
972
template<typename Protocol>
973
class ManagedContainer : public nsTHashtable<nsPtrHashKey<Protocol>>
974
{
975
  typedef nsTHashtable<nsPtrHashKey<Protocol>> BaseClass;
976
977
public:
978
  // Having the core logic work on void pointers, rather than typed pointers,
979
  // means that we can have one instance of this code out-of-line, rather
980
  // than several hundred instances of this code out-of-lined.  (Those
981
  // repeated instances don't necessarily get folded together by the linker
982
  // because they contain member offsets and such that differ between the
983
  // functions.)  We do have to pay for it with some eye-bleedingly bad casts,
984
  // though.
985
  void ToArray(nsTArray<Protocol*>& aArray) const {
986
    ::mozilla::ipc::TableToArray(*reinterpret_cast<const nsTHashtable<nsPtrHashKey<void>>*>
987
                                 (static_cast<const BaseClass*>(this)),
988
                                 reinterpret_cast<nsTArray<void*>&>(aArray));
989
  }
990
};
991
992
template<typename Protocol>
993
Protocol*
994
LoneManagedOrNullAsserts(const ManagedContainer<Protocol>& aManagees)
995
{
996
    if (aManagees.IsEmpty()) {
997
        return nullptr;
998
    }
999
    MOZ_ASSERT(aManagees.Count() == 1);
1000
    return aManagees.ConstIter().Get()->GetKey();
1001
}
1002
1003
// appId's are for B2G only currently, where managees.Count() == 1. This is
1004
// not guaranteed currently in Desktop, so for paths used for desktop,
1005
// don't assert there's one managee.
1006
template<typename Protocol>
1007
Protocol*
1008
SingleManagedOrNull(const ManagedContainer<Protocol>& aManagees)
1009
{
1010
    if (aManagees.Count() != 1) {
1011
        return nullptr;
1012
    }
1013
    return aManagees.ConstIter().Get()->GetKey();
1014
}
1015
1016
} // namespace mozilla
1017
1018
1019
namespace IPC {
1020
1021
template <>
1022
struct ParamTraits<mozilla::ipc::ActorHandle>
1023
{
1024
    typedef mozilla::ipc::ActorHandle paramType;
1025
1026
    static void Write(Message* aMsg, const paramType& aParam)
1027
    {
1028
        IPC::WriteParam(aMsg, aParam.mId);
1029
    }
1030
1031
    static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
1032
0
    {
1033
0
        int id;
1034
0
        if (IPC::ReadParam(aMsg, aIter, &id)) {
1035
0
            aResult->mId = id;
1036
0
            return true;
1037
0
        }
1038
0
        return false;
1039
0
    }
1040
1041
    static void Log(const paramType& aParam, std::wstring* aLog)
1042
    {
1043
        aLog->append(StringPrintf(L"(%d)", aParam.mId));
1044
    }
1045
};
1046
1047
template<class PFooSide>
1048
struct ParamTraits<mozilla::ipc::Endpoint<PFooSide>>
1049
{
1050
    typedef mozilla::ipc::Endpoint<PFooSide> paramType;
1051
1052
    static void Write(Message* aMsg, const paramType& aParam)
1053
    {
1054
        IPC::WriteParam(aMsg, aParam.mValid);
1055
        if (!aParam.mValid) {
1056
            return;
1057
        }
1058
1059
        IPC::WriteParam(aMsg, static_cast<uint32_t>(aParam.mMode));
1060
1061
        // We duplicate the descriptor so that our own file descriptor remains
1062
        // valid after the write. An alternative would be to set
1063
        // aParam.mTransport.mValid to false, but that won't work because aParam
1064
        // is const.
1065
        mozilla::ipc::TransportDescriptor desc = mozilla::ipc::DuplicateDescriptor(aParam.mTransport);
1066
        IPC::WriteParam(aMsg, desc);
1067
1068
        IPC::WriteParam(aMsg, aParam.mMyPid);
1069
        IPC::WriteParam(aMsg, aParam.mOtherPid);
1070
    }
1071
1072
    static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
1073
    {
1074
        MOZ_RELEASE_ASSERT(!aResult->mValid);
1075
1076
        if (!IPC::ReadParam(aMsg, aIter, &aResult->mValid)) {
1077
            return false;
1078
        }
1079
        if (!aResult->mValid) {
1080
            // Object is empty, but read succeeded.
1081
            return true;
1082
        }
1083
1084
        uint32_t mode;
1085
        if (!IPC::ReadParam(aMsg, aIter, &mode) ||
1086
            !IPC::ReadParam(aMsg, aIter, &aResult->mTransport) ||
1087
            !IPC::ReadParam(aMsg, aIter, &aResult->mMyPid) ||
1088
            !IPC::ReadParam(aMsg, aIter, &aResult->mOtherPid)) {
1089
            return false;
1090
        }
1091
        aResult->mMode = Channel::Mode(mode);
1092
        return true;
1093
    }
1094
1095
    static void Log(const paramType& aParam, std::wstring* aLog)
1096
    {
1097
        aLog->append(StringPrintf(L"Endpoint"));
1098
    }
1099
};
1100
1101
} // namespace IPC
1102
1103
1104
#endif  // mozilla_ipc_ProtocolUtils_h