Merge "cas: convert MediaCas to HIDL"
diff --git a/Android.mk b/Android.mk
index b0507b2..6fb5aec 100644
--- a/Android.mk
+++ b/Android.mk
@@ -438,10 +438,6 @@
 	location/java/android/location/INetInitiatedListener.aidl \
 	location/java/com/android/internal/location/ILocationProvider.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/IAudioRoutesObserver.aidl \
 	media/java/android/media/IMediaHTTPConnection.aidl \
@@ -614,6 +610,8 @@
     android.hardware.vibrator-V1.1-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
 LOCAL_REQUIRED_MODULES += libtextclassifier
 
diff --git a/media/java/android/media/MediaCas.java b/media/java/android/media/MediaCas.java
index ce50cc8..12352e7 100644
--- a/media/java/android/media/MediaCas.java
+++ b/media/java/android/media/MediaCas.java
@@ -18,21 +18,20 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.hardware.cas.V1_0.*;
 import android.media.MediaCasException.*;
 import android.os.Handler;
 import android.os.HandlerThread;
-import android.os.IBinder;
+import android.os.IHwBinder;
 import android.os.Looper;
 import android.os.Message;
-import android.os.Parcel;
-import android.os.Parcelable;
 import android.os.Process;
 import android.os.RemoteException;
-import android.os.ServiceManager;
-import android.os.ServiceSpecificException;
 import android.util.Log;
 import android.util.Singleton;
 
