Merge "CAS: Add AIDL Support"
diff --git a/Android.bp b/Android.bp
index 8e09157..67902b3 100644
--- a/Android.bp
+++ b/Android.bp
@@ -106,6 +106,7 @@
         ":android.security.maintenance-java-source",
         ":android.security.metrics-java-source",
         ":android.system.keystore2-V3-java-source",
+        ":android.hardware.cas-V1-java-source",
         ":credstore_aidl",
         ":dumpstate_aidl",
         ":framework_native_aidl",
@@ -196,6 +197,7 @@
         "updatable-driver-protos",
         "ota_metadata_proto_java",
         "android.hidl.base-V1.0-java",
+        "android.hardware.cas-V1-java", // AIDL
         "android.hardware.cas-V1.0-java",
         "android.hardware.cas-V1.1-java",
         "android.hardware.cas-V1.2-java",
diff --git a/core/api/current.txt b/core/api/current.txt
index d132706..a0c132f 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -21142,6 +21142,7 @@
     field public static final int PLUGIN_STATUS_PHYSICAL_MODULE_CHANGED = 0; // 0x0
     field public static final int PLUGIN_STATUS_SESSION_NUMBER_CHANGED = 1; // 0x1
     field public static final int SCRAMBLING_MODE_AES128 = 9; // 0x9
+    field public static final int SCRAMBLING_MODE_AES_CBC = 14; // 0xe
     field public static final int SCRAMBLING_MODE_AES_ECB = 10; // 0xa
     field public static final int SCRAMBLING_MODE_AES_SCTE52 = 11; // 0xb
     field public static final int SCRAMBLING_MODE_DVB_CISSA_V1 = 6; // 0x6
diff --git a/media/java/android/media/MediaCas.java b/media/java/android/media/MediaCas.java
index 582a28e..015602e 100644
--- a/media/java/android/media/MediaCas.java
+++ b/media/java/android/media/MediaCas.java
@@ -21,11 +21,12 @@
 import android.annotation.Nullable;
 import android.annotation.TestApi;
 import android.content.Context;
+import android.hardware.cas.AidlCasPluginDescriptor;
+import android.hardware.cas.ICas;
+import android.hardware.cas.ICasListener;
+import android.hardware.cas.IMediaCasService;
+import android.hardware.cas.Status;
 import android.hardware.cas.V1_0.HidlCasPluginDescriptor;
-import android.hardware.cas.V1_0.ICas;
-import android.hardware.cas.V1_0.IMediaCasService;
-import android.hardware.cas.V1_2.ICasListener;
-import android.hardware.cas.V1_2.Status;
 import android.media.MediaCasException.*;
 import android.media.tv.TvInputService.PriorityHintUseCaseType;
 import android.media.tv.tunerresourcemanager.CasSessionRequest;
@@ -39,6 +40,7 @@
 import android.os.Message;
 import android.os.Process;
 import android.os.RemoteException;
+import android.os.ServiceManager;
 import android.util.Log;
 import android.util.Singleton;
 
