Loading Android.mk +2 −4 Original line number Original line Diff line number Diff line Loading @@ -437,10 +437,6 @@ LOCAL_SRC_FILES += \ location/java/android/location/INetInitiatedListener.aidl \ location/java/android/location/INetInitiatedListener.aidl \ location/java/com/android/internal/location/ILocationProvider.aidl \ location/java/com/android/internal/location/ILocationProvider.aidl \ media/java/android/media/IAudioService.aidl \ media/java/android/media/IAudioService.aidl \ ../av/drm/libmediadrm/aidl/android/media/ICas.aidl \ ../av/drm/libmediadrm/aidl/android/media/ICasListener.aidl \ ../av/drm/libmediadrm/aidl/android/media/IDescrambler.aidl \ ../av/drm/libmediadrm/aidl/android/media/IMediaCasService.aidl \ media/java/android/media/IAudioFocusDispatcher.aidl \ media/java/android/media/IAudioFocusDispatcher.aidl \ media/java/android/media/IAudioRoutesObserver.aidl \ media/java/android/media/IAudioRoutesObserver.aidl \ media/java/android/media/IMediaHTTPConnection.aidl \ media/java/android/media/IMediaHTTPConnection.aidl \ Loading Loading @@ -613,6 +609,8 @@ LOCAL_STATIC_JAVA_LIBRARIES := \ android.hardware.vibrator-V1.1-java-constants \ android.hardware.vibrator-V1.1-java-constants \ android.hardware.wifi-V1.0-java-constants \ android.hardware.wifi-V1.0-java-constants \ include hardware/interfaces/cas/1.0/CasHal.mk # Loaded with System.loadLibrary by android.view.textclassifier # Loaded with System.loadLibrary by android.view.textclassifier LOCAL_REQUIRED_MODULES += libtextclassifier LOCAL_REQUIRED_MODULES += libtextclassifier Loading media/java/android/media/MediaCas.java +78 −130 Original line number Original line Diff line number Diff line Loading @@ -18,21 +18,20 @@ package android.media; import android.annotation.NonNull; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.Nullable; import android.hardware.cas.V1_0.*; import android.media.MediaCasException.*; import android.media.MediaCasException.*; import android.os.Handler; import android.os.Handler; import android.os.HandlerThread; import android.os.HandlerThread; import android.os.IBinder; import android.os.IHwBinder; import android.os.Looper; import android.os.Looper; import android.os.Message; import android.os.Message; import android.os.Parcel; import android.os.Parcelable; import android.os.Process; import android.os.Process; import android.os.RemoteException; import android.os.RemoteException; import android.os.ServiceManager; import android.os.ServiceSpecificException; import android.util.Log; import android.util.Log; import android.util.Singleton; import android.util.Singleton; import java.util.ArrayList; /** /** * MediaCas can be used to obtain keys for descrambling protected media streams, in * MediaCas can be used to obtain keys for descrambling protected media streams, in * conjunction with {@link android.media.MediaDescrambler}. The MediaCas APIs are * conjunction with {@link android.media.MediaDescrambler}. The MediaCas APIs are Loading Loading @@ -95,7 +94,6 @@ import android.util.Singleton; */ */ public final class MediaCas implements AutoCloseable { public final class MediaCas implements AutoCloseable { private static final String TAG = "MediaCas"; private static final String TAG = "MediaCas"; private final ParcelableCasData mCasData = new ParcelableCasData(); private ICas mICas; private ICas mICas; private EventListener mListener; private EventListener mListener; private HandlerThread mHandlerThread; private HandlerThread mHandlerThread; Loading @@ -105,8 +103,10 @@ public final class MediaCas implements AutoCloseable { new Singleton<IMediaCasService>() { new Singleton<IMediaCasService>() { @Override @Override protected IMediaCasService create() { protected IMediaCasService create() { return IMediaCasService.Stub.asInterface( try { ServiceManager.getService("media.cas")); return IMediaCasService.getService(); } catch (RemoteException e) {} return null; } } }; }; Loading Loading @@ -136,65 +136,21 @@ public final class MediaCas implements AutoCloseable { @Override @Override public void handleMessage(Message msg) { public void handleMessage(Message msg) { if (msg.what == MSG_CAS_EVENT) { if (msg.what == MSG_CAS_EVENT) { mListener.onEvent(MediaCas.this, msg.arg1, msg.arg2, (byte[]) msg.obj); mListener.onEvent(MediaCas.this, msg.arg1, msg.arg2, toBytes((ArrayList<Byte>) msg.obj)); } } } } } } private final ICasListener.Stub mBinder = new ICasListener.Stub() { private final ICasListener.Stub mBinder = new ICasListener.Stub() { @Override @Override public void onEvent(int event, int arg, @Nullable byte[] data) public void onEvent(int event, int arg, @Nullable ArrayList<Byte> data) throws RemoteException { throws RemoteException { mEventHandler.sendMessage(mEventHandler.obtainMessage( mEventHandler.sendMessage(mEventHandler.obtainMessage( EventHandler.MSG_CAS_EVENT, event, arg, data)); EventHandler.MSG_CAS_EVENT, event, arg, data)); } } }; }; /** * Class for parceling byte array data over ICas binder. */ static class ParcelableCasData implements Parcelable { private byte[] mData; private int mOffset; private int mLength; ParcelableCasData() { mData = null; mOffset = mLength = 0; } private ParcelableCasData(Parcel in) { this(); } void set(@NonNull byte[] data, int offset, int length) { mData = data; mOffset = offset; mLength = length; } @Override public int describeContents() { return 0; } @Override public void writeToParcel(Parcel dest, int flags) { dest.writeByteArray(mData, mOffset, mLength); } public static final Parcelable.Creator<ParcelableCasData> CREATOR = new Parcelable.Creator<ParcelableCasData>() { public ParcelableCasData createFromParcel(Parcel in) { return new ParcelableCasData(in); } public ParcelableCasData[] newArray(int size) { return new ParcelableCasData[size]; } }; } /** /** * Describe a CAS plugin with its CA_system_ID and string name. * Describe a CAS plugin with its CA_system_ID and string name. * * Loading @@ -210,9 +166,9 @@ public final class MediaCas implements AutoCloseable { mName = null; mName = null; } } PluginDescriptor(int CA_system_id, String name) { PluginDescriptor(@NonNull HidlCasPluginDescriptor descriptor) { mCASystemId = CA_system_id; mCASystemId = descriptor.caSystemId; mName = name; mName = descriptor.name; } } public int getSystemId() { public int getSystemId() { Loading @@ -230,13 +186,38 @@ public final class MediaCas implements AutoCloseable { } } } } private ArrayList<Byte> toByteArray(@NonNull byte[] data, int offset, int length) { ArrayList<Byte> byteArray = new ArrayList<Byte>(length); for (int i = 0; i < length; i++) { byteArray.add(Byte.valueOf(data[offset + i])); } return byteArray; } private ArrayList<Byte> toByteArray(@Nullable byte[] data) { if (data == null) { return new ArrayList<Byte>(); } return toByteArray(data, 0, data.length); } private byte[] toBytes(@NonNull ArrayList<Byte> byteArray) { byte[] data = null; if (byteArray != null) { data = new byte[byteArray.size()]; for (int i = 0; i < data.length; i++) { data[i] = byteArray.get(i); } } return data; } /** /** * Class for an open session with the CA system. * Class for an open session with the CA system. */ */ public final class Session implements AutoCloseable { public final class Session implements AutoCloseable { final byte[] mSessionId; final ArrayList<Byte> mSessionId; Session(@NonNull byte[] sessionId) { Session(@NonNull ArrayList<Byte> sessionId) { mSessionId = sessionId; mSessionId = sessionId; } } Loading @@ -254,9 +235,8 @@ public final class MediaCas implements AutoCloseable { validateInternalStates(); validateInternalStates(); try { try { mICas.setSessionPrivateData(mSessionId, data); MediaCasException.throwExceptionIfNeeded( } catch (ServiceSpecificException e) { mICas.setSessionPrivateData(mSessionId, toByteArray(data, 0, data.length))); MediaCasException.throwExceptions(e); } catch (RemoteException e) { } catch (RemoteException e) { cleanupAndRethrowIllegalState(); cleanupAndRethrowIllegalState(); } } Loading @@ -279,10 +259,8 @@ public final class MediaCas implements AutoCloseable { validateInternalStates(); validateInternalStates(); try { try { mCasData.set(data, offset, length); MediaCasException.throwExceptionIfNeeded( mICas.processEcm(mSessionId, mCasData); mICas.processEcm(mSessionId, toByteArray(data, offset, length))); } catch (ServiceSpecificException e) { MediaCasException.throwExceptions(e); } catch (RemoteException e) { } catch (RemoteException e) { cleanupAndRethrowIllegalState(); cleanupAndRethrowIllegalState(); } } Loading Loading @@ -314,56 +292,21 @@ public final class MediaCas implements AutoCloseable { validateInternalStates(); validateInternalStates(); try { try { mICas.closeSession(mSessionId); MediaCasStateException.throwExceptionIfNeeded( } catch (ServiceSpecificException e) { mICas.closeSession(mSessionId)); MediaCasStateException.throwExceptions(e); } catch (RemoteException e) { } catch (RemoteException e) { cleanupAndRethrowIllegalState(); cleanupAndRethrowIllegalState(); } } } } } } Session createFromSessionId(byte[] sessionId) { Session createFromSessionId(@NonNull ArrayList<Byte> sessionId) { if (sessionId == null || sessionId.length == 0) { if (sessionId == null || sessionId.size() == 0) { return null; return null; } } return new Session(sessionId); return new Session(sessionId); } } /** * Class for parceling CAS plugin descriptors over IMediaCasService binder. */ static class ParcelableCasPluginDescriptor extends PluginDescriptor implements Parcelable { private ParcelableCasPluginDescriptor(int CA_system_id, String name) { super(CA_system_id, name); } @Override public int describeContents() { return 0; } @Override public void writeToParcel(Parcel dest, int flags) { Log.w(TAG, "ParcelableCasPluginDescriptor.writeToParcel shouldn't be called!"); } public static final Parcelable.Creator<ParcelableCasPluginDescriptor> CREATOR = new Parcelable.Creator<ParcelableCasPluginDescriptor>() { public ParcelableCasPluginDescriptor createFromParcel(Parcel in) { int CA_system_id = in.readInt(); String name = in.readString(); return new ParcelableCasPluginDescriptor(CA_system_id, name); } public ParcelableCasPluginDescriptor[] newArray(int size) { return new ParcelableCasPluginDescriptor[size]; } }; } /** /** * Query if a certain CA system is supported on this device. * Query if a certain CA system is supported on this device. * * Loading Loading @@ -393,13 +336,14 @@ public final class MediaCas implements AutoCloseable { if (service != null) { if (service != null) { try { try { ParcelableCasPluginDescriptor[] descriptors = service.enumeratePlugins(); ArrayList<HidlCasPluginDescriptor> descriptors = if (descriptors.length == 0) { service.enumeratePlugins(); if (descriptors.size() == 0) { return null; return null; } } PluginDescriptor[] results = new PluginDescriptor[descriptors.length]; PluginDescriptor[] results = new PluginDescriptor[descriptors.size()]; for (int i = 0; i < results.length; i++) { for (int i = 0; i < results.length; i++) { results[i] = descriptors[i]; results[i] = new PluginDescriptor(descriptors.get(i)); } } return results; return results; } catch (RemoteException e) { } catch (RemoteException e) { Loading Loading @@ -430,7 +374,7 @@ public final class MediaCas implements AutoCloseable { } } } } IBinder getBinder() { IHwBinder getBinder() { validateInternalStates(); validateInternalStates(); return mICas.asBinder(); return mICas.asBinder(); Loading Loading @@ -497,14 +441,22 @@ public final class MediaCas implements AutoCloseable { validateInternalStates(); validateInternalStates(); try { try { mICas.setPrivateData(data); MediaCasException.throwExceptionIfNeeded( } catch (ServiceSpecificException e) { mICas.setPrivateData(toByteArray(data, 0, data.length))); MediaCasException.throwExceptions(e); } catch (RemoteException e) { } catch (RemoteException e) { cleanupAndRethrowIllegalState(); cleanupAndRethrowIllegalState(); } } } } private class OpenSessionCallback implements ICas.openSessionCallback { public Session mSession; public int mStatus; @Override public void onValues(int status, ArrayList<Byte> sessionId) { mStatus = status; mSession = createFromSessionId(sessionId); } } /** /** * Open a session to descramble one or more streams scrambled by the * Open a session to descramble one or more streams scrambled by the * conditional access system. * conditional access system. Loading @@ -519,9 +471,10 @@ public final class MediaCas implements AutoCloseable { validateInternalStates(); validateInternalStates(); try { try { return createFromSessionId(mICas.openSession()); OpenSessionCallback cb = new OpenSessionCallback(); } catch (ServiceSpecificException e) { mICas.openSession(cb); MediaCasException.throwExceptions(e); MediaCasException.throwExceptionIfNeeded(cb.mStatus); return cb.mSession; } catch (RemoteException e) { } catch (RemoteException e) { cleanupAndRethrowIllegalState(); cleanupAndRethrowIllegalState(); } } Loading @@ -544,10 +497,8 @@ public final class MediaCas implements AutoCloseable { validateInternalStates(); validateInternalStates(); try { try { mCasData.set(data, offset, length); MediaCasException.throwExceptionIfNeeded( mICas.processEmm(mCasData); mICas.processEmm(toByteArray(data, offset, length))); } catch (ServiceSpecificException e) { MediaCasException.throwExceptions(e); } catch (RemoteException e) { } catch (RemoteException e) { cleanupAndRethrowIllegalState(); cleanupAndRethrowIllegalState(); } } Loading Loading @@ -585,9 +536,8 @@ public final class MediaCas implements AutoCloseable { validateInternalStates(); validateInternalStates(); try { try { mICas.sendEvent(event, arg, data); MediaCasException.throwExceptionIfNeeded( } catch (ServiceSpecificException e) { mICas.sendEvent(event, arg, toByteArray(data))); MediaCasException.throwExceptions(e); } catch (RemoteException e) { } catch (RemoteException e) { cleanupAndRethrowIllegalState(); cleanupAndRethrowIllegalState(); } } Loading @@ -608,9 +558,8 @@ public final class MediaCas implements AutoCloseable { validateInternalStates(); validateInternalStates(); try { try { mICas.provision(provisionString); MediaCasException.throwExceptionIfNeeded( } catch (ServiceSpecificException e) { mICas.provision(provisionString)); MediaCasException.throwExceptions(e); } catch (RemoteException e) { } catch (RemoteException e) { cleanupAndRethrowIllegalState(); cleanupAndRethrowIllegalState(); } } Loading @@ -631,9 +580,8 @@ public final class MediaCas implements AutoCloseable { validateInternalStates(); validateInternalStates(); try { try { mICas.refreshEntitlements(refreshType, refreshData); MediaCasException.throwExceptionIfNeeded( } catch (ServiceSpecificException e) { mICas.refreshEntitlements(refreshType, toByteArray(refreshData))); MediaCasException.throwExceptions(e); } catch (RemoteException e) { } catch (RemoteException e) { cleanupAndRethrowIllegalState(); cleanupAndRethrowIllegalState(); } } Loading media/java/android/media/MediaCasException.java +14 −45 Original line number Original line Diff line number Diff line Loading @@ -16,60 +16,29 @@ package android.media; package android.media; import android.os.ServiceSpecificException; import android.hardware.cas.V1_0.Status; /** /** * Base class for MediaCas exceptions * Base class for MediaCas exceptions */ */ public class MediaCasException extends Exception { public class MediaCasException extends Exception { private MediaCasException(String detailMessage) { /** @hide */ public static final int DRM_ERROR_BASE = -2000; /** @hide */ public static final int ERROR_DRM_UNKNOWN = DRM_ERROR_BASE; /** @hide */ public static final int ERROR_DRM_NO_LICENSE = DRM_ERROR_BASE - 1; /** @hide */ public static final int ERROR_DRM_LICENSE_EXPIRED = DRM_ERROR_BASE - 2; /** @hide */ public static final int ERROR_DRM_SESSION_NOT_OPENED = DRM_ERROR_BASE - 3; /** @hide */ public static final int ERROR_DRM_DECRYPT_UNIT_NOT_INITIALIZED = DRM_ERROR_BASE - 4; /** @hide */ public static final int ERROR_DRM_DECRYPT = DRM_ERROR_BASE - 5; /** @hide */ public static final int ERROR_DRM_CANNOT_HANDLE = DRM_ERROR_BASE - 6; /** @hide */ public static final int ERROR_DRM_TAMPER_DETECTED = DRM_ERROR_BASE - 7; /** @hide */ public static final int ERROR_DRM_NOT_PROVISIONED = DRM_ERROR_BASE - 8; /** @hide */ public static final int ERROR_DRM_DEVICE_REVOKED = DRM_ERROR_BASE - 9; /** @hide */ public static final int ERROR_DRM_RESOURCE_BUSY = DRM_ERROR_BASE - 10; /** @hide */ public static final int ERROR_DRM_INSUFFICIENT_OUTPUT_PROTECTION = DRM_ERROR_BASE - 11; /** @hide */ public static final int ERROR_DRM_LAST_USED_ERRORCODE = DRM_ERROR_BASE - 11; /** @hide */ public static final int ERROR_DRM_VENDOR_MAX = DRM_ERROR_BASE - 500; /** @hide */ public static final int ERROR_DRM_VENDOR_MIN = DRM_ERROR_BASE - 999; /** @hide */ public MediaCasException(String detailMessage) { super(detailMessage); super(detailMessage); } } static void throwExceptions(ServiceSpecificException e) throws MediaCasException { static void throwExceptionIfNeeded(int error) throws MediaCasException { if (e.errorCode == ERROR_DRM_NOT_PROVISIONED) { if (error == Status.OK) { throw new NotProvisionedException(e.getMessage()); return; } else if (e.errorCode == ERROR_DRM_RESOURCE_BUSY) { } throw new ResourceBusyException(e.getMessage()); } else if (e.errorCode == ERROR_DRM_DEVICE_REVOKED) { if (error == Status.ERROR_CAS_NOT_PROVISIONED) { throw new DeniedByServerException(e.getMessage()); throw new NotProvisionedException(null); } else if (error == Status.ERROR_CAS_RESOURCE_BUSY) { throw new ResourceBusyException(null); } else if (error == Status.ERROR_CAS_DEVICE_REVOKED) { throw new DeniedByServerException(null); } else { } else { MediaCasStateException.throwExceptions(e); MediaCasStateException.throwExceptionIfNeeded(error); } } } } Loading media/java/android/media/MediaCasStateException.java +34 −19 Original line number Original line Diff line number Diff line Loading @@ -18,9 +18,8 @@ package android.media; import android.annotation.NonNull; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.Nullable; import android.os.ServiceSpecificException; import static android.media.MediaCasException.*; import android.hardware.cas.V1_0.Status; /** /** * Base class for MediaCas runtime exceptions * Base class for MediaCas runtime exceptions Loading @@ -29,46 +28,62 @@ public class MediaCasStateException extends IllegalStateException { private final int mErrorCode; private final int mErrorCode; private final String mDiagnosticInfo; private final String mDiagnosticInfo; /** @hide */ private MediaCasStateException(int err, @Nullable String msg, @Nullable String diagnosticInfo) { public MediaCasStateException(int err, @Nullable String msg, @Nullable String diagnosticInfo) { super(msg); super(msg); mErrorCode = err; mErrorCode = err; mDiagnosticInfo = diagnosticInfo; mDiagnosticInfo = diagnosticInfo; } } static void throwExceptions(ServiceSpecificException e) { static void throwExceptionIfNeeded(int err) { throwExceptionIfNeeded(err, null /* msg */); } static void throwExceptionIfNeeded(int err, @Nullable String msg) { if (err == Status.OK) { return; } if (err == Status.BAD_VALUE) { throw new IllegalArgumentException(); } String diagnosticInfo = ""; String diagnosticInfo = ""; switch (e.errorCode) { switch (err) { case ERROR_DRM_UNKNOWN: case Status.ERROR_CAS_UNKNOWN: diagnosticInfo = "General CAS error"; diagnosticInfo = "General CAS error"; break; break; case ERROR_DRM_NO_LICENSE: case Status.ERROR_CAS_NO_LICENSE: diagnosticInfo = "No license"; diagnosticInfo = "No license"; break; break; case ERROR_DRM_LICENSE_EXPIRED: case Status.ERROR_CAS_LICENSE_EXPIRED: diagnosticInfo = "License expired"; diagnosticInfo = "License expired"; break; break; case ERROR_DRM_SESSION_NOT_OPENED: case Status.ERROR_CAS_SESSION_NOT_OPENED: diagnosticInfo = "Session not opened"; diagnosticInfo = "Session not opened"; break; break; case ERROR_DRM_DECRYPT_UNIT_NOT_INITIALIZED: case Status.ERROR_CAS_CANNOT_HANDLE: diagnosticInfo = "Not initialized"; diagnosticInfo = "Unsupported scheme or data format"; break; break; case ERROR_DRM_DECRYPT: case Status.ERROR_CAS_INVALID_STATE: diagnosticInfo = "Decrypt error"; diagnosticInfo = "Invalid CAS state"; break; break; case ERROR_DRM_CANNOT_HANDLE: case Status.ERROR_CAS_INSUFFICIENT_OUTPUT_PROTECTION: diagnosticInfo = "Unsupported scheme or data format"; diagnosticInfo = "Insufficient output protection"; break; break; case ERROR_DRM_TAMPER_DETECTED: case Status.ERROR_CAS_TAMPER_DETECTED: diagnosticInfo = "Tamper detected"; diagnosticInfo = "Tamper detected"; break; break; case Status.ERROR_CAS_DECRYPT_UNIT_NOT_INITIALIZED: diagnosticInfo = "Not initialized"; break; case Status.ERROR_CAS_DECRYPT: diagnosticInfo = "Decrypt error"; break; default: default: diagnosticInfo = "Unknown CAS state exception"; diagnosticInfo = "Unknown CAS state exception"; break; break; } } throw new MediaCasStateException(e.errorCode, e.getMessage(), throw new MediaCasStateException(err, msg, String.format("%s (err=%d)", diagnosticInfo, e.errorCode)); String.format("%s (err=%d)", diagnosticInfo, err)); } } /** /** Loading media/java/android/media/MediaCodec.java +3 −2 Original line number Original line Diff line number Diff line Loading @@ -26,6 +26,7 @@ import android.media.MediaCodecInfo.CodecCapabilities; import android.os.Bundle; import android.os.Bundle; import android.os.Handler; import android.os.Handler; import android.os.IBinder; import android.os.IBinder; import android.os.IHwBinder; import android.os.Looper; import android.os.Looper; import android.os.Message; import android.os.Message; import android.os.PersistableBundle; import android.os.PersistableBundle; Loading Loading @@ -1903,7 +1904,7 @@ final public class MediaCodec { private void configure( private void configure( @Nullable MediaFormat format, @Nullable Surface surface, @Nullable MediaFormat format, @Nullable Surface surface, @Nullable MediaCrypto crypto, @Nullable IBinder descramblerBinder, @Nullable MediaCrypto crypto, @Nullable IHwBinder descramblerBinder, @ConfigureFlag int flags) { @ConfigureFlag int flags) { if (crypto != null && descramblerBinder != null) { if (crypto != null && descramblerBinder != null) { throw new IllegalArgumentException("Can't use crypto and descrambler together!"); throw new IllegalArgumentException("Can't use crypto and descrambler together!"); Loading Loading @@ -2018,7 +2019,7 @@ final public class MediaCodec { private native final void native_configure( private native final void native_configure( @Nullable String[] keys, @Nullable Object[] values, @Nullable String[] keys, @Nullable Object[] values, @Nullable Surface surface, @Nullable MediaCrypto crypto, @Nullable Surface surface, @Nullable MediaCrypto crypto, @Nullable IBinder descramblerBinder, @ConfigureFlag int flags); @Nullable IHwBinder descramblerBinder, @ConfigureFlag int flags); /** /** * Requests a Surface to use as the input to an encoder, in place of input buffers. This * Requests a Surface to use as the input to an encoder, in place of input buffers. This Loading Loading
Android.mk +2 −4 Original line number Original line Diff line number Diff line Loading @@ -437,10 +437,6 @@ LOCAL_SRC_FILES += \ location/java/android/location/INetInitiatedListener.aidl \ location/java/android/location/INetInitiatedListener.aidl \ location/java/com/android/internal/location/ILocationProvider.aidl \ location/java/com/android/internal/location/ILocationProvider.aidl \ media/java/android/media/IAudioService.aidl \ media/java/android/media/IAudioService.aidl \ ../av/drm/libmediadrm/aidl/android/media/ICas.aidl \ ../av/drm/libmediadrm/aidl/android/media/ICasListener.aidl \ ../av/drm/libmediadrm/aidl/android/media/IDescrambler.aidl \ ../av/drm/libmediadrm/aidl/android/media/IMediaCasService.aidl \ media/java/android/media/IAudioFocusDispatcher.aidl \ media/java/android/media/IAudioFocusDispatcher.aidl \ media/java/android/media/IAudioRoutesObserver.aidl \ media/java/android/media/IAudioRoutesObserver.aidl \ media/java/android/media/IMediaHTTPConnection.aidl \ media/java/android/media/IMediaHTTPConnection.aidl \ Loading Loading @@ -613,6 +609,8 @@ LOCAL_STATIC_JAVA_LIBRARIES := \ android.hardware.vibrator-V1.1-java-constants \ android.hardware.vibrator-V1.1-java-constants \ android.hardware.wifi-V1.0-java-constants \ android.hardware.wifi-V1.0-java-constants \ include hardware/interfaces/cas/1.0/CasHal.mk # Loaded with System.loadLibrary by android.view.textclassifier # Loaded with System.loadLibrary by android.view.textclassifier LOCAL_REQUIRED_MODULES += libtextclassifier LOCAL_REQUIRED_MODULES += libtextclassifier Loading
media/java/android/media/MediaCas.java +78 −130 Original line number Original line Diff line number Diff line Loading @@ -18,21 +18,20 @@ package android.media; import android.annotation.NonNull; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.Nullable; import android.hardware.cas.V1_0.*; import android.media.MediaCasException.*; import android.media.MediaCasException.*; import android.os.Handler; import android.os.Handler; import android.os.HandlerThread; import android.os.HandlerThread; import android.os.IBinder; import android.os.IHwBinder; import android.os.Looper; import android.os.Looper; import android.os.Message; import android.os.Message; import android.os.Parcel; import android.os.Parcelable; import android.os.Process; import android.os.Process; import android.os.RemoteException; import android.os.RemoteException; import android.os.ServiceManager; import android.os.ServiceSpecificException; import android.util.Log; import android.util.Log; import android.util.Singleton; import android.util.Singleton; import java.util.ArrayList; /** /** * MediaCas can be used to obtain keys for descrambling protected media streams, in * MediaCas can be used to obtain keys for descrambling protected media streams, in * conjunction with {@link android.media.MediaDescrambler}. The MediaCas APIs are * conjunction with {@link android.media.MediaDescrambler}. The MediaCas APIs are Loading Loading @@ -95,7 +94,6 @@ import android.util.Singleton; */ */ public final class MediaCas implements AutoCloseable { public final class MediaCas implements AutoCloseable { private static final String TAG = "MediaCas"; private static final String TAG = "MediaCas"; private final ParcelableCasData mCasData = new ParcelableCasData(); private ICas mICas; private ICas mICas; private EventListener mListener; private EventListener mListener; private HandlerThread mHandlerThread; private HandlerThread mHandlerThread; Loading @@ -105,8 +103,10 @@ public final class MediaCas implements AutoCloseable { new Singleton<IMediaCasService>() { new Singleton<IMediaCasService>() { @Override @Override protected IMediaCasService create() { protected IMediaCasService create() { return IMediaCasService.Stub.asInterface( try { ServiceManager.getService("media.cas")); return IMediaCasService.getService(); } catch (RemoteException e) {} return null; } } }; }; Loading Loading @@ -136,65 +136,21 @@ public final class MediaCas implements AutoCloseable { @Override @Override public void handleMessage(Message msg) { public void handleMessage(Message msg) { if (msg.what == MSG_CAS_EVENT) { if (msg.what == MSG_CAS_EVENT) { mListener.onEvent(MediaCas.this, msg.arg1, msg.arg2, (byte[]) msg.obj); mListener.onEvent(MediaCas.this, msg.arg1, msg.arg2, toBytes((ArrayList<Byte>) msg.obj)); } } } } } } private final ICasListener.Stub mBinder = new ICasListener.Stub() { private final ICasListener.Stub mBinder = new ICasListener.Stub() { @Override @Override public void onEvent(int event, int arg, @Nullable byte[] data) public void onEvent(int event, int arg, @Nullable ArrayList<Byte> data) throws RemoteException { throws RemoteException { mEventHandler.sendMessage(mEventHandler.obtainMessage( mEventHandler.sendMessage(mEventHandler.obtainMessage( EventHandler.MSG_CAS_EVENT, event, arg, data)); EventHandler.MSG_CAS_EVENT, event, arg, data)); } } }; }; /** * Class for parceling byte array data over ICas binder. */ static class ParcelableCasData implements Parcelable { private byte[] mData; private int mOffset; private int mLength; ParcelableCasData() { mData = null; mOffset = mLength = 0; } private ParcelableCasData(Parcel in) { this(); } void set(@NonNull byte[] data, int offset, int length) { mData = data; mOffset = offset; mLength = length; } @Override public int describeContents() { return 0; } @Override public void writeToParcel(Parcel dest, int flags) { dest.writeByteArray(mData, mOffset, mLength); } public static final Parcelable.Creator<ParcelableCasData> CREATOR = new Parcelable.Creator<ParcelableCasData>() { public ParcelableCasData createFromParcel(Parcel in) { return new ParcelableCasData(in); } public ParcelableCasData[] newArray(int size) { return new ParcelableCasData[size]; } }; } /** /** * Describe a CAS plugin with its CA_system_ID and string name. * Describe a CAS plugin with its CA_system_ID and string name. * * Loading @@ -210,9 +166,9 @@ public final class MediaCas implements AutoCloseable { mName = null; mName = null; } } PluginDescriptor(int CA_system_id, String name) { PluginDescriptor(@NonNull HidlCasPluginDescriptor descriptor) { mCASystemId = CA_system_id; mCASystemId = descriptor.caSystemId; mName = name; mName = descriptor.name; } } public int getSystemId() { public int getSystemId() { Loading @@ -230,13 +186,38 @@ public final class MediaCas implements AutoCloseable { } } } } private ArrayList<Byte> toByteArray(@NonNull byte[] data, int offset, int length) { ArrayList<Byte> byteArray = new ArrayList<Byte>(length); for (int i = 0; i < length; i++) { byteArray.add(Byte.valueOf(data[offset + i])); } return byteArray; } private ArrayList<Byte> toByteArray(@Nullable byte[] data) { if (data == null) { return new ArrayList<Byte>(); } return toByteArray(data, 0, data.length); } private byte[] toBytes(@NonNull ArrayList<Byte> byteArray) { byte[] data = null; if (byteArray != null) { data = new byte[byteArray.size()]; for (int i = 0; i < data.length; i++) { data[i] = byteArray.get(i); } } return data; } /** /** * Class for an open session with the CA system. * Class for an open session with the CA system. */ */ public final class Session implements AutoCloseable { public final class Session implements AutoCloseable { final byte[] mSessionId; final ArrayList<Byte> mSessionId; Session(@NonNull byte[] sessionId) { Session(@NonNull ArrayList<Byte> sessionId) { mSessionId = sessionId; mSessionId = sessionId; } } Loading @@ -254,9 +235,8 @@ public final class MediaCas implements AutoCloseable { validateInternalStates(); validateInternalStates(); try { try { mICas.setSessionPrivateData(mSessionId, data); MediaCasException.throwExceptionIfNeeded( } catch (ServiceSpecificException e) { mICas.setSessionPrivateData(mSessionId, toByteArray(data, 0, data.length))); MediaCasException.throwExceptions(e); } catch (RemoteException e) { } catch (RemoteException e) { cleanupAndRethrowIllegalState(); cleanupAndRethrowIllegalState(); } } Loading @@ -279,10 +259,8 @@ public final class MediaCas implements AutoCloseable { validateInternalStates(); validateInternalStates(); try { try { mCasData.set(data, offset, length); MediaCasException.throwExceptionIfNeeded( mICas.processEcm(mSessionId, mCasData); mICas.processEcm(mSessionId, toByteArray(data, offset, length))); } catch (ServiceSpecificException e) { MediaCasException.throwExceptions(e); } catch (RemoteException e) { } catch (RemoteException e) { cleanupAndRethrowIllegalState(); cleanupAndRethrowIllegalState(); } } Loading Loading @@ -314,56 +292,21 @@ public final class MediaCas implements AutoCloseable { validateInternalStates(); validateInternalStates(); try { try { mICas.closeSession(mSessionId); MediaCasStateException.throwExceptionIfNeeded( } catch (ServiceSpecificException e) { mICas.closeSession(mSessionId)); MediaCasStateException.throwExceptions(e); } catch (RemoteException e) { } catch (RemoteException e) { cleanupAndRethrowIllegalState(); cleanupAndRethrowIllegalState(); } } } } } } Session createFromSessionId(byte[] sessionId) { Session createFromSessionId(@NonNull ArrayList<Byte> sessionId) { if (sessionId == null || sessionId.length == 0) { if (sessionId == null || sessionId.size() == 0) { return null; return null; } } return new Session(sessionId); return new Session(sessionId); } } /** * Class for parceling CAS plugin descriptors over IMediaCasService binder. */ static class ParcelableCasPluginDescriptor extends PluginDescriptor implements Parcelable { private ParcelableCasPluginDescriptor(int CA_system_id, String name) { super(CA_system_id, name); } @Override public int describeContents() { return 0; } @Override public void writeToParcel(Parcel dest, int flags) { Log.w(TAG, "ParcelableCasPluginDescriptor.writeToParcel shouldn't be called!"); } public static final Parcelable.Creator<ParcelableCasPluginDescriptor> CREATOR = new Parcelable.Creator<ParcelableCasPluginDescriptor>() { public ParcelableCasPluginDescriptor createFromParcel(Parcel in) { int CA_system_id = in.readInt(); String name = in.readString(); return new ParcelableCasPluginDescriptor(CA_system_id, name); } public ParcelableCasPluginDescriptor[] newArray(int size) { return new ParcelableCasPluginDescriptor[size]; } }; } /** /** * Query if a certain CA system is supported on this device. * Query if a certain CA system is supported on this device. * * Loading Loading @@ -393,13 +336,14 @@ public final class MediaCas implements AutoCloseable { if (service != null) { if (service != null) { try { try { ParcelableCasPluginDescriptor[] descriptors = service.enumeratePlugins(); ArrayList<HidlCasPluginDescriptor> descriptors = if (descriptors.length == 0) { service.enumeratePlugins(); if (descriptors.size() == 0) { return null; return null; } } PluginDescriptor[] results = new PluginDescriptor[descriptors.length]; PluginDescriptor[] results = new PluginDescriptor[descriptors.size()]; for (int i = 0; i < results.length; i++) { for (int i = 0; i < results.length; i++) { results[i] = descriptors[i]; results[i] = new PluginDescriptor(descriptors.get(i)); } } return results; return results; } catch (RemoteException e) { } catch (RemoteException e) { Loading Loading @@ -430,7 +374,7 @@ public final class MediaCas implements AutoCloseable { } } } } IBinder getBinder() { IHwBinder getBinder() { validateInternalStates(); validateInternalStates(); return mICas.asBinder(); return mICas.asBinder(); Loading Loading @@ -497,14 +441,22 @@ public final class MediaCas implements AutoCloseable { validateInternalStates(); validateInternalStates(); try { try { mICas.setPrivateData(data); MediaCasException.throwExceptionIfNeeded( } catch (ServiceSpecificException e) { mICas.setPrivateData(toByteArray(data, 0, data.length))); MediaCasException.throwExceptions(e); } catch (RemoteException e) { } catch (RemoteException e) { cleanupAndRethrowIllegalState(); cleanupAndRethrowIllegalState(); } } } } private class OpenSessionCallback implements ICas.openSessionCallback { public Session mSession; public int mStatus; @Override public void onValues(int status, ArrayList<Byte> sessionId) { mStatus = status; mSession = createFromSessionId(sessionId); } } /** /** * Open a session to descramble one or more streams scrambled by the * Open a session to descramble one or more streams scrambled by the * conditional access system. * conditional access system. Loading @@ -519,9 +471,10 @@ public final class MediaCas implements AutoCloseable { validateInternalStates(); validateInternalStates(); try { try { return createFromSessionId(mICas.openSession()); OpenSessionCallback cb = new OpenSessionCallback(); } catch (ServiceSpecificException e) { mICas.openSession(cb); MediaCasException.throwExceptions(e); MediaCasException.throwExceptionIfNeeded(cb.mStatus); return cb.mSession; } catch (RemoteException e) { } catch (RemoteException e) { cleanupAndRethrowIllegalState(); cleanupAndRethrowIllegalState(); } } Loading @@ -544,10 +497,8 @@ public final class MediaCas implements AutoCloseable { validateInternalStates(); validateInternalStates(); try { try { mCasData.set(data, offset, length); MediaCasException.throwExceptionIfNeeded( mICas.processEmm(mCasData); mICas.processEmm(toByteArray(data, offset, length))); } catch (ServiceSpecificException e) { MediaCasException.throwExceptions(e); } catch (RemoteException e) { } catch (RemoteException e) { cleanupAndRethrowIllegalState(); cleanupAndRethrowIllegalState(); } } Loading Loading @@ -585,9 +536,8 @@ public final class MediaCas implements AutoCloseable { validateInternalStates(); validateInternalStates(); try { try { mICas.sendEvent(event, arg, data); MediaCasException.throwExceptionIfNeeded( } catch (ServiceSpecificException e) { mICas.sendEvent(event, arg, toByteArray(data))); MediaCasException.throwExceptions(e); } catch (RemoteException e) { } catch (RemoteException e) { cleanupAndRethrowIllegalState(); cleanupAndRethrowIllegalState(); } } Loading @@ -608,9 +558,8 @@ public final class MediaCas implements AutoCloseable { validateInternalStates(); validateInternalStates(); try { try { mICas.provision(provisionString); MediaCasException.throwExceptionIfNeeded( } catch (ServiceSpecificException e) { mICas.provision(provisionString)); MediaCasException.throwExceptions(e); } catch (RemoteException e) { } catch (RemoteException e) { cleanupAndRethrowIllegalState(); cleanupAndRethrowIllegalState(); } } Loading @@ -631,9 +580,8 @@ public final class MediaCas implements AutoCloseable { validateInternalStates(); validateInternalStates(); try { try { mICas.refreshEntitlements(refreshType, refreshData); MediaCasException.throwExceptionIfNeeded( } catch (ServiceSpecificException e) { mICas.refreshEntitlements(refreshType, toByteArray(refreshData))); MediaCasException.throwExceptions(e); } catch (RemoteException e) { } catch (RemoteException e) { cleanupAndRethrowIllegalState(); cleanupAndRethrowIllegalState(); } } Loading
media/java/android/media/MediaCasException.java +14 −45 Original line number Original line Diff line number Diff line Loading @@ -16,60 +16,29 @@ package android.media; package android.media; import android.os.ServiceSpecificException; import android.hardware.cas.V1_0.Status; /** /** * Base class for MediaCas exceptions * Base class for MediaCas exceptions */ */ public class MediaCasException extends Exception { public class MediaCasException extends Exception { private MediaCasException(String detailMessage) { /** @hide */ public static final int DRM_ERROR_BASE = -2000; /** @hide */ public static final int ERROR_DRM_UNKNOWN = DRM_ERROR_BASE; /** @hide */ public static final int ERROR_DRM_NO_LICENSE = DRM_ERROR_BASE - 1; /** @hide */ public static final int ERROR_DRM_LICENSE_EXPIRED = DRM_ERROR_BASE - 2; /** @hide */ public static final int ERROR_DRM_SESSION_NOT_OPENED = DRM_ERROR_BASE - 3; /** @hide */ public static final int ERROR_DRM_DECRYPT_UNIT_NOT_INITIALIZED = DRM_ERROR_BASE - 4; /** @hide */ public static final int ERROR_DRM_DECRYPT = DRM_ERROR_BASE - 5; /** @hide */ public static final int ERROR_DRM_CANNOT_HANDLE = DRM_ERROR_BASE - 6; /** @hide */ public static final int ERROR_DRM_TAMPER_DETECTED = DRM_ERROR_BASE - 7; /** @hide */ public static final int ERROR_DRM_NOT_PROVISIONED = DRM_ERROR_BASE - 8; /** @hide */ public static final int ERROR_DRM_DEVICE_REVOKED = DRM_ERROR_BASE - 9; /** @hide */ public static final int ERROR_DRM_RESOURCE_BUSY = DRM_ERROR_BASE - 10; /** @hide */ public static final int ERROR_DRM_INSUFFICIENT_OUTPUT_PROTECTION = DRM_ERROR_BASE - 11; /** @hide */ public static final int ERROR_DRM_LAST_USED_ERRORCODE = DRM_ERROR_BASE - 11; /** @hide */ public static final int ERROR_DRM_VENDOR_MAX = DRM_ERROR_BASE - 500; /** @hide */ public static final int ERROR_DRM_VENDOR_MIN = DRM_ERROR_BASE - 999; /** @hide */ public MediaCasException(String detailMessage) { super(detailMessage); super(detailMessage); } } static void throwExceptions(ServiceSpecificException e) throws MediaCasException { static void throwExceptionIfNeeded(int error) throws MediaCasException { if (e.errorCode == ERROR_DRM_NOT_PROVISIONED) { if (error == Status.OK) { throw new NotProvisionedException(e.getMessage()); return; } else if (e.errorCode == ERROR_DRM_RESOURCE_BUSY) { } throw new ResourceBusyException(e.getMessage()); } else if (e.errorCode == ERROR_DRM_DEVICE_REVOKED) { if (error == Status.ERROR_CAS_NOT_PROVISIONED) { throw new DeniedByServerException(e.getMessage()); throw new NotProvisionedException(null); } else if (error == Status.ERROR_CAS_RESOURCE_BUSY) { throw new ResourceBusyException(null); } else if (error == Status.ERROR_CAS_DEVICE_REVOKED) { throw new DeniedByServerException(null); } else { } else { MediaCasStateException.throwExceptions(e); MediaCasStateException.throwExceptionIfNeeded(error); } } } } Loading
media/java/android/media/MediaCasStateException.java +34 −19 Original line number Original line Diff line number Diff line Loading @@ -18,9 +18,8 @@ package android.media; import android.annotation.NonNull; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.Nullable; import android.os.ServiceSpecificException; import static android.media.MediaCasException.*; import android.hardware.cas.V1_0.Status; /** /** * Base class for MediaCas runtime exceptions * Base class for MediaCas runtime exceptions Loading @@ -29,46 +28,62 @@ public class MediaCasStateException extends IllegalStateException { private final int mErrorCode; private final int mErrorCode; private final String mDiagnosticInfo; private final String mDiagnosticInfo; /** @hide */ private MediaCasStateException(int err, @Nullable String msg, @Nullable String diagnosticInfo) { public MediaCasStateException(int err, @Nullable String msg, @Nullable String diagnosticInfo) { super(msg); super(msg); mErrorCode = err; mErrorCode = err; mDiagnosticInfo = diagnosticInfo; mDiagnosticInfo = diagnosticInfo; } } static void throwExceptions(ServiceSpecificException e) { static void throwExceptionIfNeeded(int err) { throwExceptionIfNeeded(err, null /* msg */); } static void throwExceptionIfNeeded(int err, @Nullable String msg) { if (err == Status.OK) { return; } if (err == Status.BAD_VALUE) { throw new IllegalArgumentException(); } String diagnosticInfo = ""; String diagnosticInfo = ""; switch (e.errorCode) { switch (err) { case ERROR_DRM_UNKNOWN: case Status.ERROR_CAS_UNKNOWN: diagnosticInfo = "General CAS error"; diagnosticInfo = "General CAS error"; break; break; case ERROR_DRM_NO_LICENSE: case Status.ERROR_CAS_NO_LICENSE: diagnosticInfo = "No license"; diagnosticInfo = "No license"; break; break; case ERROR_DRM_LICENSE_EXPIRED: case Status.ERROR_CAS_LICENSE_EXPIRED: diagnosticInfo = "License expired"; diagnosticInfo = "License expired"; break; break; case ERROR_DRM_SESSION_NOT_OPENED: case Status.ERROR_CAS_SESSION_NOT_OPENED: diagnosticInfo = "Session not opened"; diagnosticInfo = "Session not opened"; break; break; case ERROR_DRM_DECRYPT_UNIT_NOT_INITIALIZED: case Status.ERROR_CAS_CANNOT_HANDLE: diagnosticInfo = "Not initialized"; diagnosticInfo = "Unsupported scheme or data format"; break; break; case ERROR_DRM_DECRYPT: case Status.ERROR_CAS_INVALID_STATE: diagnosticInfo = "Decrypt error"; diagnosticInfo = "Invalid CAS state"; break; break; case ERROR_DRM_CANNOT_HANDLE: case Status.ERROR_CAS_INSUFFICIENT_OUTPUT_PROTECTION: diagnosticInfo = "Unsupported scheme or data format"; diagnosticInfo = "Insufficient output protection"; break; break; case ERROR_DRM_TAMPER_DETECTED: case Status.ERROR_CAS_TAMPER_DETECTED: diagnosticInfo = "Tamper detected"; diagnosticInfo = "Tamper detected"; break; break; case Status.ERROR_CAS_DECRYPT_UNIT_NOT_INITIALIZED: diagnosticInfo = "Not initialized"; break; case Status.ERROR_CAS_DECRYPT: diagnosticInfo = "Decrypt error"; break; default: default: diagnosticInfo = "Unknown CAS state exception"; diagnosticInfo = "Unknown CAS state exception"; break; break; } } throw new MediaCasStateException(e.errorCode, e.getMessage(), throw new MediaCasStateException(err, msg, String.format("%s (err=%d)", diagnosticInfo, e.errorCode)); String.format("%s (err=%d)", diagnosticInfo, err)); } } /** /** Loading
media/java/android/media/MediaCodec.java +3 −2 Original line number Original line Diff line number Diff line Loading @@ -26,6 +26,7 @@ import android.media.MediaCodecInfo.CodecCapabilities; import android.os.Bundle; import android.os.Bundle; import android.os.Handler; import android.os.Handler; import android.os.IBinder; import android.os.IBinder; import android.os.IHwBinder; import android.os.Looper; import android.os.Looper; import android.os.Message; import android.os.Message; import android.os.PersistableBundle; import android.os.PersistableBundle; Loading Loading @@ -1903,7 +1904,7 @@ final public class MediaCodec { private void configure( private void configure( @Nullable MediaFormat format, @Nullable Surface surface, @Nullable MediaFormat format, @Nullable Surface surface, @Nullable MediaCrypto crypto, @Nullable IBinder descramblerBinder, @Nullable MediaCrypto crypto, @Nullable IHwBinder descramblerBinder, @ConfigureFlag int flags) { @ConfigureFlag int flags) { if (crypto != null && descramblerBinder != null) { if (crypto != null && descramblerBinder != null) { throw new IllegalArgumentException("Can't use crypto and descrambler together!"); throw new IllegalArgumentException("Can't use crypto and descrambler together!"); Loading Loading @@ -2018,7 +2019,7 @@ final public class MediaCodec { private native final void native_configure( private native final void native_configure( @Nullable String[] keys, @Nullable Object[] values, @Nullable String[] keys, @Nullable Object[] values, @Nullable Surface surface, @Nullable MediaCrypto crypto, @Nullable Surface surface, @Nullable MediaCrypto crypto, @Nullable IBinder descramblerBinder, @ConfigureFlag int flags); @Nullable IHwBinder descramblerBinder, @ConfigureFlag int flags); /** /** * Requests a Surface to use as the input to an encoder, in place of input buffers. This * Requests a Surface to use as the input to an encoder, in place of input buffers. This Loading