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

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

Issue 1427183002: Move MediaDrmBridge provision communication to native side. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Bound network context into callback function instead of using factory Created 5 years, 1 month 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.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
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
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
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
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 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698