mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-09 03:15:11 +00:00
Bug 1093357 P2 Add an RAII type to safely handle serialized stream actors. r=jld
* * * Bug 1093357 P2 interdiff 001 address review feedback * * * Bug 1093357 P2 interdiff 002 refactor to IPCStream type
This commit is contained in:
parent
749d2c1626
commit
4c8ab874ba
34
ipc/glue/IPCStream.ipdlh
Normal file
34
ipc/glue/IPCStream.ipdlh
Normal file
@ -0,0 +1,34 @@
|
||||
/* 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 protocol PSendStream;
|
||||
include InputStreamParams;
|
||||
|
||||
namespace mozilla {
|
||||
namespace ipc {
|
||||
|
||||
// Do not use this directly. See IPCStream below.
|
||||
struct InputStreamParamsWithFds
|
||||
{
|
||||
InputStreamParams stream;
|
||||
OptionalFileDescriptorSet optionalFds;
|
||||
};
|
||||
|
||||
// Use IPCStream or OptionalIPCStream in your ipdl to represent serialized
|
||||
// nsIInputStreams. Then use AutoIPCStream from IPCStreamUtils.h to perform
|
||||
// the serialization.
|
||||
union IPCStream
|
||||
{
|
||||
InputStreamParamsWithFds;
|
||||
PSendStream;
|
||||
};
|
||||
|
||||
union OptionalIPCStream
|
||||
{
|
||||
IPCStream;
|
||||
void_t;
|
||||
};
|
||||
|
||||
} // namespace ipc
|
||||
} // namespace mozilla
|
462
ipc/glue/IPCStreamUtils.cpp
Normal file
462
ipc/glue/IPCStreamUtils.cpp
Normal file
@ -0,0 +1,462 @@
|
||||
/* 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 "IPCStreamUtils.h"
|
||||
|
||||
#include "nsIIPCSerializableInputStream.h"
|
||||
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/dom/PContentChild.h"
|
||||
#include "mozilla/dom/File.h"
|
||||
#include "mozilla/ipc/FileDescriptorSetChild.h"
|
||||
#include "mozilla/ipc/FileDescriptorSetParent.h"
|
||||
#include "mozilla/ipc/PBackgroundChild.h"
|
||||
#include "mozilla/ipc/SendStream.h"
|
||||
#include "nsIAsyncInputStream.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace ipc {
|
||||
|
||||
namespace {
|
||||
|
||||
// These serialization and cleanup functions could be externally exposed. For
|
||||
// now, though, keep them private to encourage use of the safer RAII
|
||||
// AutoIPCStream class.
|
||||
|
||||
template<typename M>
|
||||
void
|
||||
SerializeInputStreamWithFdsChild(nsIInputStream* aStream,
|
||||
IPCStream& aValue,
|
||||
M* aManager)
|
||||
{
|
||||
MOZ_ASSERT(aStream);
|
||||
MOZ_ASSERT(aManager);
|
||||
|
||||
// First attempt simple stream serialization
|
||||
nsCOMPtr<nsIIPCSerializableInputStream> serializable =
|
||||
do_QueryInterface(aStream);
|
||||
if (!serializable) {
|
||||
MOZ_CRASH("Input stream is not serializable!");
|
||||
}
|
||||
|
||||
aValue = InputStreamParamsWithFds();
|
||||
InputStreamParamsWithFds& streamWithFds =
|
||||
aValue.get_InputStreamParamsWithFds();
|
||||
|
||||
AutoTArray<FileDescriptor, 4> fds;
|
||||
serializable->Serialize(streamWithFds.stream(), fds);
|
||||
|
||||
if (streamWithFds.stream().type() == InputStreamParams::T__None) {
|
||||
MOZ_CRASH("Serialize failed!");
|
||||
}
|
||||
|
||||
if (fds.IsEmpty()) {
|
||||
streamWithFds.optionalFds() = void_t();
|
||||
} else {
|
||||
PFileDescriptorSetChild* fdSet =
|
||||
aManager->SendPFileDescriptorSetConstructor(fds[0]);
|
||||
for (uint32_t i = 1; i < fds.Length(); ++i) {
|
||||
Unused << fdSet->SendAddFileDescriptor(fds[i]);
|
||||
}
|
||||
|
||||
streamWithFds.optionalFds() = fdSet;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename M>
|
||||
void
|
||||
SerializeInputStreamWithFdsParent(nsIInputStream* aStream,
|
||||
IPCStream& aValue,
|
||||
M* aManager)
|
||||
{
|
||||
MOZ_ASSERT(aStream);
|
||||
MOZ_ASSERT(aManager);
|
||||
|
||||
// First attempt simple stream serialization
|
||||
nsCOMPtr<nsIIPCSerializableInputStream> serializable =
|
||||
do_QueryInterface(aStream);
|
||||
if (!serializable) {
|
||||
MOZ_CRASH("Input stream is not serializable!");
|
||||
}
|
||||
|
||||
aValue = InputStreamParamsWithFds();
|
||||
InputStreamParamsWithFds& streamWithFds =
|
||||
aValue.get_InputStreamParamsWithFds();
|
||||
|
||||
AutoTArray<FileDescriptor, 4> fds;
|
||||
serializable->Serialize(streamWithFds.stream(), fds);
|
||||
|
||||
if (streamWithFds.stream().type() == InputStreamParams::T__None) {
|
||||
MOZ_CRASH("Serialize failed!");
|
||||
}
|
||||
|
||||
streamWithFds.optionalFds() = void_t();
|
||||
if (!fds.IsEmpty()) {
|
||||
PFileDescriptorSetParent* fdSet =
|
||||
aManager->SendPFileDescriptorSetConstructor(fds[0]);
|
||||
for (uint32_t i = 1; i < fds.Length(); ++i) {
|
||||
if (NS_WARN_IF(!fdSet->SendAddFileDescriptor(fds[i]))) {
|
||||
Unused << PFileDescriptorSetParent::Send__delete__(fdSet);
|
||||
fdSet = nullptr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (fdSet) {
|
||||
streamWithFds.optionalFds() = fdSet;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<typename M>
|
||||
void
|
||||
SerializeInputStream(nsIInputStream* aStream, IPCStream& aValue, M* aManager)
|
||||
{
|
||||
MOZ_ASSERT(aStream);
|
||||
MOZ_ASSERT(aManager);
|
||||
|
||||
// First attempt simple stream serialization
|
||||
nsCOMPtr<nsIIPCSerializableInputStream> serializable =
|
||||
do_QueryInterface(aStream);
|
||||
if (serializable) {
|
||||
SerializeInputStreamWithFdsChild(aStream, aValue, aManager);
|
||||
return;
|
||||
}
|
||||
|
||||
// As a fallback, attempt to stream the data across using a SendStream
|
||||
// actor. This will fail for blocking streams.
|
||||
nsCOMPtr<nsIAsyncInputStream> asyncStream = do_QueryInterface(aStream);
|
||||
aValue = SendStreamChild::Create(asyncStream, aManager);
|
||||
|
||||
if (!aValue.get_PSendStreamChild()) {
|
||||
MOZ_CRASH("SendStream creation failed!");
|
||||
}
|
||||
}
|
||||
|
||||
template<typename M>
|
||||
void
|
||||
SerializeInputStream(nsIInputStream* aStream, OptionalIPCStream& aValue,
|
||||
M* aManager)
|
||||
{
|
||||
if (!aStream) {
|
||||
aValue = void_t();
|
||||
return;
|
||||
}
|
||||
|
||||
aValue = IPCStream();
|
||||
SerializeInputStream(aStream, aValue.get_IPCStream(),
|
||||
aManager);
|
||||
}
|
||||
|
||||
void
|
||||
CleanupIPCStream(IPCStream& aValue, bool aConsumedByIPC)
|
||||
{
|
||||
if (aValue.type() == IPCStream::T__None) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (aValue.type() == IPCStream::TInputStreamParamsWithFds) {
|
||||
|
||||
InputStreamParamsWithFds& streamWithFds =
|
||||
aValue.get_InputStreamParamsWithFds();
|
||||
|
||||
// Cleanup file descriptors if necessary
|
||||
if (streamWithFds.optionalFds().type() ==
|
||||
OptionalFileDescriptorSet::TPFileDescriptorSetChild) {
|
||||
|
||||
AutoTArray<FileDescriptor, 4> fds;
|
||||
|
||||
auto fdSetActor = static_cast<FileDescriptorSetChild*>(
|
||||
streamWithFds.optionalFds().get_PFileDescriptorSetChild());
|
||||
MOZ_ASSERT(fdSetActor);
|
||||
|
||||
if (!aConsumedByIPC) {
|
||||
Unused << fdSetActor->Send__delete__(fdSetActor);
|
||||
}
|
||||
|
||||
// FileDescriptorSet doesn't clear its fds in its ActorDestroy, so we
|
||||
// unconditionally forget them here. The fds themselves are auto-closed in
|
||||
// ~FileDescriptor since they originated in this process.
|
||||
fdSetActor->ForgetFileDescriptors(fds);
|
||||
|
||||
} else if (streamWithFds.optionalFds().type() ==
|
||||
OptionalFileDescriptorSet::TPFileDescriptorSetParent) {
|
||||
|
||||
AutoTArray<FileDescriptor, 4> fds;
|
||||
|
||||
auto fdSetActor = static_cast<FileDescriptorSetParent*>(
|
||||
streamWithFds.optionalFds().get_PFileDescriptorSetParent());
|
||||
MOZ_ASSERT(fdSetActor);
|
||||
|
||||
if (!aConsumedByIPC) {
|
||||
Unused << fdSetActor->Send__delete__(fdSetActor);
|
||||
}
|
||||
|
||||
// FileDescriptorSet doesn't clear its fds in its ActorDestroy, so we
|
||||
// unconditionally forget them here. The fds themselves are auto-closed in
|
||||
// ~FileDescriptor since they originated in this process.
|
||||
fdSetActor->ForgetFileDescriptors(fds);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(aValue.type() == IPCStream::TPSendStreamChild);
|
||||
|
||||
auto sendStream =
|
||||
static_cast<SendStreamChild*>(aValue.get_PSendStreamChild());
|
||||
|
||||
if (!aConsumedByIPC) {
|
||||
sendStream->StartDestroy();
|
||||
return;
|
||||
}
|
||||
|
||||
// If the SendStream was taken to be sent to the parent, then we need to
|
||||
// start it before forgetting about it.
|
||||
sendStream->Start();
|
||||
}
|
||||
|
||||
void
|
||||
CleanupIPCStream(OptionalIPCStream& aValue, bool aConsumedByIPC)
|
||||
{
|
||||
if (aValue.type() == OptionalIPCStream::Tvoid_t) {
|
||||
return;
|
||||
}
|
||||
|
||||
CleanupIPCStream(aValue.get_IPCStream(), aConsumedByIPC);
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
already_AddRefed<nsIInputStream>
|
||||
DeserializeIPCStream(const IPCStream& aValue)
|
||||
{
|
||||
if (aValue.type() == IPCStream::TPSendStreamParent) {
|
||||
auto sendStream =
|
||||
static_cast<SendStreamParent*>(aValue.get_PSendStreamParent());
|
||||
return sendStream->TakeReader();
|
||||
}
|
||||
|
||||
// Note, we explicitly do not support deserializing the PSendStream actor on
|
||||
// the child side. It can only be sent from child to parent.
|
||||
MOZ_ASSERT(aValue.type() == IPCStream::TInputStreamParamsWithFds);
|
||||
|
||||
const InputStreamParamsWithFds& streamWithFds =
|
||||
aValue.get_InputStreamParamsWithFds();
|
||||
|
||||
AutoTArray<FileDescriptor, 4> fds;
|
||||
if (streamWithFds.optionalFds().type() ==
|
||||
OptionalFileDescriptorSet::TPFileDescriptorSetParent) {
|
||||
|
||||
auto fdSetActor = static_cast<FileDescriptorSetParent*>(
|
||||
streamWithFds.optionalFds().get_PFileDescriptorSetParent());
|
||||
MOZ_ASSERT(fdSetActor);
|
||||
|
||||
fdSetActor->ForgetFileDescriptors(fds);
|
||||
MOZ_ASSERT(!fds.IsEmpty());
|
||||
|
||||
if (!fdSetActor->Send__delete__(fdSetActor)) {
|
||||
// child process is gone, warn and allow actor to clean up normally
|
||||
NS_WARNING("Failed to delete fd set actor.");
|
||||
}
|
||||
} else if (streamWithFds.optionalFds().type() ==
|
||||
OptionalFileDescriptorSet::TPFileDescriptorSetChild) {
|
||||
|
||||
auto fdSetActor = static_cast<FileDescriptorSetChild*>(
|
||||
streamWithFds.optionalFds().get_PFileDescriptorSetChild());
|
||||
MOZ_ASSERT(fdSetActor);
|
||||
|
||||
fdSetActor->ForgetFileDescriptors(fds);
|
||||
MOZ_ASSERT(!fds.IsEmpty());
|
||||
|
||||
Unused << fdSetActor->Send__delete__(fdSetActor);
|
||||
}
|
||||
|
||||
return DeserializeInputStream(streamWithFds.stream(), fds);
|
||||
}
|
||||
|
||||
already_AddRefed<nsIInputStream>
|
||||
DeserializeIPCStream(const OptionalIPCStream& aValue)
|
||||
{
|
||||
if (aValue.type() == OptionalIPCStream::Tvoid_t) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return DeserializeIPCStream(aValue.get_IPCStream());
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
void
|
||||
AssertValidValueToTake(const IPCStream& aVal)
|
||||
{
|
||||
MOZ_ASSERT(aVal.type() == IPCStream::TPSendStreamChild ||
|
||||
aVal.type() == IPCStream::TInputStreamParamsWithFds);
|
||||
}
|
||||
|
||||
void
|
||||
AssertValidValueToTake(const OptionalIPCStream& aVal)
|
||||
{
|
||||
MOZ_ASSERT(aVal.type() == OptionalIPCStream::Tvoid_t ||
|
||||
aVal.type() == OptionalIPCStream::TIPCStream);
|
||||
if (aVal.type() == OptionalIPCStream::TIPCStream) {
|
||||
AssertValidValueToTake(aVal.get_IPCStream());
|
||||
}
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
AutoIPCStream::AutoIPCStream()
|
||||
: mInlineValue(void_t())
|
||||
, mValue(nullptr)
|
||||
, mOptionalValue(&mInlineValue)
|
||||
, mTaken(false)
|
||||
{
|
||||
}
|
||||
|
||||
AutoIPCStream::AutoIPCStream(IPCStream& aTarget)
|
||||
: mInlineValue(void_t())
|
||||
, mValue(&aTarget)
|
||||
, mOptionalValue(nullptr)
|
||||
, mTaken(false)
|
||||
{
|
||||
}
|
||||
|
||||
AutoIPCStream::AutoIPCStream(OptionalIPCStream& aTarget)
|
||||
: mInlineValue(void_t())
|
||||
, mValue(nullptr)
|
||||
, mOptionalValue(&aTarget)
|
||||
, mTaken(false)
|
||||
{
|
||||
*mOptionalValue = void_t();
|
||||
}
|
||||
|
||||
AutoIPCStream::~AutoIPCStream()
|
||||
{
|
||||
MOZ_ASSERT(mValue || mOptionalValue);
|
||||
if (mValue && IsSet()) {
|
||||
CleanupIPCStream(*mValue, mTaken);
|
||||
} else {
|
||||
CleanupIPCStream(*mOptionalValue, mTaken);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
AutoIPCStream::Serialize(nsIInputStream* aStream, PContentChild* aManager)
|
||||
{
|
||||
MOZ_ASSERT(aStream);
|
||||
MOZ_ASSERT(aManager);
|
||||
MOZ_ASSERT(mValue || mOptionalValue);
|
||||
MOZ_ASSERT(!mTaken);
|
||||
MOZ_ASSERT(!IsSet());
|
||||
|
||||
if (mValue) {
|
||||
SerializeInputStream(aStream, *mValue, aManager);
|
||||
AssertValidValueToTake(*mValue);
|
||||
} else {
|
||||
SerializeInputStream(aStream, *mOptionalValue, aManager);
|
||||
AssertValidValueToTake(*mOptionalValue);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
AutoIPCStream::Serialize(nsIInputStream* aStream, PBackgroundChild* aManager)
|
||||
{
|
||||
MOZ_ASSERT(aStream);
|
||||
MOZ_ASSERT(aManager);
|
||||
MOZ_ASSERT(mValue || mOptionalValue);
|
||||
MOZ_ASSERT(!mTaken);
|
||||
MOZ_ASSERT(!IsSet());
|
||||
|
||||
if (mValue) {
|
||||
SerializeInputStream(aStream, *mValue, aManager);
|
||||
AssertValidValueToTake(*mValue);
|
||||
} else {
|
||||
SerializeInputStream(aStream, *mOptionalValue, aManager);
|
||||
AssertValidValueToTake(*mOptionalValue);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
AutoIPCStream::Serialize(nsIInputStream* aStream, dom::PContentParent* aManager)
|
||||
{
|
||||
MOZ_ASSERT(aStream);
|
||||
MOZ_ASSERT(aManager);
|
||||
MOZ_ASSERT(mValue || mOptionalValue);
|
||||
MOZ_ASSERT(!mTaken);
|
||||
MOZ_ASSERT(!IsSet());
|
||||
|
||||
if (mValue) {
|
||||
SerializeInputStreamWithFdsParent(aStream, *mValue, aManager);
|
||||
AssertValidValueToTake(*mValue);
|
||||
} else {
|
||||
SerializeInputStreamWithFdsParent(aStream, *mOptionalValue, aManager);
|
||||
AssertValidValueToTake(*mOptionalValue);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
AutoIPCStream::Serialize(nsIInputStream* aStream, PBackgroundParent* aManager)
|
||||
{
|
||||
MOZ_ASSERT(aStream);
|
||||
MOZ_ASSERT(aManager);
|
||||
MOZ_ASSERT(mValue || mOptionalValue);
|
||||
MOZ_ASSERT(!mTaken);
|
||||
MOZ_ASSERT(!IsSet());
|
||||
|
||||
if (mValue) {
|
||||
SerializeInputStreamWithFdsParent(aStream, *mValue, aManager);
|
||||
AssertValidValueToTake(*mValue);
|
||||
} else {
|
||||
SerializeInputStreamWithFdsParent(aStream, *mOptionalValue, aManager);
|
||||
AssertValidValueToTake(*mOptionalValue);
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
AutoIPCStream::IsSet() const
|
||||
{
|
||||
MOZ_ASSERT(mValue || mOptionalValue);
|
||||
if (mValue) {
|
||||
return mValue->type() != IPCStream::T__None;
|
||||
} else {
|
||||
return mOptionalValue->type() != OptionalIPCStream::Tvoid_t &&
|
||||
mOptionalValue->get_IPCStream().type() != IPCStream::T__None;
|
||||
}
|
||||
}
|
||||
|
||||
IPCStream&
|
||||
AutoIPCStream::TakeValue()
|
||||
{
|
||||
MOZ_ASSERT(mValue || mOptionalValue);
|
||||
MOZ_ASSERT(!mTaken);
|
||||
MOZ_ASSERT(IsSet());
|
||||
|
||||
mTaken = true;
|
||||
|
||||
if (mValue) {
|
||||
AssertValidValueToTake(*mValue);
|
||||
return *mValue;
|
||||
}
|
||||
|
||||
IPCStream& value =
|
||||
mOptionalValue->get_IPCStream();
|
||||
|
||||
AssertValidValueToTake(value);
|
||||
return value;
|
||||
}
|
||||
|
||||
OptionalIPCStream&
|
||||
AutoIPCStream::TakeOptionalValue()
|
||||
{
|
||||
MOZ_ASSERT(!mTaken);
|
||||
MOZ_ASSERT(!mValue);
|
||||
MOZ_ASSERT(mOptionalValue);
|
||||
mTaken = true;
|
||||
AssertValidValueToTake(*mOptionalValue);
|
||||
return *mOptionalValue;
|
||||
}
|
||||
|
||||
} // namespace ipc
|
||||
} // namespace mozilla
|
183
ipc/glue/IPCStreamUtils.h
Normal file
183
ipc/glue/IPCStreamUtils.h
Normal file
@ -0,0 +1,183 @@
|
||||
/* 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/. */
|
||||
|
||||
#ifndef mozilla_ipc_IPCStreamUtils_h
|
||||
#define mozilla_ipc_IPCStreamUtils_h
|
||||
|
||||
#include "mozilla/ipc/IPCStream.h"
|
||||
#include "nsIInputStream.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
namespace dom {
|
||||
class PContentChild;
|
||||
class PContentParent;
|
||||
}
|
||||
|
||||
namespace ipc {
|
||||
|
||||
class PBackgroundChild;
|
||||
class PBackgroundParent;
|
||||
|
||||
// Deserialize an IPCStream received from an actor call. These methods
|
||||
// work in both the child and parent.
|
||||
already_AddRefed<nsIInputStream>
|
||||
DeserializeIPCStream(const IPCStream& aValue);
|
||||
|
||||
already_AddRefed<nsIInputStream>
|
||||
DeserializeIPCStream(const OptionalIPCStream& aValue);
|
||||
|
||||
// RAII helper class that serializes an nsIInputStream into an IPCStream struct.
|
||||
// Any file descriptor or PSendStream actors are automatically managed
|
||||
// correctly.
|
||||
//
|
||||
// Here is a simple example:
|
||||
//
|
||||
// // in ipdl file
|
||||
// Protocol PMyStuff
|
||||
// {
|
||||
// parent:
|
||||
// async DoStuff(IPCStream aStream);
|
||||
// child:
|
||||
// async StuffDone(IPCStream aStream);
|
||||
// };
|
||||
//
|
||||
// // in child c++ code
|
||||
// void CallDoStuff(PMyStuffChild* aActor, nsIInputStream* aStream)
|
||||
// {
|
||||
// AutoIPCStream autoStream;
|
||||
// autoStream.Serialize(aStream, aActor->Manager());
|
||||
// aActor->SendDoStuff(autoStream.TakeValue());
|
||||
// }
|
||||
//
|
||||
// // in parent c++ code
|
||||
// bool
|
||||
// MyStuffParent::RecvDoStuff(const IPCStream& aIPCStream) {
|
||||
// nsCOMPtr<nsIInputStream> stream = DeserializeIPCStream(aIPCStream);
|
||||
// // Do something with stream...
|
||||
//
|
||||
// // You can also serialize streams from parent-to-child as long as
|
||||
// // they don't require PSendStream actor support.
|
||||
// AutoIPCStream anotherStream;
|
||||
// anotherStream.Serialize(mFileStream, Manager());
|
||||
// SendStuffDone(anotherStream.TakeValue());
|
||||
// }
|
||||
//
|
||||
// The AutoIPCStream RAII class may also be used if your stream is embedded
|
||||
// in a more complex IPDL structure. In this case you attach the AutoIPCStream
|
||||
// to the embedded IPCStream and call TakeValue() after you pass the structure.
|
||||
// For example:
|
||||
//
|
||||
// // in ipdl file
|
||||
// struct Stuff
|
||||
// {
|
||||
// IPCStream stream;
|
||||
// nsCString name;
|
||||
// };
|
||||
//
|
||||
// Protocol PMyStuff
|
||||
// {
|
||||
// parent:
|
||||
// async DoStuff(Stuff aStream);
|
||||
// };
|
||||
//
|
||||
// // in child c++ code
|
||||
// void CallDoStuff(PMyStuffChild* aActor, nsIInputStream* aStream)
|
||||
// {
|
||||
// Stuff stuff;
|
||||
// AutoIPCStream autoStream(stuff.stream()); // attach to IPCStream here
|
||||
// autoStream.Serialize(aStream, aActor->Manager());
|
||||
// aActor->SendDoStuff(stuff);
|
||||
// autoStream.TakeValue(); // call take value after send
|
||||
// }
|
||||
//
|
||||
// // in parent c++ code
|
||||
// bool
|
||||
// MyStuffParent::RecvDoStuff(const Stuff& aStuff) {
|
||||
// nsCOMPtr<nsIInputStream> stream = DeserializeIPCStream(aStuff.stream());
|
||||
// /* do something with the nsIInputStream */
|
||||
// }
|
||||
//
|
||||
// The AutoIPCStream class also supports OptionalIPCStream values. As long as
|
||||
// you did not initialize the object with a non-optional IPCStream, you can call
|
||||
// TakeOptionalValue() instead.
|
||||
//
|
||||
// The AutoIPCStream class can also be used to serialize nsIInputStream objects
|
||||
// on the parent side to send to the child. Currently, however, this only
|
||||
// works for directly serializable stream types. The PSendStream actor mechanism
|
||||
// is not supported in this direction yet.
|
||||
//
|
||||
// Like SerializeInputStream(), the AutoIPCStream will crash if
|
||||
// serialization cannot be completed.
|
||||
//
|
||||
// NOTE: This is not a MOZ_STACK_CLASS so that it can be more easily integrated
|
||||
// with complex ipdl structures. For example, you may want to create an
|
||||
// array of RAII AutoIPCStream objects or build your own wrapping
|
||||
// RAII object to handle other actors that need to be cleaned up.
|
||||
class AutoIPCStream final
|
||||
{
|
||||
OptionalIPCStream mInlineValue;
|
||||
IPCStream* mValue;
|
||||
OptionalIPCStream* mOptionalValue;
|
||||
bool mTaken;
|
||||
|
||||
bool
|
||||
IsSet() const;
|
||||
|
||||
public:
|
||||
// Implicitly create an OptionalIPCStream value. Either
|
||||
// TakeValue() or TakeOptionalValue() can be used.
|
||||
AutoIPCStream();
|
||||
|
||||
// Wrap an existing IPCStream. Only TakeValue() may be
|
||||
// used. If a nullptr nsIInputStream is passed to SerializeOrSend() then
|
||||
// a crash will be forced.
|
||||
explicit AutoIPCStream(IPCStream& aTarget);
|
||||
|
||||
// Wrap an existing OptionalIPCStream. Either TakeValue()
|
||||
// or TakeOptionalValue can be used.
|
||||
explicit AutoIPCStream(OptionalIPCStream& aTarget);
|
||||
|
||||
~AutoIPCStream();
|
||||
|
||||
// Serialize the input stream or create a SendStream actor using the PContent
|
||||
// manager. If neither of these succeed, then crash. This should only be
|
||||
// used on the main thread.
|
||||
void
|
||||
Serialize(nsIInputStream* aStream, dom::PContentChild* aManager);
|
||||
|
||||
// Serialize the input stream or create a SendStream actor using the
|
||||
// PBackground manager. If neither of these succeed, then crash. This can
|
||||
// be called on the main thread or Worker threads.
|
||||
void
|
||||
Serialize(nsIInputStream* aStream, PBackgroundChild* aManager);
|
||||
|
||||
// Serialize the input stream. A PSendStream cannot be used when going
|
||||
// from parent-to-child.
|
||||
void
|
||||
Serialize(nsIInputStream* aStream, dom::PContentParent* aManager);
|
||||
|
||||
// Serialize the input stream. A PSendStream cannot be used when going
|
||||
// from parent-to-child.
|
||||
void
|
||||
Serialize(nsIInputStream* aStream, PBackgroundParent* aManager);
|
||||
|
||||
// Get the IPCStream as a non-optional value. This will
|
||||
// assert if a stream has not been serialized or if it has already been taken.
|
||||
// This should only be called if the value is being, or has already been, sent
|
||||
// to the parent
|
||||
IPCStream&
|
||||
TakeValue();
|
||||
|
||||
// Get the OptionalIPCStream value. This will assert if
|
||||
// the value has already been taken. This should only be called if the value
|
||||
// is being, or has already been, sent to the parent
|
||||
OptionalIPCStream&
|
||||
TakeOptionalValue();
|
||||
};
|
||||
|
||||
} // namespace ipc
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_ipc_IPCStreamUtils_h
|
@ -23,6 +23,7 @@ EXPORTS.mozilla.ipc += [
|
||||
'GeckoChildProcessHost.h',
|
||||
'InputStreamUtils.h',
|
||||
'IOThreadChild.h',
|
||||
'IPCStreamUtils.h',
|
||||
'MessageChannel.h',
|
||||
'MessageLink.h',
|
||||
'Neutering.h',
|
||||
@ -117,6 +118,7 @@ UNIFIED_SOURCES += [
|
||||
'FileDescriptorUtils.cpp',
|
||||
'InputStreamUtils.cpp',
|
||||
'IPCMessageUtils.cpp',
|
||||
'IPCStreamUtils.cpp',
|
||||
'MessageChannel.cpp',
|
||||
'MessageLink.cpp',
|
||||
'MessagePump.cpp',
|
||||
@ -158,6 +160,7 @@ LOCAL_INCLUDES += [
|
||||
|
||||
IPDL_SOURCES = [
|
||||
'InputStreamParams.ipdlh',
|
||||
'IPCStream.ipdlh',
|
||||
'PBackground.ipdl',
|
||||
'PBackgroundSharedTypes.ipdlh',
|
||||
'PBackgroundTest.ipdl',
|
||||
|
Loading…
Reference in New Issue
Block a user