Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(436)

Unified Diff: media/base/android/java/src/org/chromium/media/MediaDrmBridge.java

Issue 1540033002: media: Create MediaCrypto upon MediaDrmBridge creation. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: comments addressed Created 4 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | media/base/android/media_drm_bridge.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: media/base/android/java/src/org/chromium/media/MediaDrmBridge.java
diff --git a/media/base/android/java/src/org/chromium/media/MediaDrmBridge.java b/media/base/android/java/src/org/chromium/media/MediaDrmBridge.java
index f259d4f636d901cd3161b0e6c6c0d701c30c36b0..4f3a343e6da181e743870a46fb58b1c5d9d60930 100644
--- a/media/base/android/java/src/org/chromium/media/MediaDrmBridge.java
+++ b/media/base/android/java/src/org/chromium/media/MediaDrmBridge.java
@@ -30,11 +30,10 @@ import java.util.UUID;
public class MediaDrmBridge {
// Implementation Notes:
// - A media crypto session (mMediaCryptoSession) is opened after MediaDrm
- // is created. This session will be added to mSessionIds and will only be
- // used to create the MediaCrypto object. Its associated mime type is
- // always null and its session ID is always INVALID_SESSION_ID.
- // - Each createSession() call creates a new session. All sessions are
- // managed in mSessionIds.
+ // is created. This session will NOT be added to mSessionIds and will only
+ // be used to create the MediaCrypto object.
+ // - Each createSession() call creates a new session. All created sessions
+ // are managed in mSessionIds.
// - Whenever NotProvisionedException is thrown, we will clean up the
// current state and start the provisioning process.
// - When provisioning is finished, we will try to resume suspended
@@ -43,12 +42,10 @@ public class MediaDrmBridge {
// b) Finish createSession() if previous createSession() was interrupted
// by a NotProvisionedException.
// - Whenever an unexpected error occurred, we'll call release() to release
- // all resources and clear all states. In that case all calls to this
- // object will be no-op. All public APIs and callbacks should check
- // mMediaBridge to make sure release() hasn't been called. Also, we call
- // release() immediately after the error happens (e.g. after mMediaDrm)
- // calls. Indirect calls should not call release() again to avoid
- // duplication (even though it doesn't hurt to call release() twice).
+ // all resources immediately, clear all states and fail all pending
+ // operations. After that all calls to this object will fail (e.g. return
+ // null or reject the promise). All public APIs and callbacks should check
+ // mMediaBridge to make sure release() hasn't been called.
private static final String TAG = "cr_media";
private static final String SECURITY_LEVEL = "securityLevel";
@@ -56,7 +53,6 @@ public class MediaDrmBridge {
private static final String PRIVACY_MODE = "privacyMode";
private static final String SESSION_SHARING = "sessionSharing";
private static final String ENABLE = "enable";
- private static final int INVALID_SESSION_ID = 0;
private static final char[] HEX_CHAR_LOOKUP = "0123456789ABCDEF".toCharArray();
private static final long INVALID_NATIVE_MEDIA_DRM_BRIDGE = 0;
@@ -69,15 +65,13 @@ public class MediaDrmBridge {
private long mNativeMediaDrmBridge;
private UUID mSchemeUUID;
- // A session only for the purpose of creating a MediaCrypto object.
- // This session is opened when createSession() is called for the first
- // time. All following createSession() calls will create a new session and
- // use it to call getKeyRequest(). No getKeyRequest() should ever be called
- // on |mMediaCryptoSession|.
+ // A session only for the purpose of creating a MediaCrypto object. Created
+ // after construction, or after the provisioning process is successfully
+ // completed. No getKeyRequest() should be called on |mMediaCryptoSession|.
private byte[] mMediaCryptoSession;
- private MediaCrypto mMediaCrypto;
- // The map of all opened sessions (excluding mMediaCryptoSession) to their mime types.
+ // The map of all opened sessions (excluding mMediaCryptoSession) to their
+ // mime types.
private HashMap<ByteBuffer, String> mSessionIds;
// The queue of all pending createSession() data.
@@ -86,10 +80,6 @@ public class MediaDrmBridge {
private boolean mResetDeviceCredentialsPending;
// MediaDrmBridge is waiting for provisioning response from the server.
- //
- // Notes about NotProvisionedException: This exception can be thrown in a
- // lot of cases. To streamline implementation, we do not catch it in private
- // non-native methods and only catch it in public APIs.
private boolean mProvisioningPending;
/**
@@ -213,40 +203,46 @@ public class MediaDrmBridge {
mMediaDrm.setPropertyString(PRIVACY_MODE, ENABLE);
mMediaDrm.setPropertyString(SESSION_SHARING, ENABLE);
-
- // We could open a MediaCrypto session here to support faster start of
- // clear lead (no need to wait for createSession()). But on
- // Android, memory and battery resources are precious and we should
- // only create a session when we are sure we'll use it.
- // TODO(xhwang): Investigate other options to support fast start.
}
/**
* Create a MediaCrypto object.
*
- * @return whether a MediaCrypto object is successfully created.
+ * @return false upon fatal error in creating MediaCrypto. Returns true
+ * otherwise, including the following two cases:
+ * 1. MediaCrypto is successfully created and notified.
+ * 2. Device is not provisioned and MediaCrypto creation will be tried
+ * again after the provisioning process is completed.
+ *
+ * When false is returned, the caller should call release(), which will
+ * notify the native code with a null MediaCrypto, if needed.
*/
- private boolean createMediaCrypto() throws android.media.NotProvisionedException {
+ private boolean createMediaCrypto() {
assert mMediaDrm != null;
assert !mProvisioningPending;
assert mMediaCryptoSession == null;
- assert mMediaCrypto == null;
- // Open media crypto session. This could throw NotProvisionedException.
- mMediaCryptoSession = openSession();
+ // Open media crypto session.
+ try {
+ mMediaCryptoSession = openSession();
+ } catch (android.media.NotProvisionedException e) {
+ Log.d(TAG, "Device not provisioned", e);
+ startProvisioning();
+ return true;
+ }
+
if (mMediaCryptoSession == null) {
Log.e(TAG, "Cannot create MediaCrypto Session.");
- release();
return false;
}
Log.d(TAG, "MediaCrypto Session created: %s", bytesToHexString(mMediaCryptoSession));
// Create MediaCrypto object.
try {
- // TODO: This requires KitKat. Is this class used on pre-KK devices?
if (MediaCrypto.isCryptoSchemeSupported(mSchemeUUID)) {
- mMediaCrypto = new MediaCrypto(mSchemeUUID, mMediaCryptoSession);
+ MediaCrypto mediaCrypto = new MediaCrypto(mSchemeUUID, mMediaCryptoSession);
Log.d(TAG, "MediaCrypto successfully created!");
+ onMediaCryptoReady(mediaCrypto);
return true;
} else {
Log.e(TAG, "Cannot create MediaCrypto for unsupported scheme.");
@@ -255,7 +251,9 @@ public class MediaDrmBridge {
Log.e(TAG, "Cannot create MediaCrypto", e);
}
- release();
+ mMediaDrm.closeSession(mMediaCryptoSession);
+ mMediaCryptoSession = null;
+
return false;
}
@@ -326,17 +324,20 @@ public class MediaDrmBridge {
Log.d(TAG, "MediaDrmBridge successfully created.");
} catch (android.media.UnsupportedSchemeException e) {
Log.e(TAG, "Unsupported DRM scheme", e);
+ return null;
} catch (java.lang.IllegalArgumentException e) {
Log.e(TAG, "Failed to create MediaDrmBridge", e);
+ return null;
} catch (java.lang.IllegalStateException e) {
Log.e(TAG, "Failed to create MediaDrmBridge", e);
+ return null;
}
- if (mediaDrmBridge == null) {
+ if (!securityLevel.isEmpty() && !mediaDrmBridge.setSecurityLevel(securityLevel)) {
return null;
}
- if (!securityLevel.isEmpty() && !mediaDrmBridge.setSecurityLevel(securityLevel)) {
+ if (!mediaDrmBridge.createMediaCrypto()) {
return null;
}
@@ -352,12 +353,9 @@ public class MediaDrmBridge {
* @return whether the security level was successfully set.
*/
private boolean setSecurityLevel(String securityLevel) {
+ assert mMediaDrm != null;
assert !securityLevel.isEmpty();
- if (mMediaDrm == null || mMediaCrypto != null) {
- return false;
- }
-
String currentSecurityLevel = mMediaDrm.getPropertyString(SECURITY_LEVEL);
Log.e(TAG, "Security level: current %s, new %s", currentSecurityLevel, securityLevel);
if (securityLevel.equals(currentSecurityLevel)) {
@@ -405,6 +403,11 @@ public class MediaDrmBridge {
*/
@CalledByNative
private void resetDeviceCredentials() {
+ if (mMediaDrm == null) {
+ onResetDeviceCredentialsCompleted(false);
+ return;
+ }
+
mResetDeviceCredentialsPending = true;
startProvisioning();
}
@@ -426,12 +429,16 @@ public class MediaDrmBridge {
private void release() {
// Note that mNativeMediaDrmBridge may have already been reset (see destroy()).
+ assert mMediaDrm != null;
+
+ // Reject all pending session creation.
for (PendingCreateSessionData data : mPendingCreateSessionDataQueue) {
onPromiseRejected(data.promiseId(), "Create session aborted.");
}
mPendingCreateSessionDataQueue.clear();
mPendingCreateSessionDataQueue = null;
+ // Close all open sessions.
for (ByteBuffer sessionId : mSessionIds.keySet()) {
try {
// Some implementations don't have removeKeys, crbug/475632
@@ -445,12 +452,20 @@ public class MediaDrmBridge {
mSessionIds.clear();
mSessionIds = null;
- // This session was closed in the "for" loop above.
- mMediaCryptoSession = null;
+ // Close mMediaCryptoSession if it's open or notify MediaCrypto
+ // creation failure if it's never successfully opened.
+ if (mMediaCryptoSession == null) {
+ // MediaCrypto never notified. Notify a null one now.
+ onMediaCryptoReady(null);
+ } else {
+ mMediaDrm.closeSession(mMediaCryptoSession);
+ mMediaCryptoSession = null;
+ }
- if (mMediaCrypto != null) {
- mMediaCrypto.release();
- mMediaCrypto = null;
+ // Fail device credentials resetting.
+ if (mResetDeviceCredentialsPending) {
+ mResetDeviceCredentialsPending = false;
+ onResetDeviceCredentialsCompleted(false);
}
if (mMediaDrm != null) {
@@ -473,7 +488,7 @@ public class MediaDrmBridge {
byte[] sessionId, byte[] data, String mime, HashMap<String, String> optionalParameters)
throws android.media.NotProvisionedException {
assert mMediaDrm != null;
- assert mMediaCrypto != null;
+ assert mMediaCryptoSession != null;
assert !mProvisioningPending;
if (optionalParameters == null) {
@@ -511,6 +526,7 @@ public class MediaDrmBridge {
private void savePendingCreateSessionData(byte[] initData, String mime,
HashMap<String, String> optionalParameters, long promiseId) {
Log.d(TAG, "savePendingCreateSessionData()");
+
mPendingCreateSessionDataQueue.offer(
new PendingCreateSessionData(initData, mime, optionalParameters, promiseId));
}
@@ -567,34 +583,23 @@ public class MediaDrmBridge {
private void createSession(byte[] initData, String mime,
HashMap<String, String> optionalParameters, long promiseId) {
Log.d(TAG, "createSession()");
+
if (mMediaDrm == null) {
Log.e(TAG, "createSession() called when MediaDrm is null.");
+ onPromiseRejected(promiseId, "MediaDrm released previously.");
return;
}
if (mProvisioningPending) {
- assert mMediaCrypto == null;
savePendingCreateSessionData(initData, mime, optionalParameters, promiseId);
return;
}
+ assert mMediaCryptoSession != null;
+
boolean newSessionOpened = false;
byte[] sessionId = null;
try {
- // Create MediaCrypto if necessary.
- if (mMediaCrypto == null) {
- boolean success = createMediaCrypto();
- // |mMediaCrypto| could be null upon failure. Notify the native code in all cases.
- onMediaCryptoReady();
- if (!success) {
- onPromiseRejected(promiseId, "MediaCrypto creation failed.");
- return;
- }
- }
-
- assert mMediaCryptoSession != null;
- assert mMediaCrypto != null;
-
sessionId = openSession();
if (sessionId == null) {
onPromiseRejected(promiseId, "Open session failed.");
@@ -763,27 +768,28 @@ public class MediaDrmBridge {
@CalledByNative
private void processProvisionResponse(boolean isResponseReceived, byte[] response) {
Log.d(TAG, "processProvisionResponse()");
- assert mProvisioningPending;
- mProvisioningPending = false;
// If |mMediaDrm| is released, there is no need to callback native.
if (mMediaDrm == null) {
return;
}
- boolean success = isResponseReceived;
- if (success) {
- success = provideProvisionResponse(response);
- }
+ assert mProvisioningPending;
+ mProvisioningPending = false;
+
+ boolean success = isResponseReceived ? provideProvisionResponse(response) : false;
if (mResetDeviceCredentialsPending) {
onResetDeviceCredentialsCompleted(success);
mResetDeviceCredentialsPending = false;
}
- if (success) {
- processPendingCreateSessionData();
+ if (!success || (mMediaCryptoSession == null && !createMediaCrypto())) {
+ release();
+ return;
}
+
+ processPendingCreateSessionData();
}
/**
@@ -810,9 +816,9 @@ public class MediaDrmBridge {
// Helper functions to make native calls.
- private void onMediaCryptoReady() {
+ private void onMediaCryptoReady(MediaCrypto mediaCrypto) {
if (isNativeMediaDrmBridgeValid()) {
- nativeOnMediaCryptoReady(mNativeMediaDrmBridge, mMediaCrypto);
+ nativeOnMediaCryptoReady(mNativeMediaDrmBridge, mediaCrypto);
}
}
« no previous file with comments | « no previous file | media/base/android/media_drm_bridge.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698