Bug 1310537 - delay dormant handling until we exit WaitForCDMState. draft
authorJW Wang <jwwang@mozilla.com>
Fri, 14 Oct 2016 15:15:18 +0800
changeset 425811 bec9063b3e2d8e4400ddb7475662b87761d9af9f
parent 425716 a84f0c8a458fb5a11530bc90de6f1eec11dfec0e
child 425814 910a0667ac71bc2f8dc209686834ab7a30801360
push id32515
push userjwwang@mozilla.com
push dateMon, 17 Oct 2016 05:42:04 +0000
bugs1310537
milestone52.0a1
Bug 1310537 - delay dormant handling until we exit WaitForCDMState. The purpose of dormant state is to release decoders. we can delay handling dormant until we really need to decode. MozReview-Commit-ID: GW4y8d40DLi
dom/media/MediaDecoderStateMachine.cpp
--- a/dom/media/MediaDecoderStateMachine.cpp
+++ b/dom/media/MediaDecoderStateMachine.cpp
@@ -326,17 +326,17 @@ private:
 };
 
 class MediaDecoderStateMachine::WaitForCDMState
   : public MediaDecoderStateMachine::StateObject
 {
 public:
   explicit WaitForCDMState(Master* aPtr) : StateObject(aPtr) {}
 
-  void Enter() {}
+  void Enter(bool aPendingDormant) { mPendingDormant = aPendingDormant; }
 
   State GetState() const override
   {
     return DECODER_STATE_WAIT_FOR_CDM;
   }
 
   bool HandleDormant(bool aDormant) override;
 
@@ -344,16 +344,19 @@ public:
 
   RefPtr<MediaDecoder::SeekPromise> HandleSeek(SeekTarget aTarget) override
   {
     SLOG("Not Enough Data to seek at this stage, queuing seek");
     mMaster->mQueuedSeek.RejectIfExists(__func__);
     mMaster->mQueuedSeek.mTarget = aTarget;
     return mMaster->mQueuedSeek.mPromise.Ensure(__func__);
   }
+
+private:
+  bool mPendingDormant = false;
 };
 
 class MediaDecoderStateMachine::DormantState
   : public MediaDecoderStateMachine::StateObject
 {
 public:
   explicit DormantState(Master* aPtr) : StateObject(aPtr) {}
 
@@ -974,63 +977,59 @@ DecodeMetadataState::OnMetadataRead(Meta
 
   mMaster->mNotifyMetadataBeforeFirstFrame =
     mMaster->mDuration.Ref().isSome() || waitingForCDM;
 
   if (mMaster->mNotifyMetadataBeforeFirstFrame) {
     mMaster->EnqueueLoadedMetadataEvent();
   }
 
-  if (mPendingDormant) {
-    // No need to store mQueuedSeek because we are at position 0.
-    SetState<DormantState>();
-    return;
-  }
-
   if (waitingForCDM) {
     // Metadata parsing was successful but we're still waiting for CDM caps
     // to become available so that we can build the correct decryptor/decoder.
-    SetState<WaitForCDMState>();
-    return;
+
+    // FIXME: passing data members to SetState() will cause UAF because |this|
+    // is deleted before the call to newState::Enter().
+    bool pendingDormant = mPendingDormant;
+    SetState<WaitForCDMState>(pendingDormant);
+  } else if (mPendingDormant) {
+    SetState<DormantState>();
+  } else {
+    SetState<DecodingFirstFrameState>();
   }
-
-  SetState<DecodingFirstFrameState>();
 }
 
 bool
 MediaDecoderStateMachine::
 WaitForCDMState::HandleDormant(bool aDormant)
 {
-  if (aDormant) {
-    // No need to store mQueuedSeek because we are at position 0.
-    SetState<DormantState>();
-  }
+  mPendingDormant = aDormant;
   return true;
 }
 
 bool
 MediaDecoderStateMachine::
 DormantState::HandleDormant(bool aDormant)
 {
   if (!aDormant) {
-    // Exit dormant state. Check if we need the CDMProxy to start decoding.
-    if (Info().IsEncrypted() && !mMaster->mCDMProxy) {
-      SetState<WaitForCDMState>();
-    } else {
-      SetState<DecodingFirstFrameState>();
-    }
+    MOZ_ASSERT(!Info().IsEncrypted() || mMaster->mCDMProxy);
+    SetState<DecodingFirstFrameState>();
   }
   return true;
 }
 
 bool
 MediaDecoderStateMachine::
 WaitForCDMState::HandleCDMProxyReady()
 {
-  SetState<DecodingFirstFrameState>();
+  if (mPendingDormant) {
+    SetState<DormantState>();
+  } else {
+    SetState<DecodingFirstFrameState>();
+  }
   return true;
 }
 
 void
 MediaDecoderStateMachine::
 DecodingFirstFrameState::Enter()
 {
   // Handle pending seek.