mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-26 22:32:46 +00:00
Bug 1315913 - Part 1: Move nsFrameMessenger structured clone Build/Unpack into StructuredCloneData and expand to support PBackground. r=baku
This commit is contained in:
parent
b1840b3633
commit
7390cfe98f
@ -202,108 +202,12 @@ NS_INTERFACE_MAP_END
|
||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(nsFrameMessageManager)
|
||||
NS_IMPL_CYCLE_COLLECTING_RELEASE(nsFrameMessageManager)
|
||||
|
||||
enum ActorFlavorEnum {
|
||||
Parent = 0,
|
||||
Child
|
||||
};
|
||||
|
||||
template <ActorFlavorEnum>
|
||||
struct BlobTraits
|
||||
{ };
|
||||
|
||||
template <>
|
||||
struct BlobTraits<Parent>
|
||||
{
|
||||
typedef mozilla::dom::BlobParent BlobType;
|
||||
typedef mozilla::dom::PBlobParent ProtocolType;
|
||||
typedef mozilla::dom::nsIContentParent ConcreteContentManagerType;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct BlobTraits<Child>
|
||||
{
|
||||
typedef mozilla::dom::BlobChild BlobType;
|
||||
typedef mozilla::dom::PBlobChild ProtocolType;
|
||||
typedef mozilla::dom::nsIContentChild ConcreteContentManagerType;
|
||||
};
|
||||
|
||||
template<ActorFlavorEnum>
|
||||
struct DataBlobs
|
||||
{ };
|
||||
|
||||
template<>
|
||||
struct DataBlobs<Parent>
|
||||
{
|
||||
typedef BlobTraits<Parent>::ProtocolType ProtocolType;
|
||||
|
||||
static InfallibleTArray<ProtocolType*>& Blobs(ClonedMessageData& aData)
|
||||
{
|
||||
return aData.blobsParent();
|
||||
}
|
||||
|
||||
static const InfallibleTArray<ProtocolType*>& Blobs(const ClonedMessageData& aData)
|
||||
{
|
||||
return aData.blobsParent();
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct DataBlobs<Child>
|
||||
{
|
||||
typedef BlobTraits<Child>::ProtocolType ProtocolType;
|
||||
|
||||
static InfallibleTArray<ProtocolType*>& Blobs(ClonedMessageData& aData)
|
||||
{
|
||||
return aData.blobsChild();
|
||||
}
|
||||
|
||||
static const InfallibleTArray<ProtocolType*>& Blobs(const ClonedMessageData& aData)
|
||||
{
|
||||
return aData.blobsChild();
|
||||
}
|
||||
};
|
||||
|
||||
template<ActorFlavorEnum Flavor>
|
||||
static bool
|
||||
BuildClonedMessageData(typename BlobTraits<Flavor>::ConcreteContentManagerType* aManager,
|
||||
StructuredCloneData& aData,
|
||||
ClonedMessageData& aClonedData)
|
||||
{
|
||||
SerializedStructuredCloneBuffer& buffer = aClonedData.data();
|
||||
auto iter = aData.Data().Iter();
|
||||
size_t size = aData.Data().Size();
|
||||
bool success;
|
||||
buffer.data = aData.Data().Borrow<js::SystemAllocPolicy>(iter, size, &success);
|
||||
if (NS_WARN_IF(!success)) {
|
||||
return false;
|
||||
}
|
||||
aClonedData.identfiers().AppendElements(aData.PortIdentifiers());
|
||||
|
||||
const nsTArray<RefPtr<BlobImpl>>& blobImpls = aData.BlobImpls();
|
||||
|
||||
if (!blobImpls.IsEmpty()) {
|
||||
typedef typename BlobTraits<Flavor>::ProtocolType ProtocolType;
|
||||
InfallibleTArray<ProtocolType*>& blobList = DataBlobs<Flavor>::Blobs(aClonedData);
|
||||
uint32_t length = blobImpls.Length();
|
||||
blobList.SetCapacity(length);
|
||||
for (uint32_t i = 0; i < length; ++i) {
|
||||
typename BlobTraits<Flavor>::BlobType* protocolActor =
|
||||
aManager->GetOrCreateActorForBlobImpl(blobImpls[i]);
|
||||
if (!protocolActor) {
|
||||
return false;
|
||||
}
|
||||
blobList.AppendElement(protocolActor);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
MessageManagerCallback::BuildClonedMessageDataForParent(nsIContentParent* aParent,
|
||||
StructuredCloneData& aData,
|
||||
ClonedMessageData& aClonedData)
|
||||
{
|
||||
return BuildClonedMessageData<Parent>(aParent, aData, aClonedData);
|
||||
return aData.BuildClonedMessageDataForParent(aParent, aClonedData);
|
||||
}
|
||||
|
||||
bool
|
||||
@ -311,51 +215,21 @@ MessageManagerCallback::BuildClonedMessageDataForChild(nsIContentChild* aChild,
|
||||
StructuredCloneData& aData,
|
||||
ClonedMessageData& aClonedData)
|
||||
{
|
||||
return BuildClonedMessageData<Child>(aChild, aData, aClonedData);
|
||||
}
|
||||
|
||||
template<ActorFlavorEnum Flavor>
|
||||
static void
|
||||
UnpackClonedMessageData(const ClonedMessageData& aClonedData,
|
||||
StructuredCloneData& aData)
|
||||
{
|
||||
const SerializedStructuredCloneBuffer& buffer = aClonedData.data();
|
||||
typedef typename BlobTraits<Flavor>::ProtocolType ProtocolType;
|
||||
const InfallibleTArray<ProtocolType*>& blobs = DataBlobs<Flavor>::Blobs(aClonedData);
|
||||
const InfallibleTArray<MessagePortIdentifier>& identifiers = aClonedData.identfiers();
|
||||
|
||||
aData.UseExternalData(buffer.data);
|
||||
|
||||
aData.PortIdentifiers().AppendElements(identifiers);
|
||||
|
||||
if (!blobs.IsEmpty()) {
|
||||
uint32_t length = blobs.Length();
|
||||
aData.BlobImpls().SetCapacity(length);
|
||||
for (uint32_t i = 0; i < length; ++i) {
|
||||
auto* blob =
|
||||
static_cast<typename BlobTraits<Flavor>::BlobType*>(blobs[i]);
|
||||
MOZ_ASSERT(blob);
|
||||
|
||||
RefPtr<BlobImpl> blobImpl = blob->GetBlobImpl();
|
||||
MOZ_ASSERT(blobImpl);
|
||||
|
||||
aData.BlobImpls().AppendElement(blobImpl);
|
||||
}
|
||||
}
|
||||
return aData.BuildClonedMessageDataForChild(aChild, aClonedData);
|
||||
}
|
||||
|
||||
void
|
||||
mozilla::dom::ipc::UnpackClonedMessageDataForParent(const ClonedMessageData& aClonedData,
|
||||
StructuredCloneData& aData)
|
||||
{
|
||||
UnpackClonedMessageData<Parent>(aClonedData, aData);
|
||||
aData.BorrowFromClonedMessageDataForParent(aClonedData);
|
||||
}
|
||||
|
||||
void
|
||||
mozilla::dom::ipc::UnpackClonedMessageDataForChild(const ClonedMessageData& aClonedData,
|
||||
StructuredCloneData& aData)
|
||||
{
|
||||
UnpackClonedMessageData<Child>(aClonedData, aData);
|
||||
aData.BorrowFromClonedMessageDataForChild(aClonedData);
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -32,6 +32,12 @@ struct MessagePortIdentifier
|
||||
bool neutered;
|
||||
};
|
||||
|
||||
/**
|
||||
* Cross-process representation for postMessage() style payloads where Blobs may
|
||||
* be referenced/"cloned" and (optionally) messageports transferred. Use
|
||||
* StructuredCloneData in your code to convert between this wire representation
|
||||
* and the StructuredCloneData StructuredCloneHolder-subclass.
|
||||
*/
|
||||
struct ClonedMessageData
|
||||
{
|
||||
SerializedStructuredCloneBuffer data;
|
||||
|
@ -40,7 +40,9 @@ StructuredCloneData::Copy(const StructuredCloneData& aData)
|
||||
NS_ENSURE_TRUE(mSharedData, false);
|
||||
}
|
||||
|
||||
PortIdentifiers().AppendElements(aData.PortIdentifiers());
|
||||
if (mSupportsTransferring) {
|
||||
PortIdentifiers().AppendElements(aData.PortIdentifiers());
|
||||
}
|
||||
|
||||
MOZ_ASSERT(BlobImpls().IsEmpty());
|
||||
BlobImpls().AppendElements(aData.BlobImpls());
|
||||
@ -96,6 +98,340 @@ StructuredCloneData::Write(JSContext* aCx,
|
||||
mInitialized = true;
|
||||
}
|
||||
|
||||
enum ActorFlavorEnum {
|
||||
Parent = 0,
|
||||
Child,
|
||||
};
|
||||
|
||||
enum ManagerFlavorEnum {
|
||||
ContentProtocol = 0,
|
||||
BackgroundProtocol
|
||||
};
|
||||
|
||||
template <ActorFlavorEnum>
|
||||
struct BlobTraits
|
||||
{ };
|
||||
|
||||
template <>
|
||||
struct BlobTraits<Parent>
|
||||
{
|
||||
typedef mozilla::dom::BlobParent BlobType;
|
||||
typedef mozilla::dom::PBlobParent ProtocolType;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct BlobTraits<Child>
|
||||
{
|
||||
typedef mozilla::dom::BlobChild BlobType;
|
||||
typedef mozilla::dom::PBlobChild ProtocolType;
|
||||
};
|
||||
|
||||
template <ActorFlavorEnum, ManagerFlavorEnum>
|
||||
struct ParentManagerTraits
|
||||
{ };
|
||||
|
||||
template<>
|
||||
struct ParentManagerTraits<Parent, ContentProtocol>
|
||||
{
|
||||
typedef mozilla::dom::nsIContentParent ConcreteContentManagerType;
|
||||
};
|
||||
|
||||
template<>
|
||||
struct ParentManagerTraits<Child, ContentProtocol>
|
||||
{
|
||||
typedef mozilla::dom::nsIContentChild ConcreteContentManagerType;
|
||||
};
|
||||
|
||||
template<>
|
||||
struct ParentManagerTraits<Parent, BackgroundProtocol>
|
||||
{
|
||||
typedef mozilla::ipc::PBackgroundParent ConcreteContentManagerType;
|
||||
};
|
||||
|
||||
template<>
|
||||
struct ParentManagerTraits<Child, BackgroundProtocol>
|
||||
{
|
||||
typedef mozilla::ipc::PBackgroundChild ConcreteContentManagerType;
|
||||
};
|
||||
|
||||
template<ActorFlavorEnum>
|
||||
struct DataBlobs
|
||||
{ };
|
||||
|
||||
template<>
|
||||
struct DataBlobs<Parent>
|
||||
{
|
||||
typedef BlobTraits<Parent>::ProtocolType ProtocolType;
|
||||
|
||||
static InfallibleTArray<ProtocolType*>& Blobs(ClonedMessageData& aData)
|
||||
{
|
||||
return aData.blobsParent();
|
||||
}
|
||||
|
||||
static const InfallibleTArray<ProtocolType*>& Blobs(const ClonedMessageData& aData)
|
||||
{
|
||||
return aData.blobsParent();
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct DataBlobs<Child>
|
||||
{
|
||||
typedef BlobTraits<Child>::ProtocolType ProtocolType;
|
||||
|
||||
static InfallibleTArray<ProtocolType*>& Blobs(ClonedMessageData& aData)
|
||||
{
|
||||
return aData.blobsChild();
|
||||
}
|
||||
|
||||
static const InfallibleTArray<ProtocolType*>& Blobs(const ClonedMessageData& aData)
|
||||
{
|
||||
return aData.blobsChild();
|
||||
}
|
||||
};
|
||||
|
||||
template<ActorFlavorEnum Flavor, ManagerFlavorEnum ManagerFlavor>
|
||||
static bool
|
||||
BuildClonedMessageData(typename ParentManagerTraits<Flavor, ManagerFlavor>::ConcreteContentManagerType* aManager,
|
||||
StructuredCloneData& aData,
|
||||
ClonedMessageData& aClonedData)
|
||||
{
|
||||
SerializedStructuredCloneBuffer& buffer = aClonedData.data();
|
||||
auto iter = aData.Data().Iter();
|
||||
size_t size = aData.Data().Size();
|
||||
bool success;
|
||||
buffer.data = aData.Data().Borrow<js::SystemAllocPolicy>(iter, size, &success);
|
||||
if (NS_WARN_IF(!success)) {
|
||||
return false;
|
||||
}
|
||||
if (aData.SupportsTransferring()) {
|
||||
aClonedData.identfiers().AppendElements(aData.PortIdentifiers());
|
||||
}
|
||||
|
||||
const nsTArray<RefPtr<BlobImpl>>& blobImpls = aData.BlobImpls();
|
||||
|
||||
if (!blobImpls.IsEmpty()) {
|
||||
typedef typename BlobTraits<Flavor>::BlobType BlobType;
|
||||
typedef typename BlobTraits<Flavor>::ProtocolType ProtocolType;
|
||||
InfallibleTArray<ProtocolType*>& blobList = DataBlobs<Flavor>::Blobs(aClonedData);
|
||||
uint32_t length = blobImpls.Length();
|
||||
blobList.SetCapacity(length);
|
||||
for (uint32_t i = 0; i < length; ++i) {
|
||||
BlobType* protocolActor = BlobType::GetOrCreate(aManager, blobImpls[i]);
|
||||
if (!protocolActor) {
|
||||
return false;
|
||||
}
|
||||
blobList.AppendElement(protocolActor);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
StructuredCloneData::BuildClonedMessageDataForParent(
|
||||
nsIContentParent* aParent,
|
||||
ClonedMessageData& aClonedData)
|
||||
{
|
||||
return BuildClonedMessageData<Parent, ContentProtocol>(aParent, *this, aClonedData);
|
||||
}
|
||||
|
||||
bool
|
||||
StructuredCloneData::BuildClonedMessageDataForChild(
|
||||
nsIContentChild* aChild,
|
||||
ClonedMessageData& aClonedData)
|
||||
{
|
||||
return BuildClonedMessageData<Child, ContentProtocol>(aChild, *this, aClonedData);
|
||||
}
|
||||
|
||||
bool
|
||||
StructuredCloneData::BuildClonedMessageDataForBackgroundParent(
|
||||
PBackgroundParent* aParent,
|
||||
ClonedMessageData& aClonedData)
|
||||
{
|
||||
return BuildClonedMessageData<Parent, BackgroundProtocol>(aParent, *this, aClonedData);
|
||||
}
|
||||
|
||||
bool
|
||||
StructuredCloneData::BuildClonedMessageDataForBackgroundChild(
|
||||
PBackgroundChild* aChild,
|
||||
ClonedMessageData& aClonedData)
|
||||
{
|
||||
return BuildClonedMessageData<Child, BackgroundProtocol>(aChild, *this, aClonedData);
|
||||
}
|
||||
|
||||
// See the StructuredCloneData class block comment for the meanings of each val.
|
||||
enum MemoryFlavorEnum {
|
||||
BorrowMemory = 0,
|
||||
CopyMemory,
|
||||
StealMemory
|
||||
};
|
||||
|
||||
template<MemoryFlavorEnum>
|
||||
struct MemoryTraits
|
||||
{ };
|
||||
|
||||
template<>
|
||||
struct MemoryTraits<BorrowMemory>
|
||||
{
|
||||
typedef const mozilla::dom::ClonedMessageData ClonedMessageType;
|
||||
|
||||
static void ProvideBuffer(const ClonedMessageData& aClonedData,
|
||||
StructuredCloneData& aData)
|
||||
{
|
||||
const SerializedStructuredCloneBuffer& buffer = aClonedData.data();
|
||||
aData.UseExternalData(buffer.data);
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct MemoryTraits<CopyMemory>
|
||||
{
|
||||
typedef const mozilla::dom::ClonedMessageData ClonedMessageType;
|
||||
|
||||
static void ProvideBuffer(const ClonedMessageData& aClonedData,
|
||||
StructuredCloneData& aData)
|
||||
{
|
||||
const SerializedStructuredCloneBuffer& buffer = aClonedData.data();
|
||||
aData.CopyExternalData(buffer.data);
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct MemoryTraits<StealMemory>
|
||||
{
|
||||
// note: not const!
|
||||
typedef mozilla::dom::ClonedMessageData ClonedMessageType;
|
||||
|
||||
static void ProvideBuffer(ClonedMessageData& aClonedData,
|
||||
StructuredCloneData& aData)
|
||||
{
|
||||
SerializedStructuredCloneBuffer& buffer = aClonedData.data();
|
||||
aData.StealExternalData(buffer.data);
|
||||
}
|
||||
};
|
||||
|
||||
// Note that there isn't actually a difference between Parent/BackgroundParent
|
||||
// and Child/BackgroundChild in this implementation. The calling methods,
|
||||
// however, do maintain the distinction for code-reading purposes and are backed
|
||||
// by assertions to enforce there is no misuse.
|
||||
template<MemoryFlavorEnum MemoryFlavor, ActorFlavorEnum Flavor>
|
||||
static void
|
||||
UnpackClonedMessageData(typename MemoryTraits<MemoryFlavor>::ClonedMessageType& aClonedData,
|
||||
StructuredCloneData& aData)
|
||||
{
|
||||
typedef typename BlobTraits<Flavor>::ProtocolType ProtocolType;
|
||||
const InfallibleTArray<ProtocolType*>& blobs = DataBlobs<Flavor>::Blobs(aClonedData);
|
||||
const InfallibleTArray<MessagePortIdentifier>& identifiers = aClonedData.identfiers();
|
||||
|
||||
MemoryTraits<MemoryFlavor>::ProvideBuffer(aClonedData, aData);
|
||||
|
||||
if (aData.SupportsTransferring()) {
|
||||
aData.PortIdentifiers().AppendElements(identifiers);
|
||||
}
|
||||
|
||||
if (!blobs.IsEmpty()) {
|
||||
uint32_t length = blobs.Length();
|
||||
aData.BlobImpls().SetCapacity(length);
|
||||
for (uint32_t i = 0; i < length; ++i) {
|
||||
auto* blob =
|
||||
static_cast<typename BlobTraits<Flavor>::BlobType*>(blobs[i]);
|
||||
MOZ_ASSERT(blob);
|
||||
|
||||
RefPtr<BlobImpl> blobImpl = blob->GetBlobImpl();
|
||||
MOZ_ASSERT(blobImpl);
|
||||
|
||||
aData.BlobImpls().AppendElement(blobImpl);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
StructuredCloneData::BorrowFromClonedMessageDataForParent(const ClonedMessageData& aClonedData)
|
||||
{
|
||||
// PContent parent is always main thread and actor constraints demand we're
|
||||
// likewise on that thread.
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
UnpackClonedMessageData<BorrowMemory, Parent>(aClonedData, *this);
|
||||
}
|
||||
|
||||
void
|
||||
StructuredCloneData::BorrowFromClonedMessageDataForChild(const ClonedMessageData& aClonedData)
|
||||
{
|
||||
// PContent child is always main thread and actor constraints demand we're
|
||||
// likewise on that thread.
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
UnpackClonedMessageData<BorrowMemory, Child>(aClonedData, *this);
|
||||
}
|
||||
|
||||
void
|
||||
StructuredCloneData::BorrowFromClonedMessageDataForBackgroundParent(const ClonedMessageData& aClonedData)
|
||||
{
|
||||
MOZ_ASSERT(IsOnBackgroundThread());
|
||||
UnpackClonedMessageData<BorrowMemory, Parent>(aClonedData, *this);
|
||||
}
|
||||
|
||||
void
|
||||
StructuredCloneData::BorrowFromClonedMessageDataForBackgroundChild(const ClonedMessageData& aClonedData)
|
||||
{
|
||||
// No thread assertion; BackgroundChild can happen on any thread.
|
||||
UnpackClonedMessageData<BorrowMemory, Child>(aClonedData, *this);
|
||||
}
|
||||
|
||||
void
|
||||
StructuredCloneData::CopyFromClonedMessageDataForParent(const ClonedMessageData& aClonedData)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
UnpackClonedMessageData<CopyMemory, Parent>(aClonedData, *this);
|
||||
}
|
||||
|
||||
void
|
||||
StructuredCloneData::CopyFromClonedMessageDataForChild(const ClonedMessageData& aClonedData)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
UnpackClonedMessageData<CopyMemory, Child>(aClonedData, *this);
|
||||
}
|
||||
|
||||
void
|
||||
StructuredCloneData::CopyFromClonedMessageDataForBackgroundParent(const ClonedMessageData& aClonedData)
|
||||
{
|
||||
MOZ_ASSERT(IsOnBackgroundThread());
|
||||
UnpackClonedMessageData<BorrowMemory, Parent>(aClonedData, *this);
|
||||
}
|
||||
|
||||
void
|
||||
StructuredCloneData::CopyFromClonedMessageDataForBackgroundChild(const ClonedMessageData& aClonedData)
|
||||
{
|
||||
UnpackClonedMessageData<CopyMemory, Child>(aClonedData, *this);
|
||||
}
|
||||
|
||||
void
|
||||
StructuredCloneData::StealFromClonedMessageDataForParent(ClonedMessageData& aClonedData)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
UnpackClonedMessageData<StealMemory, Parent>(aClonedData, *this);
|
||||
}
|
||||
|
||||
void
|
||||
StructuredCloneData::StealFromClonedMessageDataForChild(ClonedMessageData& aClonedData)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
UnpackClonedMessageData<StealMemory, Child>(aClonedData, *this);
|
||||
}
|
||||
|
||||
void
|
||||
StructuredCloneData::StealFromClonedMessageDataForBackgroundParent(ClonedMessageData& aClonedData)
|
||||
{
|
||||
MOZ_ASSERT(IsOnBackgroundThread());
|
||||
UnpackClonedMessageData<StealMemory, Parent>(aClonedData, *this);
|
||||
}
|
||||
|
||||
void
|
||||
StructuredCloneData::StealFromClonedMessageDataForBackgroundChild(ClonedMessageData& aClonedData)
|
||||
{
|
||||
UnpackClonedMessageData<StealMemory, Child>(aClonedData, *this);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
StructuredCloneData::WriteIPCParams(IPC::Message* aMsg) const
|
||||
{
|
||||
@ -128,6 +464,25 @@ StructuredCloneData::CopyExternalData(const char* aData,
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
StructuredCloneData::CopyExternalData(const JSStructuredCloneData& aData)
|
||||
{
|
||||
MOZ_ASSERT(!mInitialized);
|
||||
mSharedData = SharedJSAllocatedData::CreateFromExternalData(aData);
|
||||
NS_ENSURE_TRUE(mSharedData, false);
|
||||
mInitialized = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
StructuredCloneData::StealExternalData(JSStructuredCloneData& aData)
|
||||
{
|
||||
MOZ_ASSERT(!mInitialized);
|
||||
mSharedData = new SharedJSAllocatedData(Move(aData));
|
||||
mInitialized = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace ipc
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
@ -18,9 +18,30 @@ class Message;
|
||||
class PickleIterator;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
namespace ipc {
|
||||
|
||||
class PBackgroundChild;
|
||||
class PBackgroundParent;
|
||||
|
||||
} // namespace ipc
|
||||
|
||||
namespace dom {
|
||||
|
||||
class nsIContentChild;
|
||||
class nsIContentParent;
|
||||
|
||||
namespace ipc {
|
||||
|
||||
/**
|
||||
* Wraps the non-reference-counted JSStructuredCloneData class to have a
|
||||
* reference count so that multiple StructuredCloneData instances can reference
|
||||
* a single underlying serialized representation.
|
||||
*
|
||||
* As used by StructuredCloneData, it is an invariant that our
|
||||
* JSStructuredCloneData owns its buffers. (For the non-owning case,
|
||||
* StructuredCloneData uses mExternalData which holds a BufferList::Borrow()ed
|
||||
* read-only view of the data.)
|
||||
*/
|
||||
class SharedJSAllocatedData final
|
||||
{
|
||||
public:
|
||||
@ -63,14 +84,74 @@ private:
|
||||
JSStructuredCloneData mData;
|
||||
};
|
||||
|
||||
/**
|
||||
* IPC-aware StructuredCloneHolder subclass that serves as both a helper class
|
||||
* for dealing with message data (blobs, transferables) and also an IPDL
|
||||
* data-type in cases where message data is not needed. If your use-case does
|
||||
* not (potentially) involve IPC, then you should use StructuredCloneHolder or
|
||||
* one of its other subclasses instead.
|
||||
*
|
||||
* ## Usage ##
|
||||
*
|
||||
* The general recipe for using this class is:
|
||||
* - In your IPDL definition, use the ClonedMessageData type whenever you want
|
||||
* to send a structured clone that may include blobs or transferables such as
|
||||
* message ports.
|
||||
* - To send the data, instantiate a StructuredCloneData instance and Write()
|
||||
* into it like a normal structure clone. When you are ready to send the
|
||||
* ClonedMessageData-bearing IPC message, use the appropriate
|
||||
* BuildClonedMessageDataFor{Parent,Child,BackgroundParent,BackgroundChild}
|
||||
* method to populate the ClonedMessageData and then send it before your
|
||||
* StructuredCloneData instance is destroyed. (Buffer borrowing is used
|
||||
* under-the-hood to avoid duplicating the serialized data, requiring this.)
|
||||
* - To receive the data, instantiate a StructuredCloneData and use the
|
||||
* appropriate {Borrow,Copy,Steal}FromClonedMessageDataFor{Parent,Child,
|
||||
* BackgroundParent,BackgroundChild} method. See the memory management
|
||||
* section for more info.
|
||||
*
|
||||
* Variations:
|
||||
* - If transferables are not allowed (ex: BroadcastChannel), then use the
|
||||
* StructuredCloneDataNoTransfers subclass instead of StructuredCloneData.
|
||||
*
|
||||
* ## Memory Management ##
|
||||
*
|
||||
* Serialized structured clone representations can be quite large. So it's best
|
||||
* to avoid wasteful duplication. When Write()ing into the StructuredCloneData,
|
||||
* you don't need to worry about this[1], but when you already have serialized
|
||||
* structured clone data you plan to Read(), you do need to. Similarly, if
|
||||
* you're using StructuredCloneData as an IPDL type, it efficiently unmarshals.
|
||||
*
|
||||
* The from-ClonedMessageData memory management strategies available are:
|
||||
* - Borrow: Create a JSStructuredCloneData that holds a non-owning, read-only
|
||||
* BufferList::Borrow()ed copy of the source. Your StructuredCloneData needs
|
||||
* to be destroyed before the source is. Commonly used when the
|
||||
* StructuredCloneData instance is stack-allocated (and Read() is used before
|
||||
* the function returns).
|
||||
* - Copy: Makes a reference-counted copy of the source JSStructuredCloneData,
|
||||
* making it safe for the StructuredCloneData to outlive the source data.
|
||||
* - Steal: Steal the buffers from the underlying JSStructuredCloneData so that
|
||||
* it's safe for the StructuredCloneData to outlive the source data. This is
|
||||
* safe to use with IPC-provided ClonedMessageData instances because
|
||||
* JSStructuredCloneData's IPC ParamTraits::Read method uses ExtractBuffers,
|
||||
* returning a fatal false if unable to extract. (And
|
||||
* SerializedStructuredCloneBuffer wraps/defers to it.) But if it's possible
|
||||
* the ClonedMessageData came from a different source that might have borrowed
|
||||
* the buffers itself, then things will crash. That would be a pretty crazy
|
||||
* implementation; if you see one, change it to use SharedJSAllocatedData.
|
||||
*
|
||||
* 1: Specifically, in the Write() case an owning SharedJSAllocatedData is
|
||||
* created efficiently (by stealing from StructuredCloneHolder). The
|
||||
* BuildClonedMessageDataFor* method can be called at any time and it will
|
||||
* borrow the underlying memory. While it would be even better if
|
||||
* SerializedStructuredCloneBuffer could hold a SharedJSAllocatedData ref,
|
||||
* there's no reason you can't wait to BuildClonedMessageDataFor* until you
|
||||
* need to make the IPC Send* call.
|
||||
*/
|
||||
class StructuredCloneData : public StructuredCloneHolder
|
||||
{
|
||||
public:
|
||||
StructuredCloneData()
|
||||
: StructuredCloneHolder(StructuredCloneHolder::CloningSupported,
|
||||
StructuredCloneHolder::TransferringSupported,
|
||||
StructuredCloneHolder::StructuredCloneScope::DifferentProcess)
|
||||
, mInitialized(false)
|
||||
: StructuredCloneData(StructuredCloneHolder::TransferringSupported)
|
||||
{}
|
||||
|
||||
StructuredCloneData(const StructuredCloneData&) = delete;
|
||||
@ -111,6 +192,41 @@ public:
|
||||
JS::Handle<JS::Value> aTransfers,
|
||||
ErrorResult &aRv);
|
||||
|
||||
// Actor-varying methods to convert the structured clone stored in this holder
|
||||
// by a previous call to Write() into ClonedMessageData IPC representation.
|
||||
// (Blobs are represented in IPC by PBlob actors, so we need the parent to be
|
||||
// able to create them.)
|
||||
bool BuildClonedMessageDataForParent(nsIContentParent* aParent,
|
||||
ClonedMessageData& aClonedData);
|
||||
bool BuildClonedMessageDataForChild(nsIContentChild* aChild,
|
||||
ClonedMessageData& aClonedData);
|
||||
bool BuildClonedMessageDataForBackgroundParent(mozilla::ipc::PBackgroundParent* aParent,
|
||||
ClonedMessageData& aClonedData);
|
||||
bool BuildClonedMessageDataForBackgroundChild(mozilla::ipc::PBackgroundChild* aChild,
|
||||
ClonedMessageData& aClonedData);
|
||||
|
||||
// Actor-varying and memory-management-strategy-varying methods to initialize
|
||||
// this holder from a ClonedMessageData representation.
|
||||
void BorrowFromClonedMessageDataForParent(const ClonedMessageData& aClonedData);
|
||||
void BorrowFromClonedMessageDataForChild(const ClonedMessageData& aClonedData);
|
||||
void BorrowFromClonedMessageDataForBackgroundParent(const ClonedMessageData& aClonedData);
|
||||
void BorrowFromClonedMessageDataForBackgroundChild(const ClonedMessageData& aClonedData);
|
||||
|
||||
void CopyFromClonedMessageDataForParent(const ClonedMessageData& aClonedData);
|
||||
void CopyFromClonedMessageDataForChild(const ClonedMessageData& aClonedData);
|
||||
void CopyFromClonedMessageDataForBackgroundParent(const ClonedMessageData& aClonedData);
|
||||
void CopyFromClonedMessageDataForBackgroundChild(const ClonedMessageData& aClonedData);
|
||||
|
||||
// The steal variants of course take a non-const ClonedMessageData.
|
||||
void StealFromClonedMessageDataForParent(ClonedMessageData& aClonedData);
|
||||
void StealFromClonedMessageDataForChild(ClonedMessageData& aClonedData);
|
||||
void StealFromClonedMessageDataForBackgroundParent(ClonedMessageData& aClonedData);
|
||||
void StealFromClonedMessageDataForBackgroundChild(ClonedMessageData& aClonedData);
|
||||
|
||||
|
||||
// Initialize this instance, borrowing the contents of the given
|
||||
// JSStructuredCloneData. You are responsible for ensuring that this
|
||||
// StructuredCloneData instance is destroyed before aData is destroyed.
|
||||
bool UseExternalData(const JSStructuredCloneData& aData)
|
||||
{
|
||||
auto iter = aData.Iter();
|
||||
@ -121,7 +237,19 @@ public:
|
||||
return success;
|
||||
}
|
||||
|
||||
// Initialize this instance by copying the given data that probably came from
|
||||
// nsStructuredClone doing a base64 decode. Don't use this.
|
||||
bool CopyExternalData(const char* aData, size_t aDataLength);
|
||||
// Initialize this instance by copying the contents of an existing
|
||||
// JSStructuredCloneData. Use when this StructuredCloneData instance may
|
||||
// outlive aData.
|
||||
bool CopyExternalData(const JSStructuredCloneData& aData);
|
||||
|
||||
// Initialize this instance by stealing the contents of aData via Move
|
||||
// constructor, clearing the original aData as a side-effect. This is only
|
||||
// safe if aData owns the underlying buffers. This is the case for instances
|
||||
// provided by IPC to Recv calls.
|
||||
bool StealExternalData(JSStructuredCloneData& aData);
|
||||
|
||||
JSStructuredCloneData& Data()
|
||||
{
|
||||
@ -143,16 +271,40 @@ public:
|
||||
return mSharedData;
|
||||
}
|
||||
|
||||
bool SupportsTransferring()
|
||||
{
|
||||
return mSupportsTransferring;
|
||||
}
|
||||
|
||||
// For IPC serialization
|
||||
void WriteIPCParams(IPC::Message* aMessage) const;
|
||||
bool ReadIPCParams(const IPC::Message* aMessage, PickleIterator* aIter);
|
||||
|
||||
protected:
|
||||
explicit StructuredCloneData(TransferringSupport aSupportsTransferring)
|
||||
: StructuredCloneHolder(StructuredCloneHolder::CloningSupported,
|
||||
aSupportsTransferring,
|
||||
StructuredCloneHolder::StructuredCloneScope::DifferentProcess)
|
||||
, mInitialized(false)
|
||||
{}
|
||||
|
||||
|
||||
private:
|
||||
JSStructuredCloneData mExternalData;
|
||||
RefPtr<SharedJSAllocatedData> mSharedData;
|
||||
bool mInitialized;
|
||||
};
|
||||
|
||||
/**
|
||||
* For use when transferring should not be supported.
|
||||
*/
|
||||
class StructuredCloneDataNoTransfers : public StructuredCloneData {
|
||||
public:
|
||||
StructuredCloneDataNoTransfers()
|
||||
: StructuredCloneData(StructuredCloneHolder::TransferringNotSupported)
|
||||
{}
|
||||
};
|
||||
|
||||
} // namespace ipc
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
Loading…
Reference in New Issue
Block a user