Source code

Revision control

Copy as Markdown

Other Tools

/* -*- 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