Bug 1319790 - add assertions to detect if MediaDecoder is deleted without Shutdown() being called. r?kaku draft
authorJW Wang <jwwang@mozilla.com>
Thu, 24 Nov 2016 11:59:18 +0800
changeset 443285 81ac9540741531200540c8651e76c4ec66cc7efb
parent 443284 29c0c0121522637ce169eb1adb6ba9b2c9b87dea
child 538014 47bea4116362d997ad7c5200dbfe6bd5fefecce8
push id36949
push userjwwang@mozilla.com
push dateThu, 24 Nov 2016 06:23:45 +0000
reviewerskaku
bugs1319790
milestone53.0a1
Bug 1319790 - add assertions to detect if MediaDecoder is deleted without Shutdown() being called. r?kaku Also call mResourceCallback->Disconnect() in the destructor in case Shutdown() is not called to avoid dangling pointer. MozReview-Commit-ID: 1qV4m8nWlGq
dom/media/MediaDecoder.cpp
--- a/dom/media/MediaDecoder.cpp
+++ b/dom/media/MediaDecoder.cpp
@@ -147,19 +147,21 @@ MediaDecoder::ResourceCallback::Connect(
   mDecoder = aDecoder;
   mTimer = do_CreateInstance("@mozilla.org/timer;1");
 }
 
 void
 MediaDecoder::ResourceCallback::Disconnect()
 {
   MOZ_ASSERT(NS_IsMainThread());
-  mDecoder = nullptr;
-  mTimer->Cancel();
-  mTimer = nullptr;
+  if (mDecoder) {
+    mDecoder = nullptr;
+    mTimer->Cancel();
+    mTimer = nullptr;
+  }
 }
 
 MediaDecoderOwner*
 MediaDecoder::ResourceCallback::GetMediaOwner() const
 {
   MOZ_ASSERT(NS_IsMainThread());
   return mDecoder ? mDecoder->mOwner : nullptr;
 }
@@ -282,17 +284,17 @@ MediaDecoder::ResourceCallback::NotifyBy
   });
   AbstractThread::MainThread()->Dispatch(r.forget());
 }
 
 void
 MediaDecoder::NotifyOwnerActivityChanged(bool aIsVisible)
 {
   MOZ_ASSERT(NS_IsMainThread());
-  MOZ_ASSERT(!IsShutdown());
+  MOZ_DIAGNOSTIC_ASSERT(!IsShutdown());
   SetElementVisibility(aIsVisible);
 
   MediaDecoderOwner* owner = GetOwner();
   NS_ENSURE_TRUE_VOID(owner);
 
   dom::HTMLMediaElement* element = owner->GetMediaElement();
   NS_ENSURE_TRUE_VOID(element);
 
@@ -303,17 +305,17 @@ MediaDecoder::NotifyOwnerActivityChanged
   RefPtr<KnowsCompositor> knowsCompositor = layerManager->AsShadowForwarder();
   mCompositorUpdatedEvent.Notify(knowsCompositor);
 }
 
 void
 MediaDecoder::Pause()
 {
   MOZ_ASSERT(NS_IsMainThread());
-  MOZ_ASSERT(!IsShutdown());
+  MOZ_DIAGNOSTIC_ASSERT(!IsShutdown());
   if (mPlayState == PLAY_STATE_LOADING || IsEnded()) {
     mNextState = PLAY_STATE_PAUSED;
     return;
   }
   ChangeState(PLAY_STATE_PAUSED);
 }
 
 void
