зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1759563 - Add SerializedComplexity to limit the complexity of serialized IPCStream instances, r=asuth,necko-reviewers,dragana
This will improve the efficiency of serializing large data pipes, which in bad cases can end up serializing very small amounts of data in individual pipes over IPC, and acts as a compliment to the existing logic for limiting serialized message sizes. It is also necessary for the changes in bug 1754004, which require the ability to include FileDescriptor inline in the message, which could blow out our FileDescriptor count limits if pipe creation was unlimited. In some tests, this change reduces the number of pipes required to serialize a nsIInputStream from over 5000 to 1. Differential Revision: https://phabricator.services.mozilla.com/D141036
This commit is contained in:
Родитель
e00878d3f2
Коммит
7aead901b8
|
@ -598,6 +598,13 @@ RemoteLazyInputStream::OnInputStreamReady(nsIAsyncInputStream* aStream) {
|
|||
|
||||
// nsIIPCSerializableInputStream
|
||||
|
||||
void RemoteLazyInputStream::SerializedComplexity(uint32_t aMaxSize,
|
||||
uint32_t* aSizeUsed,
|
||||
uint32_t* aNewPipes,
|
||||
uint32_t* aTransferables) {
|
||||
*aTransferables = 1;
|
||||
}
|
||||
|
||||
void RemoteLazyInputStream::Serialize(
|
||||
mozilla::ipc::InputStreamParams& aParams,
|
||||
FileDescriptorArray& aFileDescriptors, bool aDelayedStart,
|
||||
|
|
|
@ -78,6 +78,14 @@ NS_IMETHODIMP DecryptingInputStreamBase::GetCloneable(bool* aCloneable) {
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
void DecryptingInputStreamBase::SerializedComplexity(uint32_t aMaxSize,
|
||||
uint32_t* aSizeUsed,
|
||||
uint32_t* aPipes,
|
||||
uint32_t* aTransferables) {
|
||||
(*mBaseIPCSerializableInputStream)
|
||||
->SerializedComplexity(aMaxSize, aSizeUsed, aPipes, aTransferables);
|
||||
}
|
||||
|
||||
void DecryptingInputStreamBase::Serialize(
|
||||
mozilla::ipc::InputStreamParams& aParams,
|
||||
FileDescriptorArray& aFileDescriptors, bool aDelayedStart,
|
||||
|
|
|
@ -53,6 +53,10 @@ class DecryptingInputStreamBase : public nsIInputStream,
|
|||
using nsICloneableInputStream::GetCloneable;
|
||||
NS_IMETHOD GetCloneable(bool* aCloneable) final;
|
||||
|
||||
void SerializedComplexity(uint32_t aMaxSize, uint32_t* aSizeUsed,
|
||||
uint32_t* aPipes,
|
||||
uint32_t* aTransferables) override;
|
||||
|
||||
using nsIIPCSerializableInputStream::Serialize;
|
||||
void Serialize(mozilla::ipc::InputStreamParams& aParams,
|
||||
FileDescriptorArray& aFileDescriptors, bool aDelayedStart,
|
||||
|
|
|
@ -655,6 +655,16 @@ NS_IMETHODIMP DataPipeReceiver::AsyncWait(nsIInputStreamCallback* aCallback,
|
|||
|
||||
// nsIIPCSerializableInputStream
|
||||
|
||||
void DataPipeReceiver::SerializedComplexity(uint32_t aMaxSize,
|
||||
uint32_t* aSizeUsed,
|
||||
uint32_t* aPipes,
|
||||
uint32_t* aTransferables) {
|
||||
// We report DataPipeReceiver as taking one transferrable to serialize, rather
|
||||
// than one pipe, as we aren't starting a new pipe for this purpose, and are
|
||||
// instead transferring an existing pipe.
|
||||
*aTransferables = 1;
|
||||
}
|
||||
|
||||
void DataPipeReceiver::Serialize(InputStreamParams& aParams,
|
||||
FileDescriptorArray& aFileDescriptors,
|
||||
bool aDelayedStart, uint32_t aMaxSize,
|
||||
|
|
|
@ -124,6 +124,23 @@ void SerializeInputStreamAsPipeInternal(nsIInputStream* aInputStream,
|
|||
|
||||
} // namespace
|
||||
|
||||
void InputStreamHelper::SerializedComplexity(nsIInputStream* aInputStream,
|
||||
uint32_t aMaxSize,
|
||||
uint32_t* aSizeUsed,
|
||||
uint32_t* aPipes,
|
||||
uint32_t* aTransferables) {
|
||||
MOZ_ASSERT(aInputStream);
|
||||
|
||||
nsCOMPtr<nsIIPCSerializableInputStream> serializable =
|
||||
do_QueryInterface(aInputStream);
|
||||
if (!serializable) {
|
||||
MOZ_CRASH("Input stream is not serializable!");
|
||||
}
|
||||
|
||||
serializable->SerializedComplexity(aMaxSize, aSizeUsed, aPipes,
|
||||
aTransferables);
|
||||
}
|
||||
|
||||
void InputStreamHelper::SerializeInputStream(
|
||||
nsIInputStream* aInputStream, InputStreamParams& aParams,
|
||||
nsTArray<FileDescriptor>& aFileDescriptors, bool aDelayedStart,
|
||||
|
|
|
@ -42,6 +42,10 @@ class ChildToParentStreamActorManager {
|
|||
// If you want to serialize an inputStream, please use AutoIPCStream.
|
||||
class InputStreamHelper {
|
||||
public:
|
||||
static void SerializedComplexity(nsIInputStream* aInputStream,
|
||||
uint32_t aMaxSize, uint32_t* aSizeUsed,
|
||||
uint32_t* aPipes, uint32_t* aTransferables);
|
||||
|
||||
// These 2 methods allow to serialize an inputStream into InputStreamParams.
|
||||
// The manager is needed in case a stream needs to serialize itself as
|
||||
// IPCRemoteStream.
|
||||
|
|
|
@ -37,6 +37,39 @@ class NS_NO_VTABLE nsIIPCSerializableInputStream : public nsISupports {
|
|||
|
||||
NS_DECLARE_STATIC_IID_ACCESSOR(NS_IIPCSERIALIZABLEINPUTSTREAM_IID)
|
||||
|
||||
// Determine the serialized complexity of this input stream, initializing
|
||||
// `*aSizeUsed`, `*aPipes` and `*aTransferables` to the number of inline
|
||||
// bytes/pipes/transferable resources which would be used. This will be used
|
||||
// by other `Serialize` implementations to potentially simplify the resulting
|
||||
// stream, reducing the number of pipes or file descriptors required.
|
||||
//
|
||||
// Each outparameter corresponds to a type of resource which will be included
|
||||
// in the serialized message, as follows:
|
||||
//
|
||||
// *aSizeUsed:
|
||||
// Raw bytes to be included inline in the message's payload, usually in the
|
||||
// form of a nsCString for a StringInputStreamParams. This must be less
|
||||
// than or equal to `aMaxSize`. Larger payloads should instead be
|
||||
// serialized using SerializeInputStreamAsPipe.
|
||||
// *aPipes:
|
||||
// New pipes, created using SerializeInputStreamAsPipe, which will be used
|
||||
// to asynchronously transfer part of the pipe over IPC. Callers such as
|
||||
// nsMultiplexInputStream may choose to serialize themselves as a DataPipe
|
||||
// if they contain DataPipes themselves, so existing DataPipe instances
|
||||
// which are cheaply transferred should be counted as transferrables.
|
||||
// *aTransferables:
|
||||
// Existing objects which can be more cheaply transferred over IPC than by
|
||||
// serializing them inline in a payload or transferring them through a new
|
||||
// DataPipe. This includes RemoteLazyInputStreams, FileDescriptors, and
|
||||
// existing DataPipeReceiver instances.
|
||||
//
|
||||
// Callers of this method must have initialized all of `*aSizeUsed`,
|
||||
// `*aPipes`, and `*aTransferables` to 0, so implementations are not required
|
||||
// to initialize all outparameters. The outparameters must not be null.
|
||||
virtual void SerializedComplexity(uint32_t aMaxSize, uint32_t* aSizeUsed,
|
||||
uint32_t* aPipes,
|
||||
uint32_t* aTransferables) = 0;
|
||||
|
||||
virtual void Serialize(
|
||||
mozilla::ipc::InputStreamParams& aParams,
|
||||
FileDescriptorArray& aFileDescriptors, bool aDelayedStart,
|
||||
|
@ -57,6 +90,9 @@ NS_DEFINE_STATIC_IID_ACCESSOR(nsIIPCSerializableInputStream,
|
|||
NS_IIPCSERIALIZABLEINPUTSTREAM_IID)
|
||||
|
||||
#define NS_DECL_NSIIPCSERIALIZABLEINPUTSTREAM \
|
||||
virtual void SerializedComplexity(uint32_t aMaxSize, uint32_t* aSizeUsed, \
|
||||
uint32_t* aPipes, \
|
||||
uint32_t* aTransferrables) override; \
|
||||
virtual void Serialize( \
|
||||
mozilla::ipc::InputStreamParams&, FileDescriptorArray&, bool, uint32_t, \
|
||||
uint32_t*, mozilla::ipc::ParentToChildStreamActorManager*) override; \
|
||||
|
@ -68,58 +104,35 @@ NS_DEFINE_STATIC_IID_ACCESSOR(nsIIPCSerializableInputStream,
|
|||
virtual bool Deserialize(const mozilla::ipc::InputStreamParams&, \
|
||||
const FileDescriptorArray&) override;
|
||||
|
||||
#define NS_FORWARD_NSIIPCSERIALIZABLEINPUTSTREAM(_to) \
|
||||
virtual void Serialize( \
|
||||
mozilla::ipc::InputStreamParams& aParams, \
|
||||
FileDescriptorArray& aFileDescriptors, bool aDelayedStart, \
|
||||
uint32_t aMaxSize, uint32_t* aSizeUsed, \
|
||||
mozilla::ipc::ParentToChildStreamActorManager* aManager) override { \
|
||||
_to Serialize(aParams, aFileDescriptors, aDelayedStart, aMaxSize, \
|
||||
aSizeUsed, aManager); \
|
||||
} \
|
||||
\
|
||||
virtual void Serialize( \
|
||||
mozilla::ipc::InputStreamParams& aParams, \
|
||||
FileDescriptorArray& aFileDescriptors, bool aDelayedStart, \
|
||||
uint32_t aMaxSize, uint32_t* aSizeUsed, \
|
||||
mozilla::ipc::ChildToParentStreamActorManager* aManager) override { \
|
||||
_to Serialize(aParams, aFileDescriptors, aDelayedStart, aMaxSize, \
|
||||
aSizeUsed, aManager); \
|
||||
} \
|
||||
\
|
||||
virtual bool Deserialize(const mozilla::ipc::InputStreamParams& aParams, \
|
||||
const FileDescriptorArray& aFileDescriptors) \
|
||||
override { \
|
||||
return _to Deserialize(aParams, aFileDescriptors); \
|
||||
}
|
||||
|
||||
#define NS_FORWARD_SAFE_NSIIPCSERIALIZABLEINPUTSTREAM(_to) \
|
||||
virtual void Serialize( \
|
||||
mozilla::ipc::InputStreamParams& aParams, \
|
||||
FileDescriptorArray& aFileDescriptors, bool aDelayedStart, \
|
||||
uint32_t aMaxSize, uint32_t* aSizeUsed, \
|
||||
mozilla::ipc::ParentToChildStreamActorManager* aManager) override { \
|
||||
if (_to) { \
|
||||
_to->Serialize(aParams, aFileDescriptors, aDelayedStart, aMaxSize, \
|
||||
aSizeUsed, aManager); \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
virtual void Serialize( \
|
||||
mozilla::ipc::InputStreamParams& aParams, \
|
||||
FileDescriptorArray& aFileDescriptors, bool aDelayedStart, \
|
||||
uint32_t aMaxSize, uint32_t* aSizeUsed, \
|
||||
mozilla::ipc::ChildToParentStreamActorManager* aManager) override { \
|
||||
if (_to) { \
|
||||
_to->Serialize(aParams, aFileDescriptors, aDelayedStart, aMaxSize, \
|
||||
aSizeUsed, aManager); \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
virtual bool Deserialize(const mozilla::ipc::InputStreamParams& aParams, \
|
||||
const FileDescriptorArray& aFileDescriptors) \
|
||||
override { \
|
||||
return _to ? _to->Deserialize(aParams, aFileDescriptors) : false; \
|
||||
#define NS_FORWARD_NSIIPCSERIALIZABLEINPUTSTREAM(_to) \
|
||||
virtual void SerializedComplexity(uint32_t aMaxSize, uint32_t* aSizeUsed, \
|
||||
uint32_t* aPipes, \
|
||||
uint32_t* aTransferables) override { \
|
||||
_to SerializedComplexity(aMaxSize, aSizeUsed, aPipes, aTransferables); \
|
||||
}; \
|
||||
\
|
||||
virtual void Serialize( \
|
||||
mozilla::ipc::InputStreamParams& aParams, \
|
||||
FileDescriptorArray& aFileDescriptors, bool aDelayedStart, \
|
||||
uint32_t aMaxSize, uint32_t* aSizeUsed, \
|
||||
mozilla::ipc::ParentToChildStreamActorManager* aManager) override { \
|
||||
_to Serialize(aParams, aFileDescriptors, aDelayedStart, aMaxSize, \
|
||||
aSizeUsed, aManager); \
|
||||
} \
|
||||
\
|
||||
virtual void Serialize( \
|
||||
mozilla::ipc::InputStreamParams& aParams, \
|
||||
FileDescriptorArray& aFileDescriptors, bool aDelayedStart, \
|
||||
uint32_t aMaxSize, uint32_t* aSizeUsed, \
|
||||
mozilla::ipc::ChildToParentStreamActorManager* aManager) override { \
|
||||
_to Serialize(aParams, aFileDescriptors, aDelayedStart, aMaxSize, \
|
||||
aSizeUsed, aManager); \
|
||||
} \
|
||||
\
|
||||
virtual bool Deserialize(const mozilla::ipc::InputStreamParams& aParams, \
|
||||
const FileDescriptorArray& aFileDescriptors) \
|
||||
override { \
|
||||
return _to Deserialize(aParams, aFileDescriptors); \
|
||||
}
|
||||
|
||||
#endif // mozilla_ipc_nsIIPCSerializableInputStream_h
|
||||
|
|
|
@ -291,6 +291,13 @@ PartiallySeekableInputStream::OnInputStreamReady(nsIAsyncInputStream* aStream) {
|
|||
|
||||
// nsIIPCSerializableInputStream
|
||||
|
||||
void PartiallySeekableInputStream::SerializedComplexity(
|
||||
uint32_t aMaxSize, uint32_t* aSizeUsed, uint32_t* aPipes,
|
||||
uint32_t* aTransferables) {
|
||||
mozilla::ipc::InputStreamHelper::SerializedComplexity(
|
||||
mInputStream, aMaxSize, aSizeUsed, aPipes, aTransferables);
|
||||
}
|
||||
|
||||
void PartiallySeekableInputStream::Serialize(
|
||||
mozilla::ipc::InputStreamParams& aParams,
|
||||
FileDescriptorArray& aFileDescriptors, bool aDelayedStart,
|
||||
|
|
|
@ -577,6 +577,19 @@ nsBufferedInputStream::GetUnbufferedStream(nsISupports** aStream) {
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
void nsBufferedInputStream::SerializedComplexity(uint32_t aMaxSize,
|
||||
uint32_t* aSizeUsed,
|
||||
uint32_t* aPipes,
|
||||
uint32_t* aTransferables) {
|
||||
if (mStream) {
|
||||
nsCOMPtr<nsIInputStream> stream = do_QueryInterface(mStream);
|
||||
MOZ_ASSERT(stream);
|
||||
|
||||
InputStreamHelper::SerializedComplexity(stream, aMaxSize, aSizeUsed, aPipes,
|
||||
aTransferables);
|
||||
}
|
||||
}
|
||||
|
||||
void nsBufferedInputStream::Serialize(
|
||||
InputStreamParams& aParams, FileDescriptorArray& aFileDescriptors,
|
||||
bool aDelayedStart, uint32_t aMaxSize, uint32_t* aSizeUsed,
|
||||
|
|
|
@ -540,6 +540,13 @@ nsFileInputStream::Available(uint64_t* aResult) {
|
|||
return nsFileStreamBase::Available(aResult);
|
||||
}
|
||||
|
||||
void nsFileInputStream::SerializedComplexity(uint32_t aMaxSize,
|
||||
uint32_t* aSizeUsed,
|
||||
uint32_t* aPipes,
|
||||
uint32_t* aTransferables) {
|
||||
*aTransferables = 1;
|
||||
}
|
||||
|
||||
void nsFileInputStream::Serialize(InputStreamParams& aParams,
|
||||
FileDescriptorArray& aFileDescriptors,
|
||||
bool aDelayedStart, uint32_t aMaxSize,
|
||||
|
|
|
@ -333,6 +333,19 @@ nsresult nsMIMEInputStreamConstructor(nsISupports* outer, REFNSIID iid,
|
|||
return inst->QueryInterface(iid, result);
|
||||
}
|
||||
|
||||
void nsMIMEInputStream::SerializedComplexity(uint32_t aMaxSize,
|
||||
uint32_t* aSizeUsed,
|
||||
uint32_t* aPipes,
|
||||
uint32_t* aTransferables) {
|
||||
if (nsCOMPtr<nsIIPCSerializableInputStream> serializable =
|
||||
do_QueryInterface(mStream)) {
|
||||
InputStreamHelper::SerializedComplexity(mStream, aMaxSize, aSizeUsed,
|
||||
aPipes, aTransferables);
|
||||
} else {
|
||||
*aPipes = 1;
|
||||
}
|
||||
}
|
||||
|
||||
void nsMIMEInputStream::Serialize(
|
||||
InputStreamParams& aParams, FileDescriptorArray& aFileDescriptors,
|
||||
bool aDelayedStart, uint32_t aMaxSize, uint32_t* aSizeUsed,
|
||||
|
|
|
@ -246,6 +246,14 @@ InputStreamLengthWrapper::OnInputStreamReady(nsIAsyncInputStream* aStream) {
|
|||
|
||||
// nsIIPCSerializableInputStream
|
||||
|
||||
void InputStreamLengthWrapper::SerializedComplexity(uint32_t aMaxSize,
|
||||
uint32_t* aSizeUsed,
|
||||
uint32_t* aPipes,
|
||||
uint32_t* aTransferables) {
|
||||
InputStreamHelper::SerializedComplexity(mInputStream, aMaxSize, aSizeUsed,
|
||||
aPipes, aTransferables);
|
||||
}
|
||||
|
||||
void InputStreamLengthWrapper::Serialize(
|
||||
mozilla::ipc::InputStreamParams& aParams,
|
||||
FileDescriptorArray& aFileDescriptors, bool aDelayedStart,
|
||||
|
|
|
@ -322,6 +322,13 @@ NonBlockingAsyncInputStream::AsyncWait(nsIInputStreamCallback* aCallback,
|
|||
|
||||
// nsIIPCSerializableInputStream
|
||||
|
||||
void NonBlockingAsyncInputStream::SerializedComplexity(
|
||||
uint32_t aMaxSize, uint32_t* aSizeUsed, uint32_t* aPipes,
|
||||
uint32_t* aTransferables) {
|
||||
InputStreamHelper::SerializedComplexity(mInputStream, aMaxSize, aSizeUsed,
|
||||
aPipes, aTransferables);
|
||||
}
|
||||
|
||||
void NonBlockingAsyncInputStream::Serialize(
|
||||
mozilla::ipc::InputStreamParams& aParams,
|
||||
FileDescriptorArray& aFileDescriptors, bool aDelayedStart,
|
||||
|
|
|
@ -387,6 +387,16 @@ SeekableStreamWrapper::AsyncLengthWait(nsIInputStreamLengthCallback* aCallback,
|
|||
|
||||
// nsIIPCSerializableInputStream
|
||||
|
||||
void SeekableStreamWrapper::SerializedComplexity(uint32_t aMaxSize,
|
||||
uint32_t* aSizeUsed,
|
||||
uint32_t* aPipes,
|
||||
uint32_t* aTransferables) {
|
||||
MOZ_ASSERT(IsIPCSerializableInputStream());
|
||||
nsCOMPtr<nsIInputStream> original = do_QueryInterface(mOriginal);
|
||||
mozilla::ipc::InputStreamHelper::SerializedComplexity(
|
||||
original, aMaxSize, aSizeUsed, aPipes, aTransferables);
|
||||
}
|
||||
|
||||
void SeekableStreamWrapper::Serialize(
|
||||
mozilla::ipc::InputStreamParams& aParams,
|
||||
FileDescriptorArray& aFileDescriptors, bool aDelayedStart,
|
||||
|
|
|
@ -423,6 +423,24 @@ SlicedInputStream::OnInputStreamReady(nsIAsyncInputStream* aStream) {
|
|||
|
||||
// nsIIPCSerializableInputStream
|
||||
|
||||
void SlicedInputStream::SerializedComplexity(uint32_t aMaxSize,
|
||||
uint32_t* aSizeUsed,
|
||||
uint32_t* aPipes,
|
||||
uint32_t* aTransferables) {
|
||||
InputStreamHelper::SerializedComplexity(mInputStream, aMaxSize, aSizeUsed,
|
||||
aPipes, aTransferables);
|
||||
|
||||
// If we're going to be serializing a pipe to transfer the sliced data, and we
|
||||
// are getting no efficiency improvements from transferables, stream this
|
||||
// sliced input stream directly as a pipe to avoid streaming data which will
|
||||
// be sliced off anyway.
|
||||
if (*aPipes > 0 && *aTransferables == 0) {
|
||||
*aSizeUsed = 0;
|
||||
*aPipes = 1;
|
||||
*aTransferables = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void SlicedInputStream::Serialize(
|
||||
mozilla::ipc::InputStreamParams& aParams,
|
||||
FileDescriptorArray& aFileDescriptors, bool aDelayedStart,
|
||||
|
@ -449,6 +467,14 @@ void SlicedInputStream::SerializeInternal(
|
|||
MOZ_ASSERT(mInputStream);
|
||||
MOZ_ASSERT(mWeakIPCSerializableInputStream);
|
||||
|
||||
uint32_t sizeUsed = 0, pipes = 0, transferables = 0;
|
||||
SerializedComplexity(aMaxSize, &sizeUsed, &pipes, &transferables);
|
||||
if (pipes > 0 && transferables == 0) {
|
||||
InputStreamHelper::SerializeInputStreamAsPipe(mInputStream, aParams,
|
||||
aDelayedStart, aManager);
|
||||
return;
|
||||
}
|
||||
|
||||
SlicedInputStreamParams params;
|
||||
InputStreamHelper::SerializeInputStream(mInputStream, params.stream(),
|
||||
aFileDescriptors, aDelayedStart,
|
||||
|
|
|
@ -35,9 +35,6 @@ using namespace mozilla;
|
|||
using namespace mozilla::ipc;
|
||||
|
||||
using mozilla::DeprecatedAbs;
|
||||
using mozilla::Maybe;
|
||||
using mozilla::Nothing;
|
||||
using mozilla::Some;
|
||||
|
||||
class nsMultiplexInputStream final : public nsIMultiplexInputStream,
|
||||
public nsISeekableStream,
|
||||
|
@ -123,6 +120,10 @@ class nsMultiplexInputStream final : public nsIMultiplexInputStream,
|
|||
bool mDone;
|
||||
};
|
||||
|
||||
void SerializedComplexityInternal(uint32_t aMaxSize, uint32_t* aSizeUsed,
|
||||
uint32_t* aPipes, uint32_t* aTransferables,
|
||||
bool* aSerializeAsPipe);
|
||||
|
||||
template <typename M>
|
||||
void SerializeInternal(InputStreamParams& aParams,
|
||||
FileDescriptorArray& aFileDescriptors,
|
||||
|
@ -956,6 +957,82 @@ nsresult nsMultiplexInputStreamConstructor(nsISupports* aOuter, REFNSIID aIID,
|
|||
return inst->QueryInterface(aIID, aResult);
|
||||
}
|
||||
|
||||
void nsMultiplexInputStream::SerializedComplexity(uint32_t aMaxSize,
|
||||
uint32_t* aSizeUsed,
|
||||
uint32_t* aPipes,
|
||||
uint32_t* aTransferables) {
|
||||
MutexAutoLock lock(mLock);
|
||||
bool serializeAsPipe = false;
|
||||
SerializedComplexityInternal(aMaxSize, aSizeUsed, aPipes, aTransferables,
|
||||
&serializeAsPipe);
|
||||
}
|
||||
|
||||
void nsMultiplexInputStream::SerializedComplexityInternal(
|
||||
uint32_t aMaxSize, uint32_t* aSizeUsed, uint32_t* aPipes,
|
||||
uint32_t* aTransferables, bool* aSerializeAsPipe) {
|
||||
mLock.AssertCurrentThreadOwns();
|
||||
CheckedUint32 totalSizeUsed = 0;
|
||||
CheckedUint32 totalPipes = 0;
|
||||
CheckedUint32 totalTransferables = 0;
|
||||
CheckedUint32 maxSize = aMaxSize;
|
||||
|
||||
uint32_t streamCount = mStreams.Length();
|
||||
|
||||
for (uint32_t index = 0; index < streamCount; index++) {
|
||||
uint32_t sizeUsed = 0;
|
||||
uint32_t pipes = 0;
|
||||
uint32_t transferables = 0;
|
||||
InputStreamHelper::SerializedComplexity(mStreams[index].mOriginalStream,
|
||||
maxSize.value(), &sizeUsed, &pipes,
|
||||
&transferables);
|
||||
|
||||
MOZ_ASSERT(maxSize.value() >= sizeUsed);
|
||||
|
||||
maxSize -= sizeUsed;
|
||||
MOZ_DIAGNOSTIC_ASSERT(maxSize.isValid());
|
||||
totalSizeUsed += sizeUsed;
|
||||
MOZ_DIAGNOSTIC_ASSERT(totalSizeUsed.isValid());
|
||||
totalPipes += pipes;
|
||||
MOZ_DIAGNOSTIC_ASSERT(totalPipes.isValid());
|
||||
totalTransferables += transferables;
|
||||
MOZ_DIAGNOSTIC_ASSERT(totalTransferables.isValid());
|
||||
}
|
||||
|
||||
// If the combination of all streams when serialized independently is
|
||||
// sufficiently complex, we may choose to serialize it as a pipe to limit the
|
||||
// complexity of the payload.
|
||||
if (totalTransferables.value() == 0) {
|
||||
// If there are no transferables within our serialization, and it would
|
||||
// contain at least one pipe, serialize the entire payload as a pipe for
|
||||
// simplicity.
|
||||
*aSerializeAsPipe = totalSizeUsed.value() > 0 && totalPipes.value() > 0;
|
||||
} else {
|
||||
// Otherwise, we may want to still serialize in segments to take advantage
|
||||
// of the efficiency of serializing transferables. We'll only serialize as a
|
||||
// pipe if the total attachment count exceeds kMaxAttachmentThreshold.
|
||||
static constexpr uint32_t kMaxAttachmentThreshold = 8;
|
||||
CheckedUint32 totalAttachments = totalPipes + totalTransferables;
|
||||
*aSerializeAsPipe = !totalAttachments.isValid() ||
|
||||
totalAttachments.value() > kMaxAttachmentThreshold;
|
||||
}
|
||||
|
||||
if (*aSerializeAsPipe) {
|
||||
NS_WARNING(
|
||||
nsPrintfCString("Choosing to serialize multiplex stream as a pipe "
|
||||
"(would be %u bytes, %u pipes, %u transferables)",
|
||||
totalSizeUsed.value(), totalPipes.value(),
|
||||
totalTransferables.value())
|
||||
.get());
|
||||
*aSizeUsed = 0;
|
||||
*aPipes = 1;
|
||||
*aTransferables = 0;
|
||||
} else {
|
||||
*aSizeUsed = totalSizeUsed.value();
|
||||
*aPipes = totalPipes.value();
|
||||
*aTransferables = totalTransferables.value();
|
||||
}
|
||||
}
|
||||
|
||||
void nsMultiplexInputStream::Serialize(
|
||||
InputStreamParams& aParams, FileDescriptorArray& aFileDescriptors,
|
||||
bool aDelayedStart, uint32_t aMaxSize, uint32_t* aSizeUsed,
|
||||
|
@ -978,6 +1055,19 @@ void nsMultiplexInputStream::SerializeInternal(
|
|||
bool aDelayedStart, uint32_t aMaxSize, uint32_t* aSizeUsed, M* aManager) {
|
||||
MutexAutoLock lock(mLock);
|
||||
|
||||
// Check if we should serialize this stream as a pipe to reduce complexity.
|
||||
uint32_t dummySizeUsed = 0, dummyPipes = 0, dummyTransferables = 0;
|
||||
bool serializeAsPipe = false;
|
||||
SerializedComplexityInternal(aMaxSize, &dummySizeUsed, &dummyPipes,
|
||||
&dummyTransferables, &serializeAsPipe);
|
||||
if (serializeAsPipe) {
|
||||
*aSizeUsed = 0;
|
||||
MutexAutoUnlock unlock(mLock);
|
||||
InputStreamHelper::SerializeInputStreamAsPipe(this, aParams, aDelayedStart,
|
||||
aManager);
|
||||
return;
|
||||
}
|
||||
|
||||
MultiplexInputStreamParams params;
|
||||
|
||||
CheckedUint32 totalSizeUsed = 0;
|
||||
|
|
|
@ -574,6 +574,21 @@ nsresult nsStorageInputStream::Seek(uint32_t aPosition) {
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
void nsStorageInputStream::SerializedComplexity(uint32_t aMaxSize,
|
||||
uint32_t* aSizeUsed,
|
||||
uint32_t* aPipes,
|
||||
uint32_t* aTransferables) {
|
||||
uint64_t remaining = 0;
|
||||
mozilla::DebugOnly<nsresult> rv = Available(&remaining);
|
||||
MOZ_ASSERT(NS_SUCCEEDED(rv));
|
||||
|
||||
if (remaining >= aMaxSize) {
|
||||
*aPipes = 1;
|
||||
} else {
|
||||
*aSizeUsed = remaining;
|
||||
}
|
||||
}
|
||||
|
||||
void nsStorageInputStream::Serialize(
|
||||
InputStreamParams& aParams, FileDescriptorArray&, bool aDelayedStart,
|
||||
uint32_t aMaxSize, uint32_t* aSizeUsed,
|
||||
|
|
|
@ -450,6 +450,19 @@ nsStringInputStream::Tell(int64_t* aOutWhere) {
|
|||
// nsIIPCSerializableInputStream implementation
|
||||
/////////
|
||||
|
||||
void nsStringInputStream::SerializedComplexity(uint32_t aMaxSize,
|
||||
uint32_t* aSizeUsed,
|
||||
uint32_t* aPipes,
|
||||
uint32_t* aTransferables) {
|
||||
ReentrantMonitorAutoEnter lock(mMon);
|
||||
|
||||
if (Length() >= aMaxSize) {
|
||||
*aPipes = 1;
|
||||
} else {
|
||||
*aSizeUsed = Length();
|
||||
}
|
||||
}
|
||||
|
||||
void nsStringInputStream::Serialize(
|
||||
InputStreamParams& aParams, FileDescriptorArray& /* aFDs */,
|
||||
bool aDelayedStart, uint32_t aMaxSize, uint32_t* aSizeUsed,
|
||||
|
|
|
@ -282,6 +282,8 @@ class QIInputStream final : public nsIInputStream,
|
|||
}
|
||||
|
||||
// nsIIPCSerializableInputStream
|
||||
void SerializedComplexity(uint32_t, uint32_t*, uint32_t*,
|
||||
uint32_t*) override {}
|
||||
void Serialize(mozilla::ipc::InputStreamParams&, FileDescriptorArray&, bool,
|
||||
uint32_t, uint32_t*,
|
||||
mozilla::ipc::ParentToChildStreamActorManager*) override {}
|
||||
|
|
Загрузка…
Ссылка в новой задаче