Modular DRM for MediaPlayer/Race at stop/releaseDrm

Bug: 34559906
Bug: 37960096
Test: GTS LLAMA_H264_XX_V0_SYNC (1000 rounds)
Change-Id: I8576fb9dadf8922c2a54f2ea9e199d2e07c1820e
diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.cpp b/media/libmediaplayerservice/nuplayer/GenericSource.cpp
index 22b09d4..00a1f9c 100644
--- a/media/libmediaplayerservice/nuplayer/GenericSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/GenericSource.cpp
@@ -98,6 +98,7 @@
     mBufferingMonitor->stop();
 
     mIsDrmProtected = false;
+    mIsDrmReleased = false;
     mIsSecure = false;
     mMimes.clear();
 }
@@ -690,6 +691,17 @@
           break;
       }
 
+      case kWhatReleaseDrm:
+      {
+          status_t status = onReleaseDrm();
+          sp<AMessage> response = new AMessage;
+          response->setInt32("status", status);
+          sp<AReplyToken> replyID;
+          CHECK(msg->senderAwaitsResponse(&replyID));
+          response->postReply(replyID);
+          break;
+      }
+
       default:
           Source::onMessageReceived(msg);
           break;
@@ -839,6 +851,13 @@
         return -EWOULDBLOCK;
     }
 
+    // If has gone through stop/releaseDrm sequence, we no longer send down any buffer b/c
+    // the codec's crypto object has gone away (b/37960096).
+    // Note: This will be unnecessary when stop() changes behavior and releases codec (b/35248283).
+    if (!mStarted && mIsDrmReleased) {
+        return -EWOULDBLOCK;
+    }
+
     Track *track = audio ? &mAudioTrack : &mVideoTrack;
 
     if (track->mSource == NULL) {
@@ -1897,11 +1916,31 @@
     return status;
 }
 
+status_t NuPlayer::GenericSource::releaseDrm()
+{
+    ALOGV("releaseDrm");
+
+    sp<AMessage> msg = new AMessage(kWhatReleaseDrm, this);
+
+    // synchronous call to update the source states before the player proceedes with crypto cleanup
+    sp<AMessage> response;
+    status_t status = msg->postAndAwaitResponse(&response);
+
+    if (status == OK && response != NULL) {
+        ALOGD("releaseDrm ret: OK ");
+    } else {
+        ALOGE("releaseDrm err: %d", status);
+    }
+
+    return status;
+}
+
 status_t NuPlayer::GenericSource::onPrepareDrm(const sp<AMessage> &msg)
 {
     ALOGV("onPrepareDrm ");
 
     mIsDrmProtected = false;
+    mIsDrmReleased = false;
     mIsSecure = false;
 
     uint8_t *uuid;
@@ -1949,8 +1988,26 @@
     return status;
 }
 
+status_t NuPlayer::GenericSource::onReleaseDrm()
+{
+    if (mIsDrmProtected) {
+        mIsDrmProtected = false;
+        // to prevent returning any more buffer after stop/releaseDrm (b/37960096)
+        mIsDrmReleased = true;
+        ALOGV("onReleaseDrm: mIsDrmProtected is reset.");
+    } else {
+        ALOGE("onReleaseDrm: mIsDrmProtected is already false.");
+    }
+
+    return OK;
+}
+
 status_t NuPlayer::GenericSource::checkDrmInfo()
 {
+    // clearing the flag at prepare in case the player is reused after stop/releaseDrm with the
+    // same source without being reset (called by prepareAsync/initFromDataSource)
+    mIsDrmReleased = false;
+
     if (mFileMeta == NULL) {
         ALOGI("checkDrmInfo: No metadata");
         return OK; // letting the caller responds accordingly
diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.h b/media/libmediaplayerservice/nuplayer/GenericSource.h
index 64f21a6..b0c6695 100644
--- a/media/libmediaplayerservice/nuplayer/GenericSource.h
+++ b/media/libmediaplayerservice/nuplayer/GenericSource.h
@@ -91,6 +91,8 @@
     virtual status_t prepareDrm(
             const uint8_t uuid[16], const Vector<uint8_t> &drmSessionId, sp<ICrypto> *crypto);
 
+    virtual status_t releaseDrm();
+
 
 protected:
     virtual ~GenericSource();
@@ -119,6 +121,7 @@
         kWhatSecureDecodersInstantiated,
         // Modular DRM
         kWhatPrepareDrm,
+        kWhatReleaseDrm,
     };
 
     struct Track {
@@ -308,10 +311,12 @@
 
     // Modular DRM
     bool mIsDrmProtected;
+    bool mIsDrmReleased;
     Vector<String8> mMimes;
 
     status_t checkDrmInfo();
     status_t onPrepareDrm(const sp<AMessage> &msg);
+    status_t onReleaseDrm();
 
     DISALLOW_EVIL_CONSTRUCTORS(GenericSource);
 };
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
index 0d4c730..6ded392 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
@@ -2787,6 +2787,11 @@
 
     status_t status;
     if (mCrypto != NULL) {
+        // notifying the source first before removing crypto from codec
+        if (mSource != NULL) {
+            mSource->releaseDrm();
+        }
+
         status=OK;
         // first making sure the codecs have released their crypto reference
         const sp<DecoderBase> &videoDecoder = getDecoder(false/*audio*/);