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.TargetApi; | 7 import android.annotation.TargetApi; |
8 import android.media.MediaCrypto; | 8 import android.media.MediaCrypto; |
9 import android.media.MediaDrm; | 9 import android.media.MediaDrm; |
10 import android.os.AsyncTask; | |
11 import android.os.Build; | 10 import android.os.Build; |
12 | 11 |
13 import org.chromium.base.Log; | 12 import org.chromium.base.Log; |
14 import org.chromium.base.annotations.CalledByNative; | 13 import org.chromium.base.annotations.CalledByNative; |
15 import org.chromium.base.annotations.JNINamespace; | 14 import org.chromium.base.annotations.JNINamespace; |
16 | 15 |
17 import java.io.BufferedInputStream; | |
18 import java.io.ByteArrayOutputStream; | |
19 import java.io.IOException; | |
20 import java.net.HttpURLConnection; | |
21 import java.net.MalformedURLException; | |
22 import java.net.URL; | |
23 import java.nio.ByteBuffer; | 16 import java.nio.ByteBuffer; |
24 import java.util.ArrayDeque; | 17 import java.util.ArrayDeque; |
25 import java.util.ArrayList; | 18 import java.util.ArrayList; |
26 import java.util.Arrays; | 19 import java.util.Arrays; |
27 import java.util.HashMap; | 20 import java.util.HashMap; |
28 import java.util.List; | 21 import java.util.List; |
29 import java.util.UUID; | 22 import java.util.UUID; |
30 | 23 |
31 /** | 24 /** |
32 * A wrapper of the android MediaDrm class. Each MediaDrmBridge manages multiple | 25 * A wrapper of the android MediaDrm class. Each MediaDrmBridge manages multiple |
(...skipping 17 matching lines...) Expand all Loading... | |
50 // b) Finish createSession() if previous createSession() was interrupted | 43 // b) Finish createSession() if previous createSession() was interrupted |
51 // by a NotProvisionedException. | 44 // by a NotProvisionedException. |
52 // - Whenever an unexpected error occurred, we'll call release() to release | 45 // - Whenever an unexpected error occurred, we'll call release() to release |
53 // all resources and clear all states. In that case all calls to this | 46 // all resources and clear all states. In that case all calls to this |
54 // object will be no-op. All public APIs and callbacks should check | 47 // object will be no-op. All public APIs and callbacks should check |
55 // mMediaBridge to make sure release() hasn't been called. Also, we call | 48 // mMediaBridge to make sure release() hasn't been called. Also, we call |
56 // release() immediately after the error happens (e.g. after mMediaDrm) | 49 // release() immediately after the error happens (e.g. after mMediaDrm) |
57 // calls. Indirect calls should not call release() again to avoid | 50 // calls. Indirect calls should not call release() again to avoid |
58 // duplication (even though it doesn't hurt to call release() twice). | 51 // duplication (even though it doesn't hurt to call release() twice). |
59 | 52 |
60 private static final String TAG = "cr.media"; | 53 private static final String TAG = "cr_media"; |
61 private static final String SECURITY_LEVEL = "securityLevel"; | 54 private static final String SECURITY_LEVEL = "securityLevel"; |
62 private static final String SERVER_CERTIFICATE = "serviceCertificate"; | 55 private static final String SERVER_CERTIFICATE = "serviceCertificate"; |
63 private static final String PRIVACY_MODE = "privacyMode"; | 56 private static final String PRIVACY_MODE = "privacyMode"; |
64 private static final String SESSION_SHARING = "sessionSharing"; | 57 private static final String SESSION_SHARING = "sessionSharing"; |
65 private static final String ENABLE = "enable"; | 58 private static final String ENABLE = "enable"; |
66 private static final int INVALID_SESSION_ID = 0; | 59 private static final int INVALID_SESSION_ID = 0; |
67 private static final char[] HEX_CHAR_LOOKUP = "0123456789ABCDEF".toCharArray (); | 60 private static final char[] HEX_CHAR_LOOKUP = "0123456789ABCDEF".toCharArray (); |
68 private static final long INVALID_NATIVE_MEDIA_DRM_BRIDGE = 0; | 61 private static final long INVALID_NATIVE_MEDIA_DRM_BRIDGE = 0; |
69 | 62 |
70 // On Android L and before, MediaDrm doesn't support KeyStatus. Use a dummy | 63 // On Android L and before, MediaDrm doesn't support KeyStatus. Use a dummy |
(...skipping 335 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
406 private MediaCrypto getMediaCrypto() { | 399 private MediaCrypto getMediaCrypto() { |
407 return mMediaCrypto; | 400 return mMediaCrypto; |
408 } | 401 } |
409 | 402 |
410 /** | 403 /** |
411 * Reset the device DRM credentials. | 404 * Reset the device DRM credentials. |
412 */ | 405 */ |
413 @CalledByNative | 406 @CalledByNative |
414 private void resetDeviceCredentials() { | 407 private void resetDeviceCredentials() { |
415 mResetDeviceCredentialsPending = true; | 408 mResetDeviceCredentialsPending = true; |
416 MediaDrm.ProvisionRequest request = mMediaDrm.getProvisionRequest(); | 409 startProvisioning(); |
417 PostRequestTask postTask = new PostRequestTask(request.getData()); | |
418 postTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, request.getDe faultUrl()); | |
419 } | 410 } |
420 | 411 |
421 /** | 412 /** |
422 * Destroy the MediaDrmBridge object. | 413 * Destroy the MediaDrmBridge object. |
423 */ | 414 */ |
424 @CalledByNative | 415 @CalledByNative |
425 private void destroy() { | 416 private void destroy() { |
426 mNativeMediaDrmBridge = INVALID_NATIVE_MEDIA_DRM_BRIDGE; | 417 mNativeMediaDrmBridge = INVALID_NATIVE_MEDIA_DRM_BRIDGE; |
427 if (mMediaDrm != null) { | 418 if (mMediaDrm != null) { |
428 release(); | 419 release(); |
(...skipping 304 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
733 @CalledByNative | 724 @CalledByNative |
734 private String getSecurityLevel() { | 725 private String getSecurityLevel() { |
735 if (mMediaDrm == null) { | 726 if (mMediaDrm == null) { |
736 Log.e(TAG, "getSecurityLevel() called when MediaDrm is null."); | 727 Log.e(TAG, "getSecurityLevel() called when MediaDrm is null."); |
737 return null; | 728 return null; |
738 } | 729 } |
739 return mMediaDrm.getPropertyString("securityLevel"); | 730 return mMediaDrm.getPropertyString("securityLevel"); |
740 } | 731 } |
741 | 732 |
742 private void startProvisioning() { | 733 private void startProvisioning() { |
734 if (mProvisioningPending) { | |
735 Log.d(TAG, "startProvisioning: another provisioning is in progress, returning"); | |
736 return; | |
737 } | |
738 | |
743 Log.d(TAG, "startProvisioning"); | 739 Log.d(TAG, "startProvisioning"); |
740 mProvisioningPending = true; | |
744 assert mMediaDrm != null; | 741 assert mMediaDrm != null; |
745 assert !mProvisioningPending; | |
746 mProvisioningPending = true; | |
747 MediaDrm.ProvisionRequest request = mMediaDrm.getProvisionRequest(); | 742 MediaDrm.ProvisionRequest request = mMediaDrm.getProvisionRequest(); |
748 PostRequestTask postTask = new PostRequestTask(request.getData()); | 743 |
749 postTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, request.getDe faultUrl()); | 744 if (isNativeMediaDrmBridgeValid()) { |
745 nativeOnStartProvisioning( | |
746 mNativeMediaDrmBridge, request.getDefaultUrl(), request.getD ata()); | |
747 } | |
750 } | 748 } |
751 | 749 |
752 /** | 750 /** |
753 * Called when the provision response is received. | 751 * Called when the provision response is received. |
754 * | 752 * |
755 * @param response Response data from the provision server. | 753 * @param response Response data from the provision server. |
756 */ | 754 */ |
757 private void onProvisionResponse(byte[] response) { | 755 @CalledByNative |
758 Log.d(TAG, "onProvisionResponse()"); | 756 private void processProvisionResponse(boolean success, byte[] response) { |
757 Log.d(TAG, "processProvisionResponse()"); | |
759 assert mProvisioningPending; | 758 assert mProvisioningPending; |
760 mProvisioningPending = false; | 759 mProvisioningPending = false; |
761 | 760 |
762 // If |mMediaDrm| is released, there is no need to callback native. | 761 // If |mMediaDrm| is released, there is no need to callback native. |
763 if (mMediaDrm == null) { | 762 if (mMediaDrm == null) { |
764 return; | 763 return; |
765 } | 764 } |
766 | 765 |
767 boolean success = provideProvisionResponse(response); | 766 if (success) { |
767 success = provideProvisionResponse(response); | |
xhwang
2015/11/13 05:15:42
nit: usually we don't change the input parameter.
Tima Vaisburd
2015/11/13 21:04:44
Done.
| |
768 } | |
768 | 769 |
769 if (mResetDeviceCredentialsPending) { | 770 if (mResetDeviceCredentialsPending) { |
770 onResetDeviceCredentialsCompleted(success); | 771 onResetDeviceCredentialsCompleted(success); |
771 mResetDeviceCredentialsPending = false; | 772 mResetDeviceCredentialsPending = false; |
772 } | 773 } |
773 | 774 |
774 if (success) { | 775 if (success) { |
775 processPendingCreateSessionData(); | 776 processPendingCreateSessionData(); |
776 } | 777 } |
777 } | 778 } |
778 | 779 |
779 /** | 780 /** |
780 * Provide the provisioning response to MediaDrm. | 781 * Provides the provision response to MediaDrm. |
781 * | 782 * |
782 * @returns false if the response is invalid or on error, true otherwise. | 783 * @returns false if the response is invalid or on error, true otherwise. |
783 */ | 784 */ |
784 boolean provideProvisionResponse(byte[] response) { | 785 boolean provideProvisionResponse(byte[] response) { |
785 if (response == null || response.length == 0) { | 786 if (response == null || response.length == 0) { |
786 Log.e(TAG, "Invalid provision response."); | 787 Log.e(TAG, "Invalid provision response."); |
787 return false; | 788 return false; |
788 } | 789 } |
789 | 790 |
790 try { | 791 try { |
(...skipping 168 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
959 | 960 |
960 @TargetApi(Build.VERSION_CODES.M) | 961 @TargetApi(Build.VERSION_CODES.M) |
961 private class ExpirationUpdateListener implements MediaDrm.OnExpirationUpdat eListener { | 962 private class ExpirationUpdateListener implements MediaDrm.OnExpirationUpdat eListener { |
962 @Override | 963 @Override |
963 public void onExpirationUpdate(MediaDrm md, byte[] sessionId, long expir ationTime) { | 964 public void onExpirationUpdate(MediaDrm md, byte[] sessionId, long expir ationTime) { |
964 Log.d(TAG, "ExpirationUpdate: " + bytesToHexString(sessionId) + ", " + expirationTime); | 965 Log.d(TAG, "ExpirationUpdate: " + bytesToHexString(sessionId) + ", " + expirationTime); |
965 onSessionExpirationUpdate(sessionId, expirationTime); | 966 onSessionExpirationUpdate(sessionId, expirationTime); |
966 } | 967 } |
967 } | 968 } |
968 | 969 |
969 private class PostRequestTask extends AsyncTask<String, Void, Void> { | |
970 private static final String TAG = "PostRequestTask"; | |
971 | |
972 private byte[] mDrmRequest; | |
973 private byte[] mResponseBody; | |
974 | |
975 public PostRequestTask(byte[] drmRequest) { | |
976 mDrmRequest = drmRequest; | |
977 } | |
978 | |
979 @Override | |
980 protected Void doInBackground(String... urls) { | |
981 mResponseBody = postRequest(urls[0], mDrmRequest); | |
982 if (mResponseBody != null) { | |
983 Log.d(TAG, "response length=%d", mResponseBody.length); | |
984 } | |
985 return null; | |
986 } | |
987 | |
988 private byte[] postRequest(String url, byte[] drmRequest) { | |
989 HttpURLConnection urlConnection = null; | |
990 try { | |
991 URL request = new URL(url + "&signedRequest=" + new String(drmRe quest)); | |
992 urlConnection = (HttpURLConnection) request.openConnection(); | |
993 urlConnection.setDoOutput(true); | |
994 urlConnection.setDoInput(true); | |
995 urlConnection.setUseCaches(false); | |
996 urlConnection.setRequestMethod("POST"); | |
997 urlConnection.setRequestProperty("User-Agent", "Widevine CDM v1. 0"); | |
998 urlConnection.setRequestProperty("Content-Type", "application/js on"); | |
999 | |
1000 int responseCode = urlConnection.getResponseCode(); | |
1001 if (responseCode == 200) { | |
1002 BufferedInputStream bis = | |
1003 new BufferedInputStream(urlConnection.getInputStream ()); | |
1004 ByteArrayOutputStream bos = new ByteArrayOutputStream(); | |
1005 int read = 0; | |
1006 int bufferSize = 512; | |
1007 byte[] buffer = new byte[bufferSize]; | |
1008 try { | |
1009 while (true) { | |
1010 read = bis.read(buffer); | |
1011 if (read == -1) break; | |
1012 bos.write(buffer, 0, read); | |
1013 } | |
1014 } finally { | |
1015 bis.close(); | |
1016 } | |
1017 return bos.toByteArray(); | |
1018 } else { | |
1019 Log.d(TAG, "Server returned HTTP error code %d", responseCod e); | |
1020 return null; | |
1021 } | |
1022 } catch (MalformedURLException e) { | |
1023 e.printStackTrace(); | |
1024 } catch (IOException e) { | |
1025 e.printStackTrace(); | |
1026 } catch (IllegalStateException e) { | |
1027 e.printStackTrace(); | |
1028 } finally { | |
1029 if (urlConnection != null) urlConnection.disconnect(); | |
1030 } | |
1031 return null; | |
1032 } | |
1033 | |
1034 @Override | |
1035 protected void onPostExecute(Void v) { | |
1036 onProvisionResponse(mResponseBody); | |
1037 } | |
1038 } | |
1039 | |
1040 // Native functions. At the native side, must post the task immediately to | 970 // Native functions. At the native side, must post the task immediately to |
1041 // avoid reentrancy issues. | 971 // avoid reentrancy issues. |
1042 private native void nativeOnMediaCryptoReady(long nativeMediaDrmBridge); | 972 private native void nativeOnMediaCryptoReady(long nativeMediaDrmBridge); |
1043 | 973 |
974 private native void nativeOnStartProvisioning( | |
975 long nativeMediaDrmBridge, String defaultUrl, byte[] requestData); | |
976 | |
1044 private native void nativeOnPromiseResolved(long nativeMediaDrmBridge, long promiseId); | 977 private native void nativeOnPromiseResolved(long nativeMediaDrmBridge, long promiseId); |
1045 private native void nativeOnPromiseResolvedWithSession( | 978 private native void nativeOnPromiseResolvedWithSession( |
1046 long nativeMediaDrmBridge, long promiseId, byte[] sessionId); | 979 long nativeMediaDrmBridge, long promiseId, byte[] sessionId); |
1047 private native void nativeOnPromiseRejected( | 980 private native void nativeOnPromiseRejected( |
1048 long nativeMediaDrmBridge, long promiseId, String errorMessage); | 981 long nativeMediaDrmBridge, long promiseId, String errorMessage); |
1049 | 982 |
1050 private native void nativeOnSessionMessage(long nativeMediaDrmBridge, byte[] sessionId, | 983 private native void nativeOnSessionMessage(long nativeMediaDrmBridge, byte[] sessionId, |
1051 int requestType, byte[] message, String destinationUrl); | 984 int requestType, byte[] message, String destinationUrl); |
1052 private native void nativeOnSessionClosed(long nativeMediaDrmBridge, byte[] sessionId); | 985 private native void nativeOnSessionClosed(long nativeMediaDrmBridge, byte[] sessionId); |
1053 private native void nativeOnSessionKeysChange(long nativeMediaDrmBridge, byt e[] sessionId, | 986 private native void nativeOnSessionKeysChange(long nativeMediaDrmBridge, byt e[] sessionId, |
1054 Object[] keysInfo, boolean hasAdditionalUsableKey); | 987 Object[] keysInfo, boolean hasAdditionalUsableKey); |
1055 private native void nativeOnSessionExpirationUpdate( | 988 private native void nativeOnSessionExpirationUpdate( |
1056 long nativeMediaDrmBridge, byte[] sessionId, long expirationTime); | 989 long nativeMediaDrmBridge, byte[] sessionId, long expirationTime); |
1057 private native void nativeOnLegacySessionError( | 990 private native void nativeOnLegacySessionError( |
1058 long nativeMediaDrmBridge, byte[] sessionId, String errorMessage); | 991 long nativeMediaDrmBridge, byte[] sessionId, String errorMessage); |
1059 | 992 |
1060 private native void nativeOnResetDeviceCredentialsCompleted( | 993 private native void nativeOnResetDeviceCredentialsCompleted( |
1061 long nativeMediaDrmBridge, boolean success); | 994 long nativeMediaDrmBridge, boolean success); |
1062 } | 995 } |
OLD | NEW |