@@ -47,6 +49,7 @@
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -114,9 +117,10 @@
  */
 public final class MediaCas implements AutoCloseable {
     private static final String TAG = "MediaCas";
-    private ICas mICas;
-    private android.hardware.cas.V1_1.ICas mICasV11;
-    private android.hardware.cas.V1_2.ICas mICasV12;
+    private ICas mICas = null;
+    private android.hardware.cas.V1_0.ICas mICasHidl = null;
+    private android.hardware.cas.V1_1.ICas mICasHidl11 = null;
+    private android.hardware.cas.V1_2.ICas mICasHidl12 = null;
     private EventListener mListener;
     private HandlerThread mHandlerThread;
     private EventHandler mEventHandler;
@@ -133,88 +137,84 @@
      *
      * @hide
      */
-    @IntDef(prefix = "SCRAMBLING_MODE_",
-            value = {SCRAMBLING_MODE_RESERVED, SCRAMBLING_MODE_DVB_CSA1, SCRAMBLING_MODE_DVB_CSA2,
-            SCRAMBLING_MODE_DVB_CSA3_STANDARD,
-            SCRAMBLING_MODE_DVB_CSA3_MINIMAL, SCRAMBLING_MODE_DVB_CSA3_ENHANCE,
-            SCRAMBLING_MODE_DVB_CISSA_V1, SCRAMBLING_MODE_DVB_IDSA,
-            SCRAMBLING_MODE_MULTI2, SCRAMBLING_MODE_AES128, SCRAMBLING_MODE_AES_ECB,
-            SCRAMBLING_MODE_AES_SCTE52, SCRAMBLING_MODE_TDES_ECB, SCRAMBLING_MODE_TDES_SCTE52})
+    @IntDef(
+            prefix = "SCRAMBLING_MODE_",
+            value = {
+                SCRAMBLING_MODE_RESERVED,
+                SCRAMBLING_MODE_DVB_CSA1,
+                SCRAMBLING_MODE_DVB_CSA2,
+                SCRAMBLING_MODE_DVB_CSA3_STANDARD,
+                SCRAMBLING_MODE_DVB_CSA3_MINIMAL,
+                SCRAMBLING_MODE_DVB_CSA3_ENHANCE,
+                SCRAMBLING_MODE_DVB_CISSA_V1,
+                SCRAMBLING_MODE_DVB_IDSA,
+                SCRAMBLING_MODE_MULTI2,
+                SCRAMBLING_MODE_AES128,
+                SCRAMBLING_MODE_AES_CBC,
+                SCRAMBLING_MODE_AES_ECB,
+                SCRAMBLING_MODE_AES_SCTE52,
+                SCRAMBLING_MODE_TDES_ECB,
+                SCRAMBLING_MODE_TDES_SCTE52
+            })
     @Retention(RetentionPolicy.SOURCE)
     public @interface ScramblingMode {}
 
-    /**
-     * DVB (Digital Video Broadcasting) reserved mode.
-     */
-    public static final int SCRAMBLING_MODE_RESERVED =
-            android.hardware.cas.V1_2.ScramblingMode.RESERVED;
-    /**
-     * DVB (Digital Video Broadcasting) Common Scrambling Algorithm (CSA) 1.
-     */
-    public static final int SCRAMBLING_MODE_DVB_CSA1 =
-            android.hardware.cas.V1_2.ScramblingMode.DVB_CSA1;
-    /**
-     * DVB CSA 2.
-     */
-    public static final int SCRAMBLING_MODE_DVB_CSA2 =
-            android.hardware.cas.V1_2.ScramblingMode.DVB_CSA2;
-    /**
-     * DVB CSA 3 in standard mode.
-     */
+    /** DVB (Digital Video Broadcasting) reserved mode. */
+    public static final int SCRAMBLING_MODE_RESERVED = android.hardware.cas.ScramblingMode.RESERVED;
+
+    /** DVB (Digital Video Broadcasting) Common Scrambling Algorithm (CSA) 1. */
+    public static final int SCRAMBLING_MODE_DVB_CSA1 = android.hardware.cas.ScramblingMode.DVB_CSA1;
+
+    /** DVB CSA 2. */
+    public static final int SCRAMBLING_MODE_DVB_CSA2 = android.hardware.cas.ScramblingMode.DVB_CSA2;
+
+    /** DVB CSA 3 in standard mode. */
     public static final int SCRAMBLING_MODE_DVB_CSA3_STANDARD =
-            android.hardware.cas.V1_2.ScramblingMode.DVB_CSA3_STANDARD;
-    /**
-     * DVB CSA 3 in minimally enhanced mode.
-     */
+            android.hardware.cas.ScramblingMode.DVB_CSA3_STANDARD;
+
+    /** DVB CSA 3 in minimally enhanced mode. */
     public static final int SCRAMBLING_MODE_DVB_CSA3_MINIMAL =
-            android.hardware.cas.V1_2.ScramblingMode.DVB_CSA3_MINIMAL;
-    /**
-     * DVB CSA 3 in fully enhanced mode.
-     */
+            android.hardware.cas.ScramblingMode.DVB_CSA3_MINIMAL;
+
+    /** DVB CSA 3 in fully enhanced mode. */
     public static final int SCRAMBLING_MODE_DVB_CSA3_ENHANCE =
-            android.hardware.cas.V1_2.ScramblingMode.DVB_CSA3_ENHANCE;
-    /**
-     * DVB Common IPTV Software-oriented Scrambling Algorithm (CISSA) Version 1.
-     */
+            android.hardware.cas.ScramblingMode.DVB_CSA3_ENHANCE;
+
+    /** DVB Common IPTV Software-oriented Scrambling Algorithm (CISSA) Version 1. */
     public static final int SCRAMBLING_MODE_DVB_CISSA_V1 =
-            android.hardware.cas.V1_2.ScramblingMode.DVB_CISSA_V1;
-    /**
-     * ATIS-0800006 IIF Default Scrambling Algorithm (IDSA).
-     */
-    public static final int SCRAMBLING_MODE_DVB_IDSA =
-            android.hardware.cas.V1_2.ScramblingMode.DVB_IDSA;
-    /**
-     * A symmetric key algorithm.
-     */
-    public static final int SCRAMBLING_MODE_MULTI2 =
-            android.hardware.cas.V1_2.ScramblingMode.MULTI2;
-    /**
-     * Advanced Encryption System (AES) 128-bit Encryption mode.
-     */
-    public static final int SCRAMBLING_MODE_AES128 =
-            android.hardware.cas.V1_2.ScramblingMode.AES128;
-    /**
-     * Advanced Encryption System (AES) Electronic Code Book (ECB) mode.
-     */
-    public static final int SCRAMBLING_MODE_AES_ECB =
-            android.hardware.cas.V1_2.ScramblingMode.AES_ECB;
+            android.hardware.cas.ScramblingMode.DVB_CISSA_V1;
+
+    /** ATIS-0800006 IIF Default Scrambling Algorithm (IDSA). */
+    public static final int SCRAMBLING_MODE_DVB_IDSA = android.hardware.cas.ScramblingMode.DVB_IDSA;
+
+    /** A symmetric key algorithm. */
+    public static final int SCRAMBLING_MODE_MULTI2 = android.hardware.cas.ScramblingMode.MULTI2;
+
+    /** Advanced Encryption System (AES) 128-bit Encryption mode. */
+    public static final int SCRAMBLING_MODE_AES128 = android.hardware.cas.ScramblingMode.AES128;
+
+    /** Advanced Encryption System (AES) Cipher Block Chaining (CBC) mode. */
+    public static final int SCRAMBLING_MODE_AES_CBC = android.hardware.cas.ScramblingMode.AES_CBC;
+
+    /** Advanced Encryption System (AES) Electronic Code Book (ECB) mode. */
+    public static final int SCRAMBLING_MODE_AES_ECB = android.hardware.cas.ScramblingMode.AES_ECB;
+
     /**
      * Advanced Encryption System (AES) Society of Cable Telecommunications Engineers (SCTE) 52
      * mode.
      */
     public static final int SCRAMBLING_MODE_AES_SCTE52 =
-            android.hardware.cas.V1_2.ScramblingMode.AES_SCTE52;
-    /**
-     * Triple Data Encryption Algorithm (TDES) Electronic Code Book (ECB) mode.
-     */
-    public static final int SCRAMBLING_MODE_TDES_ECB =
-            android.hardware.cas.V1_2.ScramblingMode.TDES_ECB;
+            android.hardware.cas.ScramblingMode.AES_SCTE52;
+
+    /** Triple Data Encryption Algorithm (TDES) Electronic Code Book (ECB) mode. */
+    public static final int SCRAMBLING_MODE_TDES_ECB = android.hardware.cas.ScramblingMode.TDES_ECB;
+
     /**
      * Triple Data Encryption Algorithm (TDES) Society of Cable Telecommunications Engineers (SCTE)
      * 52 mode.
      */
     public static final int SCRAMBLING_MODE_TDES_SCTE52 =
-            android.hardware.cas.V1_2.ScramblingMode.TDES_SCTE52;
+            android.hardware.cas.ScramblingMode.TDES_SCTE52;
 
     /**
      * Usages used to open cas sessions.
@@ -226,25 +226,21 @@
             SESSION_USAGE_TIMESHIFT})
     @Retention(RetentionPolicy.SOURCE)
     public @interface SessionUsage {}
-    /**
-     * Cas session is used to descramble live streams.
-     */
-    public static final int SESSION_USAGE_LIVE = android.hardware.cas.V1_2.SessionIntent.LIVE;
-    /**
-     * Cas session is used to descramble recoreded streams.
-     */
-    public static final int SESSION_USAGE_PLAYBACK =
-            android.hardware.cas.V1_2.SessionIntent.PLAYBACK;
-    /**
-     * Cas session is used to descramble live streams and encrypt local recorded content
-     */
-    public static final int SESSION_USAGE_RECORD = android.hardware.cas.V1_2.SessionIntent.RECORD;
+
+    /** Cas session is used to descramble live streams. */
+    public static final int SESSION_USAGE_LIVE = android.hardware.cas.SessionIntent.LIVE;
+
+    /** Cas session is used to descramble recoreded streams. */
+    public static final int SESSION_USAGE_PLAYBACK = android.hardware.cas.SessionIntent.PLAYBACK;
+
+    /** Cas session is used to descramble live streams and encrypt local recorded content */
+    public static final int SESSION_USAGE_RECORD = android.hardware.cas.SessionIntent.RECORD;
+
     /**
      * Cas session is used to descramble live streams , encrypt local recorded content and playback
      * local encrypted content.
      */
-    public static final int SESSION_USAGE_TIMESHIFT =
-            android.hardware.cas.V1_2.SessionIntent.TIMESHIFT;
+    public static final int SESSION_USAGE_TIMESHIFT = android.hardware.cas.SessionIntent.TIMESHIFT;
 
     /**
      * Plugin status events sent from cas system.
@@ -261,63 +257,90 @@
      * physical CAS modules.
      */
     public static final int PLUGIN_STATUS_PHYSICAL_MODULE_CHANGED =
-            android.hardware.cas.V1_2.StatusEvent.PLUGIN_PHYSICAL_MODULE_CHANGED;
-    /**
-     * The event to indicate that the number of CAS system's session is changed.
-     */
+            android.hardware.cas.StatusEvent.PLUGIN_PHYSICAL_MODULE_CHANGED;
+
+    /** The event to indicate that the number of CAS system's session is changed. */
     public static final int PLUGIN_STATUS_SESSION_NUMBER_CHANGED =
-            android.hardware.cas.V1_2.StatusEvent.PLUGIN_SESSION_NUMBER_CHANGED;
+            android.hardware.cas.StatusEvent.PLUGIN_SESSION_NUMBER_CHANGED;
 
-    private static final Singleton<IMediaCasService> sService = new Singleton<IMediaCasService>() {
-        @Override
-        protected IMediaCasService create() {
-            try {
-                Log.d(TAG, "Trying to get cas@1.2 service");
-                android.hardware.cas.V1_2.IMediaCasService serviceV12 =
-                        android.hardware.cas.V1_2.IMediaCasService.getService(true /*wait*/);
-                if (serviceV12 != null) {
-                    return serviceV12;
-                }
-            } catch (Exception eV1_2) {
-                Log.d(TAG, "Failed to get cas@1.2 service");
-            }
-
-            try {
-                    Log.d(TAG, "Trying to get cas@1.1 service");
-                    android.hardware.cas.V1_1.IMediaCasService serviceV11 =
-                            android.hardware.cas.V1_1.IMediaCasService.getService(true /*wait*/);
-                    if (serviceV11 != null) {
-                        return serviceV11;
+    private static final Singleton<IMediaCasService> sService =
+            new Singleton<IMediaCasService>() {
+                @Override
+                protected IMediaCasService create() {
+                    try {
+                        Log.d(TAG, "Trying to get AIDL service");
+                        IMediaCasService serviceAidl =
+                                IMediaCasService.Stub.asInterface(
+                                        ServiceManager.getService(
+                                                IMediaCasService.DESCRIPTOR + "/default"));
+                        if (serviceAidl != null) {
+                            return serviceAidl;
+                        }
+                    } catch (Exception eAidl) {
+                        Log.d(TAG, "Failed to get cas AIDL service");
                     }
-            } catch (Exception eV1_1) {
-                Log.d(TAG, "Failed to get cas@1.1 service");
-            }
+                    return null;
+                }
+            };
 
-            try {
-                Log.d(TAG, "Trying to get cas@1.0 service");
-                return IMediaCasService.getService(true /*wait*/);
-            } catch (Exception eV1_0) {
-                Log.d(TAG, "Failed to get cas@1.0 service");
-            }
+    private static final Singleton<android.hardware.cas.V1_0.IMediaCasService> sServiceHidl =
+            new Singleton<android.hardware.cas.V1_0.IMediaCasService>() {
+                @Override
+                protected android.hardware.cas.V1_0.IMediaCasService create() {
+                    try {
+                        Log.d(TAG, "Trying to get cas@1.2 service");
+                        android.hardware.cas.V1_2.IMediaCasService serviceV12 =
+                                android.hardware.cas.V1_2.IMediaCasService.getService(
+                                        true /*wait*/);
+                        if (serviceV12 != null) {
+                            return serviceV12;
+                        }
+                    } catch (Exception eV1_2) {
+                        Log.d(TAG, "Failed to get cas@1.2 service");
+                    }
 
-            return null;
-        }
-    };
+                    try {
+                        Log.d(TAG, "Trying to get cas@1.1 service");
+                        android.hardware.cas.V1_1.IMediaCasService serviceV11 =
+                                android.hardware.cas.V1_1.IMediaCasService.getService(
+                                        true /*wait*/);
+                        if (serviceV11 != null) {
+                            return serviceV11;
+                        }
+                    } catch (Exception eV1_1) {
+                        Log.d(TAG, "Failed to get cas@1.1 service");
+                    }
+
+                    try {
+                        Log.d(TAG, "Trying to get cas@1.0 service");
+                        return android.hardware.cas.V1_0.IMediaCasService.getService(true /*wait*/);
+                    } catch (Exception eV1_0) {
+                        Log.d(TAG, "Failed to get cas@1.0 service");
+                    }
+
+                    return null;
+                }
+            };
 
     static IMediaCasService getService() {
         return sService.get();
     }
 
+    static android.hardware.cas.V1_0.IMediaCasService getServiceHidl() {
+        return sServiceHidl.get();
+    }
+
     private void validateInternalStates() {
-        if (mICas == null) {
+        if (mICas == null && mICasHidl == null) {
             throw new IllegalStateException();
         }
     }
 
     private void cleanupAndRethrowIllegalState() {
         mICas = null;
-        mICasV11 = null;
-        mICasV12 = null;
+        mICasHidl = null;
+        mICasHidl11 = null;
+        mICasHidl12 = null;
         throw new IllegalStateException();
     }
 
@@ -341,7 +364,7 @@
                         toBytes((ArrayList<Byte>) msg.obj));
             } else if (msg.what == MSG_CAS_SESSION_EVENT) {
                 Bundle bundle = msg.getData();
-                ArrayList<Byte> sessionId = toByteArray(bundle.getByteArray(SESSION_KEY));
+                byte[] sessionId = bundle.getByteArray(SESSION_KEY);
                 mListener.onSessionEvent(MediaCas.this,
                         createFromSessionId(sessionId), msg.arg1, msg.arg2,
                         bundle.getByteArray(DATA_KEY));
@@ -357,40 +380,94 @@
         }
     }
 
