Bug 1500049 - Wait for MediaCacheStreams to close properly before finishing MediaDecoder shutdown. r=bryce

Differential Revision: https://phabricator.services.mozilla.com/D52052

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Andreas Pehrson 2019-11-13 08:58:34 +00:00
Родитель b59f1080f0
Коммит 4c3bf72271
15 изменённых файлов: 67 добавлений и 32 удалений

Просмотреть файл

@ -221,13 +221,27 @@ void ChannelMediaDecoder::Shutdown() {
mResourceCallback->Disconnect(); mResourceCallback->Disconnect();
MediaDecoder::Shutdown(); MediaDecoder::Shutdown();
// Force any outstanding seek and byterange requests to complete
// to prevent shutdown from deadlocking.
if (mResource) { if (mResource) {
mResource->Close(); // Force any outstanding seek and byterange requests to complete
// to prevent shutdown from deadlocking.
mResourceClosePromise = mResource->Close();
} }
} }
void ChannelMediaDecoder::ShutdownInternal() {
if (!mResourceClosePromise) {
MediaShutdownManager::Instance().Unregister(this);
return;
}
mResourceClosePromise->Then(
AbstractMainThread(), __func__,
[self = RefPtr<ChannelMediaDecoder>(this)] {
MediaShutdownManager::Instance().Unregister(self);
});
return;
}
nsresult ChannelMediaDecoder::Load(nsIChannel* aChannel, nsresult ChannelMediaDecoder::Load(nsIChannel* aChannel,
bool aIsPrivateBrowsing, bool aIsPrivateBrowsing,
nsIStreamListener** aStreamListener) { nsIStreamListener** aStreamListener) {

Просмотреть файл

@ -59,6 +59,7 @@ class ChannelMediaDecoder
}; };
protected: protected:
void ShutdownInternal() override;
void OnPlaybackEvent(MediaPlaybackEvent&& aEvent) override; void OnPlaybackEvent(MediaPlaybackEvent&& aEvent) override;
void DurationChanged() override; void DurationChanged() override;
void MetadataLoaded(UniquePtr<MediaInfo> aInfo, UniquePtr<MetadataTags> aTags, void MetadataLoaded(UniquePtr<MediaInfo> aInfo, UniquePtr<MetadataTags> aTags,
@ -156,6 +157,10 @@ class ChannelMediaDecoder
// True if we've been notified that the ChannelMediaResource has // True if we've been notified that the ChannelMediaResource has
// a principal. // a principal.
bool mInitialChannelPrincipalKnown = false; bool mInitialChannelPrincipalKnown = false;
// Set in Shutdown() when we start closing mResource, if mResource is set.
// Must resolve before we unregister the shutdown blocker.
RefPtr<GenericPromise> mResourceClosePromise;
}; };
} // namespace mozilla } // namespace mozilla

Просмотреть файл

