Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 package org.chromium.media; | 5 package org.chromium.media; |
| 6 | 6 |
| 7 import android.annotation.SuppressLint; | 7 import android.annotation.SuppressLint; |
| 8 import android.annotation.TargetApi; | 8 import android.annotation.TargetApi; |
| 9 import android.media.MediaCrypto; | 9 import android.media.MediaCrypto; |
| 10 import android.media.MediaDrm; | 10 import android.media.MediaDrm; |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 76 | 76 |
| 77 // A session only for the purpose of creating a MediaCrypto object. Created | 77 // A session only for the purpose of creating a MediaCrypto object. Created |
| 78 // after construction, or after the provisioning process is successfully | 78 // after construction, or after the provisioning process is successfully |
| 79 // completed. No getKeyRequest() should be called on |mMediaCryptoSession|. | 79 // completed. No getKeyRequest() should be called on |mMediaCryptoSession|. |
| 80 private SessionId mMediaCryptoSession; | 80 private SessionId mMediaCryptoSession; |
| 81 | 81 |
| 82 // The map of all opened sessions (excluding mMediaCryptoSession) to their | 82 // The map of all opened sessions (excluding mMediaCryptoSession) to their |
| 83 // associated meta data, e.g. mime types, key types. | 83 // associated meta data, e.g. mime types, key types. |
| 84 private MediaDrmSessionManager mSessionManager; | 84 private MediaDrmSessionManager mSessionManager; |
| 85 | 85 |
| 86 // The persistent storage to record origin provisioning informations. | |
| 87 private MediaDrmStorageBridge mStorage; | |
| 88 | |
| 86 // The queue of all pending createSession() data. | 89 // The queue of all pending createSession() data. |
| 87 private ArrayDeque<PendingCreateSessionData> mPendingCreateSessionDataQueue; | 90 private ArrayDeque<PendingCreateSessionData> mPendingCreateSessionDataQueue; |
| 88 | 91 |
| 89 private boolean mResetDeviceCredentialsPending; | 92 private boolean mResetDeviceCredentialsPending; |
| 90 | 93 |
| 91 // MediaDrmBridge is waiting for provisioning response from the server. | 94 // MediaDrmBridge is waiting for provisioning response from the server. |
| 92 private boolean mProvisioningPending; | 95 private boolean mProvisioningPending; |
| 93 | 96 |
| 94 /** | 97 /** |
| 95 * An equivalent of MediaDrm.KeyStatus, which is only available on M+. | 98 * An equivalent of MediaDrm.KeyStatus, which is only available on M+. |
| (...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 189 | 192 |
| 190 private boolean isNativeMediaDrmBridgeValid() { | 193 private boolean isNativeMediaDrmBridgeValid() { |
| 191 return mNativeMediaDrmBridge != INVALID_NATIVE_MEDIA_DRM_BRIDGE; | 194 return mNativeMediaDrmBridge != INVALID_NATIVE_MEDIA_DRM_BRIDGE; |
| 192 } | 195 } |
| 193 | 196 |
| 194 private boolean isWidevine() { | 197 private boolean isWidevine() { |
| 195 return mSchemeUUID.equals(WIDEVINE_UUID); | 198 return mSchemeUUID.equals(WIDEVINE_UUID); |
| 196 } | 199 } |
| 197 | 200 |
| 198 @TargetApi(Build.VERSION_CODES.M) | 201 @TargetApi(Build.VERSION_CODES.M) |
| 199 private MediaDrmBridge(UUID schemeUUID, long nativeMediaDrmBridge) | 202 private MediaDrmBridge(UUID schemeUUID, long nativeMediaDrmBridge, |
| 200 throws android.media.UnsupportedSchemeException { | 203 long nativeMediaDrmStorageBridge) throws android.media.UnsupportedSc hemeException { |
| 201 mSchemeUUID = schemeUUID; | 204 mSchemeUUID = schemeUUID; |
| 202 mMediaDrm = new MediaDrm(schemeUUID); | 205 mMediaDrm = new MediaDrm(schemeUUID); |
| 203 | 206 |
| 204 mNativeMediaDrmBridge = nativeMediaDrmBridge; | 207 mNativeMediaDrmBridge = nativeMediaDrmBridge; |
| 205 assert isNativeMediaDrmBridgeValid(); | 208 assert isNativeMediaDrmBridgeValid(); |
| 206 | 209 |
| 207 mSessionManager = new MediaDrmSessionManager(); | 210 mStorage = new MediaDrmStorageBridge(nativeMediaDrmStorageBridge); |
| 211 mSessionManager = new MediaDrmSessionManager(mStorage); | |
| 212 | |
| 208 mPendingCreateSessionDataQueue = new ArrayDeque<PendingCreateSessionData >(); | 213 mPendingCreateSessionDataQueue = new ArrayDeque<PendingCreateSessionData >(); |
| 209 mResetDeviceCredentialsPending = false; | 214 mResetDeviceCredentialsPending = false; |
| 210 mProvisioningPending = false; | 215 mProvisioningPending = false; |
| 211 | 216 |
| 212 mMediaDrm.setOnEventListener(new EventListener()); | 217 mMediaDrm.setOnEventListener(new EventListener()); |
| 213 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { | 218 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { |
| 214 mMediaDrm.setOnExpirationUpdateListener(new ExpirationUpdateListener (), null); | 219 mMediaDrm.setOnExpirationUpdateListener(new ExpirationUpdateListener (), null); |
| 215 mMediaDrm.setOnKeyStatusChangeListener(new KeyStatusChangeListener() , null); | 220 mMediaDrm.setOnKeyStatusChangeListener(new KeyStatusChangeListener() , null); |
| 216 } | 221 } |
| 217 | 222 |
| (...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 323 return MediaDrm.isCryptoSchemeSupported(cryptoScheme, containerMimeType) ; | 328 return MediaDrm.isCryptoSchemeSupported(cryptoScheme, containerMimeType) ; |
| 324 } | 329 } |
| 325 | 330 |
| 326 /** | 331 /** |
| 327 * Create a new MediaDrmBridge from the crypto scheme UUID. | 332 * Create a new MediaDrmBridge from the crypto scheme UUID. |
| 328 * | 333 * |
| 329 * @param schemeUUID Crypto scheme UUID. | 334 * @param schemeUUID Crypto scheme UUID. |
| 330 * @param securityOrigin Security origin. Empty value means no need for orig in isolated storage. | 335 * @param securityOrigin Security origin. Empty value means no need for orig in isolated storage. |
| 331 * @param securityLevel Security level. If empty, the default one should be used. | 336 * @param securityLevel Security level. If empty, the default one should be used. |
| 332 * @param nativeMediaDrmBridge Native object of this class. | 337 * @param nativeMediaDrmBridge Native object of this class. |
| 338 * @param nativeMediaDrmStorageBridge Native object of persistent storage. | |
| 333 */ | 339 */ |
| 334 @CalledByNative | 340 @CalledByNative |
| 335 private static MediaDrmBridge create(byte[] schemeUUID, String securityOrigi n, | 341 private static MediaDrmBridge create(byte[] schemeUUID, String securityOrigi n, |
| 336 String securityLevel, long nativeMediaDrmBridge) { | 342 String securityLevel, long nativeMediaDrmBridge, long nativeMediaDrm StorageBridge) { |
| 337 UUID cryptoScheme = getUUIDFromBytes(schemeUUID); | 343 UUID cryptoScheme = getUUIDFromBytes(schemeUUID); |
| 338 if (cryptoScheme == null || !MediaDrm.isCryptoSchemeSupported(cryptoSche me)) { | 344 if (cryptoScheme == null || !MediaDrm.isCryptoSchemeSupported(cryptoSche me)) { |
| 339 return null; | 345 return null; |
| 340 } | 346 } |
| 341 | 347 |
| 342 MediaDrmBridge mediaDrmBridge = null; | 348 MediaDrmBridge mediaDrmBridge = null; |
| 343 try { | 349 try { |
| 344 mediaDrmBridge = new MediaDrmBridge(cryptoScheme, nativeMediaDrmBrid ge); | 350 mediaDrmBridge = new MediaDrmBridge( |
| 351 cryptoScheme, nativeMediaDrmBridge, nativeMediaDrmStorageBri dge); | |
| 345 Log.d(TAG, "MediaDrmBridge successfully created."); | 352 Log.d(TAG, "MediaDrmBridge successfully created."); |
| 346 } catch (android.media.UnsupportedSchemeException e) { | 353 } catch (android.media.UnsupportedSchemeException e) { |
| 347 Log.e(TAG, "Unsupported DRM scheme", e); | 354 Log.e(TAG, "Unsupported DRM scheme", e); |
| 348 return null; | 355 return null; |
| 349 } catch (java.lang.IllegalArgumentException e) { | 356 } catch (java.lang.IllegalArgumentException e) { |
| 350 Log.e(TAG, "Failed to create MediaDrmBridge", e); | 357 Log.e(TAG, "Failed to create MediaDrmBridge", e); |
| 351 return null; | 358 return null; |
| 352 } catch (java.lang.IllegalStateException e) { | 359 } catch (java.lang.IllegalStateException e) { |
| 353 Log.e(TAG, "Failed to create MediaDrmBridge", e); | 360 Log.e(TAG, "Failed to create MediaDrmBridge", e); |
| 354 return null; | 361 return null; |
| (...skipping 151 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 506 try { | 513 try { |
| 507 // Some implementations don't have removeKeys, crbug/475632 | 514 // Some implementations don't have removeKeys, crbug/475632 |
| 508 mMediaDrm.removeKeys(sessionId.drmId()); | 515 mMediaDrm.removeKeys(sessionId.drmId()); |
| 509 } catch (Exception e) { | 516 } catch (Exception e) { |
| 510 Log.e(TAG, "removeKeys failed: ", e); | 517 Log.e(TAG, "removeKeys failed: ", e); |
| 511 } | 518 } |
| 512 | 519 |
| 513 closeSessionNoException(sessionId); | 520 closeSessionNoException(sessionId); |
| 514 onSessionClosed(sessionId); | 521 onSessionClosed(sessionId); |
| 515 } | 522 } |
| 516 mSessionManager = new MediaDrmSessionManager(); | 523 mSessionManager = new MediaDrmSessionManager(mStorage); |
| 517 | 524 |
| 518 // Close mMediaCryptoSession if it's open or notify MediaCrypto | 525 // Close mMediaCryptoSession if it's open or notify MediaCrypto |
| 519 // creation failure if it's never successfully opened. | 526 // creation failure if it's never successfully opened. |
| 520 if (mMediaCryptoSession == null) { | 527 if (mMediaCryptoSession == null) { |
| 521 // MediaCrypto never notified. Notify a null one now. | 528 // MediaCrypto never notified. Notify a null one now. |
| 522 onMediaCryptoReady(null); | 529 onMediaCryptoReady(null); |
| 523 } else { | 530 } else { |
| 524 closeSessionNoException(mMediaCryptoSession); | 531 closeSessionNoException(mMediaCryptoSession); |
| 525 mMediaCryptoSession = null; | 532 mMediaCryptoSession = null; |
| 526 } | 533 } |
| (...skipping 383 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 910 if (mResetDeviceCredentialsPending) { | 917 if (mResetDeviceCredentialsPending) { |
| 911 onResetDeviceCredentialsCompleted(success); | 918 onResetDeviceCredentialsCompleted(success); |
| 912 mResetDeviceCredentialsPending = false; | 919 mResetDeviceCredentialsPending = false; |
| 913 } | 920 } |
| 914 | 921 |
| 915 if (!success || (mMediaCryptoSession == null && !createMediaCrypto())) { | 922 if (!success || (mMediaCryptoSession == null && !createMediaCrypto())) { |
| 916 release(); | 923 release(); |
| 917 return; | 924 return; |
| 918 } | 925 } |
| 919 | 926 |
| 920 processPendingCreateSessionData(); | 927 if (!useOriginIsolatedStorage()) { |
| 928 processPendingCreateSessionData(); | |
| 929 return; | |
| 930 } | |
| 931 | |
| 932 mStorage.onProvisioned(new Callback<Boolean>() { | |
| 933 @Override | |
| 934 public void onResult(Boolean initSuccess) { | |
| 935 if (!initSuccess) { | |
| 936 Log.e(TAG, "Failed to initialize storage for origin"); | |
| 937 release(); | |
| 938 return; | |
| 939 } | |
| 940 | |
| 941 processPendingCreateSessionData(); | |
| 942 } | |
| 943 }); | |
| 944 } | |
| 945 | |
| 946 private boolean useOriginIsolatedStorage() { | |
| 947 assert mMediaDrm != null; | |
| 948 | |
| 949 boolean isMOrHigher = Build.VERSION.SDK_INT >= Build.VERSION_CODES.M; | |
| 950 boolean isOriginSet = !isWidevine() || !mMediaDrm.getPropertyString(ORIG IN).isEmpty(); | |
|
xhwang
2017/03/31 03:47:57
Is it ever possible that getPropertyString(ORIGIN)
yucliu1
2017/03/31 05:38:17
We should check origin only for M or higher device
xhwang
2017/03/31 06:25:50
At least for now, per-origin provisioning is a req
yucliu1
2017/03/31 18:42:30
Good point! And I think we want to disable the fea
| |
| 951 | |
| 952 return isMOrHigher && isOriginSet; | |
| 921 } | 953 } |
| 922 | 954 |
| 923 /** | 955 /** |
| 924 * Provides the provision response to MediaDrm. | 956 * Provides the provision response to MediaDrm. |
| 925 * | 957 * |
| 926 * @returns false if the response is invalid or on error, true otherwise. | 958 * @returns false if the response is invalid or on error, true otherwise. |
| 927 */ | 959 */ |
| 928 boolean provideProvisionResponse(byte[] response) { | 960 boolean provideProvisionResponse(byte[] response) { |
| 929 if (response == null || response.length == 0) { | 961 if (response == null || response.length == 0) { |
| 930 Log.e(TAG, "Invalid provision response."); | 962 Log.e(TAG, "Invalid provision response."); |
| (...skipping 205 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1136 long nativeMediaDrmBridge, byte[] emeSessionId, int requestType, byt e[] message); | 1168 long nativeMediaDrmBridge, byte[] emeSessionId, int requestType, byt e[] message); |
| 1137 private native void nativeOnSessionClosed(long nativeMediaDrmBridge, byte[] emeSessionId); | 1169 private native void nativeOnSessionClosed(long nativeMediaDrmBridge, byte[] emeSessionId); |
| 1138 private native void nativeOnSessionKeysChange(long nativeMediaDrmBridge, byt e[] emeSessionId, | 1170 private native void nativeOnSessionKeysChange(long nativeMediaDrmBridge, byt e[] emeSessionId, |
| 1139 Object[] keysInfo, boolean hasAdditionalUsableKey); | 1171 Object[] keysInfo, boolean hasAdditionalUsableKey); |
| 1140 private native void nativeOnSessionExpirationUpdate( | 1172 private native void nativeOnSessionExpirationUpdate( |
| 1141 long nativeMediaDrmBridge, byte[] emeSessionId, long expirationTime) ; | 1173 long nativeMediaDrmBridge, byte[] emeSessionId, long expirationTime) ; |
| 1142 | 1174 |
| 1143 private native void nativeOnResetDeviceCredentialsCompleted( | 1175 private native void nativeOnResetDeviceCredentialsCompleted( |
| 1144 long nativeMediaDrmBridge, boolean success); | 1176 long nativeMediaDrmBridge, boolean success); |
| 1145 } | 1177 } |
| OLD | NEW |