@@ -353,17 +355,17 @@ MediaDecoder::CanonicalDurationOrNull()
   MOZ_ASSERT(mDecoderStateMachine);
   return mDecoderStateMachine->CanonicalDuration();
 }
 
 void
 MediaDecoder::SetInfinite(bool aInfinite)
 {
   MOZ_ASSERT(NS_IsMainThread());
-  MOZ_ASSERT(!IsShutdown());
+  MOZ_DIAGNOSTIC_ASSERT(!IsShutdown());
   mInfiniteStream = aInfinite;
   DurationChanged();
 }
 
 bool
 MediaDecoder::IsInfinite() const
 {
   MOZ_ASSERT(NS_IsMainThread());
@@ -454,17 +456,17 @@ MediaDecoder::MediaDecoder(MediaDecoderO
 
 #undef INIT_MIRROR
 #undef INIT_CANONICAL
 
 void
 MediaDecoder::Shutdown()
 {
   MOZ_ASSERT(NS_IsMainThread());
-  MOZ_ASSERT(!IsShutdown());
+  MOZ_DIAGNOSTIC_ASSERT(!IsShutdown());
 
   // Unwatch all watch targets to prevent further notifications.
   mWatchManager.Shutdown();
 
   mResourceCallback->Disconnect();
 
   mCDMProxyPromiseHolder.RejectIfExists(true, __func__);
 
@@ -505,16 +507,18 @@ MediaDecoder::Shutdown()
 
   ChangeState(PLAY_STATE_SHUTDOWN);
   mOwner = nullptr;
 }
 
 MediaDecoder::~MediaDecoder()
 {
   MOZ_ASSERT(NS_IsMainThread());
+  MOZ_DIAGNOSTIC_ASSERT(IsShutdown());
+  mResourceCallback->Disconnect();
   MediaMemoryTracker::RemoveMediaDecoder(this);
   UnpinForSeek();
   MOZ_COUNT_DTOR(MediaDecoder);
 }
 
 void
 MediaDecoder::OnPlaybackEvent(MediaEventType aEvent)
 {
@@ -550,17 +554,17 @@ MediaDecoder::OnPlaybackErrorEvent(const
   DecodeError(aError);
 }
 
 void
 MediaDecoder::OnDecoderDoctorEvent(DecoderDoctorEvent aEvent)
 {
   MOZ_ASSERT(NS_IsMainThread());
   // OnDecoderDoctorEvent is disconnected at shutdown time.
-  MOZ_ASSERT(!IsShutdown());
+  MOZ_DIAGNOSTIC_ASSERT(!IsShutdown());
   HTMLMediaElement* element = mOwner->GetMediaElement();
   if (!element) {
     return;
   }
   nsIDocument* doc = element->OwnerDoc();
   if (!doc) {
     return;
   }
@@ -684,17 +688,17 @@ MediaDecoder::Play()
   ChangeState(PLAY_STATE_PLAYING);
   return NS_OK;
 }
 
 nsresult
 MediaDecoder::Seek(double aTime, SeekTarget::Type aSeekType, dom::Promise* aPromise /*=nullptr*/)
 {
   MOZ_ASSERT(NS_IsMainThread());
-  MOZ_ASSERT(!IsShutdown());
+  MOZ_DIAGNOSTIC_ASSERT(!IsShutdown());
 
   MOZ_ASSERT(aTime >= 0.0, "Cannot seek to a negative value.");
 
   int64_t timeUsecs = TimeUnit::FromSeconds(aTime).ToMicroseconds();
 
   mLogicalPosition = aTime;
 
   mLogicallySeeking = true;
@@ -784,17 +788,17 @@ MediaDecoder::OnMetadataUpdate(TimedMeta
 }
 
 void
 MediaDecoder::MetadataLoaded(nsAutoPtr<MediaInfo> aInfo,
                              nsAutoPtr<MetadataTags> aTags,
                              MediaDecoderEventVisibility aEventVisibility)
 {
   MOZ_ASSERT(NS_IsMainThread());
-  MOZ_ASSERT(!IsShutdown());
+  MOZ_DIAGNOSTIC_ASSERT(!IsShutdown());
 
   DECODER_LOG("MetadataLoaded, channels=%u rate=%u hasAudio=%d hasVideo=%d",
               aInfo->mAudio.mChannels, aInfo->mAudio.mRate,
               aInfo->HasAudio(), aInfo->HasVideo());
 
   mMediaSeekable = aInfo->mMediaSeekable;
   mMediaSeekableOnlyInBufferedRanges = aInfo->mMediaSeekableOnlyInBufferedRanges;
   mInfo = aInfo.forget();
@@ -857,17 +861,17 @@ MediaDecoder::PlayStateStr()
   return ToPlayStateStr(mPlayState);
 }
 
 void
 MediaDecoder::FirstFrameLoaded(nsAutoPtr<MediaInfo> aInfo,
                                MediaDecoderEventVisibility aEventVisibility)
 {
   MOZ_ASSERT(NS_IsMainThread());
-  MOZ_ASSERT(!IsShutdown());
+  MOZ_DIAGNOSTIC_ASSERT(!IsShutdown());
 
   DECODER_LOG("FirstFrameLoaded, channels=%u rate=%u hasAudio=%d hasVideo=%d mPlayState=%s",
               aInfo->mAudio.mChannels, aInfo->mAudio.mRate,
               aInfo->HasAudio(), aInfo->HasVideo(), PlayStateStr());
 
   mInfo = aInfo.forget();
 
   Invalidate();
@@ -893,25 +897,25 @@ MediaDecoder::FirstFrameLoaded(nsAutoPtr
     mOwner->FirstFrameLoaded();
   }
 }
 
 void
 MediaDecoder::NetworkError()
 {
   MOZ_ASSERT(NS_IsMainThread());
-  MOZ_ASSERT(!IsShutdown());
+  MOZ_DIAGNOSTIC_ASSERT(!IsShutdown());
   mOwner->NetworkError();
 }
 
 void
 MediaDecoder::DecodeError(const MediaResult& aError)
 {
   MOZ_ASSERT(NS_IsMainThread());
-  MOZ_ASSERT(!IsShutdown());
+  MOZ_DIAGNOSTIC_ASSERT(!IsShutdown());
   mOwner->DecodeError(aError);
 }
 
 void
 MediaDecoder::UpdateSameOriginStatus(bool aSameOrigin)
 {
   MOZ_ASSERT(NS_IsMainThread());
   mSameOriginMedia = aSameOrigin;
@@ -923,17 +927,17 @@ MediaDecoder::IsSeeking() const
   MOZ_ASSERT(NS_IsMainThread());
   return mLogicallySeeking;
 }
 
 bool
 MediaDecoder::OwnerHasError() const
 {
   MOZ_ASSERT(NS_IsMainThread());
-  MOZ_ASSERT(!IsShutdown());
+  MOZ_DIAGNOSTIC_ASSERT(!IsShutdown());
   return mOwner->HasError();
 }
 
 class MediaElementGMPCrashHelper : public GMPCrashHelper
 {
 public:
   explicit MediaElementGMPCrashHelper(HTMLMediaElement* aElement)
     : mElement(aElement)
@@ -973,17 +977,17 @@ MediaDecoder::IsShutdown() const
   MOZ_ASSERT(NS_IsMainThread());
   return mPlayState == PLAY_STATE_SHUTDOWN;
 }
 
 void
 MediaDecoder::PlaybackEnded()
 {
   MOZ_ASSERT(NS_IsMainThread());
-  MOZ_ASSERT(!IsShutdown());
+  MOZ_DIAGNOSTIC_ASSERT(!IsShutdown());
 
   if (mLogicallySeeking || mPlayState == PLAY_STATE_LOADING) {
     return;
   }
 
   ChangeState(PLAY_STATE_ENDED);
   InvalidateWithFlags(VideoFrameContainer::INVALIDATE_FORCE);
   mOwner->PlaybackEnded();
@@ -1050,37 +1054,37 @@ MediaDecoder::UpdatePlaybackRate()
 
   mResource->SetPlaybackRate(rate);
 }
 
 void
 MediaDecoder::NotifySuspendedStatusChanged()
 {
   MOZ_ASSERT(NS_IsMainThread());
-  MOZ_ASSERT(!IsShutdown());
+  MOZ_DIAGNOSTIC_ASSERT(!IsShutdown());
   if (mResource) {
     bool suspended = mResource->IsSuspendedByCache();
     mOwner->NotifySuspendedByCache(suspended);
   }
 }
 
 void
 MediaDecoder::NotifyBytesDownloaded()
 {
   MOZ_ASSERT(NS_IsMainThread());
-  MOZ_ASSERT(!IsShutdown());
+  MOZ_DIAGNOSTIC_ASSERT(!IsShutdown());
   UpdatePlaybackRate();
   mOwner->DownloadProgressed();
 }
 
 void
 MediaDecoder::NotifyDownloadEnded(nsresult aStatus)
 {
   MOZ_ASSERT(NS_IsMainThread());
-  MOZ_ASSERT(!IsShutdown());
+  MOZ_DIAGNOSTIC_ASSERT(!IsShutdown());
 
   DECODER_LOG("NotifyDownloadEnded, status=%x", aStatus);
 
   if (aStatus == NS_BINDING_ABORTED) {
     // Download has been cancelled by user.
     mOwner->LoadAborted();
     return;
   }
@@ -1096,44 +1100,44 @@ MediaDecoder::NotifyDownloadEnded(nsresu
     NetworkError();
   }
 }
 
 void
 MediaDecoder::NotifyPrincipalChanged()
 {
   MOZ_ASSERT(NS_IsMainThread());
-  MOZ_ASSERT(!IsShutdown());
+  MOZ_DIAGNOSTIC_ASSERT(!IsShutdown());
   nsCOMPtr<nsIPrincipal> newPrincipal = GetCurrentPrincipal();
   mMediaPrincipalHandle = MakePrincipalHandle(newPrincipal);
   mOwner->NotifyDecoderPrincipalChanged();
 }
 
 void
 MediaDecoder::NotifyBytesConsumed(int64_t aBytes, int64_t aOffset)
 {
   MOZ_ASSERT(NS_IsMainThread());
-  MOZ_ASSERT(!IsShutdown());
+  MOZ_DIAGNOSTIC_ASSERT(!IsShutdown());
 
   if (mIgnoreProgressData) {
     return;
   }
 
   MOZ_ASSERT(mDecoderStateMachine);
   if (aOffset >= mDecoderPosition) {
     mPlaybackStatistics->AddBytes(aBytes);
   }
   mDecoderPosition = aOffset + aBytes;
 }
 
 void
 MediaDecoder::OnSeekResolved()
 {
   MOZ_ASSERT(NS_IsMainThread());
-  MOZ_ASSERT(!IsShutdown());
+  MOZ_DIAGNOSTIC_ASSERT(!IsShutdown());
   mSeekRequest.Complete();
 
   {
     // An additional seek was requested while the current seek was
     // in operation.
     UnpinForSeek();
     mLogicallySeeking = false;
   }
@@ -1153,17 +1157,17 @@ MediaDecoder::OnSeekRejected()
   mLogicallySeeking = false;
   AsyncRejectSeekDOMPromiseIfExists();
 }
 
 void
 MediaDecoder::SeekingStarted()
 {
   MOZ_ASSERT(NS_IsMainThread());
-  MOZ_ASSERT(!IsShutdown());
+  MOZ_DIAGNOSTIC_ASSERT(!IsShutdown());
   mOwner->SeekStarted();
 }
 
 void
 MediaDecoder::ChangeState(PlayState aState)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(!IsShutdown(), "SHUTDOWN is the final state.");
@@ -1181,17 +1185,17 @@ MediaDecoder::ChangeState(PlayState aSta
     RemoveMediaTracks();
   }
 }
 
 void
 MediaDecoder::UpdateLogicalPositionInternal()
 {
   MOZ_ASSERT(NS_IsMainThread());
-  MOZ_ASSERT(!IsShutdown());
+  MOZ_DIAGNOSTIC_ASSERT(!IsShutdown());
 
   double currentPosition = static_cast<double>(CurrentPosition()) / static_cast<double>(USECS_PER_S);
   if (mPlayState == PLAY_STATE_ENDED) {
     currentPosition = std::max(currentPosition, mDuration);
   }
   bool logicalPositionChanged = mLogicalPosition != currentPosition;
   mLogicalPosition = currentPosition;
 
@@ -1205,17 +1209,17 @@ MediaDecoder::UpdateLogicalPositionInter
     FireTimeUpdate();
   }
 }
 
 void
 MediaDecoder::DurationChanged()
 {
   MOZ_ASSERT(NS_IsMainThread());
-  MOZ_ASSERT(!IsShutdown());
+  MOZ_DIAGNOSTIC_ASSERT(!IsShutdown());
 
   double oldDuration = mDuration;
   if (IsInfinite()) {
     mDuration = std::numeric_limits<double>::infinity();
   } else if (mExplicitDuration.Ref().isSome()) {
     mDuration = mExplicitDuration.Ref().ref();
   } else if (mStateMachineDuration.Ref().isSome()) {
     mDuration = mStateMachineDuration.Ref().ref().ToSeconds();
@@ -1482,32 +1486,32 @@ void MediaDecoder::AddSizeOfResources(Re
   if (GetResource()) {
     aSizes->mByteSize += GetResource()->SizeOfIncludingThis(aSizes->mMallocSizeOf);
   }
 }
 
 void
 MediaDecoder::NotifyDataArrived() {
   MOZ_ASSERT(NS_IsMainThread());
-  MOZ_ASSERT(!IsShutdown());
+  MOZ_DIAGNOSTIC_ASSERT(!IsShutdown());
   mDataArrivedEvent.Notify();
 }
 
 // Provide access to the state machine object
 MediaDecoderStateMachine*
 MediaDecoder::GetStateMachine() const {
   MOZ_ASSERT(NS_IsMainThread());
   return mDecoderStateMachine;
 }
 
 void
 MediaDecoder::FireTimeUpdate()
 {
   MOZ_ASSERT(NS_IsMainThread());
-  MOZ_ASSERT(!IsShutdown());
+  MOZ_DIAGNOSTIC_ASSERT(!IsShutdown());
   mOwner->FireTimeUpdate(true);
 }
 
 void
 MediaDecoder::PinForSeek()
 {
   MOZ_ASSERT(NS_IsMainThread());
   MediaResource* resource = GetResource();
@@ -1646,17 +1650,17 @@ MediaDecoder::GetOwner() const
   // mOwner is valid until shutdown.
   return mOwner;
 }
 
 void
 MediaDecoder::ConstructMediaTracks()
 {
   MOZ_ASSERT(NS_IsMainThread());
-  MOZ_ASSERT(!IsShutdown());
+  MOZ_DIAGNOSTIC_ASSERT(!IsShutdown());
 
   if (mMediaTracksConstructed || !mInfo) {
     return;
   }
 
   HTMLMediaElement* element = mOwner->GetMediaElement();
   if (!element) {
     return;
@@ -1683,17 +1687,17 @@ MediaDecoder::ConstructMediaTracks()
     track->SetEnabledInternal(info.mEnabled, MediaTrack::FIRE_NO_EVENTS);
   }
 }
 
 void
 MediaDecoder::RemoveMediaTracks()
 {
   MOZ_ASSERT(NS_IsMainThread());
-  MOZ_ASSERT(!IsShutdown());
+  MOZ_DIAGNOSTIC_ASSERT(!IsShutdown());
 
   HTMLMediaElement* element = mOwner->GetMediaElement();
   if (!element) {
     return;
   }
 
   AudioTrackList* audioList = element->AudioTracks();
   if (audioList) {
@@ -1721,17 +1725,17 @@ MediaDecoder::NextFrameBufferedStatus()
   return GetBuffered().Contains(interval)
     ? MediaDecoderOwner::NEXT_FRAME_AVAILABLE
     : MediaDecoderOwner::NEXT_FRAME_UNAVAILABLE;
 }
 
 void
 MediaDecoder::DumpDebugInfo()
 {
-  MOZ_ASSERT(!IsShutdown());
+  MOZ_DIAGNOSTIC_ASSERT(!IsShutdown());
   DUMP_LOG("metadata: channels=%u rate=%u hasAudio=%d hasVideo=%d, "
            "state: mPlayState=%s mdsm=%p",
            mInfo ? mInfo->mAudio.mChannels : 0, mInfo ? mInfo->mAudio.mRate : 0,
            mInfo ? mInfo->HasAudio() : 0, mInfo ? mInfo->HasVideo() : 0,
            PlayStateStr(), GetStateMachine());
 
   nsString str;
   GetMozDebugReaderData(str);
@@ -1742,17 +1746,17 @@ MediaDecoder::DumpDebugInfo()
   if (GetStateMachine()) {
     GetStateMachine()->DumpDebugInfo();
   }
 }
 
 void
 MediaDecoder::NotifyAudibleStateChanged()
 {
-  MOZ_ASSERT(!IsShutdown());
+  MOZ_DIAGNOSTIC_ASSERT(!IsShutdown());
   mOwner->SetAudibleState(mIsAudioDataAudible);
 }
 
 MediaMemoryTracker::MediaMemoryTracker()
 {
 }
 
 void