@ -589,15 +589,15 @@ nsresult ChannelMediaResource::SetupChannelHeaders(int64_t aOffset) {
return NS_OK; return NS_OK;
} }
nsresult ChannelMediaResource::Close() { RefPtr<GenericPromise> ChannelMediaResource::Close() {
NS_ASSERTION(NS_IsMainThread(), "Only call on main thread"); NS_ASSERTION(NS_IsMainThread(), "Only call on main thread");
if (!mClosed) { if (!mClosed) {
CloseChannel(); CloseChannel();
mCacheStream.Close();
mClosed = true; mClosed = true;
return mCacheStream.Close();
} }
return NS_OK; return GenericPromise::CreateAndResolve(true, __func__);
} }
already_AddRefed<nsIPrincipal> ChannelMediaResource::GetCurrentPrincipal() { already_AddRefed<nsIPrincipal> ChannelMediaResource::GetCurrentPrincipal() {

Просмотреть файл

@ -117,7 +117,7 @@ class ChannelMediaResource
// Main thread // Main thread
nsresult Open(nsIStreamListener** aStreamListener) override; nsresult Open(nsIStreamListener** aStreamListener) override;
nsresult Close() override; RefPtr<GenericPromise> Close() override;
void Suspend(bool aCloseImmediately) override; void Suspend(bool aCloseImmediately) override;
void Resume() override; void Resume() override;
already_AddRefed<nsIPrincipal> GetCurrentPrincipal() override; already_AddRefed<nsIPrincipal> GetCurrentPrincipal() override;

Просмотреть файл

@ -148,7 +148,9 @@ nsresult CloneableWithRangeMediaResource::Open(
return NS_OK; return NS_OK;
} }
nsresult CloneableWithRangeMediaResource::Close() { return NS_OK; } RefPtr<GenericPromise> CloneableWithRangeMediaResource::Close() {
return GenericPromise::CreateAndResolve(true, __func__);
}
already_AddRefed<nsIPrincipal> already_AddRefed<nsIPrincipal>
CloneableWithRangeMediaResource::GetCurrentPrincipal() { CloneableWithRangeMediaResource::GetCurrentPrincipal() {

Просмотреть файл

@ -27,7 +27,7 @@ class CloneableWithRangeMediaResource : public BaseMediaResource {
// Main thread // Main thread
nsresult Open(nsIStreamListener** aStreamListener) override; nsresult Open(nsIStreamListener** aStreamListener) override;
nsresult Close() override; RefPtr<GenericPromise> Close() override;
void Suspend(bool aCloseImmediately) override {} void Suspend(bool aCloseImmediately) override {}
void Resume() override {} void Resume() override {}
already_AddRefed<nsIPrincipal> GetCurrentPrincipal() override; already_AddRefed<nsIPrincipal> GetCurrentPrincipal() override;

Просмотреть файл

@ -95,7 +95,7 @@ nsresult FileMediaResource::Open(nsIStreamListener** aStreamListener) {
return NS_OK; return NS_OK;
} }
nsresult FileMediaResource::Close() { RefPtr<GenericPromise> FileMediaResource::Close() {
NS_ASSERTION(NS_IsMainThread(), "Only call on main thread"); NS_ASSERTION(NS_IsMainThread(), "Only call on main thread");
// Since mChennel is only accessed by main thread, there is no necessary to // Since mChennel is only accessed by main thread, there is no necessary to
@ -105,7 +105,7 @@ nsresult FileMediaResource::Close() {
mChannel = nullptr; mChannel = nullptr;
} }
return NS_OK; return GenericPromise::CreateAndResolve(true, __func__);
} }
already_AddRefed<nsIPrincipal> FileMediaResource::GetCurrentPrincipal() { already_AddRefed<nsIPrincipal> FileMediaResource::GetCurrentPrincipal() {

Просмотреть файл

@ -23,7 +23,7 @@ class FileMediaResource : public BaseMediaResource {
// Main thread // Main thread
nsresult Open(nsIStreamListener** aStreamListener) override; nsresult Open(nsIStreamListener** aStreamListener) override;
nsresult Close() override; RefPtr<GenericPromise> Close() override;
void Suspend(bool aCloseImmediately) override {} void Suspend(bool aCloseImmediately) override {}
void Resume() override {} void Resume() override {}
already_AddRefed<nsIPrincipal> GetCurrentPrincipal() override; already_AddRefed<nsIPrincipal> GetCurrentPrincipal() override;

Просмотреть файл

@ -161,7 +161,7 @@ class MediaCache {
// file backing will be provided. // file backing will be provided.
static RefPtr<MediaCache> GetMediaCache(int64_t aContentLength); static RefPtr<MediaCache> GetMediaCache(int64_t aContentLength);
nsIEventTarget* OwnerThread() const { return sThread; } nsISerialEventTarget* OwnerThread() const { return sThread; }
// Brutally flush the cache contents. Main thread only. // Brutally flush the cache contents. Main thread only.
void Flush(); void Flush();
@ -2196,17 +2196,18 @@ bool MediaCacheStream::AreAllStreamsForResourceSuspended(AutoLock& aLock) {
return true; return true;
} }
void MediaCacheStream::Close() { RefPtr<GenericPromise> MediaCacheStream::Close() {
MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(NS_IsMainThread());
if (!mMediaCache) { if (!mMediaCache) {
return; return GenericPromise::CreateAndResolve(true, __func__);
} }
OwnerThread()->Dispatch(NS_NewRunnableFunction(
"MediaCacheStream::Close", return InvokeAsync(OwnerThread(), "MediaCacheStream::Close",
[this, client = RefPtr<ChannelMediaResource>(mClient)]() { [this, client = RefPtr<ChannelMediaResource>(mClient)] {
AutoLock lock(mMediaCache->Monitor()); AutoLock lock(mMediaCache->Monitor());
CloseInternal(lock); CloseInternal(lock);
})); return GenericPromise::CreateAndResolve(true, __func__);
});
} }
void MediaCacheStream::CloseInternal(AutoLock& aLock) { void MediaCacheStream::CloseInternal(AutoLock& aLock) {
@ -2734,7 +2735,7 @@ void MediaCacheStream::InitAsCloneInternal(MediaCacheStream* aOriginal) {
lock.NotifyAll(); lock.NotifyAll();
} }
nsIEventTarget* MediaCacheStream::OwnerThread() const { nsISerialEventTarget* MediaCacheStream::OwnerThread() const {
return mMediaCache->OwnerThread(); return mMediaCache->OwnerThread();
} }

Просмотреть файл

@ -217,12 +217,12 @@ class MediaCacheStream : public DecoderDoctorLifeLogger<MediaCacheStream> {
// on this class. // on this class.
void InitAsClone(MediaCacheStream* aOriginal); void InitAsClone(MediaCacheStream* aOriginal);
nsIEventTarget* OwnerThread() const; nsISerialEventTarget* OwnerThread() const;
// These are called on the main thread. // These are called on the main thread.
// This must be called (and return) before the ChannelMediaResource // This must be called (and resolve) before the ChannelMediaResource
// used to create this MediaCacheStream is deleted. // used to create this MediaCacheStream is deleted.
void Close(); RefPtr<GenericPromise> Close();
// This returns true when the stream has been closed. // This returns true when the stream has been closed.
bool IsClosed(AutoLock&) const { return mClosed; } bool IsClosed(AutoLock&) const { return mClosed; }
// Returns true when this stream is can be shared by a new resource load. // Returns true when this stream is can be shared by a new resource load.

Просмотреть файл

@ -390,7 +390,7 @@ void MediaDecoder::Shutdown() {
nsCOMPtr<nsIRunnable> r = nsCOMPtr<nsIRunnable> r =
NS_NewRunnableFunction("MediaDecoder::Shutdown", [self]() { NS_NewRunnableFunction("MediaDecoder::Shutdown", [self]() {
self->mVideoFrameContainer = nullptr; self->mVideoFrameContainer = nullptr;
MediaShutdownManager::Instance().Unregister(self); self->ShutdownInternal();
}); });
mAbstractMainThread->Dispatch(r.forget()); mAbstractMainThread->Dispatch(r.forget());
} }
@ -531,11 +531,16 @@ void MediaDecoder::OnStoreDecoderBenchmark(const VideoInfo& aInfo) {
} }
} }
void MediaDecoder::ShutdownInternal() {
MOZ_ASSERT(NS_IsMainThread());
MediaShutdownManager::Instance().Unregister(this);
}
void MediaDecoder::FinishShutdown() { void MediaDecoder::FinishShutdown() {
MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(NS_IsMainThread());
SetStateMachine(nullptr); SetStateMachine(nullptr);
mVideoFrameContainer = nullptr; mVideoFrameContainer = nullptr;
MediaShutdownManager::Instance().Unregister(this); ShutdownInternal();
} }
nsresult MediaDecoder::InitializeStateMachine() { nsresult MediaDecoder::InitializeStateMachine() {

Просмотреть файл

@ -403,6 +403,11 @@ class MediaDecoder : public DecoderDoctorLifeLogger<MediaDecoder> {
void SetStateMachineParameters(); void SetStateMachineParameters();
// Called when MediaDecoder shutdown is finished. Subclasses use this to clean
// up internal structures, and unregister potential shutdown blockers when
// they're done.
virtual void ShutdownInternal();
bool IsShutdown() const; bool IsShutdown() const;
// Called to notify the decoder that the duration has changed. // Called to notify the decoder that the duration has changed.

Просмотреть файл

@ -60,8 +60,11 @@ class MediaResource : public DecoderDoctorLifeLogger<MediaResource> {
// Close the resource, stop any listeners, channels, etc. // Close the resource, stop any listeners, channels, etc.
// Cancels any currently blocking Read request and forces that request to // Cancels any currently blocking Read request and forces that request to
// return an error. // return an error. This must be called (and resolve) before the MediaResource
virtual nsresult Close() { return NS_OK; } // is deleted.
virtual RefPtr<GenericPromise> Close() {
return GenericPromise::CreateAndResolve(true, __func__);
}
// These methods are called off the main thread. // These methods are called off the main thread.
// Read up to aCount bytes from the stream. The read starts at // Read up to aCount bytes from the stream. The read starts at

Просмотреть файл

@ -24,11 +24,11 @@ mozilla::LogModule* GetSourceBufferResourceLog() {
namespace mozilla { namespace mozilla {
nsresult SourceBufferResource::Close() { RefPtr<GenericPromise> SourceBufferResource::Close() {
MOZ_ASSERT(OnThread()); MOZ_ASSERT(OnThread());
SBR_DEBUG("Close"); SBR_DEBUG("Close");
mClosed = true; mClosed = true;
return NS_OK; return GenericPromise::CreateAndResolve(true, __func__);
} }
nsresult SourceBufferResource::ReadAt(int64_t aOffset, char* aBuffer, nsresult SourceBufferResource::ReadAt(int64_t aOffset, char* aBuffer,

Просмотреть файл

@ -36,7 +36,7 @@ class SourceBufferResource final
public DecoderDoctorLifeLogger<SourceBufferResource> { public DecoderDoctorLifeLogger<SourceBufferResource> {
public: public:
SourceBufferResource(); SourceBufferResource();
nsresult Close() override; RefPtr<GenericPromise> Close() override;
nsresult ReadAt(int64_t aOffset, char* aBuffer, uint32_t aCount, nsresult ReadAt(int64_t aOffset, char* aBuffer, uint32_t aCount,
uint32_t* aBytes) override; uint32_t* aBytes) override;
// Memory-based and no locks, caching discouraged. // Memory-based and no locks, caching discouraged.