-    private final ICasListener.Stub mBinder = new ICasListener.Stub() {
-        @Override
-        public void onEvent(int event, int arg, @Nullable ArrayList<Byte> data)
-                throws RemoteException {
-            if (mEventHandler != null) {
-                mEventHandler.sendMessage(mEventHandler.obtainMessage(
-                    EventHandler.MSG_CAS_EVENT, event, arg, data));
-            }
-        }
-        @Override
-        public void onSessionEvent(@NonNull ArrayList<Byte> sessionId,
-                int event, int arg, @Nullable ArrayList<Byte> data)
-                throws RemoteException {
-            if (mEventHandler != null) {
-                Message msg = mEventHandler.obtainMessage();
-                msg.what = EventHandler.MSG_CAS_SESSION_EVENT;
-                msg.arg1 = event;
-                msg.arg2 = arg;
-                Bundle bundle = new Bundle();
-                bundle.putByteArray(EventHandler.SESSION_KEY, toBytes(sessionId));
-                bundle.putByteArray(EventHandler.DATA_KEY, toBytes(data));
-                msg.setData(bundle);
-                mEventHandler.sendMessage(msg);
-            }
-        }
-        @Override
-        public void onStatusUpdate(byte status, int arg)
-                throws RemoteException {
-            if (mEventHandler != null) {
-                mEventHandler.sendMessage(mEventHandler.obtainMessage(
-                    EventHandler.MSG_CAS_STATUS_EVENT, status, arg));
-            }
-        }
-    };
+    private final ICasListener.Stub mBinder =
+            new ICasListener.Stub() {
+                @Override
+                public void onEvent(int event, int arg, byte[] data) throws RemoteException {
+                    if (mEventHandler != null) {
+                        mEventHandler.sendMessage(
+                                mEventHandler.obtainMessage(
+                                        EventHandler.MSG_CAS_EVENT, event, arg, data));
+                    }
+                }
+
+                @Override
+                public void onSessionEvent(byte[] sessionId, int event, int arg, byte[] data)
+                        throws RemoteException {
+                    if (mEventHandler != null) {
+                        Message msg = mEventHandler.obtainMessage();
+                        msg.what = EventHandler.MSG_CAS_SESSION_EVENT;
+                        msg.arg1 = event;
+                        msg.arg2 = arg;
+                        Bundle bundle = new Bundle();
+                        bundle.putByteArray(EventHandler.SESSION_KEY, sessionId);
+                        bundle.putByteArray(EventHandler.DATA_KEY, data);
+                        msg.setData(bundle);
+                        mEventHandler.sendMessage(msg);
+                    }
+                }
+
+                @Override
+                public void onStatusUpdate(byte status, int arg) throws RemoteException {
+                    if (mEventHandler != null) {
+                        mEventHandler.sendMessage(
+                                mEventHandler.obtainMessage(
+                                        EventHandler.MSG_CAS_STATUS_EVENT, status, arg));
+                    }
+                }
+
+                @Override
+                public synchronized String getInterfaceHash() throws android.os.RemoteException {
+                    return ICasListener.Stub.HASH;
+                }
+
+                @Override
+                public int getInterfaceVersion() throws android.os.RemoteException {
+                    return ICasListener.Stub.VERSION;
+                }
+            };
+
+    private final android.hardware.cas.V1_2.ICasListener.Stub mBinderHidl =
+            new android.hardware.cas.V1_2.ICasListener.Stub() {
+                @Override
+                public void onEvent(int event, int arg, @Nullable ArrayList<Byte> data)
+                        throws RemoteException {
+                    if (mEventHandler != null) {
+                        mEventHandler.sendMessage(
+                                mEventHandler.obtainMessage(
+                                        EventHandler.MSG_CAS_EVENT, event, arg, data));
+                    }
+                }
+
+                @Override
+                public void onSessionEvent(
+                        @NonNull ArrayList<Byte> sessionId,
+                        int event,
+                        int arg,
+                        @Nullable ArrayList<Byte> data)
+                        throws RemoteException {
+                    if (mEventHandler != null) {
+                        Message msg = mEventHandler.obtainMessage();
+                        msg.what = EventHandler.MSG_CAS_SESSION_EVENT;
+                        msg.arg1 = event;
+                        msg.arg2 = arg;
+                        Bundle bundle = new Bundle();
+                        bundle.putByteArray(EventHandler.SESSION_KEY, toBytes(sessionId));
+                        bundle.putByteArray(EventHandler.DATA_KEY, toBytes(data));
+                        msg.setData(bundle);
+                        mEventHandler.sendMessage(msg);
+                    }
+                }
+
+                @Override
+                public void onStatusUpdate(byte status, int arg) throws RemoteException {
+                    if (mEventHandler != null) {
+                        mEventHandler.sendMessage(
+                                mEventHandler.obtainMessage(
+                                        EventHandler.MSG_CAS_STATUS_EVENT, status, arg));
+                    }
+                }
+            };
 
     private final TunerResourceManager.ResourcesReclaimListener mResourceListener =
             new TunerResourceManager.ResourcesReclaimListener() {
@@ -422,6 +499,11 @@
             mName = null;
         }
 
