ProtocolUtils.h (31222B)
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 https://mozilla.org/MPL/2.0/. */ 6 7 #ifndef mozilla_ipc_ProtocolUtils_h 8 #define mozilla_ipc_ProtocolUtils_h 9 10 #include <cstddef> 11 #include <cstdint> 12 #include <utility> 13 #include "IPCMessageStart.h" 14 #include "base/basictypes.h" 15 #include "base/process.h" 16 #include "chrome/common/ipc_message.h" 17 #include "mojo/core/ports/port_ref.h" 18 #include "mozilla/AlreadyAddRefed.h" 19 #include "mozilla/Assertions.h" 20 #include "mozilla/Attributes.h" 21 #include "mozilla/FunctionRef.h" 22 #include "mozilla/MoveOnlyFunction.h" 23 #include "mozilla/Mutex.h" 24 #include "mozilla/RefPtr.h" 25 #include "mozilla/UniquePtr.h" 26 #include "mozilla/ipc/MessageChannel.h" 27 #include "mozilla/ipc/MessageLink.h" 28 #include "mozilla/ipc/Shmem.h" 29 #include "nsPrintfCString.h" 30 #include "nsTHashMap.h" 31 #include "nsDebug.h" 32 #include "nsISupports.h" 33 #include "nsTArrayForwardDeclare.h" 34 #include "nsTHashSet.h" 35 36 // XXX Things that could be moved to ProtocolUtils.cpp 37 #include "base/process_util.h" // for CloseProcessHandle 38 #include "prenv.h" // for PR_GetEnv 39 40 #if defined(ANDROID) && defined(DEBUG) 41 # include <android/log.h> 42 #endif 43 44 template <typename T> 45 class nsPtrHashKey; 46 47 // WARNING: this takes into account the private, special-message-type 48 // enum in ipc_channel.h. They need to be kept in sync. 49 namespace { 50 // XXX the max message ID is actually kuint32max now ... when this 51 // changed, the assumptions of the special message IDs changed in that 52 // they're not carving out messages from likely-unallocated space, but 53 // rather carving out messages from the end of space allocated to 54 // protocol 0. Oops! We can get away with this until protocol 0 55 // starts approaching its 65,536th message. 56 enum { 57 // Message types used by DataPipe 58 DATA_PIPE_CLOSED_MESSAGE_TYPE = kuint16max - 18, 59 DATA_PIPE_BYTES_CONSUMED_MESSAGE_TYPE = kuint16max - 17, 60 61 // Message types used by NodeChannel 62 ACCEPT_INVITE_MESSAGE_TYPE = kuint16max - 16, 63 REQUEST_INTRODUCTION_MESSAGE_TYPE = kuint16max - 15, 64 INTRODUCE_MESSAGE_TYPE = kuint16max - 14, 65 BROADCAST_MESSAGE_TYPE = kuint16max - 13, 66 EVENT_MESSAGE_TYPE = kuint16max - 12, 67 68 // Message types used by MessageChannel 69 MANAGED_ENDPOINT_DROPPED_MESSAGE_TYPE = kuint16max - 11, 70 MANAGED_ENDPOINT_BOUND_MESSAGE_TYPE = kuint16max - 10, 71 IMPENDING_SHUTDOWN_MESSAGE_TYPE = kuint16max - 9, 72 BUILD_IDS_MATCH_MESSAGE_TYPE = kuint16max - 8, 73 BUILD_ID_MESSAGE_TYPE = kuint16max - 7, // unused 74 CHANNEL_OPENED_MESSAGE_TYPE = kuint16max - 6, 75 SHMEM_DESTROYED_MESSAGE_TYPE = kuint16max - 5, 76 SHMEM_CREATED_MESSAGE_TYPE = kuint16max - 4, 77 GOODBYE_MESSAGE_TYPE = kuint16max - 3, 78 CANCEL_MESSAGE_TYPE = kuint16max - 2, 79 80 // kuint16max - 1 is used by ipc_channel.h. 81 }; 82 83 } // namespace 84 85 class MessageLoop; 86 class PickleIterator; 87 class nsISerialEventTarget; 88 89 namespace mozilla { 90 class SchedulerGroup; 91 class UntypedManagedContainer; 92 93 namespace dom { 94 class ContentParent; 95 } // namespace dom 96 97 namespace net { 98 class NeckoParent; 99 } // namespace net 100 101 namespace ipc { 102 103 class ProtocolFdMapping; 104 class ProtocolCloneContext; 105 106 // Helper type used to specify process info when constructing endpoints for 107 // [NeedsOtherPid] toplevel actors. 108 struct EndpointProcInfo { 109 base::ProcessId mPid = base::kInvalidProcessId; 110 GeckoChildID mChildID = kInvalidGeckoChildID; 111 112 bool operator==(const EndpointProcInfo& aOther) const { 113 return mPid == aOther.mPid && mChildID == aOther.mChildID; 114 } 115 bool operator!=(const EndpointProcInfo& aOther) const { 116 return !operator==(aOther); 117 } 118 119 static EndpointProcInfo Invalid() { return {}; } 120 static EndpointProcInfo Current(); 121 }; 122 123 // Used to pass references to protocol actors across the wire. 124 // Actors created on the parent-side have a positive ID, and actors 125 // allocated on the child side have a negative ID. 126 using ActorId = IPC::Message::routeid_t; 127 128 enum class LinkStatus : uint8_t { 129 // The actor has not established a link yet, or the actor is no longer in use 130 // by IPC, and its 'Dealloc' method has been called or is being called. 131 // 132 // NOTE: This state is used instead of an explicit `Freed` state when IPC no 133 // longer holds references to the current actor as we currently re-open 134 // existing actors. Once we fix these poorly behaved actors, this loopback 135 // state can be split to have the final state not be the same as the initial 136 // state. 137 Inactive, 138 139 // A live link is connected to the other side of this actor. 140 Connected, 141 142 // The link has begun being destroyed. Messages may no longer be sent. The 143 // ActorDestroy method is queued to be called, but has not been invoked yet, 144 // as managed actors still need to be destroyed first. 145 // 146 // NOTE: While no new IPC can be received at this point, `CanRecv` will still 147 // be true until `LinkStatus::Destroyed`. 148 Doomed, 149 150 // The actor has been destroyed, and ActorDestroy has been called, however an 151 // ActorLifecycleProxy still holds a reference to the actor. 152 Destroyed, 153 }; 154 155 typedef IPCMessageStart ProtocolId; 156 157 // Generated by IPDL compiler 158 const char* ProtocolIdToName(IPCMessageStart aId); 159 160 class IRefCountedProtocol; 161 class IToplevelProtocol; 162 class ActorLifecycleProxy; 163 class WeakActorLifecycleProxy; 164 class IPDLResolverInner; 165 class UntypedManagedEndpoint; 166 167 class IProtocol : public HasResultCodes { 168 public: 169 enum ActorDestroyReason { 170 FailedConstructor, 171 Deletion, 172 AncestorDeletion, 173 NormalShutdown, 174 AbnormalShutdown, 175 ManagedEndpointDropped 176 }; 177 178 using ProcessId = base::ProcessId; 179 using Message = IPC::Message; 180 181 IProtocol(ProtocolId aProtoId, Side aSide) 182 : mId(0), 183 mProtocolId(aProtoId), 184 mSide(aSide), 185 mLinkStatus(LinkStatus::Inactive), 186 mLifecycleProxy(nullptr), 187 mManager(nullptr), 188 mToplevel(nullptr) {} 189 190 IToplevelProtocol* ToplevelProtocol() { return mToplevel; } 191 const IToplevelProtocol* ToplevelProtocol() const { return mToplevel; } 192 193 // Lookup() is forwarded directly to the toplevel protocol. 194 IProtocol* Lookup(ActorId aId); 195 196 Shmem CreateSharedMemory(size_t aSize, bool aUnsafe); 197 Shmem::Segment* LookupSharedMemory(ActorId aId); 198 bool IsTrackingSharedMemory(const Shmem::Segment* aSegment); 199 bool DestroySharedMemory(Shmem& aShmem); 200 201 MessageChannel* GetIPCChannel(); 202 const MessageChannel* GetIPCChannel() const; 203 204 // Get the nsISerialEventTarget which all messages sent to this actor will be 205 // processed on. Unless stated otherwise, all operations on IProtocol which 206 // don't occur on this `nsISerialEventTarget` are unsafe. 207 nsISerialEventTarget* GetActorEventTarget(); 208 209 // Actor lifecycle and other properties. 210 ProtocolId GetProtocolId() const { return mProtocolId; } 211 const char* GetProtocolName() const { return ProtocolIdToName(mProtocolId); } 212 213 ActorId Id() const { return mId; } 214 IRefCountedProtocol* Manager() const { return mManager; } 215 216 uint32_t AllManagedActorsCount() const; 217 218 ActorLifecycleProxy* GetLifecycleProxy() { return mLifecycleProxy; } 219 WeakActorLifecycleProxy* GetWeakLifecycleProxy(); 220 221 Side GetSide() const { return mSide; } 222 bool CanSend() const { return mLinkStatus == LinkStatus::Connected; } 223 224 // Returns `true` for an active actor until the actor's `ActorDestroy` method 225 // has been called. 226 bool CanRecv() const { 227 return mLinkStatus == LinkStatus::Connected || 228 mLinkStatus == LinkStatus::Doomed; 229 } 230 231 // Deallocate a managee given its type. 232 virtual void DeallocManagee(ProtocolId, IProtocol*) = 0; 233 234 virtual Result OnMessageReceived(const Message& aMessage) = 0; 235 virtual Result OnMessageReceived(const Message& aMessage, 236 UniquePtr<Message>& aReply) = 0; 237 bool AllocShmem(size_t aSize, Shmem* aOutMem); 238 bool AllocUnsafeShmem(size_t aSize, Shmem* aOutMem); 239 bool DeallocShmem(Shmem& aMem); 240 241 void FatalError(const char* const aErrorMsg); 242 virtual void HandleFatalError(const char* aErrorMsg); 243 244 protected: 245 virtual ~IProtocol(); 246 247 friend class IToplevelProtocol; 248 friend class ActorLifecycleProxy; 249 friend class IPDLResolverInner; 250 friend class UntypedManagedEndpoint; 251 friend struct IPC::ParamTraits<IProtocol*>; 252 253 // We have separate functions because the accessibility code and BrowserParent 254 // manually calls SetManager. 255 void SetManager(IRefCountedProtocol* aManager); 256 257 // Clear `mManager` and `mToplevel` to nullptr. Only intended to be called 258 // within the unlink implementation of cycle collected IPDL actors with cycle 259 // collected managers. 260 void UnlinkManager(); 261 262 // Sets the manager for the protocol and registers the protocol with 263 // its manager, setting up channels for the protocol as well. Not 264 // for use outside of IPDL. 265 bool SetManagerAndRegister(IRefCountedProtocol* aManager, 266 ActorId aId = kNullActorId); 267 268 // Helpers for calling `Send` on our underlying IPC channel. 269 bool ChannelSend(UniquePtr<IPC::Message> aMsg, 270 IPC::Message::seqno_t* aSeqno = nullptr); 271 bool ChannelSend(UniquePtr<IPC::Message> aMsg, 272 UniquePtr<IPC::Message>* aReply); 273 274 // Internal method called when the actor becomes connected. 275 already_AddRefed<ActorLifecycleProxy> ActorConnected(); 276 277 // Internal method called when actor becomes disconnected. 278 void ActorDisconnected(ActorDestroyReason aWhy); 279 280 // Gets the list of ProtocolIds managed by this protocol. 281 virtual Span<const ProtocolId> ManagedProtocolIds() const = 0; 282 283 // Get the ManagedContainer for actors of the given protocol managed by this 284 // protocol. This returns a container if and only if passed a ProtocolId in 285 // `ManagedProtocolIds()`. 286 virtual UntypedManagedContainer* GetManagedActors(ProtocolId aProtocol) = 0; 287 const UntypedManagedContainer* GetManagedActors(ProtocolId aProtocol) const { 288 return const_cast<IProtocol*>(this)->GetManagedActors(aProtocol); 289 } 290 291 // Called internally to reject the callbacks for all async-returns methods 292 // in-progress on this actor with the given ResponseRejectReason. 293 virtual void RejectPendingResponses(ResponseRejectReason aReason) {} 294 295 // Called when the actor has been destroyed due to an error, a __delete__ 296 // message, or a __doom__ reply. 297 virtual void ActorDestroy(ActorDestroyReason aWhy) {} 298 299 // Called when IPC has acquired its first reference to the actor. This method 300 // may take references which will later be freed by `ActorDealloc`. 301 virtual void ActorAlloc() = 0; 302 303 // Called when IPC has released its final reference to the actor. It will call 304 // the dealloc method, causing the actor to be actually freed. 305 // 306 // The actor has been freed after this method returns. 307 virtual void ActorDealloc() = 0; 308 309 static const ActorId kNullActorId = 0; 310 311 private: 312 #ifdef DEBUG 313 void WarnMessageDiscarded(IPC::Message* aMsg); 314 #else 315 void WarnMessageDiscarded(IPC::Message*) {} 316 #endif 317 318 void DoomSubtree(); 319 320 // Internal function returning an arbitrary directly managed actor. Used to 321 // identify managed actors to destroy when tearing down an actor tree. 322 IProtocol* PeekManagedActor() const; 323 324 ActorId mId; 325 const ProtocolId mProtocolId; 326 const Side mSide; 327 LinkStatus mLinkStatus; 328 ActorLifecycleProxy* mLifecycleProxy; 329 RefPtr<IRefCountedProtocol> mManager; 330 IToplevelProtocol* mToplevel; 331 }; 332 333 #define IPC_OK() mozilla::ipc::IPCResult::Ok() 334 #define IPC_FAIL(actor, why) \ 335 mozilla::ipc::IPCResult::Fail(WrapNotNull(actor), __func__, (why)) 336 #define IPC_FAIL_NO_REASON(actor) \ 337 mozilla::ipc::IPCResult::Fail(WrapNotNull(actor), __func__) 338 339 /* 340 * IPC_FAIL_UNSAFE_PRINTF(actor, format, ...) 341 * 342 * Create a failure IPCResult with a dynamic reason-string. 343 * 344 * @note This macro causes data collection because IPC failure reasons may be 345 * sent to crash-stats, where they are publicly visible. Firefox data stewards 346 * must do data review on usages of this macro. 347 */ 348 #define IPC_FAIL_UNSAFE_PRINTF(actor, format, ...) \ 349 mozilla::ipc::IPCResult::FailUnsafePrintfImpl( \ 350 WrapNotNull(actor), __func__, nsPrintfCString(format, ##__VA_ARGS__)) 351 352 #define IPC_TEST_FAIL(actor) \ 353 mozilla::ipc::IPCResult::FailForTesting(WrapNotNull(actor), __func__, "") 354 355 /** 356 * All message deserializers and message handlers should return this type via 357 * the above macros. We use a less generic name here to avoid conflict with 358 * `mozilla::Result` because we have quite a few `using namespace mozilla::ipc;` 359 * in the code base. 360 * 361 * Note that merely constructing a failure-result, whether directly or via the 362 * IPC_FAIL macros, causes the associated error message to be processed 363 * immediately. 364 */ 365 class IPCResult { 366 public: 367 static IPCResult Ok() { return IPCResult(true); } 368 369 // IPC failure messages can sometimes end up in telemetry. As such, to avoid 370 // accidentally exfiltrating sensitive information without a data review, we 371 // require that they be constant strings. 372 template <size_t N, size_t M> 373 static IPCResult Fail(NotNull<IProtocol*> aActor, const char (&aWhere)[N], 374 const char (&aWhy)[M]) { 375 return FailImpl(aActor, aWhere, aWhy); 376 } 377 template <size_t N> 378 static IPCResult Fail(NotNull<IProtocol*> aActor, const char (&aWhere)[N]) { 379 return FailImpl(aActor, aWhere, ""); 380 } 381 382 MOZ_IMPLICIT operator bool() const { return mSuccess; } 383 384 // Only used by IPC_FAIL_UNSAFE_PRINTF (q.v.). Do not call this directly. (Or 385 // at least get data-review's approval if you do.) 386 template <size_t N> 387 static IPCResult FailUnsafePrintfImpl(NotNull<IProtocol*> aActor, 388 const char (&aWhere)[N], 389 nsPrintfCString const& aWhy) { 390 return FailImpl(aActor, aWhere, aWhy.get()); 391 } 392 393 // Only used in testing. 394 static IPCResult FailForTesting(NotNull<IProtocol*> aActor, 395 const char* aWhere, const char* aWhy); 396 397 private: 398 static IPCResult FailImpl(NotNull<IProtocol*> aActor, const char* aWhere, 399 const char* aWhy); 400 401 explicit IPCResult(bool aResult) : mSuccess(aResult) {} 402 bool mSuccess; 403 }; 404 405 class UntypedEndpoint; 406 407 template <class PFooSide> 408 class Endpoint; 409 410 template <class PFooSide> 411 class ManagedEndpoint; 412 413 /** 414 * All refcounted protocols should inherit this class. 415 */ 416 class IRefCountedProtocol : public IProtocol { 417 public: 418 NS_INLINE_DECL_PURE_VIRTUAL_REFCOUNTING 419 420 using IProtocol::IProtocol; 421 }; 422 423 /** 424 * All top-level protocols should inherit this class. 425 * 426 * IToplevelProtocol tracks all top-level protocol actors created from 427 * this protocol actor. 428 */ 429 class IToplevelProtocol : public IRefCountedProtocol { 430 friend class IProtocol; 431 template <class PFooSide> 432 friend class Endpoint; 433 434 protected: 435 explicit IToplevelProtocol(const char* aName, ProtocolId aProtoId, 436 Side aSide); 437 ~IToplevelProtocol() = default; 438 439 public: 440 // Shadows the method on IProtocol, which will forward to the top. 441 IProtocol* Lookup(Shmem::id_t aId); 442 443 Shmem CreateSharedMemory(size_t aSize, bool aUnsafe); 444 Shmem::Segment* LookupSharedMemory(Shmem::id_t aId); 445 bool IsTrackingSharedMemory(const Shmem::Segment* aSegment); 446 bool DestroySharedMemory(Shmem& aShmem); 447 448 MessageChannel* GetIPCChannel() { return &mChannel; } 449 const MessageChannel* GetIPCChannel() const { return &mChannel; } 450 451 void SetOtherEndpointProcInfo(EndpointProcInfo aOtherProcInfo); 452 453 virtual void ProcessingError(Result aError, const char* aMsgName) {} 454 455 bool Open(ScopedPort aPort, const nsID& aMessageChannelId, 456 EndpointProcInfo aOtherProcInfo, 457 nsISerialEventTarget* aEventTarget = nullptr); 458 459 bool Open(IToplevelProtocol* aTarget, nsISerialEventTarget* aEventTarget, 460 mozilla::ipc::Side aSide = mozilla::ipc::UnknownSide); 461 462 // Open a toplevel actor such that both ends of the actor's channel are on 463 // the same thread. This method should be called on the thread to perform 464 // the link. 465 // 466 // WARNING: Attempting to send a sync message on the same thread will crash. 467 bool OpenOnSameThread(IToplevelProtocol* aTarget, 468 mozilla::ipc::Side aSide = mozilla::ipc::UnknownSide); 469 470 /** 471 * This sends a special message that is processed on the IO thread, so that 472 * other actors can know that the process will soon shutdown. 473 */ 474 void NotifyImpendingShutdown(); 475 476 void Close(); 477 478 void SetReplyTimeoutMs(int32_t aTimeoutMs); 479 480 void DeallocShmems(); 481 bool ShmemCreated(const Message& aMsg); 482 bool ShmemDestroyed(const Message& aMsg); 483 484 virtual bool ShouldContinueFromReplyTimeout() { return false; } 485 486 // WARNING: This function is called with the MessageChannel monitor held. 487 virtual void IntentionalCrash() { MOZ_CRASH("Intentional IPDL crash"); } 488 489 // The code here is only useful for fuzzing. It should not be used for any 490 // other purpose. 491 #ifdef DEBUG 492 // Returns true if we should simulate a timeout. 493 // WARNING: This is a testing-only function that is called with the 494 // MessageChannel monitor held. Don't do anything fancy here or we could 495 // deadlock. 496 virtual bool ArtificialTimeout() { return false; } 497 498 // Returns true if we want to cause the worker thread to sleep with the 499 // monitor unlocked. 500 virtual bool NeedArtificialSleep() { return false; } 501 502 // This function should be implemented to sleep for some amount of time on 503 // the worker thread. Will only be called if NeedArtificialSleep() returns 504 // true. 505 virtual void ArtificialSleep() {} 506 #else 507 bool ArtificialTimeout() { return false; } 508 bool NeedArtificialSleep() { return false; } 509 void ArtificialSleep() {} 510 #endif 511 512 bool IsOnCxxStack() const; 513 514 virtual void ProcessRemoteNativeEventsInInterruptCall() {} 515 516 virtual void OnChannelReceivedMessage(const Message& aMsg) {} 517 518 // MessageChannel lifecycle callbacks. 519 void OnIPCChannelOpened() { 520 // Leak the returned ActorLifecycleProxy reference. It will be destroyed in 521 // `OnChannelClose` or `OnChannelError`. 522 ActorConnected().leak(); 523 } 524 void OnChannelClose() { 525 // Re-acquire the ActorLifecycleProxy reference acquired in 526 // OnIPCChannelOpened. 527 RefPtr<ActorLifecycleProxy> proxy = dont_AddRef(GetLifecycleProxy()); 528 ActorDisconnected(NormalShutdown); 529 DeallocShmems(); 530 } 531 void OnChannelError() { 532 // Re-acquire the ActorLifecycleProxy reference acquired in 533 // OnIPCChannelOpened. 534 RefPtr<ActorLifecycleProxy> proxy = dont_AddRef(GetLifecycleProxy()); 535 ActorDisconnected(AbnormalShutdown); 536 DeallocShmems(); 537 } 538 539 base::ProcessId OtherPidMaybeInvalid() const { return mOtherPid; } 540 GeckoChildID OtherChildIDMaybeInvalid() const { return mOtherChildID; } 541 542 private: 543 int64_t NextId(); 544 545 template <class T> 546 using IDMap = nsTHashMap<int64_t, T>; 547 548 base::ProcessId mOtherPid; 549 GeckoChildID mOtherChildID; 550 551 // NOTE NOTE NOTE 552 // Used to be on mState 553 int64_t mLastLocalId; 554 IDMap<RefPtr<ActorLifecycleProxy>> mActorMap; 555 IDMap<RefPtr<Shmem::Segment>> mShmemMap; 556 557 MessageChannel mChannel; 558 }; 559 560 class IShmemAllocator { 561 public: 562 virtual bool AllocShmem(size_t aSize, mozilla::ipc::Shmem* aShmem) = 0; 563 virtual bool AllocUnsafeShmem(size_t aSize, mozilla::ipc::Shmem* aShmem) = 0; 564 virtual bool DeallocShmem(mozilla::ipc::Shmem& aShmem) = 0; 565 }; 566 567 #define FORWARD_SHMEM_ALLOCATOR_TO(aImplClass) \ 568 virtual bool AllocShmem(size_t aSize, mozilla::ipc::Shmem* aShmem) \ 569 override { \ 570 return aImplClass::AllocShmem(aSize, aShmem); \ 571 } \ 572 virtual bool AllocUnsafeShmem(size_t aSize, mozilla::ipc::Shmem* aShmem) \ 573 override { \ 574 return aImplClass::AllocUnsafeShmem(aSize, aShmem); \ 575 } \ 576 virtual bool DeallocShmem(mozilla::ipc::Shmem& aShmem) override { \ 577 return aImplClass::DeallocShmem(aShmem); \ 578 } 579 580 inline bool LoggingEnabled() { 581 #if defined(DEBUG) || defined(FUZZING) 582 return !!PR_GetEnv("MOZ_IPC_MESSAGE_LOG"); 583 #else 584 return false; 585 #endif 586 } 587 588 #if defined(DEBUG) || defined(FUZZING) 589 bool LoggingEnabledFor(const char* aTopLevelProtocol, mozilla::ipc::Side aSide, 590 const char* aFilter); 591 #endif 592 593 inline bool LoggingEnabledFor(const char* aTopLevelProtocol, 594 mozilla::ipc::Side aSide) { 595 #if defined(DEBUG) || defined(FUZZING) 596 return LoggingEnabledFor(aTopLevelProtocol, aSide, 597 PR_GetEnv("MOZ_IPC_MESSAGE_LOG")); 598 #else 599 return false; 600 #endif 601 } 602 603 MOZ_NEVER_INLINE void LogMessageForProtocol(const char* aTopLevelProtocol, 604 base::ProcessId aOtherPid, 605 const char* aContextDescription, 606 uint32_t aMessageId, 607 MessageDirection aDirection); 608 609 MOZ_NEVER_INLINE void ProtocolErrorBreakpoint(const char* aMsg); 610 611 // IPC::MessageReader and IPC::MessageWriter call this function for FatalError 612 // calls which come from serialization/deserialization. 613 MOZ_NEVER_INLINE void PickleFatalError(const char* aMsg, IProtocol* aActor); 614 615 // The code generator calls this function for errors which come from the 616 // methods of protocols. Doing this saves codesize by making the error 617 // cases significantly smaller. 618 MOZ_NEVER_INLINE void FatalError(const char* aMsg, bool aIsParent); 619 620 // The code generator calls this function for errors which are not 621 // protocol-specific: errors in generated struct methods or errors in 622 // transition functions, for instance. Doing this saves codesize by 623 // by making the error cases significantly smaller. 624 MOZ_NEVER_INLINE void LogicError(const char* aMsg); 625 626 MOZ_NEVER_INLINE void ActorIdReadError(const char* aActorDescription); 627 628 MOZ_NEVER_INLINE void BadActorIdError(const char* aActorDescription); 629 630 MOZ_NEVER_INLINE void ActorLookupError(const char* aActorDescription); 631 632 MOZ_NEVER_INLINE void MismatchedActorTypeError(const char* aActorDescription); 633 634 MOZ_NEVER_INLINE void UnionTypeReadError(const char* aUnionName); 635 636 MOZ_NEVER_INLINE void ArrayLengthReadError(const char* aElementName); 637 638 MOZ_NEVER_INLINE void SentinelReadError(const char* aElementName); 639 640 /** 641 * Annotate the crash reporter with the error code from the most recent system 642 * call. Returns the system error. 643 */ 644 void AnnotateSystemError(); 645 646 // The ActorLifecycleProxy is a helper type used internally by IPC to maintain a 647 // maybe-owning reference to an IProtocol object. For well-behaved actors 648 // which are not freed until after their `Dealloc` method is called, a 649 // reference to an actor's `ActorLifecycleProxy` object is an owning one, as the 650 // `Dealloc` method will only be called when all references to the 651 // `ActorLifecycleProxy` are released. 652 // 653 // Unfortunately, some actors may be destroyed before their `Dealloc` method 654 // is called. For these actors, `ActorLifecycleProxy` acts as a weak pointer, 655 // and will begin to return `nullptr` from its `Get()` method once the 656 // corresponding actor object has been destroyed. 657 // 658 // When calling a `Recv` method, IPC will hold a `ActorLifecycleProxy` reference 659 // to the target actor, meaning that well-behaved actors can behave as though a 660 // strong reference is being held. 661 // 662 // Generic IPC code MUST treat ActorLifecycleProxy references as weak 663 // references! 664 class ActorLifecycleProxy { 665 public: 666 NS_INLINE_DECL_REFCOUNTING_ONEVENTTARGET(ActorLifecycleProxy) 667 668 IProtocol* Get() { return mActor; } 669 670 WeakActorLifecycleProxy* GetWeakProxy(); 671 672 private: 673 friend class IProtocol; 674 675 explicit ActorLifecycleProxy(IProtocol* aActor); 676 ~ActorLifecycleProxy(); 677 678 ActorLifecycleProxy(const ActorLifecycleProxy&) = delete; 679 ActorLifecycleProxy& operator=(const ActorLifecycleProxy&) = delete; 680 681 IProtocol* MOZ_NON_OWNING_REF mActor; 682 683 // When requested, the current self-referencing weak reference for this 684 // ActorLifecycleProxy. 685 RefPtr<WeakActorLifecycleProxy> mWeakProxy; 686 }; 687 688 // Unlike ActorLifecycleProxy, WeakActorLifecycleProxy only holds a weak 689 // reference to both the proxy and the actual actor, meaning that holding this 690 // type will not attempt to keep the actor object alive. 691 // 692 // This type is safe to hold on threads other than the actor's thread, but is 693 // _NOT_ safe to access on other threads, as actors and ActorLifecycleProxy 694 // objects are not threadsafe. 695 class WeakActorLifecycleProxy final { 696 public: 697 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(WeakActorLifecycleProxy) 698 699 // May only be called on the actor's event target. 700 // Will return `nullptr` if the actor has already been destroyed from IPC's 701 // point of view. 702 IProtocol* Get() const; 703 704 // Safe to call on any thread. 705 nsISerialEventTarget* ActorEventTarget() const { return mActorEventTarget; } 706 707 private: 708 friend class ActorLifecycleProxy; 709 710 explicit WeakActorLifecycleProxy(ActorLifecycleProxy* aProxy); 711 ~WeakActorLifecycleProxy(); 712 713 WeakActorLifecycleProxy(const WeakActorLifecycleProxy&) = delete; 714 WeakActorLifecycleProxy& operator=(const WeakActorLifecycleProxy&) = delete; 715 716 // This field may only be accessed on the actor's thread, and will be 717 // automatically cleared when the ActorLifecycleProxy is destroyed. 718 ActorLifecycleProxy* MOZ_NON_OWNING_REF mProxy; 719 720 // The serial event target which owns the actor, and is the only thread where 721 // it is OK to access the ActorLifecycleProxy. 722 const nsCOMPtr<nsISerialEventTarget> mActorEventTarget; 723 }; 724 725 class IPDLResolverInner final { 726 public: 727 NS_INLINE_DECL_THREADSAFE_REFCOUNTING_WITH_DESTROY(IPDLResolverInner, 728 Destroy()) 729 730 explicit IPDLResolverInner(UniquePtr<IPC::Message> aReply, IProtocol* aActor); 731 732 template <typename F> 733 void Resolve(F&& aWrite) { 734 ResolveOrReject(true, std::forward<F>(aWrite)); 735 } 736 737 private: 738 void ResolveOrReject(bool aResolve, 739 FunctionRef<void(IPC::Message*, IProtocol*)> aWrite); 740 741 void Destroy(); 742 ~IPDLResolverInner(); 743 744 UniquePtr<IPC::Message> mReply; 745 RefPtr<WeakActorLifecycleProxy> mWeakProxy; 746 }; 747 748 // Member type added by the IPDL compiler to actors with async-returns messages. 749 // Manages a table mapping outstanding async message seqnos to the corresponding 750 // IPDL-generated callback which handles validating, deserializing, and 751 // dispatching the reply. 752 class IPDLAsyncReturnsCallbacks : public HasResultCodes { 753 public: 754 // Internal resolve callback signature. The callback should deserialize from 755 // the IPC::MessageReader* argument. 756 using Callback = 757 mozilla::MoveOnlyFunction<Result(IPC::MessageReader* IProtocol)>; 758 using seqno_t = IPC::Message::seqno_t; 759 using msgid_t = IPC::Message::msgid_t; 760 761 void AddCallback(seqno_t aSeqno, msgid_t aType, Callback aResolve, 762 RejectCallback aReject); 763 Result GotReply(IProtocol* aActor, const IPC::Message& aMessage); 764 void RejectPendingResponses(ResponseRejectReason aReason); 765 766 private: 767 struct EntryKey { 768 seqno_t mSeqno; 769 msgid_t mType; 770 771 bool operator==(const EntryKey& aOther) const; 772 bool operator<(const EntryKey& aOther) const; 773 }; 774 struct Entry : EntryKey { 775 Callback mResolve; 776 RejectCallback mReject; 777 }; 778 779 // NOTE: We expect this table to be quite small most of the time (usually 0-1 780 // entries), so use a sorted array as backing storage to reduce unnecessary 781 // overhead. 782 nsTArray<Entry> mMap; 783 }; 784 785 } // namespace ipc 786 787 // Base class for `ManagedContainer` - contains a series of IProtocol* instances 788 // of the same type (as specified by the subclass), and allows iterating over 789 // them. 790 class UntypedManagedContainer { 791 public: 792 using iterator = nsTArray<mozilla::ipc::IProtocol*>::const_iterator; 793 794 iterator begin() const { return mArray.cbegin(); } 795 iterator end() const { return mArray.cend(); } 796 797 bool IsEmpty() const { return mArray.IsEmpty(); } 798 uint32_t Count() const { return mArray.Length(); } 799 800 protected: 801 explicit UntypedManagedContainer(mozilla::ipc::ProtocolId aProtocolId) 802 #ifdef DEBUG 803 : mProtocolId(aProtocolId) 804 #endif 805 { 806 } 807 808 private: 809 friend class mozilla::ipc::IProtocol; 810 811 bool EnsureRemoved(mozilla::ipc::IProtocol* aElement) { 812 return mArray.RemoveElementSorted(aElement); 813 } 814 815 void Insert(mozilla::ipc::IProtocol* aElement) { 816 MOZ_ASSERT(aElement->GetProtocolId() == mProtocolId, 817 "ManagedContainer can only contain a single protocol"); 818 // Equivalent to `InsertElementSorted`, avoiding inserting a duplicate 819 // element. See bug 1896166. 820 size_t index = mArray.IndexOfFirstElementGt(aElement); 821 if (index == 0 || mArray[index - 1] != aElement) { 822 mArray.InsertElementAt(index, aElement); 823 } 824 } 825 826 nsTArray<mozilla::ipc::IProtocol*> mArray; 827 #ifdef DEBUG 828 mozilla::ipc::ProtocolId mProtocolId; 829 #endif 830 }; 831 832 template <typename Protocol> 833 class ManagedContainer : public UntypedManagedContainer { 834 public: 835 ManagedContainer() : UntypedManagedContainer(Protocol::kProtocolId) {} 836 837 // Input iterator which downcasts to the protocol type while iterating over 838 // the untyped container. 839 class iterator { 840 public: 841 using value_type = Protocol*; 842 using difference_type = ptrdiff_t; 843 using pointer = value_type*; 844 using reference = value_type; 845 using iterator_category = std::input_iterator_tag; 846 847 private: 848 friend class ManagedContainer; 849 explicit iterator(const UntypedManagedContainer::iterator& aIter) 850 : mIter(aIter) {} 851 UntypedManagedContainer::iterator mIter; 852 853 public: 854 iterator() = default; 855 856 bool operator==(const iterator& aRhs) const { return mIter == aRhs.mIter; } 857 bool operator!=(const iterator& aRhs) const { return mIter != aRhs.mIter; } 858 859 // NOTE: operator->() cannot be implemented without a proxy type. 860 // This is OK, and the same approach taken by C++20's transform_view. 861 reference operator*() const { return static_cast<value_type>(*mIter); } 862 863 iterator& operator++() { 864 ++mIter; 865 return *this; 866 } 867 iterator operator++(int) { return iterator{mIter++}; } 868 }; 869 870 iterator begin() const { return iterator{UntypedManagedContainer::begin()}; } 871 iterator end() const { return iterator{UntypedManagedContainer::end()}; } 872 873 void ToArray(nsTArray<Protocol*>& aArray) const { 874 aArray.SetCapacity(Count()); 875 for (Protocol* p : *this) { 876 aArray.AppendElement(p); 877 } 878 } 879 }; 880 881 template <typename Protocol> 882 Protocol* LoneManagedOrNullAsserts( 883 const ManagedContainer<Protocol>& aManagees) { 884 if (aManagees.IsEmpty()) { 885 return nullptr; 886 } 887 MOZ_ASSERT(aManagees.Count() == 1); 888 return *aManagees.begin(); 889 } 890 891 template <typename Protocol> 892 Protocol* SingleManagedOrNull(const ManagedContainer<Protocol>& aManagees) { 893 if (aManagees.Count() != 1) { 894 return nullptr; 895 } 896 return *aManagees.begin(); 897 } 898 899 } // namespace mozilla 900 901 #endif // mozilla_ipc_ProtocolUtils_h