From 8606c335c302d90ccd5545537bc1f7e4d217ebf9 Mon Sep 17 00:00:00 2001 From: Hassan Shojania Date: Mon, 27 Feb 2017 13:34:48 -0800 Subject: [PATCH] Earlier processing of DrmInfo notification Bug: 35681236 Test: Manual through the test app Change-Id: I652e3c9742d7c55ab639c9df3ed1e6a0e035e6a4 --- media/java/android/media/MediaPlayer.java | 70 +++++++++++++++++------ 1 file changed, 52 insertions(+), 18 deletions(-) diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java index 5008a5f8c5c27..389b08aeead0a 100644 --- a/media/java/android/media/MediaPlayer.java +++ b/media/java/android/media/MediaPlayer.java @@ -1250,6 +1250,11 @@ public class MediaPlayer extends PlayerBase public void prepare() throws IOException, IllegalStateException { _prepare(); scanInternalSubtitleTracks(); + + // DrmInfo, if any, has been resolved by now. + synchronized (mDrmLock) { + mDrmInfoResolved = true; + } } private native void _prepare() throws IOException, IllegalStateException; @@ -3142,12 +3147,6 @@ public class MediaPlayer extends PlayerBase sendMessage(msg2); } - // MEDIA_DRM_INFO is fired (if available) before MEDIA_PREPARED. - // An empty mDrmInfo indicates prepared is done but the source is not DRM protected. - // Setting this before the callback so onPreparedListener can call getDrmInfo to - // get the right state - mDrmInfoResolved = true; - OnPreparedListener onPreparedListener = mOnPreparedListener; if (onPreparedListener != null) onPreparedListener.onPrepared(mMediaPlayer); @@ -3159,12 +3158,14 @@ public class MediaPlayer extends PlayerBase if (msg.obj == null) { Log.w(TAG, "MEDIA_DRM_INFO msg.obj=NULL"); } else if (msg.obj instanceof Parcel) { - Parcel parcel = (Parcel)msg.obj; - DrmInfo drmInfo = new DrmInfo(parcel); + // The parcel was parsed already in postEventFromNative + DrmInfo drmInfo = null; OnDrmInfoHandlerDelegate onDrmInfoHandlerDelegate; synchronized (mDrmLock) { - mDrmInfo = drmInfo.makeCopy(); + if (mOnDrmInfoHandlerDelegate != null && mDrmInfo != null) { + drmInfo = mDrmInfo.makeCopy(); + } // local copy while keeping the lock onDrmInfoHandlerDelegate = mOnDrmInfoHandlerDelegate; } @@ -3359,10 +3360,43 @@ public class MediaPlayer extends PlayerBase return; } - if (what == MEDIA_INFO && arg1 == MEDIA_INFO_STARTED_AS_NEXT) { - // this acquires the wakelock if needed, and sets the client side state - mp.start(); + switch (what) { + case MEDIA_INFO: + if (arg1 == MEDIA_INFO_STARTED_AS_NEXT) { + // this acquires the wakelock if needed, and sets the client side state + mp.start(); + } + break; + + case MEDIA_DRM_INFO: + // We need to derive mDrmInfo before prepare() returns so processing it here + // before the notification is sent to EventHandler below. EventHandler runs in the + // notification looper so its handleMessage might process the event after prepare() + // has returned. + Log.v(TAG, "postEventFromNative MEDIA_DRM_INFO"); + if (obj instanceof Parcel) { + Parcel parcel = (Parcel)obj; + DrmInfo drmInfo = new DrmInfo(parcel); + synchronized (mp.mDrmLock) { + mp.mDrmInfo = drmInfo; + } + } else { + Log.w(TAG, "MEDIA_DRM_INFO msg.obj of unexpected type " + obj); + } + break; + + case MEDIA_PREPARED: + // By this time, we've learned about DrmInfo's presence or absence. This is meant + // mainly for prepareAsync() use case. For prepare(), this still can run to a race + // condition b/c MediaPlayerNative releases the prepare() lock before calling notify + // so we also set mDrmInfoResolved in prepare(). + synchronized (mp.mDrmLock) { + mp.mDrmInfoResolved = true; + } + break; + } + if (mp.mEventHandler != null) { Message m = mp.mEventHandler.obtainMessage(what, arg1, arg2, obj); mp.mEventHandler.sendMessage(m); @@ -4086,16 +4120,16 @@ public class MediaPlayer extends PlayerBase * If the device has not been provisioned before, this call also provisions the device * which involves accessing the provisioning server and can take a variable time to * complete depending on the network connectivity. - * If OnDrmPreparedListener is registered, prepareDrm() runs in non-blocking + * If {@code OnDrmPreparedListener} is registered, prepareDrm() runs in non-blocking * mode by launching the provisioning in the background and returning. The listener * will be called when provisioning and preperation has finished. If a - * OnDrmPreparedListener is not registered, prepareDrm() waits till provisioning + * {@code OnDrmPreparedListener} is not registered, prepareDrm() waits till provisioning * and preperation has finished, i.e., runs in blocking mode. *

- * If OnDrmPreparedListener is registered, it is called to indicated the DRM session - * being ready regardless of blocking or non-blocking mode. The application should - * not make any assumption about its call sequence (e.g., before or after prepareDrm - * returns) or the thread context that will execute the listener. + * If {@code OnDrmPreparedListener} is registered, it is called to indicate the DRM + * session being ready. The application should not make any assumption about its call + * sequence (e.g., before or after prepareDrm returns), or the thread context that will + * execute the listener (unless the listener is registered with a handler thread). *

* * @param uuid The UUID of the crypto scheme.