+        PluginDescriptor(@NonNull AidlCasPluginDescriptor descriptor) {
+            mCASystemId = descriptor.caSystemId;
+            mName = descriptor.name;
+        }
+
         PluginDescriptor(@NonNull HidlCasPluginDescriptor descriptor) {
             mCASystemId = descriptor.caSystemId;
             mName = descriptor.name;
@@ -467,19 +549,20 @@
         }
         return data;
     }
+
     /**
      * Class for an open session with the CA system.
      */
     public final class Session implements AutoCloseable {
-        final ArrayList<Byte> mSessionId;
+        final byte[] mSessionId;
         boolean mIsClosed = false;
 
-        Session(@NonNull ArrayList<Byte> sessionId) {
-            mSessionId = new ArrayList<Byte>(sessionId);
+        Session(@NonNull byte[] sessionId) {
+            mSessionId = sessionId;
         }
 
         private void validateSessionInternalStates() {
-            if (mICas == null) {
+            if (mICas == null && mICasHidl == null) {
                 throw new IllegalStateException();
             }
             if (mIsClosed) {
@@ -496,7 +579,7 @@
          */
         public boolean equals(Object obj) {
             if (obj instanceof Session) {
-                return mSessionId.equals(((Session) obj).mSessionId);
+                return Arrays.equals(mSessionId, ((Session) obj).mSessionId);
             }
             return false;
         }
@@ -515,8 +598,13 @@
             validateSessionInternalStates();
 
             try {
-                MediaCasException.throwExceptionIfNeeded(
-                        mICas.setSessionPrivateData(mSessionId, toByteArray(data, 0, data.length)));
+                if (mICas != null) {
+                    mICas.setSessionPrivateData(mSessionId, data);
+                } else {
+                    MediaCasException.throwExceptionIfNeeded(
+                            mICasHidl.setSessionPrivateData(
+                                    toByteArray(mSessionId), toByteArray(data, 0, data.length)));
+                }
             } catch (RemoteException e) {
                 cleanupAndRethrowIllegalState();
             }
@@ -539,8 +627,13 @@
             validateSessionInternalStates();
 
             try {
-                MediaCasException.throwExceptionIfNeeded(
-                        mICas.processEcm(mSessionId, toByteArray(data, offset, length)));
+                if (mICas != null) {
+                    mICas.processEcm(mSessionId, data);
+                } else {
+                    MediaCasException.throwExceptionIfNeeded(
+                            mICasHidl.processEcm(
+                                    toByteArray(mSessionId), toByteArray(data, offset, length)));
+                }
             } catch (RemoteException e) {
                 cleanupAndRethrowIllegalState();
             }
@@ -576,15 +669,23 @@
         public void sendSessionEvent(int event, int arg, @Nullable byte[] data)
                 throws MediaCasException {
             validateSessionInternalStates();
+            if (mICas != null) {
+                try {
+                    mICas.sendSessionEvent(mSessionId, event, arg, data);
+                } catch (RemoteException e) {
+                    cleanupAndRethrowIllegalState();
+                }
+            }
 
-            if (mICasV11 == null) {
+            if (mICasHidl11 == null) {
                 Log.d(TAG, "Send Session Event isn't supported by cas@1.0 interface");
                 throw new UnsupportedCasException("Send Session Event is not supported");
             }
 
             try {
                 MediaCasException.throwExceptionIfNeeded(
-                        mICasV11.sendSessionEvent(mSessionId, event, arg, toByteArray(data)));
+                        mICasHidl11.sendSessionEvent(
+                                toByteArray(mSessionId), event, arg, toByteArray(data)));
             } catch (RemoteException e) {
                 cleanupAndRethrowIllegalState();
             }
@@ -600,7 +701,7 @@
         @NonNull
         public byte[] getSessionId() {
             validateSessionInternalStates();
-            return toBytes(mSessionId);
+            return mSessionId;
         }
 
         /**
@@ -613,8 +714,12 @@
         public void close() {
             validateSessionInternalStates();
             try {
-                MediaCasStateException.throwExceptionIfNeeded(
-                        mICas.closeSession(mSessionId));
+                if (mICas != null) {
+                    mICas.closeSession(mSessionId);
+                } else {
+                    MediaCasStateException.throwExceptionIfNeeded(
+                            mICasHidl.closeSession(toByteArray(mSessionId)));
+                }
                 mIsClosed = true;
                 removeSessionFromResourceMap(this);
             } catch (RemoteException e) {
@@ -623,8 +728,8 @@
         }
     }
 
-    Session createFromSessionId(@NonNull ArrayList<Byte> sessionId) {
-        if (sessionId == null || sessionId.size() == 0) {
+    Session createFromSessionId(byte[] sessionId) {
+        if (sessionId == null || sessionId.length == 0) {
             return null;
         }
         return new Session(sessionId);
@@ -638,12 +743,20 @@
      * @return Whether the specified CA system is supported on this device.
      */
     public static boolean isSystemIdSupported(int CA_system_id) {
-        IMediaCasService service = getService();
-
+        IMediaCasService service = sService.get();
         if (service != null) {
             try {
                 return service.isSystemIdSupported(CA_system_id);
             } catch (RemoteException e) {
+                return false;
+            }
+        }
+
+        android.hardware.cas.V1_0.IMediaCasService serviceHidl = sServiceHidl.get();
+        if (serviceHidl != null) {
+            try {
+                return serviceHidl.isSystemIdSupported(CA_system_id);
+            } catch (RemoteException e) {
             }
         }
         return false;
@@ -655,12 +768,26 @@
      * @return an array of descriptors for the available CA plugins.
      */
     public static PluginDescriptor[] enumeratePlugins() {
-        IMediaCasService service = getService();
-
+        IMediaCasService service = sService.get();
         if (service != null) {
             try {
-                ArrayList<HidlCasPluginDescriptor> descriptors =
-                        service.enumeratePlugins();
+                AidlCasPluginDescriptor[] descriptors = service.enumeratePlugins();
+                if (descriptors.length == 0) {
+                    return null;
+                }
+                PluginDescriptor[] results = new PluginDescriptor[descriptors.length];
+                for (int i = 0; i < results.length; i++) {
+                    results[i] = new PluginDescriptor(descriptors[i]);
+                }
+                return results;
+            } catch (RemoteException e) {
+            }
+        }
+
+        android.hardware.cas.V1_0.IMediaCasService serviceHidl = sServiceHidl.get();
+        if (serviceHidl != null) {
+            try {
+                ArrayList<HidlCasPluginDescriptor> descriptors = serviceHidl.enumeratePlugins();
                 if (descriptors.size() == 0) {
                     return null;
                 }
@@ -680,29 +807,40 @@
             mCasSystemId = casSystemId;
             mUserId = Process.myUid();
             IMediaCasService service = getService();
-            android.hardware.cas.V1_2.IMediaCasService serviceV12 =
-                    android.hardware.cas.V1_2.IMediaCasService.castFrom(service);
-            if (serviceV12 == null) {
-                android.hardware.cas.V1_1.IMediaCasService serviceV11 =
-                    android.hardware.cas.V1_1.IMediaCasService.castFrom(service);
-                if (serviceV11 == null) {
-                    Log.d(TAG, "Used cas@1_0 interface to create plugin");
-                    mICas = service.createPlugin(casSystemId, mBinder);
-                } else {
-                    Log.d(TAG, "Used cas@1.1 interface to create plugin");
-                    mICas = mICasV11 = serviceV11.createPluginExt(casSystemId, mBinder);
-                }
+            if (service != null) {
+                Log.d(TAG, "Use CAS AIDL interface to create plugin");
+                mICas = service.createPlugin(casSystemId, mBinder);
             } else {
-                Log.d(TAG, "Used cas@1.2 interface to create plugin");
-                mICas = mICasV11 = mICasV12 =
-                    android.hardware.cas.V1_2.ICas
-                        .castFrom(serviceV12.createPluginExt(casSystemId, mBinder));
+                android.hardware.cas.V1_0.IMediaCasService serviceV10 = getServiceHidl();
+                android.hardware.cas.V1_2.IMediaCasService serviceV12 =
+                        android.hardware.cas.V1_2.IMediaCasService.castFrom(serviceV10);
+                if (serviceV12 == null) {
+                    android.hardware.cas.V1_1.IMediaCasService serviceV11 =
+                            android.hardware.cas.V1_1.IMediaCasService.castFrom(serviceV10);
+                    if (serviceV11 == null) {
+                    Log.d(TAG, "Used cas@1_0 interface to create plugin");
+                        mICasHidl = serviceV10.createPlugin(casSystemId, mBinderHidl);
+                    } else {
+                    Log.d(TAG, "Used cas@1.1 interface to create plugin");
+                        mICasHidl =
+                                mICasHidl11 = serviceV11.createPluginExt(casSystemId, mBinderHidl);
+                    }
+                } else {
+                    Log.d(TAG, "Used cas@1.2 interface to create plugin");
+                    mICasHidl =
+                            mICasHidl11 =
+                                    mICasHidl12 =
+                                            android.hardware.cas.V1_2.ICas.castFrom(
+                                                    serviceV12.createPluginExt(
+                                                            casSystemId, mBinderHidl));
+                }
             }
         } catch(Exception e) {
             Log.e(TAG, "Failed to create plugin: " + e);
             mICas = null;
+            mICasHidl = null;
         } finally {
-            if (mICas == null) {
+            if (mICas == null && mICasHidl == null) {
                 throw new UnsupportedCasException(
                     "Unsupported casSystemId " + casSystemId);
             }
@@ -783,9 +921,22 @@
     }
 
     IHwBinder getBinder() {
+        if (mICas != null) {
+            return null; // Return IHwBinder only for HIDL
+        }
+
         validateInternalStates();
 
-        return mICas.asBinder();
+        return mICasHidl.asBinder();
+    }
+
+    /**
+     * Check if the HAL is an AIDL implementation
+     *
+     * @hide
+     */
+    public boolean isAidlHal() {
+        return mICas != null;
     }
 
     /**
@@ -886,8 +1037,12 @@
         validateInternalStates();
 
         try {
-            MediaCasException.throwExceptionIfNeeded(
-                    mICas.setPrivateData(toByteArray(data, 0, data.length)));
+            if (mICas != null) {
+                mICas.setPrivateData(data);
+            } else {
+                MediaCasException.throwExceptionIfNeeded(
+                        mICasHidl.setPrivateData(toByteArray(data, 0, data.length)));
+            }
         } catch (RemoteException e) {
             cleanupAndRethrowIllegalState();
         }
@@ -899,7 +1054,7 @@
         @Override
         public void onValues(int status, ArrayList<Byte> sessionId) {
             mStatus = status;
-            mSession = createFromSessionId(sessionId);
+            mSession = createFromSessionId(toBytes(sessionId));
         }
     }
 
@@ -912,7 +1067,7 @@
         @Override
         public void onValues(int status, ArrayList<Byte> sessionId) {
             mStatus = status;
-            mSession = createFromSessionId(sessionId);
+            mSession = createFromSessionId(toBytes(sessionId));
         }
     }
 
@@ -971,15 +1126,19 @@
         int sessionResourceHandle = getSessionResourceHandle();
 
         try {
-            OpenSessionCallback cb = new OpenSessionCallback();
-            mICas.openSession(cb);
-            MediaCasException.throwExceptionIfNeeded(cb.mStatus);
-            addSessionToResourceMap(cb.mSession, sessionResourceHandle);
-            Log.d(TAG, "Write Stats Log for succeed to Open Session.");
-            FrameworkStatsLog
-                    .write(FrameworkStatsLog.TV_CAS_SESSION_OPEN_STATUS, mUserId, mCasSystemId,
+            if (mICasHidl != null) {
+                OpenSessionCallback cb = new OpenSessionCallback();
+                mICasHidl.openSession(cb);
+                MediaCasException.throwExceptionIfNeeded(cb.mStatus);
+                addSessionToResourceMap(cb.mSession, sessionResourceHandle);
+                Log.d(TAG, "Write Stats Log for succeed to Open Session.");
+                FrameworkStatsLog.write(
+                        FrameworkStatsLog.TV_CAS_SESSION_OPEN_STATUS,
+                        mUserId,
+                        mCasSystemId,
                         FrameworkStatsLog.TV_CAS_SESSION_OPEN_STATUS__STATE__SUCCEEDED);
-            return cb.mSession;
+                return cb.mSession;
+            }
         } catch (RemoteException e) {
             cleanupAndRethrowIllegalState();
         }
@@ -1012,14 +1171,30 @@
             throws MediaCasException {
         int sessionResourceHandle = getSessionResourceHandle();
 
-        if (mICasV12 == null) {
+        if (mICas != null) {
+            try {
+                byte[] sessionId = mICas.openSession(sessionUsage, scramblingMode);
+                Session session = createFromSessionId(sessionId);
+                addSessionToResourceMap(session, sessionResourceHandle);
+                Log.d(TAG, "Write Stats Log for succeed to Open Session.");
+                FrameworkStatsLog.write(
+                        FrameworkStatsLog.TV_CAS_SESSION_OPEN_STATUS,
+                        mUserId,
+                        mCasSystemId,
+                        FrameworkStatsLog.TV_CAS_SESSION_OPEN_STATUS__STATE__SUCCEEDED);
+                return session;
+            } catch (RemoteException e) {
+                cleanupAndRethrowIllegalState();
+            }
+        }
+        if (mICasHidl12 == null) {
             Log.d(TAG, "Open Session with scrambling mode is only supported by cas@1.2+ interface");
             throw new UnsupportedCasException("Open Session with scrambling mode is not supported");
         }
 
         try {
             OpenSession_1_2_Callback cb = new OpenSession_1_2_Callback();
-            mICasV12.openSession_1_2(sessionUsage, scramblingMode, cb);
+            mICasHidl12.openSession_1_2(sessionUsage, scramblingMode, cb);
             MediaCasException.throwExceptionIfNeeded(cb.mStatus);
             addSessionToResourceMap(cb.mSession, sessionResourceHandle);
             Log.d(TAG, "Write Stats Log for succeed to Open Session.");
@@ -1053,8 +1228,12 @@
         validateInternalStates();
 
         try {
-            MediaCasException.throwExceptionIfNeeded(
-                    mICas.processEmm(toByteArray(data, offset, length)));
+            if (mICas != null) {
+                mICas.processEmm(Arrays.copyOfRange(data, offset, length));
+            } else {
+                MediaCasException.throwExceptionIfNeeded(
+                        mICasHidl.processEmm(toByteArray(data, offset, length)));
+            }
         } catch (RemoteException e) {
             cleanupAndRethrowIllegalState();
         }
@@ -1092,8 +1271,12 @@
         validateInternalStates();
 
         try {
-            MediaCasException.throwExceptionIfNeeded(
-                    mICas.sendEvent(event, arg, toByteArray(data)));
+            if (mICas != null) {
+                mICas.sendEvent(event, arg, data);
+            } else {
+                MediaCasException.throwExceptionIfNeeded(
+                        mICasHidl.sendEvent(event, arg, toByteArray(data)));
+            }
         } catch (RemoteException e) {
             cleanupAndRethrowIllegalState();
         }
@@ -1114,8 +1297,11 @@
         validateInternalStates();
 
         try {
-            MediaCasException.throwExceptionIfNeeded(
-                    mICas.provision(provisionString));
+            if (mICas != null) {
+                mICas.provision(provisionString);
+            } else {
+                MediaCasException.throwExceptionIfNeeded(mICasHidl.provision(provisionString));
+            }
         } catch (RemoteException e) {
             cleanupAndRethrowIllegalState();
         }
@@ -1136,8 +1322,12 @@
         validateInternalStates();
 
         try {
-            MediaCasException.throwExceptionIfNeeded(
-                    mICas.refreshEntitlements(refreshType, toByteArray(refreshData)));
+            if (mICas != null) {
+                mICas.refreshEntitlements(refreshType, refreshData);
+            } else {
+                MediaCasException.throwExceptionIfNeeded(
+                        mICasHidl.refreshEntitlements(refreshType, toByteArray(refreshData)));
+            }
         } catch (RemoteException e) {
             cleanupAndRethrowIllegalState();
         }
@@ -1163,6 +1353,13 @@
             } finally {
                 mICas = null;
             }
+        } else if (mICasHidl != null) {
+            try {
+                mICasHidl.release();
+            } catch (RemoteException e) {
+            } finally {
+                mICasHidl = mICasHidl11 = mICasHidl12 = null;
+            }
         }
 
         if (mTunerResourceManager != null) {
diff --git a/media/java/android/media/MediaDescrambler.java b/media/java/android/media/MediaDescrambler.java
index 99bd254..b4bdf93d 100644
--- a/media/java/android/media/MediaDescrambler.java
+++ b/media/java/android/media/MediaDescrambler.java
@@ -17,14 +17,26 @@
 package android.media;
 
 import android.annotation.NonNull;
-import android.hardware.cas.V1_0.*;
+import android.hardware.cas.DestinationBuffer;
+import android.hardware.cas.IDescrambler;
+import android.hardware.cas.ScramblingControl;
+import android.hardware.cas.SharedBuffer;
+import android.hardware.cas.SubSample;
+import android.hardware.cas.V1_0.IDescramblerBase;
+import android.hardware.common.Ashmem;
+import android.hardware.common.NativeHandle;
 import android.media.MediaCasException.UnsupportedCasException;
 import android.os.IHwBinder;
+import android.os.ParcelFileDescriptor;
 import android.os.RemoteException;
 import android.os.ServiceSpecificException;
+import android.os.SharedMemory;
+import android.system.ErrnoException;
 import android.util.Log;
 
+import java.io.IOException;
 import java.nio.ByteBuffer;
+import java.util.ArrayList;
 
 /**
  * MediaDescrambler class can be used in conjunction with {@link android.media.MediaCodec}
@@ -39,7 +51,198 @@
  */
 public final class MediaDescrambler implements AutoCloseable {
     private static final String TAG = "MediaDescrambler";
-    private IDescramblerBase mIDescrambler;
+    private DescramblerWrapper mIDescrambler;
+
+    private interface DescramblerWrapper {
+
+        IHwBinder asBinder();
+
+        int descramble(
+                @NonNull ByteBuffer srcBuf,
+                @NonNull ByteBuffer dstBuf,
+                @NonNull MediaCodec.CryptoInfo cryptoInfo)
+                throws RemoteException;
+
+        boolean requiresSecureDecoderComponent(@NonNull String mime) throws RemoteException;
+
+        void setMediaCasSession(byte[] sessionId) throws RemoteException;
+
+        void release() throws RemoteException;
+    }
+    ;
+
+    private long getSubsampleInfo(
+            int numSubSamples,
+            int[] numBytesOfClearData,
+            int[] numBytesOfEncryptedData,
+            SubSample[] subSamples) {
+        long totalSize = 0;
+
+        for (int i = 0; i < numSubSamples; i++) {
+            totalSize += numBytesOfClearData[i];
+            subSamples[i].numBytesOfClearData = numBytesOfClearData[i];
+            totalSize += numBytesOfEncryptedData[i];
+            subSamples[i].numBytesOfEncryptedData = numBytesOfEncryptedData[i];
+        }
+        return totalSize;
+    }
+
+    private ParcelFileDescriptor createSharedMemory(ByteBuffer buffer, String name)
+            throws RemoteException {
+        byte[] source = buffer.array();
+        if (source.length == 0) {
+            return null;
+        }
+        ParcelFileDescriptor fd = null;
+        try {
+            SharedMemory ashmem = SharedMemory.create(name == null ? "" : name, source.length);
+            ByteBuffer ptr = ashmem.mapReadWrite();
+            ptr.put(buffer);
+            ashmem.unmap(ptr);
+            fd = ashmem.getFdDup();
+            return fd;
+        } catch (ErrnoException | IOException e) {
+            throw new RemoteException(e);
+        }
+    }
+
+    private class AidlDescrambler implements DescramblerWrapper {
+
+        IDescrambler mAidlDescrambler;
+
+        AidlDescrambler(IDescrambler aidlDescrambler) {
+            mAidlDescrambler = aidlDescrambler;
+        }
+
+        @Override
+        public IHwBinder asBinder() {
+            return null;
+        }
+
+        @Override
+        public int descramble(
+                @NonNull ByteBuffer src,
+                @NonNull ByteBuffer dst,
+                @NonNull MediaCodec.CryptoInfo cryptoInfo)
+                throws RemoteException {
+            SubSample[] subSamples = new SubSample[cryptoInfo.numSubSamples];
+            long totalLength =
+                    getSubsampleInfo(
+                            cryptoInfo.numSubSamples,
+                            cryptoInfo.numBytesOfClearData,
+                            cryptoInfo.numBytesOfEncryptedData,
+                            subSamples);
+            SharedBuffer srcBuffer = new SharedBuffer();
+            DestinationBuffer dstBuffer;
+            srcBuffer.heapBase = new Ashmem();
+            srcBuffer.heapBase.fd = createSharedMemory(src, "Descrambler Source Buffer");
+            srcBuffer.heapBase.size = src.array().length;
+            if (dst == null) {
+                dstBuffer = DestinationBuffer.nonsecureMemory(srcBuffer);
+            } else {
+                ParcelFileDescriptor pfd =
+                        createSharedMemory(dst, "Descrambler Destination Buffer");
+                NativeHandle nh = new NativeHandle();
+                nh.fds = new ParcelFileDescriptor[] {pfd};
+                nh.ints = new int[] {1}; // Mark 1 since source buffer also uses it?
+                dstBuffer = DestinationBuffer.secureMemory(nh);
+            }
+            @ScramblingControl int control = cryptoInfo.key[0];
+
+            return mAidlDescrambler.descramble(
+                    (byte) control,
+                    subSamples,
+                    srcBuffer,
+                    src.position(),
+                    dstBuffer,
+                    dst.position());
+        }
+
+        @Override
+        public boolean requiresSecureDecoderComponent(@NonNull String mime) throws RemoteException {
+            return mAidlDescrambler.requiresSecureDecoderComponent(mime);
+        }
+
+        @Override
+        public void setMediaCasSession(byte[] sessionId) throws RemoteException {
+            mAidlDescrambler.setMediaCasSession(sessionId);
+        }
+
+        @Override
+        public void release() throws RemoteException {
+            mAidlDescrambler.release();
+        }
+    }
+
+    private class HidlDescrambler implements DescramblerWrapper {
+
+        IDescramblerBase mHidlDescrambler;
+
+        HidlDescrambler(IDescramblerBase hidlDescrambler) {
+            mHidlDescrambler = hidlDescrambler;
+            native_setup(hidlDescrambler.asBinder());
+        }
+
+        @Override
+        public IHwBinder asBinder() {
+            return mHidlDescrambler.asBinder();
+        }
+
+        @Override
+        public int descramble(
+                @NonNull ByteBuffer srcBuf,
+                @NonNull ByteBuffer dstBuf,
+                @NonNull MediaCodec.CryptoInfo cryptoInfo)
+                throws RemoteException {
+
+            try {
+                return native_descramble(
+                        cryptoInfo.key[0],
+                        cryptoInfo.key[1],
+                        cryptoInfo.numSubSamples,
+                        cryptoInfo.numBytesOfClearData,
+                        cryptoInfo.numBytesOfEncryptedData,
+                        srcBuf,
+                        srcBuf.position(),
+                        srcBuf.limit(),
+                        dstBuf,
+                        dstBuf.position(),
+                        dstBuf.limit());
+            } catch (ServiceSpecificException e) {
+                MediaCasStateException.throwExceptionIfNeeded(e.errorCode, e.getMessage());
+            } catch (RemoteException e) {
+                cleanupAndRethrowIllegalState();
+            }
+            return -1;
+        }
+
+        @Override
+        public boolean requiresSecureDecoderComponent(@NonNull String mime) throws RemoteException {
+            return mHidlDescrambler.requiresSecureDecoderComponent(mime);
+        }
+
+        @Override
+        public void setMediaCasSession(byte[] sessionId) throws RemoteException {
+            ArrayList<Byte> byteArray = new ArrayList<>();
+
+            if (sessionId != null) {
+                int length = sessionId.length;
+                byteArray = new ArrayList<Byte>(length);
+                for (int i = 0; i < length; i++) {
+                    byteArray.add(Byte.valueOf(sessionId[i]));
+                }
+            }
+
+            MediaCasStateException.throwExceptionIfNeeded(
+                    mHidlDescrambler.setMediaCasSession(byteArray));
+        }
+
+        @Override
+        public void release() throws RemoteException {
+            mHidlDescrambler.release();
+            native_release();
+        }
+    }
 
     private final void validateInternalStates() {
         if (mIDescrambler == null) {
@@ -61,7 +264,14 @@
      */
     public MediaDescrambler(int CA_system_id) throws UnsupportedCasException {
         try {
-            mIDescrambler = MediaCas.getService().createDescrambler(CA_system_id);
+            if (MediaCas.getService() != null) {
+                mIDescrambler =
+                        new AidlDescrambler(MediaCas.getService().createDescrambler(CA_system_id));
+            } else if (MediaCas.getServiceHidl() != null) {
+                mIDescrambler =
+                        new HidlDescrambler(
+                                MediaCas.getServiceHidl().createDescrambler(CA_system_id));
+            }
         } catch(Exception e) {
             Log.e(TAG, "Failed to create descrambler: " + e);
             mIDescrambler = null;
@@ -70,7 +280,6 @@
                 throw new UnsupportedCasException("Unsupported CA_system_id " + CA_system_id);
             }
         }
-        native_setup(mIDescrambler.asBinder());
     }
 
     IHwBinder getBinder() {
@@ -117,8 +326,7 @@
         validateInternalStates();
 
         try {
-            MediaCasStateException.throwExceptionIfNeeded(
-                    mIDescrambler.setMediaCasSession(session.mSessionId));
+            mIDescrambler.setMediaCasSession(session.mSessionId);
         } catch (RemoteException e) {
             cleanupAndRethrowIllegalState();
         }
@@ -126,27 +334,31 @@
 
     /**
      * Scramble control value indicating that the samples are not scrambled.
+     *
      * @see #descramble(ByteBuffer, ByteBuffer, android.media.MediaCodec.CryptoInfo)
      */
-    public static final byte SCRAMBLE_CONTROL_UNSCRAMBLED = 0;
+    public static final byte SCRAMBLE_CONTROL_UNSCRAMBLED = (byte) ScramblingControl.UNSCRAMBLED;
 
     /**
      * Scramble control value reserved and shouldn't be used currently.
+     *
      * @see #descramble(ByteBuffer, ByteBuffer, android.media.MediaCodec.CryptoInfo)
      */
-    public static final byte SCRAMBLE_CONTROL_RESERVED    = 1;
+    public static final byte SCRAMBLE_CONTROL_RESERVED = (byte) ScramblingControl.RESERVED;
 
     /**
      * Scramble control value indicating that the even key is used.
+     *
      * @see #descramble(ByteBuffer, ByteBuffer, android.media.MediaCodec.CryptoInfo)
      */
-    public static final byte SCRAMBLE_CONTROL_EVEN_KEY     = 2;
+    public static final byte SCRAMBLE_CONTROL_EVEN_KEY = (byte) ScramblingControl.EVENKEY;
 
     /**
      * Scramble control value indicating that the odd key is used.
+     *
      * @see #descramble(ByteBuffer, ByteBuffer, android.media.MediaCodec.CryptoInfo)
      */
-    public static final byte SCRAMBLE_CONTROL_ODD_KEY      = 3;
+    public static final byte SCRAMBLE_CONTROL_ODD_KEY = (byte) ScramblingControl.ODDKEY;
 
     /**
      * Scramble flag for a hint indicating that the descrambling request is for
@@ -207,14 +419,7 @@
         }
 
         try {
-            return native_descramble(
-                    cryptoInfo.key[0],
-                    cryptoInfo.key[1],
-                    cryptoInfo.numSubSamples,
-                    cryptoInfo.numBytesOfClearData,
-                    cryptoInfo.numBytesOfEncryptedData,
-                    srcBuf, srcBuf.position(), srcBuf.limit(),
-                    dstBuf, dstBuf.position(), dstBuf.limit());
+            return mIDescrambler.descramble(srcBuf, dstBuf, cryptoInfo);
         } catch (ServiceSpecificException e) {
             MediaCasStateException.throwExceptionIfNeeded(e.errorCode, e.getMessage());
         } catch (RemoteException e) {
@@ -233,7 +438,6 @@
                 mIDescrambler = null;
             }
         }
-        native_release();
     }
 
     @Override
@@ -256,4 +460,4 @@
     }
 
     private long mNativeContext;
-}
\ No newline at end of file
+}
diff --git a/media/java/android/media/MediaExtractor.java b/media/java/android/media/MediaExtractor.java
index dab188e..b11a810 100644
--- a/media/java/android/media/MediaExtractor.java
+++ b/media/java/android/media/MediaExtractor.java
@@ -36,7 +36,6 @@
 import java.lang.annotation.RetentionPolicy;
 import java.nio.ByteBuffer;
 import java.nio.ByteOrder;
-import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashMap;
 import java.util.List;
@@ -325,14 +324,6 @@
         }
     }
 
-    private ArrayList<Byte> toByteArray(@NonNull byte[] data) {
-        ArrayList<Byte> byteArray = new ArrayList<Byte>(data.length);
-        for (int i = 0; i < data.length; i++) {
-            byteArray.add(i, Byte.valueOf(data[i]));
-        }
-        return byteArray;
-    }
-
     /**
      * Retrieves the information about the conditional access system used to scramble
      * a track.
@@ -357,7 +348,7 @@
                 buf.rewind();
                 final byte[] sessionId = new byte[buf.remaining()];
                 buf.get(sessionId);
-                session = mMediaCas.createFromSessionId(toByteArray(sessionId));
+                session = mMediaCas.createFromSessionId(sessionId);
             }
             return new CasInfo(systemId, session, privateData);
         }