mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-03-04 07:40:42 +00:00
168 lines
6.1 KiB
C++
168 lines
6.1 KiB
C++
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
#include "mozilla/ipc/Endpoint.h"
|
|
#include "chrome/common/ipc_message.h"
|
|
#include "mozilla/ipc/IPDLParamTraits.h"
|
|
#include "nsThreadUtils.h"
|
|
#include "mozilla/ipc/ProtocolMessageUtils.h"
|
|
|
|
namespace mozilla::ipc {
|
|
|
|
UntypedManagedEndpoint::UntypedManagedEndpoint(IProtocol* aActor)
|
|
: mInner(Some(Inner{
|
|
/* mOtherSide */ aActor->GetWeakLifecycleProxy(),
|
|
/* mToplevel */ nullptr,
|
|
aActor->Id(),
|
|
aActor->GetProtocolId(),
|
|
aActor->Manager()->Id(),
|
|
aActor->Manager()->GetProtocolId(),
|
|
})) {}
|
|
|
|
UntypedManagedEndpoint::~UntypedManagedEndpoint() {
|
|
if (!IsValid()) {
|
|
return;
|
|
}
|
|
|
|
if (mInner->mOtherSide) {
|
|
// If this ManagedEndpoint was never sent over IPC, deliver a fake
|
|
// MANAGED_ENDPOINT_DROPPED_MESSAGE_TYPE message directly to the other side
|
|
// actor.
|
|
mInner->mOtherSide->ActorEventTarget()->Dispatch(NS_NewRunnableFunction(
|
|
"~ManagedEndpoint (Local)",
|
|
[otherSide = mInner->mOtherSide, id = mInner->mId] {
|
|
if (IProtocol* actor = otherSide->Get(); actor && actor->CanRecv()) {
|
|
MOZ_DIAGNOSTIC_ASSERT(actor->Id() == id, "Wrong Actor?");
|
|
RefPtr<ActorLifecycleProxy> strongProxy(actor->GetLifecycleProxy());
|
|
strongProxy->Get()->OnMessageReceived(
|
|
IPC::Message(id, MANAGED_ENDPOINT_DROPPED_MESSAGE_TYPE));
|
|
}
|
|
}));
|
|
} else if (mInner->mToplevel) {
|
|
// If it was sent over IPC, we'll need to send the message to the sending
|
|
// side. Let's send the message async.
|
|
mInner->mToplevel->ActorEventTarget()->Dispatch(NS_NewRunnableFunction(
|
|
"~ManagedEndpoint (Remote)",
|
|
[toplevel = mInner->mToplevel, id = mInner->mId] {
|
|
if (IProtocol* actor = toplevel->Get();
|
|
actor && actor->CanSend() && actor->GetIPCChannel()) {
|
|
actor->GetIPCChannel()->Send(MakeUnique<IPC::Message>(
|
|
id, MANAGED_ENDPOINT_DROPPED_MESSAGE_TYPE));
|
|
}
|
|
}));
|
|
}
|
|
}
|
|
|
|
bool UntypedManagedEndpoint::BindCommon(IProtocol* aActor,
|
|
IRefCountedProtocol* aManager) {
|
|
MOZ_ASSERT(aManager);
|
|
if (!mInner) {
|
|
NS_WARNING("Cannot bind to invalid endpoint");
|
|
return false;
|
|
}
|
|
|
|
// Perform thread assertions.
|
|
if (mInner->mToplevel) {
|
|
MOZ_DIAGNOSTIC_ASSERT(
|
|
mInner->mToplevel->ActorEventTarget()->IsOnCurrentThread());
|
|
MOZ_DIAGNOSTIC_ASSERT(aManager->ToplevelProtocol() ==
|
|
mInner->mToplevel->Get());
|
|
}
|
|
|
|
if (NS_WARN_IF(aManager->Id() != mInner->mManagerId) ||
|
|
NS_WARN_IF(aManager->GetProtocolId() != mInner->mManagerType) ||
|
|
NS_WARN_IF(aActor->GetProtocolId() != mInner->mType)) {
|
|
MOZ_ASSERT_UNREACHABLE("Actor and manager do not match Endpoint");
|
|
return false;
|
|
}
|
|
|
|
if (!aManager->CanSend() || !aManager->GetIPCChannel()) {
|
|
NS_WARNING("Manager cannot send");
|
|
return false;
|
|
}
|
|
|
|
int32_t id = mInner->mId;
|
|
mInner.reset();
|
|
|
|
// Our typed caller will insert the actor into the managed container.
|
|
MOZ_ALWAYS_TRUE(aActor->SetManagerAndRegister(aManager, id));
|
|
|
|
aManager->GetIPCChannel()->Send(
|
|
MakeUnique<IPC::Message>(id, MANAGED_ENDPOINT_BOUND_MESSAGE_TYPE));
|
|
return true;
|
|
}
|
|
|
|
/* static */
|
|
void IPDLParamTraits<UntypedManagedEndpoint>::Write(IPC::MessageWriter* aWriter,
|
|
IProtocol* aActor,
|
|
paramType&& aParam) {
|
|
bool isValid = aParam.mInner.isSome();
|
|
WriteIPDLParam(aWriter, aActor, isValid);
|
|
if (!isValid) {
|
|
return;
|
|
}
|
|
|
|
auto inner = std::move(*aParam.mInner);
|
|
aParam.mInner.reset();
|
|
|
|
MOZ_RELEASE_ASSERT(inner.mOtherSide, "Has not been sent over IPC yet");
|
|
MOZ_RELEASE_ASSERT(inner.mOtherSide->ActorEventTarget()->IsOnCurrentThread(),
|
|
"Must be being sent from the correct thread");
|
|
MOZ_RELEASE_ASSERT(
|
|
inner.mOtherSide->Get() && inner.mOtherSide->Get()->ToplevelProtocol() ==
|
|
aActor->ToplevelProtocol(),
|
|
"Must be being sent over the same toplevel protocol");
|
|
|
|
WriteIPDLParam(aWriter, aActor, inner.mId);
|
|
WriteIPDLParam(aWriter, aActor, inner.mType);
|
|
WriteIPDLParam(aWriter, aActor, inner.mManagerId);
|
|
WriteIPDLParam(aWriter, aActor, inner.mManagerType);
|
|
}
|
|
|
|
/* static */
|
|
bool IPDLParamTraits<UntypedManagedEndpoint>::Read(IPC::MessageReader* aReader,
|
|
IProtocol* aActor,
|
|
paramType* aResult) {
|
|
*aResult = UntypedManagedEndpoint{};
|
|
bool isValid = false;
|
|
if (!aActor || !ReadIPDLParam(aReader, aActor, &isValid)) {
|
|
return false;
|
|
}
|
|
if (!isValid) {
|
|
return true;
|
|
}
|
|
|
|
aResult->mInner.emplace();
|
|
auto& inner = *aResult->mInner;
|
|
inner.mToplevel = aActor->ToplevelProtocol()->GetWeakLifecycleProxy();
|
|
return ReadIPDLParam(aReader, aActor, &inner.mId) &&
|
|
ReadIPDLParam(aReader, aActor, &inner.mType) &&
|
|
ReadIPDLParam(aReader, aActor, &inner.mManagerId) &&
|
|
ReadIPDLParam(aReader, aActor, &inner.mManagerType);
|
|
}
|
|
|
|
} // namespace mozilla::ipc
|
|
|
|
namespace IPC {
|
|
|
|
void ParamTraits<mozilla::ipc::UntypedEndpoint>::Write(MessageWriter* aWriter,
|
|
paramType&& aParam) {
|
|
IPC::WriteParam(aWriter, std::move(aParam.mPort));
|
|
IPC::WriteParam(aWriter, aParam.mMessageChannelId);
|
|
IPC::WriteParam(aWriter, aParam.mMyPid);
|
|
IPC::WriteParam(aWriter, aParam.mOtherPid);
|
|
}
|
|
|
|
bool ParamTraits<mozilla::ipc::UntypedEndpoint>::Read(MessageReader* aReader,
|
|
paramType* aResult) {
|
|
return IPC::ReadParam(aReader, &aResult->mPort) &&
|
|
IPC::ReadParam(aReader, &aResult->mMessageChannelId) &&
|
|
IPC::ReadParam(aReader, &aResult->mMyPid) &&
|
|
IPC::ReadParam(aReader, &aResult->mOtherPid);
|
|
}
|
|
|
|
} // namespace IPC
|