Endpoint.cpp (6028B)
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 "mozilla/ipc/Endpoint.h" 8 #include "chrome/common/ipc_message.h" 9 #include "ipc/IPCMessageUtilsSpecializations.h" 10 #include "nsThreadUtils.h" 11 #include "mozilla/ipc/ProtocolMessageUtils.h" 12 13 namespace mozilla::ipc { 14 15 UntypedManagedEndpoint::UntypedManagedEndpoint(IProtocol* aActor) 16 : mInner(Some(Inner{ 17 /* mOtherSide */ aActor->GetWeakLifecycleProxy(), 18 /* mToplevel */ nullptr, 19 aActor->Id(), 20 aActor->GetProtocolId(), 21 aActor->Manager()->Id(), 22 aActor->Manager()->GetProtocolId(), 23 })) {} 24 25 UntypedManagedEndpoint::~UntypedManagedEndpoint() { 26 if (!IsValid()) { 27 return; 28 } 29 30 if (mInner->mOtherSide) { 31 // If this ManagedEndpoint was never sent over IPC, deliver a fake 32 // MANAGED_ENDPOINT_DROPPED_MESSAGE_TYPE message directly to the other side 33 // actor. 34 mInner->mOtherSide->ActorEventTarget()->Dispatch(NS_NewRunnableFunction( 35 "~ManagedEndpoint (Local)", 36 [otherSide = mInner->mOtherSide, id = mInner->mId] { 37 if (IProtocol* actor = otherSide->Get(); actor && actor->CanRecv()) { 38 MOZ_DIAGNOSTIC_ASSERT(actor->Id() == id, "Wrong Actor?"); 39 RefPtr<ActorLifecycleProxy> strongProxy(actor->GetLifecycleProxy()); 40 strongProxy->Get()->OnMessageReceived( 41 IPC::Message(id, MANAGED_ENDPOINT_DROPPED_MESSAGE_TYPE)); 42 } 43 })); 44 } else if (mInner->mToplevel) { 45 // If it was sent over IPC, we'll need to send the message to the sending 46 // side. Let's send the message async. 47 mInner->mToplevel->ActorEventTarget()->Dispatch(NS_NewRunnableFunction( 48 "~ManagedEndpoint (Remote)", 49 [toplevel = mInner->mToplevel, id = mInner->mId] { 50 if (IProtocol* actor = toplevel->Get(); 51 actor && actor->CanSend() && actor->GetIPCChannel()) { 52 actor->GetIPCChannel()->Send(MakeUnique<IPC::Message>( 53 id, MANAGED_ENDPOINT_DROPPED_MESSAGE_TYPE)); 54 } 55 })); 56 } 57 } 58 59 bool UntypedManagedEndpoint::BindCommon(IProtocol* aActor, 60 IRefCountedProtocol* aManager) { 61 MOZ_ASSERT(aManager); 62 if (!mInner) { 63 NS_WARNING("Cannot bind to invalid endpoint"); 64 return false; 65 } 66 67 // Perform thread assertions. 68 if (mInner->mToplevel) { 69 MOZ_DIAGNOSTIC_ASSERT( 70 mInner->mToplevel->ActorEventTarget()->IsOnCurrentThread()); 71 MOZ_DIAGNOSTIC_ASSERT(aManager->ToplevelProtocol() == 72 mInner->mToplevel->Get()); 73 } 74 75 if (NS_WARN_IF(aManager->Id() != mInner->mManagerId) || 76 NS_WARN_IF(aManager->GetProtocolId() != mInner->mManagerType) || 77 NS_WARN_IF(aActor->GetProtocolId() != mInner->mType)) { 78 MOZ_ASSERT_UNREACHABLE("Actor and manager do not match Endpoint"); 79 return false; 80 } 81 82 if (!aManager->CanSend() || !aManager->GetIPCChannel()) { 83 NS_WARNING("Manager cannot send"); 84 return false; 85 } 86 87 ActorId id = mInner->mId; 88 mInner.reset(); 89 90 // Our typed caller will insert the actor into the managed container. 91 MOZ_ALWAYS_TRUE(aActor->SetManagerAndRegister(aManager, id)); 92 93 aManager->GetIPCChannel()->Send( 94 MakeUnique<IPC::Message>(id, MANAGED_ENDPOINT_BOUND_MESSAGE_TYPE)); 95 return true; 96 } 97 98 } // namespace mozilla::ipc 99 100 namespace IPC { 101 102 /* static */ 103 void ParamTraits<mozilla::ipc::UntypedManagedEndpoint>::Write( 104 MessageWriter* aWriter, paramType&& aParam) { 105 bool isValid = aParam.mInner.isSome(); 106 WriteParam(aWriter, isValid); 107 if (!isValid) { 108 return; 109 } 110 111 auto inner = std::move(*aParam.mInner); 112 aParam.mInner.reset(); 113 114 MOZ_RELEASE_ASSERT(inner.mOtherSide, "Has not been sent over IPC yet"); 115 MOZ_RELEASE_ASSERT(inner.mOtherSide->ActorEventTarget()->IsOnCurrentThread(), 116 "Must be being sent from the correct thread"); 117 MOZ_RELEASE_ASSERT(inner.mOtherSide->Get() && aWriter->GetActor() && 118 inner.mOtherSide->Get()->ToplevelProtocol() == 119 aWriter->GetActor()->ToplevelProtocol(), 120 "Must be being sent over the same toplevel protocol"); 121 122 WriteParam(aWriter, inner.mId); 123 WriteParam(aWriter, inner.mType); 124 WriteParam(aWriter, inner.mManagerId); 125 WriteParam(aWriter, inner.mManagerType); 126 } 127 128 /* static */ 129 bool ParamTraits<mozilla::ipc::UntypedManagedEndpoint>::Read( 130 MessageReader* aReader, paramType* aResult) { 131 *aResult = mozilla::ipc::UntypedManagedEndpoint{}; 132 bool isValid = false; 133 if (!aReader->GetActor() || !ReadParam(aReader, &isValid)) { 134 return false; 135 } 136 if (!isValid) { 137 return true; 138 } 139 140 aResult->mInner.emplace(); 141 auto& inner = *aResult->mInner; 142 inner.mToplevel = 143 aReader->GetActor()->ToplevelProtocol()->GetWeakLifecycleProxy(); 144 return ReadParam(aReader, &inner.mId) && ReadParam(aReader, &inner.mType) && 145 ReadParam(aReader, &inner.mManagerId) && 146 ReadParam(aReader, &inner.mManagerType); 147 } 148 149 void ParamTraits<mozilla::ipc::UntypedEndpoint>::Write(MessageWriter* aWriter, 150 paramType&& aParam) { 151 IPC::WriteParam(aWriter, std::move(aParam.mPort)); 152 IPC::WriteParam(aWriter, aParam.mMessageChannelId); 153 IPC::WriteParam(aWriter, aParam.mMyProcInfo); 154 IPC::WriteParam(aWriter, aParam.mOtherProcInfo); 155 } 156 157 bool ParamTraits<mozilla::ipc::UntypedEndpoint>::Read(MessageReader* aReader, 158 paramType* aResult) { 159 return IPC::ReadParam(aReader, &aResult->mPort) && 160 IPC::ReadParam(aReader, &aResult->mMessageChannelId) && 161 IPC::ReadParam(aReader, &aResult->mMyProcInfo) && 162 IPC::ReadParam(aReader, &aResult->mOtherProcInfo); 163 } 164 165 } // namespace IPC