+import java.util.ArrayList;
+
 /**
  * MediaCas can be used to obtain keys for descrambling protected media streams, in
  * conjunction with {@link android.media.MediaDescrambler}. The MediaCas APIs are
@@ -95,7 +94,6 @@
  */
 public final class MediaCas implements AutoCloseable {
     private static final String TAG = "MediaCas";
-    private final ParcelableCasData mCasData = new ParcelableCasData();
     private ICas mICas;
     private EventListener mListener;
     private HandlerThread mHandlerThread;
@@ -105,8 +103,10 @@
             new Singleton<IMediaCasService>() {
         @Override
         protected IMediaCasService create() {
-            return IMediaCasService.Stub.asInterface(
-                    ServiceManager.getService("media.cas"));
+            try {
+                return IMediaCasService.getService();
+            } catch (RemoteException e) {}
+            return null;
         }
     };
 
@@ -136,14 +136,15 @@
         @Override
         public void handleMessage(Message msg) {
             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() {
         @Override
-        public void onEvent(int event, int arg, @Nullable byte[] data)
+        public void onEvent(int event, int arg, @Nullable ArrayList<Byte> data)
                 throws RemoteException {
             mEventHandler.sendMessage(mEventHandler.obtainMessage(
                     EventHandler.MSG_CAS_EVENT, event, arg, data));
@@ -151,51 +152,6 @@
     };
 
     /**
-     * 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.
      *
      * Returned as results of {@link #enumeratePlugins}.
@@ -210,9 +166,9 @@
             mName = null;
         }
 
-        PluginDescriptor(int CA_system_id, String name) {
-            mCASystemId = CA_system_id;
-            mName = name;
+        PluginDescriptor(@NonNull HidlCasPluginDescriptor descriptor) {
+            mCASystemId = descriptor.caSystemId;
+            mName = descriptor.name;
         }
 
         public int getSystemId() {
@@ -230,13 +186,38 @@
         }
     }
 
+    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.
      */
     public final class Session implements AutoCloseable {
-        final byte[] mSessionId;
+        final ArrayList<Byte> mSessionId;
 
-        Session(@NonNull byte[] sessionId) {
+        Session(@NonNull ArrayList<Byte> sessionId) {
             mSessionId = sessionId;
         }
 
@@ -254,9 +235,8 @@
             validateInternalStates();
 
             try {
-                mICas.setSessionPrivateData(mSessionId, data);
-            } catch (ServiceSpecificException e) {
-                MediaCasException.throwExceptions(e);
+                MediaCasException.throwExceptionIfNeeded(
+                        mICas.setSessionPrivateData(mSessionId, toByteArray(data, 0, data.length)));
             } catch (RemoteException e) {
                 cleanupAndRethrowIllegalState();
             }
@@ -279,10 +259,8 @@
             validateInternalStates();
 
             try {
-                mCasData.set(data, offset, length);
-                mICas.processEcm(mSessionId, mCasData);
-            } catch (ServiceSpecificException e) {
-                MediaCasException.throwExceptions(e);
+                MediaCasException.throwExceptionIfNeeded(
+                        mICas.processEcm(mSessionId, toByteArray(data, offset, length)));
             } catch (RemoteException e) {
                 cleanupAndRethrowIllegalState();
             }
@@ -314,57 +292,22 @@
             validateInternalStates();
 
             try {
-                mICas.closeSession(mSessionId);
-            } catch (ServiceSpecificException e) {
-                MediaCasStateException.throwExceptions(e);
+                MediaCasStateException.throwExceptionIfNeeded(
+                        mICas.closeSession(mSessionId));
             } catch (RemoteException e) {
                 cleanupAndRethrowIllegalState();
             }
         }
     }
 
-    Session createFromSessionId(byte[] sessionId) {
-        if (sessionId == null || sessionId.length == 0) {
+    Session createFromSessionId(@NonNull ArrayList<Byte> sessionId) {
+        if (sessionId == null || sessionId.size() == 0) {
             return null;
         }
         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.
      *
      * @param CA_system_id the id of the CA system.
@@ -393,13 +336,14 @@
 
         if (service != null) {
             try {
-                ParcelableCasPluginDescriptor[] descriptors = service.enumeratePlugins();
-                if (descriptors.length == 0) {
+                ArrayList<HidlCasPluginDescriptor> descriptors =
+                        service.enumeratePlugins();
+                if (descriptors.size() == 0) {
                     return null;
                 }
-                PluginDescriptor[] results = new PluginDescriptor[descriptors.length];
+                PluginDescriptor[] results = new PluginDescriptor[descriptors.size()];
                 for (int i = 0; i < results.length; i++) {
-                    results[i] = descriptors[i];
+                    results[i] = new PluginDescriptor(descriptors.get(i));
                 }
                 return results;
             } catch (RemoteException e) {
@@ -430,7 +374,7 @@
         }
     }
 
-    IBinder getBinder() {
+    IHwBinder getBinder() {
         validateInternalStates();
 
         return mICas.asBinder();
@@ -497,14 +441,22 @@
         validateInternalStates();
 
         try {
-            mICas.setPrivateData(data);
-        } catch (ServiceSpecificException e) {
-            MediaCasException.throwExceptions(e);
+            MediaCasException.throwExceptionIfNeeded(
+                    mICas.setPrivateData(toByteArray(data, 0, data.length)));
         } catch (RemoteException e) {
             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
      * conditional access system.
@@ -519,9 +471,10 @@
         validateInternalStates();
 
         try {
-            return createFromSessionId(mICas.openSession());
-        } catch (ServiceSpecificException e) {
-            MediaCasException.throwExceptions(e);
+            OpenSessionCallback cb = new OpenSessionCallback();
+            mICas.openSession(cb);
+            MediaCasException.throwExceptionIfNeeded(cb.mStatus);
+            return cb.mSession;
         } catch (RemoteException e) {
             cleanupAndRethrowIllegalState();
         }
@@ -544,10 +497,8 @@
         validateInternalStates();
 
         try {
-            mCasData.set(data, offset, length);
-            mICas.processEmm(mCasData);
-        } catch (ServiceSpecificException e) {
-            MediaCasException.throwExceptions(e);
+            MediaCasException.throwExceptionIfNeeded(
+                    mICas.processEmm(toByteArray(data, offset, length)));
         } catch (RemoteException e) {
             cleanupAndRethrowIllegalState();
         }
@@ -585,9 +536,8 @@
         validateInternalStates();
 
         try {
-            mICas.sendEvent(event, arg, data);
-        } catch (ServiceSpecificException e) {
-            MediaCasException.throwExceptions(e);
+            MediaCasException.throwExceptionIfNeeded(
+                    mICas.sendEvent(event, arg, toByteArray(data)));
         } catch (RemoteException e) {
             cleanupAndRethrowIllegalState();
         }
@@ -608,9 +558,8 @@
         validateInternalStates();
 
         try {
-            mICas.provision(provisionString);
-        } catch (ServiceSpecificException e) {
-            MediaCasException.throwExceptions(e);
+            MediaCasException.throwExceptionIfNeeded(
+                    mICas.provision(provisionString));
         } catch (RemoteException e) {
             cleanupAndRethrowIllegalState();
         }
@@ -631,9 +580,8 @@
         validateInternalStates();
 
         try {
-            mICas.refreshEntitlements(refreshType, refreshData);
-        } catch (ServiceSpecificException e) {
-            MediaCasException.throwExceptions(e);
+            MediaCasException.throwExceptionIfNeeded(
+                    mICas.refreshEntitlements(refreshType, toByteArray(refreshData)));
         } catch (RemoteException e) {
             cleanupAndRethrowIllegalState();
         }
diff --git a/media/java/android/media/MediaCasException.java b/media/java/android/media/MediaCasException.java
index 485f6ee..35fb104 100644
--- a/media/java/android/media/MediaCasException.java
+++ b/media/java/android/media/MediaCasException.java
@@ -16,60 +16,29 @@
 
 package android.media;
 
-import android.os.ServiceSpecificException;
+import android.hardware.cas.V1_0.Status;
 
 /**
  * Base class for MediaCas exceptions
  */
 public class MediaCasException extends Exception {
-
-    /** @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) {
+    private MediaCasException(String detailMessage) {
         super(detailMessage);
     }
 
-    static void throwExceptions(ServiceSpecificException e) throws MediaCasException {
-        if (e.errorCode == ERROR_DRM_NOT_PROVISIONED) {
-            throw new NotProvisionedException(e.getMessage());
-        } else if (e.errorCode == ERROR_DRM_RESOURCE_BUSY) {
-            throw new ResourceBusyException(e.getMessage());
-        } else if (e.errorCode == ERROR_DRM_DEVICE_REVOKED) {
-            throw new DeniedByServerException(e.getMessage());
+    static void throwExceptionIfNeeded(int error) throws MediaCasException {
+        if (error == Status.OK) {
+            return;
+        }
+
+        if (error == Status.ERROR_CAS_NOT_PROVISIONED) {
+            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 {
-            MediaCasStateException.throwExceptions(e);
+            MediaCasStateException.throwExceptionIfNeeded(error);
         }
     }
 
diff --git a/media/java/android/media/MediaCasStateException.java b/media/java/android/media/MediaCasStateException.java
index cf05c29..26c5792 100644
--- a/media/java/android/media/MediaCasStateException.java
+++ b/media/java/android/media/MediaCasStateException.java
@@ -18,9 +18,8 @@
 
 import android.annotation.NonNull;
 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
@@ -29,46 +28,62 @@
     private final int mErrorCode;
     private final String mDiagnosticInfo;
 
-    /** @hide */
-    public MediaCasStateException(int err, @Nullable String msg, @Nullable String diagnosticInfo) {
+    private MediaCasStateException(int err, @Nullable String msg, @Nullable String diagnosticInfo) {
         super(msg);
         mErrorCode = err;
         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 = "";
-        switch (e.errorCode) {
-        case ERROR_DRM_UNKNOWN:
+        switch (err) {
+        case Status.ERROR_CAS_UNKNOWN:
             diagnosticInfo = "General CAS error";
             break;
-        case ERROR_DRM_NO_LICENSE:
+        case Status.ERROR_CAS_NO_LICENSE:
             diagnosticInfo = "No license";
             break;
-        case ERROR_DRM_LICENSE_EXPIRED:
+        case Status.ERROR_CAS_LICENSE_EXPIRED:
             diagnosticInfo = "License expired";
             break;
-        case ERROR_DRM_SESSION_NOT_OPENED:
+        case Status.ERROR_CAS_SESSION_NOT_OPENED:
             diagnosticInfo = "Session not opened";
             break;
-        case ERROR_DRM_DECRYPT_UNIT_NOT_INITIALIZED:
-            diagnosticInfo = "Not initialized";
-            break;
-        case ERROR_DRM_DECRYPT:
-            diagnosticInfo = "Decrypt error";
-            break;
-        case ERROR_DRM_CANNOT_HANDLE:
+        case Status.ERROR_CAS_CANNOT_HANDLE:
             diagnosticInfo = "Unsupported scheme or data format";
             break;
-        case ERROR_DRM_TAMPER_DETECTED:
+        case Status.ERROR_CAS_INVALID_STATE:
+            diagnosticInfo = "Invalid CAS state";
+            break;
+        case Status.ERROR_CAS_INSUFFICIENT_OUTPUT_PROTECTION:
+            diagnosticInfo = "Insufficient output protection";
+            break;
+        case Status.ERROR_CAS_TAMPER_DETECTED:
             diagnosticInfo = "Tamper detected";
             break;
+        case Status.ERROR_CAS_DECRYPT_UNIT_NOT_INITIALIZED:
+            diagnosticInfo = "Not initialized";
+            break;
+        case Status.ERROR_CAS_DECRYPT:
+            diagnosticInfo = "Decrypt error";
+            break;
         default:
             diagnosticInfo = "Unknown CAS state exception";
             break;
         }
-        throw new MediaCasStateException(e.errorCode, e.getMessage(),
-                String.format("%s (err=%d)", diagnosticInfo, e.errorCode));
+        throw new MediaCasStateException(err, msg,
+                String.format("%s (err=%d)", diagnosticInfo, err));
     }
 
     /**
diff --git a/media/java/android/media/MediaCodec.java b/media/java/android/media/MediaCodec.java
index e667554..3d5f6bc 100644
--- a/media/java/android/media/MediaCodec.java
+++ b/media/java/android/media/MediaCodec.java
@@ -26,6 +26,7 @@
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
+import android.os.IHwBinder;
 import android.os.Looper;
 import android.os.Message;
 import android.os.PersistableBundle;
@@ -1903,7 +1904,7 @@
 
     private void configure(
             @Nullable MediaFormat format, @Nullable Surface surface,
-            @Nullable MediaCrypto crypto, @Nullable IBinder descramblerBinder,
+            @Nullable MediaCrypto crypto, @Nullable IHwBinder descramblerBinder,
             @ConfigureFlag int flags) {
         if (crypto != null && descramblerBinder != null) {
             throw new IllegalArgumentException("Can't use crypto and descrambler together!");
@@ -2018,7 +2019,7 @@
     private native final void native_configure(
             @Nullable String[] keys, @Nullable Object[] values,
             @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
diff --git a/media/java/android/media/MediaDescrambler.java b/media/java/android/media/MediaDescrambler.java
index b75b7dd..40c837b 100644
--- a/media/java/android/media/MediaDescrambler.java
+++ b/media/java/android/media/MediaDescrambler.java
@@ -17,10 +17,9 @@
 package android.media;
 
 import android.annotation.NonNull;
+import android.hardware.cas.V1_0.*;
 import android.media.MediaCasException.UnsupportedCasException;
-import android.os.IBinder;
-import android.os.Parcel;
-import android.os.Parcelable;
+import android.os.IHwBinder;
 import android.os.RemoteException;
 import android.os.ServiceSpecificException;
 import android.util.Log;
@@ -40,7 +39,7 @@
  */
 public final class MediaDescrambler implements AutoCloseable {
     private static final String TAG = "MediaDescrambler";
-    private IDescrambler mIDescrambler;
+    private IDescramblerBase mIDescrambler;
 
     private final void validateInternalStates() {
         if (mIDescrambler == null) {
@@ -54,39 +53,6 @@
     }
 
     /**
-     * Class for parceling descrambling parameters over IDescrambler binder.
-     */
-    // This class currently is not used by Java binder. descramble() goes through
-    // jni to use shared memory. However, the parcelable is still required for AIDL.
-    static class DescrambleInfo implements Parcelable {
-        private DescrambleInfo() {
-        }
-
-        private DescrambleInfo(Parcel in) {
-        }
-
-        @Override
-        public int describeContents() {
-            return 0;
-        }
-
-        @Override
-        public void writeToParcel(Parcel dest, int flags) {
-        }
-
-        public static final Parcelable.Creator<DescrambleInfo> CREATOR
-                = new Parcelable.Creator<DescrambleInfo>() {
-            public DescrambleInfo createFromParcel(Parcel in) {
-                return new DescrambleInfo(in);
-            }
-
-            public DescrambleInfo[] newArray(int size) {
-                return new DescrambleInfo[size];
-            }
-        };
-    }
-
-    /**
      * Instantiate a MediaDescrambler.
      *
      * @param CA_system_id The system id of the scrambling scheme.
@@ -107,7 +73,7 @@
         native_setup(mIDescrambler.asBinder());
     }
 
-    IBinder getBinder() {
+    IHwBinder getBinder() {
         validateInternalStates();
 
         return mIDescrambler.asBinder();
@@ -151,9 +117,8 @@
         validateInternalStates();
 
         try {
-            mIDescrambler.setMediaCasSession(session.mSessionId);
-        } catch (ServiceSpecificException e) {
-            MediaCasStateException.throwExceptions(e);
+            MediaCasStateException.throwExceptionIfNeeded(
+                    mIDescrambler.setMediaCasSession(session.mSessionId));
         } catch (RemoteException e) {
             cleanupAndRethrowIllegalState();
         }
@@ -210,7 +175,9 @@
                     srcBuf, srcBuf.position(), srcBuf.limit(),
                     dstBuf, dstBuf.position(), dstBuf.limit());
         } catch (ServiceSpecificException e) {
-            MediaCasStateException.throwExceptions(e);
+            MediaCasStateException.throwExceptionIfNeeded(e.errorCode, e.getMessage());
+        } catch (RemoteException e) {
+            cleanupAndRethrowIllegalState();
         }
         return -1;
     }
@@ -234,12 +201,12 @@
     }
 
     private static native final void native_init();
-    private native final void native_setup(@NonNull IBinder decramblerBinder);
+    private native final void native_setup(@NonNull IHwBinder decramblerBinder);
     private native final void native_release();
     private native final int native_descramble(
             byte key, int numSubSamples, int[] numBytesOfClearData, int[] numBytesOfEncryptedData,
             @NonNull ByteBuffer srcBuf, int srcOffset, int srcLimit,
-            ByteBuffer dstBuf, int dstOffset, int dstLimit);
+            ByteBuffer dstBuf, int dstOffset, int dstLimit) throws RemoteException;
 
     static {
         System.loadLibrary("media_jni");
diff --git a/media/java/android/media/MediaExtractor.java b/media/java/android/media/MediaExtractor.java
index fe461be..2c1b4b3 100644
--- a/media/java/android/media/MediaExtractor.java
+++ b/media/java/android/media/MediaExtractor.java
@@ -26,8 +26,8 @@
 import android.media.MediaFormat;
 import android.media.MediaHTTPService;
 import android.net.Uri;
-import android.os.Bundle;
 import android.os.IBinder;
+import android.os.IHwBinder;
 import android.os.PersistableBundle;
 
 import com.android.internal.util.Preconditions;
@@ -38,9 +38,8 @@
 import java.lang.annotation.RetentionPolicy;
 import java.nio.ByteBuffer;
 import java.nio.ByteOrder;
-import java.util.Collections;
+import java.util.ArrayList;
 import java.util.HashMap;
-import java.util.List;
 import java.util.Map;
 import java.util.UUID;
 
@@ -263,7 +262,7 @@
         nativeSetMediaCas(mediaCas.getBinder());
     }
 
-    private native final void nativeSetMediaCas(@NonNull IBinder casBinder);
+    private native final void nativeSetMediaCas(@NonNull IHwBinder casBinder);
 
     /**
      * Describes the conditional access system used to scramble a track.
@@ -300,6 +299,14 @@
         }
     }
 
+    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.
@@ -317,7 +324,7 @@
                 buf.rewind();
                 final byte[] sessionId = new byte[buf.remaining()];
                 buf.get(sessionId);
-                session = mMediaCas.createFromSessionId(sessionId);
+                session = mMediaCas.createFromSessionId(toByteArray(sessionId));
             }
             return new CasInfo(systemId, session);
         }
diff --git a/media/jni/Android.bp b/media/jni/Android.bp
index 9686ab5..02667ca 100644
--- a/media/jni/Android.bp
+++ b/media/jni/Android.bp
@@ -50,6 +50,12 @@
         "libexif",
         "libpiex",
         "libandroidfw",
+        "libhidlbase",
+        "libhidltransport",
+        "android.hardware.cas@1.0",
+        "android.hardware.cas.native@1.0",
+        "android.hidl.memory@1.0",
+        "android.hidl.token@1.0-utils",
     ],
 
     header_libs: ["libhardware_headers"],
diff --git a/media/jni/android_media_MediaCodec.cpp b/media/jni/android_media_MediaCodec.cpp
index 04230a0..a27d157 100644
--- a/media/jni/android_media_MediaCodec.cpp
+++ b/media/jni/android_media_MediaCodec.cpp
@@ -21,6 +21,7 @@
 #include "android_media_MediaCodec.h"
 
 #include "android_media_MediaCrypto.h"
+#include "android_media_MediaDescrambler.h"
 #include "android_media_MediaMetricsJNI.h"
 #include "android_media_Utils.h"
 #include "android_runtime/AndroidRuntime.h"
@@ -29,7 +30,7 @@
 #include "jni.h"
 #include "JNIHelp.h"
 
-#include <android/media/IDescrambler.h>
+#include <android/hardware/cas/native/1.0/IDescrambler.h>
 
 #include <cutils/compiler.h>
 
@@ -1010,8 +1011,7 @@
 
     sp<IDescrambler> descrambler;
     if (descramblerBinderObj != NULL) {
-        sp<IBinder> binder = ibinderForJavaObject(env, descramblerBinderObj);
-        descrambler = interface_cast<IDescrambler>(binder);
+        descrambler = JDescrambler::GetDescrambler(env, descramblerBinderObj);
     }
 
     err = codec->configure(format, bufferProducer, crypto, descrambler, flags);
@@ -1952,7 +1952,7 @@
 
     { "native_configure",
       "([Ljava/lang/String;[Ljava/lang/Object;Landroid/view/Surface;"
-      "Landroid/media/MediaCrypto;Landroid/os/IBinder;I)V",
+      "Landroid/media/MediaCrypto;Landroid/os/IHwBinder;I)V",
       (void *)android_media_MediaCodec_native_configure },
 
     { "native_setSurface",
diff --git a/media/jni/android_media_MediaCodec.h b/media/jni/android_media_MediaCodec.h
index c9a1700..2ec8703 100644
--- a/media/jni/android_media_MediaCodec.h
+++ b/media/jni/android_media_MediaCodec.h
@@ -36,10 +36,13 @@
 struct MediaCodec;
 struct PersistentSurface;
 class Surface;
-namespace media {
-class IDescrambler;
-};
-using namespace media;
+namespace hardware {
+namespace cas {
+namespace native {
+namespace V1_0 {
+struct IDescrambler;
+}}}}
+using hardware::cas::native::V1_0::IDescrambler;
 
 struct JMediaCodec : public AHandler {
     JMediaCodec(
diff --git a/media/jni/android_media_MediaDescrambler.cpp b/media/jni/android_media_MediaDescrambler.cpp
index 85d33b7..bee5218 100644
--- a/media/jni/android_media_MediaDescrambler.cpp
+++ b/media/jni/android_media_MediaDescrambler.cpp
@@ -20,16 +20,19 @@
 
 #include "android_media_MediaDescrambler.h"
 #include "android_runtime/AndroidRuntime.h"
-#include "android_util_Binder.h"
+#include "android_os_HwRemoteBinder.h"
 #include "JNIHelp.h"
 
-#include <android/media/IDescrambler.h>
+#include <android/hardware/cas/native/1.0/BpHwDescrambler.h>
+#include <android/hardware/cas/native/1.0/BnHwDescrambler.h>
 #include <binder/MemoryDealer.h>
+#include <hidl/HidlSupport.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <nativehelper/ScopedLocalRef.h>
 
 namespace android {
-using media::MediaDescrambler::DescrambleInfo;
+
+using hardware::hidl_handle;
 
 struct fields_t {
     jfieldID context;
@@ -94,10 +97,9 @@
 }
 
 JDescrambler::JDescrambler(JNIEnv *env, jobject descramblerBinderObj) {
-    sp<IDescrambler> cas;
-    if (descramblerBinderObj != NULL) {
-        sp<IBinder> binder = ibinderForJavaObject(env, descramblerBinderObj);
-        mDescrambler = interface_cast<IDescrambler>(binder);
+    mDescrambler = GetDescrambler(env, descramblerBinderObj);
+    if (mDescrambler == NULL) {
+        jniThrowException(env, "java/lang/NullPointerException", NULL);
     }
 }
 
@@ -108,9 +110,23 @@
     mDealer.clear();
 }
 
-void JDescrambler::ensureBufferCapacity(size_t neededSize) {
+// static
+sp<IDescrambler> JDescrambler::GetDescrambler(JNIEnv *env, jobject obj) {
+    if (obj != NULL) {
+        sp<hardware::IBinder> hwBinder =
+                JHwRemoteBinder::GetNativeContext(env, obj)->getBinder();
+
+        if (hwBinder != NULL) {
+            return hardware::fromBinder<
+                    IDescrambler, BpHwDescrambler, BnHwDescrambler>(hwBinder);
+        }
+    }
+    return NULL;
+}
+
+bool JDescrambler::ensureBufferCapacity(size_t neededSize) {
     if (mMem != NULL && mMem->size() >= neededSize) {
-        return;
+        return true;
     }
 
     ALOGV("ensureBufferCapacity: current size %zu, new size %zu",
@@ -122,49 +138,84 @@
     neededSize = (neededSize + 65535) & ~65535;
     mDealer = new MemoryDealer(neededSize, "JDescrambler");
     mMem = mDealer->allocate(neededSize);
+
+    ssize_t offset;
+    size_t size;
+    sp<IMemoryHeap> heap = mMem->getMemory(&offset, &size);
+    if (heap == NULL) {
+        return false;
+    }
+
+    native_handle_t* nativeHandle = native_handle_create(1, 0);
+    if (!nativeHandle) {
+        ALOGE("ensureBufferCapacity: failed to create native handle");
+        return false;
+    }
+    nativeHandle->data[0] = heap->getHeapID();
+    mDescramblerSrcBuffer.heapBase = hidl_memory("ashmem",
+            hidl_handle(nativeHandle), heap->getSize());
+    mDescramblerSrcBuffer.offset = (uint64_t) offset;
+    mDescramblerSrcBuffer.size = (uint64_t) size;
+    return true;
 }
 
-Status JDescrambler::descramble(
+status_t JDescrambler::descramble(
         jbyte key,
-        size_t numSubSamples,
         ssize_t totalLength,
-        DescramblerPlugin::SubSample *subSamples,
+        const hidl_vec<SubSample>& subSamples,
         const void *srcPtr,
         jint srcOffset,
         void *dstPtr,
         jint dstOffset,
-        ssize_t *result) {
+        Status *status,
+        uint32_t *bytesWritten,
+        hidl_string *detailedError) {
     // TODO: IDescrambler::descramble() is re-entrant, however because we
     // only have 1 shared mem buffer, we can only do 1 descramble at a time.
     // Concurrency might be improved by allowing on-demand allocation of up
     // to 2 shared mem buffers.
     Mutex::Autolock autolock(mSharedMemLock);
 
-    ensureBufferCapacity(totalLength);
+    if (!ensureBufferCapacity(totalLength)) {
+        return NO_MEMORY;
+    }
 
     memcpy(mMem->pointer(),
             (const void*)((const uint8_t*)srcPtr + srcOffset), totalLength);
 
-    DescrambleInfo info;
-    info.dstType = DescrambleInfo::kDestinationTypeVmPointer;
-    info.numSubSamples = numSubSamples;
-    info.scramblingControl = (DescramblerPlugin::ScramblingControl) key;
-    info.subSamples = subSamples;
-    info.srcMem = mMem;
-    info.srcOffset = 0;
-    info.dstPtr = NULL;
-    info.dstOffset = 0;
+    DestinationBuffer dstBuffer;
+    dstBuffer.type = BufferType::SHARED_MEMORY;
+    dstBuffer.nonsecureMemory = mDescramblerSrcBuffer;
 
-    int32_t descrambleResult;
-    Status status = mDescrambler->descramble(info, &descrambleResult);
+    auto err = mDescrambler->descramble(
+            (ScramblingControl) key,
+            subSamples,
+            mDescramblerSrcBuffer,
+            0,
+            dstBuffer,
+            0,
+            [&status, &bytesWritten, &detailedError] (
+                    Status _status, uint32_t _bytesWritten,
+                    const hidl_string& _detailedError) {
+                *status = _status;
+                *bytesWritten = _bytesWritten;
+                *detailedError = _detailedError;
+            });
 
-    if (status.isOk()) {
-        *result = (descrambleResult <= totalLength) ? descrambleResult : -1;
-        if (*result > 0) {
-            memcpy((void*)((uint8_t*)dstPtr + dstOffset), mMem->pointer(), *result);
+    if (!err.isOk()) {
+        return FAILED_TRANSACTION;
+    }
+
+    if (*status == Status::OK) {
+        if (*bytesWritten > 0 && (ssize_t) *bytesWritten <= totalLength) {
+            memcpy((void*)((uint8_t*)dstPtr + dstOffset), mMem->pointer(), *bytesWritten);
+        } else {
+            // status seems OK but bytesWritten is invalid, we really
+            // have no idea what is wrong.
+            *status = Status::ERROR_CAS_UNKNOWN;
         }
     }
-    return status;
+    return OK;
 }
 
 }  // namespace android
@@ -191,10 +242,10 @@
 
 static ssize_t getSubSampleInfo(JNIEnv *env, jint numSubSamples,
         jintArray numBytesOfClearDataObj, jintArray numBytesOfEncryptedDataObj,
-        DescramblerPlugin::SubSample **outSubSamples) {
+        hidl_vec<SubSample> *outSubSamples) {
 
-    if (numSubSamples <= 0 || numSubSamples >=
-            (signed)(INT32_MAX / sizeof(DescramblerPlugin::SubSample)) ) {
+    if (numSubSamples <= 0 ||
+            numSubSamples >= (signed)(INT32_MAX / sizeof(SubSample))) {
         // subSamples array may silently overflow if number of samples are
         // too large.  Use INT32_MAX as maximum allocation size may be less
         // than SIZE_MAX on some platforms.
@@ -215,24 +266,23 @@
             ? NULL
             : env->GetIntArrayElements(numBytesOfEncryptedDataObj, &isCopy);
 
-    DescramblerPlugin::SubSample *subSamples =
-            new(std::nothrow) DescramblerPlugin::SubSample[numSubSamples];
-
+    outSubSamples->resize(numSubSamples);
+    SubSample *subSamples = outSubSamples->data();
     if (subSamples == NULL) {
         ALOGE("Failed to allocate SubSample array!");
         return -1;
     }
 
     for (jint i = 0; i < numSubSamples; ++i) {
-        subSamples[i].mNumBytesOfClearData =
+        subSamples[i].numBytesOfClearData =
             (numBytesOfClearData == NULL) ? 0 : numBytesOfClearData[i];
 
-        subSamples[i].mNumBytesOfEncryptedData =
+        subSamples[i].numBytesOfEncryptedData =
             (numBytesOfEncryptedData == NULL)
                 ? 0 : numBytesOfEncryptedData[i];
 
-        totalSize += subSamples[i].mNumBytesOfClearData +
-                subSamples[i].mNumBytesOfEncryptedData;
+        totalSize += subSamples[i].numBytesOfClearData +
+                subSamples[i].numBytesOfEncryptedData;
     }
 
     if (numBytesOfEncryptedData != NULL) {
@@ -248,12 +298,9 @@
     }
 
     if (totalSize < 0) {
-        delete[] subSamples;
         return -1;
     }
 
-    *outSubSamples = subSamples;
-
     return totalSize;
 }
 
@@ -280,12 +327,6 @@
             clazz.get(), ctor, serviceSpecificError, msgObj.get());
 }
 
-static void throwServiceSpecificException(
-        JNIEnv *env, int serviceSpecificError, const char *msg) {
-    jthrowable exception = createServiceSpecificException(env, serviceSpecificError, msg);
-    env->Throw(exception);
-}
-
 static jint android_media_MediaDescrambler_native_descramble(
         JNIEnv *env, jobject thiz, jbyte key, jint numSubSamples,
         jintArray numBytesOfClearDataObj, jintArray numBytesOfEncryptedDataObj,
@@ -293,11 +334,12 @@
         jobject dstBuf, jint dstOffset, jint dstLimit) {
     sp<JDescrambler> descrambler = getDescrambler(env, thiz);
     if (descrambler == NULL) {
-        jniThrowException(env, "java/lang/IllegalStateException", NULL);
+        jniThrowException(env, "java/lang/IllegalStateException",
+                "Invalid descrambler object!");
         return -1;
     }
 
-    DescramblerPlugin::SubSample *subSamples = NULL;
+    hidl_vec<SubSample> subSamples;
     ssize_t totalLength = getSubSampleInfo(
             env, numSubSamples, numBytesOfClearDataObj,
             numBytesOfEncryptedDataObj, &subSamples);
@@ -307,7 +349,6 @@
         return -1;
     }
 
-    ssize_t result = -1;
     void *srcPtr = NULL, *dstPtr = NULL;
     jbyteArray srcArray = NULL, dstArray = NULL;
     status_t err = getBufferAndSize(
@@ -329,13 +370,15 @@
     }
 
     Status status;
-    if (err == OK) {
-        status = descrambler->descramble(
-                key, numSubSamples, totalLength, subSamples,
-                srcPtr, srcOffset, dstPtr, dstOffset, &result);
-    }
+    uint32_t bytesWritten;
+    hidl_string detailedError;
 
-    delete[] subSamples;
+    err = descrambler->descramble(
+            key, totalLength, subSamples,
+            srcPtr, srcOffset, dstPtr, dstOffset,
+            &status, &bytesWritten, &detailedError);
+
+    // Release byte array before throwing
     if (srcArray != NULL) {
         env->ReleaseByteArrayElements(srcArray, (jbyte *)srcPtr, 0);
     }
@@ -343,51 +386,17 @@
         env->ReleaseByteArrayElements(dstArray, (jbyte *)dstPtr, 0);
     }
 
-    if (!status.isOk()) {
-        switch (status.exceptionCode()) {
-            case Status::EX_SECURITY:
-                jniThrowException(env, "java/lang/SecurityException",
-                        status.exceptionMessage());
-                break;
-            case Status::EX_BAD_PARCELABLE:
-                jniThrowException(env, "java/lang/BadParcelableException",
-                        status.exceptionMessage());
-                break;
-            case Status::EX_ILLEGAL_ARGUMENT:
-                jniThrowException(env, "java/lang/IllegalArgumentException",
-                        status.exceptionMessage());
-                break;
-            case Status::EX_NULL_POINTER:
-                jniThrowException(env, "java/lang/NullPointerException",
-                        status.exceptionMessage());
-                break;
-            case Status::EX_ILLEGAL_STATE:
-                jniThrowException(env, "java/lang/IllegalStateException",
-                        status.exceptionMessage());
-                break;
-            case Status::EX_NETWORK_MAIN_THREAD:
-                jniThrowException(env, "java/lang/NetworkOnMainThreadException",
-                        status.exceptionMessage());
-                break;
-            case Status::EX_UNSUPPORTED_OPERATION:
-                jniThrowException(env, "java/lang/UnsupportedOperationException",
-                        status.exceptionMessage());
-                break;
-            case Status::EX_SERVICE_SPECIFIC:
-                throwServiceSpecificException(env, status.serviceSpecificErrorCode(),
-                        status.exceptionMessage());
-                break;
-            default:
-            {
-                String8 msg;
-                msg.appendFormat("Unknown exception code: %d, msg: %s",
-                        status.exceptionCode(), status.exceptionMessage().string());
-                jniThrowException(env, "java/lang/RuntimeException", msg.string());
-                break;
-            }
-        }
+    if (err == NO_MEMORY) {
+        jniThrowException(env, "java/lang/OutOfMemoryError", NULL);
+    } else if (err == FAILED_TRANSACTION) {
+        jniThrowException(env, "android/os/RemoteException", NULL);
+    } else if (status != Status::OK) {
+        // Throw ServiceSpecific with cas error code and detailed msg,
+        // which will be re-thrown as MediaCasStateException.
+        env->Throw(createServiceSpecificException(
+                env, (int) status, detailedError.c_str()));
     }
-    return result;
+    return bytesWritten;
 }
 
 static const JNINativeMethod gMethods[] = {
@@ -395,7 +404,7 @@
             (void *)android_media_MediaDescrambler_native_release },
     { "native_init", "()V",
             (void *)android_media_MediaDescrambler_native_init },
-    { "native_setup", "(Landroid/os/IBinder;)V",
+    { "native_setup", "(Landroid/os/IHwBinder;)V",
             (void *)android_media_MediaDescrambler_native_setup },
     { "native_descramble", "(BI[I[ILjava/nio/ByteBuffer;IILjava/nio/ByteBuffer;II)I",
             (void *)android_media_MediaDescrambler_native_descramble },
diff --git a/media/jni/android_media_MediaDescrambler.h b/media/jni/android_media_MediaDescrambler.h
index aeef05e..015fad2 100644
--- a/media/jni/android_media_MediaDescrambler.h
+++ b/media/jni/android_media_MediaDescrambler.h
@@ -19,34 +19,37 @@
 
 #include "jni.h"
 
-#include <binder/Status.h>
-#include <media/cas/DescramblerAPI.h>
+#include <android/hardware/cas/native/1.0/IDescrambler.h>
+
 #include <media/stagefright/foundation/ABase.h>
 #include <utils/Mutex.h>
-#include <utils/RefBase.h>
 
 namespace android {
 class IMemory;
 class MemoryDealer;
-namespace media {
-class IDescrambler;
-};
-using namespace media;
-using binder::Status;
+
+using hardware::hidl_memory;
+using hardware::hidl_string;
+using hardware::hidl_vec;
+using namespace hardware::cas::V1_0;
+using namespace hardware::cas::native::V1_0;
 
 struct JDescrambler : public RefBase {
     JDescrambler(JNIEnv *env, jobject descramberBinderObj);
 
-    Status descramble(
+    status_t descramble(
             jbyte key,
-            size_t numSubSamples,
             ssize_t totalLength,
-            DescramblerPlugin::SubSample *subSamples,
+            const hidl_vec<SubSample>& subSamples,
             const void *srcPtr,
             jint srcOffset,
             void *dstPtr,
             jint dstOffset,
-            ssize_t *result);
+            Status *status,
+            uint32_t *bytesWritten,
+            hidl_string *detailedError);
+
+    static sp<IDescrambler> GetDescrambler(JNIEnv *env, jobject obj);
 
 protected:
     virtual ~JDescrambler();
@@ -55,9 +58,11 @@
     sp<IDescrambler> mDescrambler;
     sp<IMemory> mMem;
     sp<MemoryDealer> mDealer;
+    SharedBuffer mDescramblerSrcBuffer;
+
     Mutex mSharedMemLock;
 
-    void ensureBufferCapacity(size_t neededSize);
+    bool ensureBufferCapacity(size_t neededSize);
 
     DISALLOW_EVIL_CONSTRUCTORS(JDescrambler);
 };
diff --git a/media/jni/android_media_MediaExtractor.cpp b/media/jni/android_media_MediaExtractor.cpp
index 9e5d3d1..c9657b1 100644
--- a/media/jni/android_media_MediaExtractor.cpp
+++ b/media/jni/android_media_MediaExtractor.cpp
@@ -18,16 +18,20 @@
 #define LOG_TAG "MediaExtractor-JNI"
 #include <utils/Log.h>
 
+#include "android_media_MediaDataSource.h"
 #include "android_media_MediaExtractor.h"
 #include "android_media_MediaMetricsJNI.h"
-
 #include "android_media_Utils.h"
+#include "android_os_HwRemoteBinder.h"
 #include "android_runtime/AndroidRuntime.h"
 #include "android_runtime/Log.h"
+#include "android_util_Binder.h"
 #include "jni.h"
 #include "JNIHelp.h"
-#include "android_media_MediaDataSource.h"
 
+#include <android/hardware/cas/1.0/BpHwCas.h>
+#include <android/hardware/cas/1.0/BnHwCas.h>
+#include <hidl/HybridInterface.h>
 #include <media/IMediaHTTPService.h>
 #include <media/hardware/CryptoAPI.h>
 #include <media/stagefright/foundation/ABuffer.h>
@@ -37,14 +41,12 @@
 #include <media/stagefright/MediaErrors.h>
 #include <media/stagefright/MetaData.h>
 #include <media/stagefright/NuMediaExtractor.h>
-#include <android/media/ICas.h>
-
 #include <nativehelper/ScopedLocalRef.h>
 
-#include "android_util_Binder.h"
-
 namespace android {
 
+using namespace hardware::cas::V1_0;
+
 struct fields_t {
     jfieldID context;
 
@@ -89,8 +91,28 @@
     return mImpl->setDataSource(datasource);
 }
 
-status_t JMediaExtractor::setMediaCas(const sp<ICas> &cas) {
-    return mImpl->setMediaCas(cas);
+status_t JMediaExtractor::setMediaCas(JNIEnv *env, jobject casBinderObj) {
+    if (casBinderObj == NULL) {
+        return BAD_VALUE;
+    }
+
+    sp<hardware::IBinder> hwBinder =
+        JHwRemoteBinder::GetNativeContext(env, casBinderObj)->getBinder();
+    if (hwBinder == NULL) {
+        return BAD_VALUE;
+    }
+
+    sp<ICas> cas = hardware::fromBinder<ICas, BpHwCas, BnHwCas>(hwBinder);
+    if (cas == NULL) {
+        return BAD_VALUE;
+    }
+
+    HalToken halToken;
+    if (!createHalToken(cas, &halToken)) {
+        return BAD_VALUE;
+    }
+
+    return mImpl->setMediaCas(halToken);
 }
 
 size_t JMediaExtractor::countTracks() const {
@@ -748,23 +770,13 @@
         return;
     }
 
-    if (casBinderObj == NULL) {
-        jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
-        return;
-    }
-
-    sp<ICas> cas;
-    if (casBinderObj != NULL) {
-        sp<IBinder> binder = ibinderForJavaObject(env, casBinderObj);
-        cas = interface_cast<ICas>(binder);
-    }
-    status_t err = extractor->setMediaCas(cas);
+    status_t err = extractor->setMediaCas(env, casBinderObj);
 
     if (err != OK) {
-        cas.clear();
+        extractor.clear();
         jniThrowException(
                 env,
-                "java/io/IllegalArgumentException",
+                "java/lang/IllegalArgumentException",
                 "Failed to set MediaCas on extractor.");
     }
 }
@@ -896,7 +908,7 @@
     { "setDataSource", "(Landroid/media/MediaDataSource;)V",
       (void *)android_media_MediaExtractor_setDataSourceCallback },
 
-    { "nativeSetMediaCas", "(Landroid/os/IBinder;)V",
+    { "nativeSetMediaCas", "(Landroid/os/IHwBinder;)V",
       (void *)android_media_MediaExtractor_setMediaCas },
 
     { "getCachedDuration", "()J",
diff --git a/media/jni/android_media_MediaExtractor.h b/media/jni/android_media_MediaExtractor.h
index 3d8c50b..94d36f2 100644
--- a/media/jni/android_media_MediaExtractor.h
+++ b/media/jni/android_media_MediaExtractor.h
@@ -28,10 +28,6 @@
 #include "jni.h"
 
 namespace android {
-namespace media {
-class ICas;
-};
-using namespace media;
 
 struct IMediaHTTPService;
 class MetaData;
@@ -48,7 +44,7 @@
     status_t setDataSource(int fd, off64_t offset, off64_t size);
     status_t setDataSource(const sp<DataSource> &source);
 
-    status_t setMediaCas(const sp<ICas> &cas);
+    status_t setMediaCas(JNIEnv *env, jobject casBinderObj);
 
     size_t countTracks() const;
     status_t getTrackFormat(size_t index, jobject *format) const;