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

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

Issue 2796843002: [Clank] Load/Remove persistent license (Closed)
Patch Set: Bug fix Created 3 years, 8 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 unified diff | Download patch
OLDNEW
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 79 matching lines...) Expand 10 before | Expand all | Expand 10 after
90 private ArrayDeque<PendingCreateSessionData> mPendingCreateSessionDataQueue; 90 private ArrayDeque<PendingCreateSessionData> mPendingCreateSessionDataQueue;
91 91
92 private boolean mResetDeviceCredentialsPending; 92 private boolean mResetDeviceCredentialsPending;
93 93
94 // MediaDrmBridge is waiting for provisioning response from the server. 94 // MediaDrmBridge is waiting for provisioning response from the server.
95 private boolean mProvisioningPending; 95 private boolean mProvisioningPending;
96 96
97 // Boolean to track if 'ORIGIN' is set in MediaDrm. 97 // Boolean to track if 'ORIGIN' is set in MediaDrm.
98 private boolean mOriginSet = false; 98 private boolean mOriginSet = false;
99 99
100 // Delay the MediaDrm event handle if present.
101 private SessionEventDeferrer mSessionEventDeferrer = null;
102
103 // Block MediaDrm event for |mSessionId|.
104 private static class SessionEventDeferrer {
xhwang 2017/04/05 18:31:50 Please add more comments why we need this.
yucliu1 2017/04/05 23:04:07 Done.
105 private final SessionId mSessionId;
106 private final ArrayList<Runnable> mEventHandlers;
107
108 SessionEventDeferrer(SessionId sessionId) {
109 mSessionId = sessionId;
110 mEventHandlers = new ArrayList<>();
111 }
112
113 boolean shouldDefer(SessionId sessionId) {
114 return mSessionId.isEqual(sessionId);
115 }
116
117 void defer(Runnable handler) {
118 mEventHandlers.add(handler);
119 }
120
121 void fire() {
122 for (Runnable r : mEventHandlers) {
123 r.run();
124 }
125
126 mEventHandlers.clear();
127 }
128 }
129
100 /** 130 /**
101 * An equivalent of MediaDrm.KeyStatus, which is only available on M+. 131 * An equivalent of MediaDrm.KeyStatus, which is only available on M+.
102 */ 132 */
103 @MainDex 133 @MainDex
104 private static class KeyStatus { 134 private static class KeyStatus {
105 private final byte[] mKeyId; 135 private final byte[] mKeyId;
106 private final int mStatusCode; 136 private final int mStatusCode;
107 137
108 private KeyStatus(byte[] keyId, int statusCode) { 138 private KeyStatus(byte[] keyId, int statusCode) {
109 mKeyId = keyId; 139 mKeyId = keyId;
(...skipping 456 matching lines...) Expand 10 before | Expand all | Expand 10 after
566 assert mMediaCryptoSession != null; 596 assert mMediaCryptoSession != null;
567 assert !mProvisioningPending; 597 assert !mProvisioningPending;
568 598
569 if (optionalParameters == null) { 599 if (optionalParameters == null) {
570 optionalParameters = new HashMap<String, String>(); 600 optionalParameters = new HashMap<String, String>();
571 } 601 }
572 602
573 MediaDrm.KeyRequest request = null; 603 MediaDrm.KeyRequest request = null;
574 604
575 try { 605 try {
576 request = mMediaDrm.getKeyRequest( 606 byte[] scopeId =
577 sessionId.drmId(), data, mime, keyType, optionalParameters); 607 keyType == MediaDrm.KEY_TYPE_RELEASE ? sessionId.keySetId() : sessionId.drmId();
608 assert scopeId != null;
609 request = mMediaDrm.getKeyRequest(scopeId, data, mime, keyType, opti onalParameters);
578 } catch (IllegalStateException e) { 610 } catch (IllegalStateException e) {
579 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && e 611 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && e
580 instanceof android.media.MediaDrm.MediaDrmStateException) { 612 instanceof android.media.MediaDrm.MediaDrmStateException) {
581 // See b/21307186 for details. 613 // See b/21307186 for details.
582 Log.e(TAG, "MediaDrmStateException fired during getKeyRequest(). ", e); 614 Log.e(TAG, "MediaDrmStateException fired during getKeyRequest(). ", e);
583 } 615 }
584 } 616 }
585 617
586 String result = (request != null) ? "successed" : "failed"; 618 String result = (request != null) ? "successed" : "failed";
587 Log.d(TAG, "getKeyRequest %s!", result); 619 Log.d(TAG, "getKeyRequest %s!", result);
(...skipping 230 matching lines...) Expand 10 before | Expand all | Expand 10 after
818 final SessionId sessionId = getSessionIdByEmeId(emeSessionId); 850 final SessionId sessionId = getSessionIdByEmeId(emeSessionId);
819 if (sessionId == null) { 851 if (sessionId == null) {
820 assert false; // Should never happen. 852 assert false; // Should never happen.
821 onPromiseRejected(promiseId, 853 onPromiseRejected(promiseId,
822 "Invalid session in updateSession: " + SessionId.toHexString (emeSessionId)); 854 "Invalid session in updateSession: " + SessionId.toHexString (emeSessionId));
823 return; 855 return;
824 } 856 }
825 857
826 try { 858 try {
827 SessionInfo sessionInfo = mSessionManager.get(sessionId); 859 SessionInfo sessionInfo = mSessionManager.get(sessionId);
828 byte[] keySetId = mMediaDrm.provideKeyResponse(sessionId.drmId(), re sponse); 860 boolean isKeyRelease = sessionInfo.keyType() == MediaDrm.KEY_TYPE_RE LEASE;
829 861
830 if (keySetId != null && keySetId.length > 0) { 862 byte[] keySetId = null;
831 assert sessionInfo.keyType() == MediaDrm.KEY_TYPE_OFFLINE; 863 if (isKeyRelease) {
832 mSessionManager.setKeySetId(sessionId, keySetId, new Callback<Bo olean>() { 864 Log.d(TAG, "updateSession() for key release");
833 @Override 865 assert sessionId.keySetId() != null;
834 public void onResult(Boolean success) { 866 mMediaDrm.provideKeyResponse(sessionId.keySetId(), response);
835 onKeyUpdated(sessionId, promiseId, success); 867 } else {
836 } 868 keySetId = mMediaDrm.provideKeyResponse(sessionId.drmId(), respo nse);
837 }); 869 }
870
871 KeyUpdatedCallback cb = new KeyUpdatedCallback(sessionId, promiseId, isKeyRelease);
872
873 if (isKeyRelease) {
874 mSessionManager.clearPersistentSessionInfo(sessionId, cb);
875 } else if (sessionInfo.keyType() == MediaDrm.KEY_TYPE_OFFLINE && key SetId != null
876 && keySetId.length > 0) {
877 mSessionManager.setKeySetId(sessionId, keySetId, cb);
838 } else { 878 } else {
839 // This can be either temporary license update or server certifi cate update. 879 // This can be either temporary license update or server certifi cate update.
840 onKeyUpdated(sessionId, promiseId, true); 880 cb.onResult(true);
841 } 881 }
842 882
843 return; 883 return;
844 } catch (android.media.NotProvisionedException e) { 884 } catch (android.media.NotProvisionedException e) {
845 // TODO(xhwang): Should we handle this? 885 // TODO(xhwang): Should we handle this?
846 Log.e(TAG, "failed to provide key response", e); 886 Log.e(TAG, "failed to provide key response", e);
847 } catch (android.media.DeniedByServerException e) { 887 } catch (android.media.DeniedByServerException e) {
848 Log.e(TAG, "failed to provide key response", e); 888 Log.e(TAG, "failed to provide key response", e);
849 } catch (java.lang.IllegalStateException e) { 889 } catch (java.lang.IllegalStateException e) {
850 Log.e(TAG, "failed to provide key response", e); 890 Log.e(TAG, "failed to provide key response", e);
851 } 891 }
852 onPromiseRejected(promiseId, "Update session failed."); 892 onPromiseRejected(promiseId, "Update session failed.");
853 release(); 893 release();
854 } 894 }
855 895
856 private void onKeyUpdated(SessionId sessionId, long promiseId, boolean succe ss) { 896 /**
857 if (!success) { 897 * Load persistent license from stroage.
858 onPromiseRejected(promiseId, "failed to update key after response ac cepted"); 898 */
899 @CalledByNative
900 private void loadSession(byte[] emeId, final long promiseId) {
901 Log.d(TAG, "loadSession()");
902 if (mProvisioningPending) {
903 onPersistentLicenseNoExist(promiseId);
859 return; 904 return;
860 } 905 }
861 906
862 Log.d(TAG, "Key successfully added for session %s", sessionId.toHexStrin g()); 907 mSessionManager.load(emeId, new Callback<SessionId>() {
863 onPromiseResolved(promiseId); 908 @Override
909 public void onResult(SessionId sessionId) {
910 if (sessionId == null) {
911 onPersistentLicenseNoExist(promiseId);
912 return;
913 }
864 914
865 if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { 915 loadSessionWithLoadedStorage(sessionId, promiseId);
866 onSessionKeysChange( 916 }
867 sessionId, getDummyKeysInfo(MediaDrm.KeyStatus.STATUS_USABLE ).toArray(), true); 917 });
918 }
919
920 /**
921 * Load session back to memory with MediaDrm. Load persistent storage
922 * before calling this. It will fail if persistent storage isn't loaded.
923 */
924 private void loadSessionWithLoadedStorage(SessionId sessionId, final long pr omiseId) {
925 byte[] drmId = null;
926 try {
927 drmId = openSession();
928 if (drmId == null) {
929 onPromiseRejected(promiseId, "Failed to open session to load lic ense");
930 return;
931 }
932
933 mSessionManager.setDrmId(sessionId, drmId);
934
935 // Defer event handlers until license is loaded.
936 assert mSessionEventDeferrer == null;
937 mSessionEventDeferrer = new SessionEventDeferrer(sessionId);
938
939 assert sessionId.keySetId() != null;
940 mMediaDrm.restoreKeys(sessionId.drmId(), sessionId.keySetId());
941
942 onPromiseResolvedWithSession(promiseId, sessionId);
943
944 mSessionEventDeferrer.fire();
945 mSessionEventDeferrer = null;
946
947 if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
948 onSessionKeysChange(sessionId,
949 getDummyKeysInfo(MediaDrm.KeyStatus.STATUS_USABLE).toArr ay(), true, false);
950 }
951 } catch (android.media.NotProvisionedException e) {
952 onPersistentLicenseNoExist(promiseId);
xhwang 2017/04/05 18:31:50 When can this happen? When user manually unprovisi
yucliu1 2017/04/05 23:04:07 Early return.
953 } catch (java.lang.IllegalStateException e) {
954 // license doesn't exist
955 if (sessionId.drmId() == null) {
956 // TODO(yucliu): Check if the license is released or doesn't exi st.
957 onPersistentLicenseNoExist(promiseId);
958 return;
959 }
960
961 closeSessionNoException(sessionId);
962 mSessionManager.clearPersistentSessionInfo(sessionId, new Callback<B oolean>() {
963 @Override
964 public void onResult(Boolean success) {
965 if (!success) {
966 Log.w(TAG, "Failed to clear persistent storage for non-e xist license");
967 }
968
969 onPersistentLicenseNoExist(promiseId);
970 }
971 });
868 } 972 }
869 } 973 }
870 974
975 private void onPersistentLicenseNoExist(long promiseId) {
976 onPromiseResolvedWithSession(promiseId, SessionId.createNoExistSessionId ());
977 }
978
979 /**
980 * Remove session from device. This will mark the key as released and
981 * generate a key release request. The license is removed from the device
982 * when the session is updated with a license release response.
983 */
984 @CalledByNative
985 private void removeSession(byte[] emeId, long promiseId) {
986 Log.d(TAG, "removeSession()");
987 SessionId sessionId = getSessionIdByEmeId(emeId);
988
989 if (sessionId == null) {
990 onPromiseRejected(promiseId, "Session doesn't exist");
991 return;
992 }
993
994 SessionInfo sessionInfo = mSessionManager.get(sessionId);
995 if (sessionInfo.keyType() != MediaDrm.KEY_TYPE_OFFLINE) {
996 // TODO(yucliu): Support 'remove' of temporary session.
997 onPromiseRejected(promiseId, "Removing temporary session isn't imple mented");
998 return;
999 }
1000
1001 assert sessionId.keySetId() != null;
1002
1003 mSessionManager.markKeyReleased(sessionId);
1004
1005 try {
1006 // Get key release request.
1007 MediaDrm.KeyRequest request = getKeyRequest(
1008 sessionId, null, sessionInfo.mimeType(), MediaDrm.KEY_TYPE_R ELEASE, null);
1009
1010 if (request == null) {
1011 onPromiseRejected(promiseId, "Fail to generate key release reque st");
1012 return;
1013 }
1014
1015 onPromiseResolved(promiseId);
1016 onSessionMessage(sessionId, request);
xhwang 2017/04/05 18:31:50 The spec says queue the message, then return the p
yucliu1 2017/04/05 23:04:07 Switched sequence to match spec.
1017 } catch (android.media.NotProvisionedException e) {
1018 Log.e(TAG, "removeSession called on unprovisioned device");
1019 onPromiseRejected(promiseId, "Unknown failure");
1020 }
1021 }
1022
871 /** 1023 /**
872 * Return the security level of this DRM object. 1024 * Return the security level of this DRM object.
873 */ 1025 */
874 @CalledByNative 1026 @CalledByNative
875 private String getSecurityLevel() { 1027 private String getSecurityLevel() {
876 if (mMediaDrm == null || !isWidevine()) { 1028 if (mMediaDrm == null || !isWidevine()) {
877 Log.e(TAG, "getSecurityLevel(): MediaDrm is null or security level i s not supported."); 1029 Log.e(TAG, "getSecurityLevel(): MediaDrm is null or security level i s not supported.");
878 return null; 1030 return null;
879 } 1031 }
880 return mMediaDrm.getPropertyString("securityLevel"); 1032 return mMediaDrm.getPropertyString("securityLevel");
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after
962 mMediaDrm.provideProvisionResponse(response); 1114 mMediaDrm.provideProvisionResponse(response);
963 return true; 1115 return true;
964 } catch (android.media.DeniedByServerException e) { 1116 } catch (android.media.DeniedByServerException e) {
965 Log.e(TAG, "failed to provide provision response", e); 1117 Log.e(TAG, "failed to provide provision response", e);
966 } catch (java.lang.IllegalStateException e) { 1118 } catch (java.lang.IllegalStateException e) {
967 Log.e(TAG, "failed to provide provision response", e); 1119 Log.e(TAG, "failed to provide provision response", e);
968 } 1120 }
969 return false; 1121 return false;
970 } 1122 }
971 1123
1124 /**
1125 * Delay session event handler if |mSessionEventDeferrer| exists and
1126 * matches |sessionId|. Otherwise run the handler immediately.
1127 */
1128 private void deferEventHandleIfNeeded(SessionId sessionId, Runnable handler) {
1129 if (mSessionEventDeferrer != null && mSessionEventDeferrer.shouldDefer(s essionId)) {
1130 mSessionEventDeferrer.defer(handler);
1131 return;
1132 }
1133
1134 handler.run();
1135 }
1136
972 // Helper functions to make native calls. 1137 // Helper functions to make native calls.
973 1138
974 private void onMediaCryptoReady(MediaCrypto mediaCrypto) { 1139 private void onMediaCryptoReady(MediaCrypto mediaCrypto) {
975 if (isNativeMediaDrmBridgeValid()) { 1140 if (isNativeMediaDrmBridgeValid()) {
976 nativeOnMediaCryptoReady(mNativeMediaDrmBridge, mediaCrypto); 1141 nativeOnMediaCryptoReady(mNativeMediaDrmBridge, mediaCrypto);
977 } 1142 }
978 } 1143 }
979 1144
980 private void onPromiseResolved(final long promiseId) { 1145 private void onPromiseResolved(final long promiseId) {
981 if (isNativeMediaDrmBridgeValid()) { 1146 if (isNativeMediaDrmBridgeValid()) {
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
1015 mNativeMediaDrmBridge, sessionId.emeId(), requestType, request.g etData()); 1180 mNativeMediaDrmBridge, sessionId.emeId(), requestType, request.g etData());
1016 } 1181 }
1017 1182
1018 private void onSessionClosed(final SessionId sessionId) { 1183 private void onSessionClosed(final SessionId sessionId) {
1019 if (isNativeMediaDrmBridgeValid()) { 1184 if (isNativeMediaDrmBridgeValid()) {
1020 nativeOnSessionClosed(mNativeMediaDrmBridge, sessionId.emeId()); 1185 nativeOnSessionClosed(mNativeMediaDrmBridge, sessionId.emeId());
1021 } 1186 }
1022 } 1187 }
1023 1188
1024 private void onSessionKeysChange(final SessionId sessionId, final Object[] k eysInfo, 1189 private void onSessionKeysChange(final SessionId sessionId, final Object[] k eysInfo,
1025 final boolean hasAdditionalUsableKey) { 1190 final boolean hasAdditionalUsableKey, final boolean isKeyRelease) {
1026 if (isNativeMediaDrmBridgeValid()) { 1191 if (isNativeMediaDrmBridgeValid()) {
1027 nativeOnSessionKeysChange( 1192 nativeOnSessionKeysChange(mNativeMediaDrmBridge, sessionId.emeId(), keysInfo,
1028 mNativeMediaDrmBridge, sessionId.emeId(), keysInfo, hasAddit ionalUsableKey); 1193 hasAdditionalUsableKey, isKeyRelease);
1029 } 1194 }
1030 } 1195 }
1031 1196
1032 private void onSessionExpirationUpdate(final SessionId sessionId, final long expirationTime) { 1197 private void onSessionExpirationUpdate(final SessionId sessionId, final long expirationTime) {
1033 if (isNativeMediaDrmBridgeValid()) { 1198 if (isNativeMediaDrmBridgeValid()) {
1034 nativeOnSessionExpirationUpdate( 1199 nativeOnSessionExpirationUpdate(
1035 mNativeMediaDrmBridge, sessionId.emeId(), expirationTime); 1200 mNativeMediaDrmBridge, sessionId.emeId(), expirationTime);
1036 } 1201 }
1037 } 1202 }
1038 1203
(...skipping 13 matching lines...) Expand all
1052 return; 1217 return;
1053 } 1218 }
1054 SessionId sessionId = getSessionIdByDrmId(drmSessionId); 1219 SessionId sessionId = getSessionIdByDrmId(drmSessionId);
1055 1220
1056 if (sessionId == null) { 1221 if (sessionId == null) {
1057 Log.e(TAG, "EventListener: Invalid session %s", 1222 Log.e(TAG, "EventListener: Invalid session %s",
1058 SessionId.toHexString(drmSessionId)); 1223 SessionId.toHexString(drmSessionId));
1059 return; 1224 return;
1060 } 1225 }
1061 1226
1227 SessionInfo sessionInfo = mSessionManager.get(sessionId);
1062 switch(event) { 1228 switch(event) {
1063 case MediaDrm.EVENT_KEY_REQUIRED: 1229 case MediaDrm.EVENT_KEY_REQUIRED:
1064 Log.d(TAG, "MediaDrm.EVENT_KEY_REQUIRED"); 1230 Log.d(TAG, "MediaDrm.EVENT_KEY_REQUIRED");
1065 if (mProvisioningPending) { 1231 if (mProvisioningPending) {
1066 return; 1232 return;
1067 } 1233 }
1068 SessionInfo sessionInfo = mSessionManager.get(sessionId);
1069 MediaDrm.KeyRequest request = null; 1234 MediaDrm.KeyRequest request = null;
1070 try { 1235 try {
1071 request = getKeyRequest(sessionId, data, sessionInfo.mim eType(), 1236 request = getKeyRequest(sessionId, data, sessionInfo.mim eType(),
1072 sessionInfo.keyType(), null); 1237 sessionInfo.keyType(), null);
1073 } catch (android.media.NotProvisionedException e) { 1238 } catch (android.media.NotProvisionedException e) {
1074 Log.e(TAG, "Device not provisioned", e); 1239 Log.e(TAG, "Device not provisioned", e);
1075 startProvisioning(); 1240 startProvisioning();
1076 return; 1241 return;
1077 } 1242 }
1078 if (request != null) { 1243 if (request != null) {
1079 onSessionMessage(sessionId, request); 1244 onSessionMessage(sessionId, request);
1080 } else { 1245 } else {
1081 if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { 1246 if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
1082 onSessionKeysChange(sessionId, 1247 onSessionKeysChange(sessionId,
1083 getDummyKeysInfo(MediaDrm.KeyStatus.STATUS_I NTERNAL_ERROR) 1248 getDummyKeysInfo(MediaDrm.KeyStatus.STATUS_I NTERNAL_ERROR)
1084 .toArray(), 1249 .toArray(),
1085 false); 1250 false, false);
1086 } 1251 }
1087 Log.e(TAG, "EventListener: getKeyRequest failed."); 1252 Log.e(TAG, "EventListener: getKeyRequest failed.");
1088 return; 1253 return;
1089 } 1254 }
1090 break; 1255 break;
1091 case MediaDrm.EVENT_KEY_EXPIRED: 1256 case MediaDrm.EVENT_KEY_EXPIRED:
1092 Log.d(TAG, "MediaDrm.EVENT_KEY_EXPIRED"); 1257 Log.d(TAG, "MediaDrm.EVENT_KEY_EXPIRED");
1093 if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { 1258 if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
1094 onSessionKeysChange(sessionId, 1259 onSessionKeysChange(sessionId,
1095 getDummyKeysInfo(MediaDrm.KeyStatus.STATUS_EXPIR ED).toArray(), 1260 getDummyKeysInfo(MediaDrm.KeyStatus.STATUS_EXPIR ED).toArray(),
1096 false); 1261 false, sessionInfo.keyType() == MediaDrm.KEY_TYP E_RELEASE);
1097 } 1262 }
1098 break; 1263 break;
1099 case MediaDrm.EVENT_VENDOR_DEFINED: 1264 case MediaDrm.EVENT_VENDOR_DEFINED:
1100 Log.d(TAG, "MediaDrm.EVENT_VENDOR_DEFINED"); 1265 Log.d(TAG, "MediaDrm.EVENT_VENDOR_DEFINED");
1101 assert false; // Should never happen. 1266 assert false; // Should never happen.
1102 break; 1267 break;
1103 default: 1268 default:
1104 Log.e(TAG, "Invalid DRM event " + event); 1269 Log.e(TAG, "Invalid DRM event " + event);
1105 return; 1270 return;
1106 } 1271 }
1107 } 1272 }
1108 } 1273 }
1109 1274
1110 @TargetApi(Build.VERSION_CODES.M) 1275 @TargetApi(Build.VERSION_CODES.M)
1111 @MainDex 1276 @MainDex
1112 private class KeyStatusChangeListener implements MediaDrm.OnKeyStatusChangeL istener { 1277 private class KeyStatusChangeListener implements MediaDrm.OnKeyStatusChangeL istener {
1113 private List<KeyStatus> getKeysInfo(List<MediaDrm.KeyStatus> keyInformat ion) { 1278 private List<KeyStatus> getKeysInfo(List<MediaDrm.KeyStatus> keyInformat ion) {
1114 List<KeyStatus> keysInfo = new ArrayList<KeyStatus>(); 1279 List<KeyStatus> keysInfo = new ArrayList<KeyStatus>();
1115 for (MediaDrm.KeyStatus keyStatus : keyInformation) { 1280 for (MediaDrm.KeyStatus keyStatus : keyInformation) {
1116 keysInfo.add(new KeyStatus(keyStatus.getKeyId(), keyStatus.getSt atusCode())); 1281 keysInfo.add(new KeyStatus(keyStatus.getKeyId(), keyStatus.getSt atusCode()));
1117 } 1282 }
1118 return keysInfo; 1283 return keysInfo;
1119 } 1284 }
1120 1285
1121 @Override 1286 @Override
1122 public void onKeyStatusChange(MediaDrm md, byte[] drmSessionId, 1287 public void onKeyStatusChange(MediaDrm md, byte[] drmSessionId,
1123 List<MediaDrm.KeyStatus> keyInformation, boolean hasNewUsableKey ) { 1288 final List<MediaDrm.KeyStatus> keyInformation, final boolean has NewUsableKey) {
1124 SessionId sessionId = getSessionIdByDrmId(drmSessionId); 1289 final SessionId sessionId = getSessionIdByDrmId(drmSessionId);
1125 1290
1126 assert sessionId != null; 1291 assert sessionId != null;
1292 assert mSessionManager.get(sessionId) != null;
1127 1293
1128 Log.d(TAG, "KeysStatusChange: " + sessionId.toHexString() + ", " + h asNewUsableKey); 1294 final boolean isKeyRelease =
1295 mSessionManager.get(sessionId).keyType() == MediaDrm.KEY_TYP E_RELEASE;
1129 1296
1130 onSessionKeysChange(sessionId, getKeysInfo(keyInformation).toArray() , hasNewUsableKey); 1297 deferEventHandleIfNeeded(sessionId, new Runnable() {
1298 @Override
1299 public void run() {
1300 Log.d(TAG,
1301 "KeysStatusChange: " + sessionId.toHexString() + ", "
1302 + hasNewUsableKey);
1303 onSessionKeysChange(sessionId, getKeysInfo(keyInformation).t oArray(),
1304 hasNewUsableKey, isKeyRelease);
1305 }
1306 });
1131 } 1307 }
1132 } 1308 }
1133 1309
1134 @TargetApi(Build.VERSION_CODES.M) 1310 @TargetApi(Build.VERSION_CODES.M)
1135 @MainDex 1311 @MainDex
1136 private class ExpirationUpdateListener implements MediaDrm.OnExpirationUpdat eListener { 1312 private class ExpirationUpdateListener implements MediaDrm.OnExpirationUpdat eListener {
1137 @Override 1313 @Override
1138 public void onExpirationUpdate(MediaDrm md, byte[] drmSessionId, long ex pirationTime) { 1314 public void onExpirationUpdate(
1139 SessionId sessionId = getSessionIdByDrmId(drmSessionId); 1315 MediaDrm md, byte[] drmSessionId, final long expirationTime) {
1316 final SessionId sessionId = getSessionIdByDrmId(drmSessionId);
1140 1317
1141 assert sessionId != null; 1318 assert sessionId != null;
1142 1319
1143 Log.d(TAG, "ExpirationUpdate: " + sessionId.toHexString() + ", " + e xpirationTime); 1320 deferEventHandleIfNeeded(sessionId, new Runnable() {
1144 onSessionExpirationUpdate(sessionId, expirationTime); 1321 @Override
1322 public void run() {
1323 Log.d(TAG,
1324 "ExpirationUpdate: " + sessionId.toHexString() + ", " + expirationTime);
1325 onSessionExpirationUpdate(sessionId, expirationTime);
1326 }
1327 });
1145 } 1328 }
1146 } 1329 }
1147 1330
1331 @MainDex
1332 private class KeyUpdatedCallback extends Callback<Boolean> {
1333 private final SessionId mSessionId;
1334 private final long mPromiseId;
1335 private final boolean mIsKeyRelease;
1336
1337 KeyUpdatedCallback(SessionId sessionId, long promiseId, boolean isKeyRel ease) {
1338 mSessionId = sessionId;
1339 mPromiseId = promiseId;
1340 mIsKeyRelease = isKeyRelease;
1341 }
1342
1343 @Override
1344 public void onResult(Boolean success) {
1345 if (!success) {
1346 onPromiseRejected(mPromiseId, "failed to update key after respon se accepted");
1347 return;
1348 }
1349
1350 Log.d(TAG, "Key successfully %s for session %s", mIsKeyRelease ? "re leased" : "added",
1351 mSessionId.toHexString());
1352 onPromiseResolved(mPromiseId);
1353
1354 if (!mIsKeyRelease && Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
1355 onSessionKeysChange(mSessionId,
1356 getDummyKeysInfo(MediaDrm.KeyStatus.STATUS_USABLE).toArr ay(), true,
1357 mIsKeyRelease);
1358 }
1359 }
1360 }
1361
1148 // Native functions. At the native side, must post the task immediately to 1362 // Native functions. At the native side, must post the task immediately to
1149 // avoid reentrancy issues. 1363 // avoid reentrancy issues.
1150 private native void nativeOnMediaCryptoReady( 1364 private native void nativeOnMediaCryptoReady(
1151 long nativeMediaDrmBridge, MediaCrypto mediaCrypto); 1365 long nativeMediaDrmBridge, MediaCrypto mediaCrypto);
1152 1366
1153 private native void nativeOnStartProvisioning( 1367 private native void nativeOnStartProvisioning(
1154 long nativeMediaDrmBridge, String defaultUrl, byte[] requestData); 1368 long nativeMediaDrmBridge, String defaultUrl, byte[] requestData);
1155 1369
1156 private native void nativeOnPromiseResolved(long nativeMediaDrmBridge, long promiseId); 1370 private native void nativeOnPromiseResolved(long nativeMediaDrmBridge, long promiseId);
1157 private native void nativeOnPromiseResolvedWithSession( 1371 private native void nativeOnPromiseResolvedWithSession(
1158 long nativeMediaDrmBridge, long promiseId, byte[] emeSessionId); 1372 long nativeMediaDrmBridge, long promiseId, byte[] emeSessionId);
1159 private native void nativeOnPromiseRejected( 1373 private native void nativeOnPromiseRejected(
1160 long nativeMediaDrmBridge, long promiseId, String errorMessage); 1374 long nativeMediaDrmBridge, long promiseId, String errorMessage);
1161 1375
1162 private native void nativeOnSessionMessage( 1376 private native void nativeOnSessionMessage(
1163 long nativeMediaDrmBridge, byte[] emeSessionId, int requestType, byt e[] message); 1377 long nativeMediaDrmBridge, byte[] emeSessionId, int requestType, byt e[] message);
1164 private native void nativeOnSessionClosed(long nativeMediaDrmBridge, byte[] emeSessionId); 1378 private native void nativeOnSessionClosed(long nativeMediaDrmBridge, byte[] emeSessionId);
1165 private native void nativeOnSessionKeysChange(long nativeMediaDrmBridge, byt e[] emeSessionId, 1379 private native void nativeOnSessionKeysChange(long nativeMediaDrmBridge, byt e[] emeSessionId,
1166 Object[] keysInfo, boolean hasAdditionalUsableKey); 1380 Object[] keysInfo, boolean hasAdditionalUsableKey, boolean isKeyRele ase);
1167 private native void nativeOnSessionExpirationUpdate( 1381 private native void nativeOnSessionExpirationUpdate(
1168 long nativeMediaDrmBridge, byte[] emeSessionId, long expirationTime) ; 1382 long nativeMediaDrmBridge, byte[] emeSessionId, long expirationTime) ;
1169 1383
1170 private native void nativeOnResetDeviceCredentialsCompleted( 1384 private native void nativeOnResetDeviceCredentialsCompleted(
1171 long nativeMediaDrmBridge, boolean success); 1385 long nativeMediaDrmBridge, boolean success);
1172 } 1386 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698