commit 6b239e496c39cf1a59732096921c963dadbfcfa9
parent 89594220989894d98fc5489c5e393e16aea8e522
Author: Andrew Osmond <aosmond@gmail.com>
Date: Thu, 8 Jan 2026 15:52:08 +0000
Bug 2008385 - Remote encoders/decoders should always check if manager thread has shutdown. r=media-playback-reviewers,padenot
Differential Revision: https://phabricator.services.mozilla.com/D278230
Diffstat:
6 files changed, 80 insertions(+), 39 deletions(-)
diff --git a/dom/media/ipc/MFCDMChild.h b/dom/media/ipc/MFCDMChild.h
@@ -85,7 +85,7 @@ class MFCDMChild final : public PMFCDMChild {
void EnsureRemote();
void Shutdown();
- nsISerialEventTarget* ManagerThread() { return mManagerThread; }
+ nsISerialEventTarget* ManagerThread() const { return mManagerThread; }
void AssertOnManagerThread() const {
MOZ_ASSERT(mManagerThread->IsOnCurrentThread());
}
@@ -97,7 +97,7 @@ class MFCDMChild final : public PMFCDMChild {
const nsString mKeySystem;
- const RefPtr<nsISerialEventTarget> mManagerThread;
+ const nsCOMPtr<nsISerialEventTarget> mManagerThread;
RefPtr<MFCDMChild> mIPDLSelfRef;
using RemotePromise = GenericNonExclusivePromise;
diff --git a/dom/media/ipc/MFMediaEngineChild.h b/dom/media/ipc/MFMediaEngineChild.h
@@ -46,7 +46,7 @@ class MFMediaEngineChild final : public PMFMediaEngineChild {
mozilla::ipc::IPCResult RecvUpdateStatisticData(const StatisticData& aData);
mozilla::ipc::IPCResult RecvNotifyResizing(uint32_t aWidth, uint32_t aHeight);
- nsISerialEventTarget* ManagerThread() { return mManagerThread; }
+ nsISerialEventTarget* ManagerThread() const { return mManagerThread; }
void AssertOnManagerThread() const {
MOZ_ASSERT(mManagerThread->IsOnCurrentThread());
}
diff --git a/dom/media/ipc/RemoteDecoderChild.cpp b/dom/media/ipc/RemoteDecoderChild.cpp
@@ -14,10 +14,11 @@ RemoteDecoderChild::RemoteDecoderChild(RemoteMediaIn aLocation)
: ShmemRecycleAllocator(this),
mLocation(aLocation),
mThread(GetCurrentSerialEventTarget()) {
- MOZ_DIAGNOSTIC_ASSERT(
- RemoteMediaManagerChild::GetManagerThread() &&
- RemoteMediaManagerChild::GetManagerThread()->IsOnCurrentThread(),
- "Must be created on the manager thread");
+#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
+ auto managerThread = RemoteMediaManagerChild::GetManagerThread();
+ MOZ_DIAGNOSTIC_ASSERT(managerThread);
+ MOZ_DIAGNOSTIC_ASSERT(managerThread->IsOnCurrentThread());
+#endif
}
RemoteDecoderChild::~RemoteDecoderChild() = default;
diff --git a/dom/media/ipc/RemoteMediaDataDecoder.cpp b/dom/media/ipc/RemoteMediaDataDecoder.cpp
@@ -48,11 +48,15 @@ RemoteMediaDataDecoder::~RemoteMediaDataDecoder() {
}
RefPtr<MediaDataDecoder::InitPromise> RemoteMediaDataDecoder::Init() {
+ auto managerThread = RemoteMediaManagerChild::GetManagerThread();
+ if (!managerThread) {
+ return InitPromise::CreateAndReject(NS_ERROR_DOM_MEDIA_CANCELED, __func__);
+ }
RefPtr<RemoteMediaDataDecoder> self = this;
- return InvokeAsync(RemoteMediaManagerChild::GetManagerThread(), __func__,
+ return InvokeAsync(managerThread, __func__,
[self]() { return self->mChild->Init(); })
->Then(
- RemoteMediaManagerChild::GetManagerThread(), __func__,
+ managerThread, __func__,
[self, this](TrackType aTrack) {
MutexAutoLock lock(mMutex);
// If shutdown has started in the meantime shutdown promise may
@@ -83,55 +87,81 @@ RefPtr<MediaDataDecoder::InitPromise> RemoteMediaDataDecoder::Init() {
RefPtr<MediaDataDecoder::DecodePromise> RemoteMediaDataDecoder::Decode(
MediaRawData* aSample) {
+ auto managerThread = RemoteMediaManagerChild::GetManagerThread();
+ if (!managerThread) {
+ return DecodePromise::CreateAndReject(NS_ERROR_DOM_MEDIA_CANCELED,
+ __func__);
+ }
RefPtr<RemoteMediaDataDecoder> self = this;
RefPtr<MediaRawData> sample = aSample;
- return InvokeAsync(
- RemoteMediaManagerChild::GetManagerThread(), __func__, [self, sample]() {
- return self->mChild->Decode(nsTArray<RefPtr<MediaRawData>>{sample});
- });
+ return InvokeAsync(managerThread, __func__, [self, sample]() {
+ return self->mChild->Decode(nsTArray<RefPtr<MediaRawData>>{sample});
+ });
}
RefPtr<MediaDataDecoder::DecodePromise> RemoteMediaDataDecoder::DecodeBatch(
nsTArray<RefPtr<MediaRawData>>&& aSamples) {
+ auto managerThread = RemoteMediaManagerChild::GetManagerThread();
+ if (!managerThread) {
+ return DecodePromise::CreateAndReject(NS_ERROR_DOM_MEDIA_CANCELED,
+ __func__);
+ }
RefPtr<RemoteMediaDataDecoder> self = this;
- return InvokeAsync(RemoteMediaManagerChild::GetManagerThread(), __func__,
+ return InvokeAsync(managerThread, __func__,
[self, samples = std::move(aSamples)]() {
return self->mChild->Decode(samples);
});
}
RefPtr<MediaDataDecoder::FlushPromise> RemoteMediaDataDecoder::Flush() {
+ auto managerThread = RemoteMediaManagerChild::GetManagerThread();
+ if (!managerThread) {
+ return FlushPromise::CreateAndReject(NS_ERROR_DOM_MEDIA_CANCELED, __func__);
+ }
RefPtr<RemoteMediaDataDecoder> self = this;
- return InvokeAsync(RemoteMediaManagerChild::GetManagerThread(), __func__,
+ return InvokeAsync(managerThread, __func__,
[self]() { return self->mChild->Flush(); });
}
RefPtr<MediaDataDecoder::DecodePromise> RemoteMediaDataDecoder::Drain() {
+ auto managerThread = RemoteMediaManagerChild::GetManagerThread();
+ if (!managerThread) {
+ return DecodePromise::CreateAndReject(NS_ERROR_DOM_MEDIA_CANCELED,
+ __func__);
+ }
RefPtr<RemoteMediaDataDecoder> self = this;
- return InvokeAsync(RemoteMediaManagerChild::GetManagerThread(), __func__,
+ return InvokeAsync(managerThread, __func__,
[self]() { return self->mChild->Drain(); });
}
RefPtr<ShutdownPromise> RemoteMediaDataDecoder::Shutdown() {
+ auto managerThread = RemoteMediaManagerChild::GetManagerThread();
+ if (!managerThread) {
+ return ShutdownPromise::CreateAndResolve(true, __func__);
+ }
RefPtr<RemoteMediaDataDecoder> self = this;
- return InvokeAsync(
- RemoteMediaManagerChild::GetManagerThread(), __func__, [self]() {
- RefPtr<ShutdownPromise> p = self->mChild->Shutdown();
-
- // We're about to be destroyed and drop our ref to
- // *DecoderChild. Make sure we put a ref into the
- // task queue for the *DecoderChild thread to keep
- // it alive until we send the delete message.
- p->Then(RemoteMediaManagerChild::GetManagerThread(), __func__,
- [child = std::move(self->mChild)](
- const ShutdownPromise::ResolveOrRejectValue& aValue) {
- MOZ_ASSERT(aValue.IsResolve());
- child->DestroyIPDL();
- return ShutdownPromise::CreateAndResolveOrReject(aValue,
- __func__);
- });
- return p;
- });
+ return InvokeAsync(managerThread, __func__, [self]() {
+ auto managerThread = RemoteMediaManagerChild::GetManagerThread();
+ if (!managerThread) {
+ return ShutdownPromise::CreateAndResolve(true, __func__);
+ }
+
+ RefPtr<ShutdownPromise> p = self->mChild->Shutdown();
+
+ // We're about to be destroyed and drop our ref to
+ // *DecoderChild. Make sure we put a ref into the
+ // task queue for the *DecoderChild thread to keep
+ // it alive until we send the delete message.
+ p->Then(managerThread, __func__,
+ [child = std::move(self->mChild)](
+ const ShutdownPromise::ResolveOrRejectValue& aValue) {
+ MOZ_ASSERT(aValue.IsResolve());
+ child->DestroyIPDL();
+ return ShutdownPromise::CreateAndResolveOrReject(aValue,
+ __func__);
+ });
+ return p;
+ });
}
bool RemoteMediaDataDecoder::IsHardwareAccelerated(
@@ -142,9 +172,13 @@ bool RemoteMediaDataDecoder::IsHardwareAccelerated(
}
void RemoteMediaDataDecoder::SetSeekThreshold(const media::TimeUnit& aTime) {
+ auto managerThread = RemoteMediaManagerChild::GetManagerThread();
+ if (!managerThread) {
+ return;
+ }
RefPtr<RemoteMediaDataDecoder> self = this;
media::TimeUnit time = aTime;
- RemoteMediaManagerChild::GetManagerThread()->Dispatch(
+ managerThread->Dispatch(
NS_NewRunnableFunction("dom::RemoteMediaDataDecoder::SetSeekThreshold",
[=]() {
MOZ_ASSERT(self->mChild);
diff --git a/dom/media/ipc/RemoteMediaManagerChild.cpp b/dom/media/ipc/RemoteMediaManagerChild.cpp
@@ -231,9 +231,9 @@ RemoteMediaManagerChild* RemoteMediaManagerChild::GetSingleton(
}
/* static */
-nsISerialEventTarget* RemoteMediaManagerChild::GetManagerThread() {
+nsCOMPtr<nsISerialEventTarget> RemoteMediaManagerChild::GetManagerThread() {
auto remoteDecoderManagerThread = sRemoteMediaManagerChildThread.Lock();
- return *remoteDecoderManagerThread;
+ return nsCOMPtr<nsISerialEventTarget>(*remoteDecoderManagerThread);
}
/* static */
@@ -639,6 +639,13 @@ RemoteMediaManagerChild::InitializeEncoder(
__func__);
}
+ auto managerThread = aEncoder->GetManagerThread();
+ if (!managerThread) {
+ return PlatformEncoderModule::CreateEncoderPromise::CreateAndReject(
+ MediaResult(NS_ERROR_DOM_MEDIA_CANCELED, "Thread shutdown"_ns),
+ __func__);
+ }
+
MOZ_ASSERT(location != RemoteMediaIn::Unspecified);
RefPtr<GenericNonExclusivePromise> p;
@@ -658,7 +665,6 @@ RemoteMediaManagerChild::InitializeEncoder(
aConfig.IsAudio() ? "audio" : "video", static_cast<int>(aConfig.mCodec),
RemoteMediaInToStr(location));
- auto* managerThread = aEncoder->GetManagerThread();
return p->Then(
managerThread, __func__,
[encoder = std::move(aEncoder), aConfig](bool) {
diff --git a/dom/media/ipc/RemoteMediaManagerChild.h b/dom/media/ipc/RemoteMediaManagerChild.h
@@ -85,7 +85,7 @@ class RemoteMediaManagerChild final
const EncoderConfig& aConfig);
// Can be called from any thread.
- static nsISerialEventTarget* GetManagerThread();
+ static nsCOMPtr<nsISerialEventTarget> GetManagerThread();
// Return the track support information based on the location of the remote
// process. Thread-safe.