cas: convert MediaCas to HIDL

- Remove AIDL interfaces.
- Replace usage with corresponding HIDL interfaces.
- Move MediaCasService implementation from frameworks/av
  to hardware/interfaces/cas.

bug: 22804304

Change-Id: I56ab22565a43e91481ac2759ce69462bcc194046
diff --git a/media/libmedia/IMediaExtractor.cpp b/media/libmedia/IMediaExtractor.cpp
index f08fabb..19b00f3 100644
--- a/media/libmedia/IMediaExtractor.cpp
+++ b/media/libmedia/IMediaExtractor.cpp
@@ -21,7 +21,6 @@
 #include <stdint.h>
 #include <sys/types.h>
 
-#include <android/media/ICas.h>
 #include <binder/IPCThreadState.h>
 #include <binder/Parcel.h>
 #include <media/IMediaExtractor.h>
@@ -117,12 +116,12 @@
         return NULL;
     }
 
-    virtual status_t setMediaCas(const sp<ICas> & cas) {
+    virtual status_t setMediaCas(const HInterfaceToken &casToken) {
         ALOGV("setMediaCas");
 
         Parcel data, reply;
         data.writeInterfaceToken(BpMediaExtractor::getInterfaceDescriptor());
-        data.writeStrongBinder(IInterface::asBinder(cas));
+        data.writeByteVector(casToken);
 
         status_t err = remote()->transact(SETMEDIACAS, data, &reply);
         if (err != NO_ERROR) {
@@ -206,15 +205,14 @@
             ALOGV("setMediaCas");
             CHECK_INTERFACE(IMediaExtractor, data, reply);
 
-            sp<IBinder> casBinder;
-            status_t err = data.readNullableStrongBinder(&casBinder);
+            HInterfaceToken casToken;
+            status_t err = data.readByteVector(&casToken);
             if (err != NO_ERROR) {
-                ALOGE("Error reading cas from parcel");
+                ALOGE("Error reading casToken from parcel");
                 return err;
             }
-            sp<ICas> cas = interface_cast<ICas>(casBinder);
 
-            reply->writeInt32(setMediaCas(cas));
+            reply->writeInt32(setMediaCas(casToken));
             return OK;
         }
         default:
diff --git a/media/libmedia/include/media/IMediaExtractor.h b/media/libmedia/include/media/IMediaExtractor.h
index ab40f53..1e13b65 100644
--- a/media/libmedia/include/media/IMediaExtractor.h
+++ b/media/libmedia/include/media/IMediaExtractor.h
@@ -20,14 +20,12 @@
 
 #include <media/IMediaSource.h>
 #include <media/stagefright/DataSource.h>
+#include <vector>
 
 namespace android {
 
 class MetaData;
-namespace media {
-class ICas;
-};
-using namespace media;
+typedef std::vector<uint8_t> HInterfaceToken;
 
 class IMediaExtractor : public IInterface {
 public:
@@ -65,7 +63,7 @@
     // for DRM
     virtual char* getDrmTrackInfo(size_t trackID, int *len)  = 0;
 
-    virtual status_t setMediaCas(const sp<ICas> &cas) = 0;
+    virtual status_t setMediaCas(const HInterfaceToken &casToken) = 0;
 
     virtual void setUID(uid_t uid)  = 0;
 
diff --git a/media/libstagefright/ACodecBufferChannel.cpp b/media/libstagefright/ACodecBufferChannel.cpp
index 0d9696f..3c7ae3e 100644
--- a/media/libstagefright/ACodecBufferChannel.cpp
+++ b/media/libstagefright/ACodecBufferChannel.cpp
@@ -20,7 +20,7 @@
 
 #include <numeric>
 
-#include <android/media/IDescrambler.h>
+#include <android/hardware/cas/native/1.0/IDescrambler.h>
 #include <binder/MemoryDealer.h>
 #include <media/openmax/OMX_Core.h>
 #include <media/stagefright/foundation/AMessage.h>
@@ -34,8 +34,11 @@
 #include "include/SharedMemoryBuffer.h"
 
 namespace android {
-using binder::Status;
-using MediaDescrambler::DescrambleInfo;
+using hardware::hidl_handle;
+using hardware::hidl_string;
+using hardware::hidl_vec;
+using namespace hardware::cas::V1_0;
+using namespace hardware::cas::native::V1_0;
 using BufferInfo = ACodecBufferChannel::BufferInfo;
 using BufferInfoIterator = std::vector<const BufferInfo>::const_iterator;
 
@@ -114,74 +117,97 @@
         return -ENOENT;
     }
 
-    ICrypto::DestinationBuffer destination;
+    native_handle_t *secureHandle = NULL;
     if (secure) {
         sp<SecureBuffer> secureData =
                 static_cast<SecureBuffer *>(it->mCodecBuffer.get());
-        destination.mType = secureData->getDestinationType();
-        if (destination.mType != ICrypto::kDestinationTypeNativeHandle) {
+        if (secureData->getDestinationType() != ICrypto::kDestinationTypeNativeHandle) {
             return BAD_VALUE;
         }
-        destination.mHandle =
-                static_cast<native_handle_t *>(secureData->getDestinationPointer());
-    } else {
-        destination.mType = ICrypto::kDestinationTypeSharedMemory;
-        destination.mSharedMemory = mDecryptDestination;
+        secureHandle = static_cast<native_handle_t *>(secureData->getDestinationPointer());
     }
-
-    ICrypto::SourceBuffer source;
-    source.mSharedMemory = it->mSharedEncryptedBuffer;
-    source.mHeapSeqNum = mHeapSeqNum;
-
     ssize_t result = -1;
     if (mCrypto != NULL) {
+        ICrypto::DestinationBuffer destination;
+        if (secure) {
+            destination.mType = ICrypto::kDestinationTypeNativeHandle;
+            destination.mHandle = secureHandle;
+        } else {
+            destination.mType = ICrypto::kDestinationTypeSharedMemory;
+            destination.mSharedMemory = mDecryptDestination;
+        }
+
+        ICrypto::SourceBuffer source;
+        source.mSharedMemory = it->mSharedEncryptedBuffer;
+        source.mHeapSeqNum = mHeapSeqNum;
+
         result = mCrypto->decrypt(key, iv, mode, pattern,
                 source, it->mClientBuffer->offset(),
                 subSamples, numSubSamples, destination, errorDetailMsg);
-    } else {
-        DescrambleInfo descrambleInfo;
-        descrambleInfo.dstType = destination.mType ==
-                ICrypto::kDestinationTypeSharedMemory ?
-                DescrambleInfo::kDestinationTypeVmPointer :
-                DescrambleInfo::kDestinationTypeNativeHandle;
-        descrambleInfo.scramblingControl = key != NULL ?
-                (DescramblerPlugin::ScramblingControl)key[0] :
-                DescramblerPlugin::kScrambling_Unscrambled;
-        descrambleInfo.numSubSamples = numSubSamples;
-        descrambleInfo.subSamples = (DescramblerPlugin::SubSample *)subSamples;
-        descrambleInfo.srcMem = it->mSharedEncryptedBuffer;
-        descrambleInfo.srcOffset = 0;
-        descrambleInfo.dstPtr = NULL;
-        descrambleInfo.dstOffset = 0;
-
-        int32_t descrambleResult = -1;
-        Status status = mDescrambler->descramble(descrambleInfo, &descrambleResult);
-
-        if (status.isOk()) {
-            result = descrambleResult;
-        }
 
         if (result < 0) {
-            ALOGE("descramble failed, exceptionCode=%d, err=%d, result=%zd",
-                    status.exceptionCode(), status.transactionError(), result);
-        } else {
-            ALOGV("descramble succeeded, result=%zd", result);
+            return result;
         }
 
-        if (result > 0 && destination.mType == ICrypto::kDestinationTypeSharedMemory) {
-            memcpy(destination.mSharedMemory->pointer(),
+        if (destination.mType == ICrypto::kDestinationTypeSharedMemory) {
+            memcpy(it->mCodecBuffer->base(), destination.mSharedMemory->pointer(), result);
+        }
+    } else {
+        // Here we cast CryptoPlugin::SubSample to hardware::cas::native::V1_0::SubSample
+        // directly, the structure definitions should match as checked in DescramblerImpl.cpp.
+        hidl_vec<SubSample> hidlSubSamples;
+        hidlSubSamples.setToExternal((SubSample *)subSamples, numSubSamples, false /*own*/);
+
+        ssize_t offset;
+        size_t size;
+        it->mSharedEncryptedBuffer->getMemory(&offset, &size);
+        hardware::cas::native::V1_0::SharedBuffer srcBuffer = {
+                .heapBase = mHidlMemory,
+                .offset = (uint64_t) offset,
+                .size = size
+        };
+
+        DestinationBuffer dstBuffer;
+        if (secure) {
+            dstBuffer.type = BufferType::NATIVE_HANDLE;
+            dstBuffer.secureMemory = hidl_handle(secureHandle);
+        } else {
+            dstBuffer.type = BufferType::SHARED_MEMORY;
+            dstBuffer.nonsecureMemory = srcBuffer;
+        }
+
+        Status status = Status::OK;
+        hidl_string detailedError;
+
+        auto returnVoid = mDescrambler->descramble(
+                key != NULL ? (ScramblingControl)key[0] : ScramblingControl::UNSCRAMBLED,
+                hidlSubSamples,
+                srcBuffer,
+                0,
+                dstBuffer,
+                0,
+                [&status, &result, &detailedError] (
+                        Status _status, uint32_t _bytesWritten,
+                        const hidl_string& _detailedError) {
+                    status = _status;
+                    result = (ssize_t)_bytesWritten;
+                    detailedError = _detailedError;
+                });
+
+        if (!returnVoid.isOk() || status != Status::OK || result < 0) {
+            ALOGE("descramble failed, trans=%s, status=%d, result=%zd",
+                    returnVoid.description().c_str(), status, result);
+            return UNKNOWN_ERROR;
+        }
+
+        ALOGV("descramble succeeded, %zd bytes", result);
+
+        if (dstBuffer.type == BufferType::SHARED_MEMORY) {
+            memcpy(it->mCodecBuffer->base(),
                     (uint8_t*)it->mSharedEncryptedBuffer->pointer(), result);
         }
     }
 
-    if (result < 0) {
-        return result;
-    }
-
-    if (destination.mType == ICrypto::kDestinationTypeSharedMemory) {
-        memcpy(it->mCodecBuffer->base(), destination.mSharedMemory->pointer(), result);
-    }
-
     it->mCodecBuffer->setRange(0, result);
 
     // Copy metadata from client to codec buffer.
@@ -275,10 +301,21 @@
         int32_t seqNum = mCrypto->setHeap(dealer->getMemoryHeap());
         if (seqNum >= 0) {
             mHeapSeqNum = seqNum;
-            ALOGD("setHeap returned mHeapSeqNum=%d", mHeapSeqNum);
+            ALOGV("setHeap returned mHeapSeqNum=%d", mHeapSeqNum);
         } else {
             mHeapSeqNum = -1;
-            ALOGD("setHeap failed, setting mHeapSeqNum=-1");
+            ALOGE("setHeap failed, setting mHeapSeqNum=-1");
+        }
+    } else if (mDescrambler != nullptr) {
+        sp<IMemoryHeap> heap = dealer->getMemoryHeap();
+        native_handle_t* nativeHandle = native_handle_create(1, 0);
+        if (nativeHandle != nullptr) {
+            int fd = heap->getHeapID();
+            nativeHandle->data[0] = fd;
+            mHidlMemory = hidl_memory("ashmem", hidl_handle(nativeHandle), heap->getSize());
+            ALOGV("created hidl_memory for descrambler");
+        } else {
+            ALOGE("failed to create hidl_memory for descrambler");
         }
     }
     return dealer;
diff --git a/media/libstagefright/Android.bp b/media/libstagefright/Android.bp
index 5fcb1fe..45a8d94 100644
--- a/media/libstagefright/Android.bp
+++ b/media/libstagefright/Android.bp
@@ -17,6 +17,7 @@
         "AudioPlayer.cpp",
         "AudioSource.cpp",
         "BufferImpl.cpp",
+        "CodecBase.cpp",
         "CallbackDataSource.cpp",
         "CameraSource.cpp",
         "CameraSourceTimeLapse.cpp",
@@ -105,6 +106,9 @@
         "libhidlmemory",
         "android.hidl.allocator@1.0",
         "android.hidl.memory@1.0",
+        "android.hidl.token@1.0-utils",
+        "android.hardware.cas@1.0",
+        "android.hardware.cas.native@1.0",
         "android.hardware.media.omx@1.0",
         "libstagefright_xmlparser@1.0",
     ],
diff --git a/media/libstagefright/CodecBase.cpp b/media/libstagefright/CodecBase.cpp
new file mode 100644
index 0000000..d0610b2
--- /dev/null
+++ b/media/libstagefright/CodecBase.cpp
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2017, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "CodecBase"
+
+#include <android/hardware/cas/native/1.0/IDescrambler.h>
+#include <media/ICrypto.h>
+#include <media/stagefright/CodecBase.h>
+#include <utils/Log.h>
+
+namespace android {
+
+void BufferChannelBase::setCrypto(const sp<ICrypto> &crypto) {
+    mCrypto = crypto;
+}
+
+void BufferChannelBase::setDescrambler(const sp<IDescrambler> &descrambler) {
+    mDescrambler = descrambler;
+}
+
+} // namespace android
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index bd71632..98d101a 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -23,7 +23,8 @@
 #include "include/SharedMemoryBuffer.h"
 #include "include/SoftwareRenderer.h"
 
-#include <android/media/IDescrambler.h>
+#include <android/hardware/cas/native/1.0/IDescrambler.h>
+
 #include <binder/IMemory.h>
 #include <binder/IPCThreadState.h>
 #include <binder/IServiceManager.h>
diff --git a/media/libstagefright/NuMediaExtractor.cpp b/media/libstagefright/NuMediaExtractor.cpp
index 51f1ba3..640cb82 100644
--- a/media/libstagefright/NuMediaExtractor.cpp
+++ b/media/libstagefright/NuMediaExtractor.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-//#define LOG_NDEBUG 0
+#define LOG_NDEBUG 0
 #define LOG_TAG "NuMediaExtractor"
 #include <utils/Log.h>
 
@@ -35,7 +35,6 @@
 #include <media/stagefright/MediaSource.h>
 #include <media/stagefright/MetaData.h>
 #include <media/stagefright/Utils.h>
-#include <android/media/ICas.h>
 
 namespace android {
 
@@ -83,8 +82,8 @@
         return ERROR_UNSUPPORTED;
     }
 
-    if (mCas != NULL) {
-        mImpl->setMediaCas(mCas);
+    if (!mCasToken.empty()) {
+        mImpl->setMediaCas(mCasToken);
     }
 
     status_t err = updateDurationAndBitrate();
@@ -119,8 +118,8 @@
         return ERROR_UNSUPPORTED;
     }
 
-    if (mCas != NULL) {
-        mImpl->setMediaCas(mCas);
+    if (!mCasToken.empty()) {
+        mImpl->setMediaCas(mCasToken);
     }
 
     err = updateDurationAndBitrate();
@@ -149,8 +148,8 @@
         return ERROR_UNSUPPORTED;
     }
 
-    if (mCas != NULL) {
-        mImpl->setMediaCas(mCas);
+    if (!mCasToken.empty()) {
+        mImpl->setMediaCas(mCasToken);
     }
 
     err = updateDurationAndBitrate();
@@ -161,24 +160,36 @@
     return err;
 }
 
-status_t NuMediaExtractor::setMediaCas(const sp<ICas> &cas) {
-    ALOGV("setMediaCas: cas=%p", cas.get());
+static String8 arrayToString(const std::vector<uint8_t> &array) {
+    String8 result;
+    for (size_t i = 0; i < array.size(); i++) {
+        result.appendFormat("%02x ", array[i]);
+    }
+    if (result.isEmpty()) {
+        result.append("(null)");
+    }
+    return result;
+}
+
+status_t NuMediaExtractor::setMediaCas(const HInterfaceToken &casToken) {
+    ALOGV("setMediaCas: casToken={%s}", arrayToString(casToken).c_str());
 
     Mutex::Autolock autoLock(mLock);
 
-    if (cas == NULL) {
+    if (casToken.empty()) {
         return BAD_VALUE;
     }
 
+    mCasToken = casToken;
+
     if (mImpl != NULL) {
-        mImpl->setMediaCas(cas);
+        mImpl->setMediaCas(casToken);
         status_t err = updateDurationAndBitrate();
         if (err != OK) {
             return err;
         }
     }
 
-    mCas = cas;
     return OK;
 }
 
diff --git a/media/libstagefright/include/ACodecBufferChannel.h b/media/libstagefright/include/ACodecBufferChannel.h
index 0da2e81..f253a52 100644
--- a/media/libstagefright/include/ACodecBufferChannel.h
+++ b/media/libstagefright/include/ACodecBufferChannel.h
@@ -30,6 +30,8 @@
 
 namespace android {
 
+using hardware::hidl_memory;
+
 /**
  * BufferChannelBase implementation for ACodec.
  */
@@ -117,6 +119,7 @@
     sp<MemoryDealer> mDealer;
     sp<IMemory> mDecryptDestination;
     int32_t mHeapSeqNum;
+    hidl_memory mHidlMemory;
 
     // These should only be accessed via std::atomic_* functions.
     //
diff --git a/media/libstagefright/include/MPEG2TSExtractor.h b/media/libstagefright/include/MPEG2TSExtractor.h
index 2a75298f..ac93b5e 100644
--- a/media/libstagefright/include/MPEG2TSExtractor.h
+++ b/media/libstagefright/include/MPEG2TSExtractor.h
@@ -45,7 +45,7 @@
 
     virtual sp<MetaData> getMetaData();
 
-    virtual status_t setMediaCas(const sp<ICas> &cas) override;
+    virtual status_t setMediaCas(const HInterfaceToken &casToken) override;
 
     virtual uint32_t flags() const;
     virtual const char * name() { return "MPEG2TSExtractor"; }
diff --git a/media/libstagefright/include/media/stagefright/CodecBase.h b/media/libstagefright/include/media/stagefright/CodecBase.h
index 0dd77ba..6245ccb 100644
--- a/media/libstagefright/include/media/stagefright/CodecBase.h
+++ b/media/libstagefright/include/media/stagefright/CodecBase.h
@@ -24,27 +24,31 @@
 
 #define STRINGIFY_ENUMS
 
-#include <media/ICrypto.h>
+#include <media/hardware/CryptoAPI.h>
+#include <media/hardware/HardwareAPI.h>
 #include <media/IOMX.h>
 #include <media/MediaCodecInfo.h>
-#include <media/stagefright/MediaErrors.h>
 #include <media/stagefright/foundation/AHandler.h>
 #include <media/stagefright/foundation/ColorUtils.h>
-#include <media/hardware/HardwareAPI.h>
-
+#include <media/stagefright/MediaErrors.h>
+#include <system/graphics.h>
 #include <utils/NativeHandle.h>
 
-#include <system/graphics.h>
-#include <android/media/IDescrambler.h>
-
 namespace android {
-using namespace media;
 class BufferChannelBase;
 struct BufferProducerWrapper;
 class MediaCodecBuffer;
 struct PersistentSurface;
 struct RenderedFrameInfo;
 class Surface;
+struct ICrypto;
+namespace hardware {
+namespace cas {
+namespace native {
+namespace V1_0 {
+struct IDescrambler;
+}}}}
+using hardware::cas::native::V1_0::IDescrambler;
 
 struct CodecBase : public AHandler, /* static */ ColorUtils {
     /**
@@ -256,13 +260,9 @@
         mCallback = std::move(callback);
     }
 
-    inline void setCrypto(const sp<ICrypto> &crypto) {
-        mCrypto = crypto;
-    }
+    void setCrypto(const sp<ICrypto> &crypto);
 
-    inline void setDescrambler(const sp<IDescrambler> &descrambler) {
-        mDescrambler = descrambler;
-    }
+    void setDescrambler(const sp<IDescrambler> &descrambler);
 
     /**
      * Queue an input buffer into the buffer channel.
diff --git a/media/libstagefright/include/media/stagefright/MediaCodec.h b/media/libstagefright/include/media/stagefright/MediaCodec.h
index 4140266..209fe12 100644
--- a/media/libstagefright/include/media/stagefright/MediaCodec.h
+++ b/media/libstagefright/include/media/stagefright/MediaCodec.h
@@ -47,10 +47,13 @@
 struct PersistentSurface;
 class SoftwareRenderer;
 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 MediaCodec : public AHandler {
     enum ConfigureFlags {
diff --git a/media/libstagefright/include/media/stagefright/MediaErrors.h b/media/libstagefright/include/media/stagefright/MediaErrors.h
index 2e663ec..6a5c6b6 100644
--- a/media/libstagefright/include/media/stagefright/MediaErrors.h
+++ b/media/libstagefright/include/media/stagefright/MediaErrors.h
@@ -79,6 +79,26 @@
     HEARTBEAT_ERROR_BASE = -3000,
     ERROR_HEARTBEAT_TERMINATE_REQUESTED                     = HEARTBEAT_ERROR_BASE,
 
+    // CAS-related error codes
+    CAS_ERROR_BASE = -4000,
+
+    ERROR_CAS_UNKNOWN                        = CAS_ERROR_BASE,
+    ERROR_CAS_NO_LICENSE                     = CAS_ERROR_BASE - 1,
+    ERROR_CAS_LICENSE_EXPIRED                = CAS_ERROR_BASE - 2,
+    ERROR_CAS_SESSION_NOT_OPENED             = CAS_ERROR_BASE - 3,
+    ERROR_CAS_DECRYPT_UNIT_NOT_INITIALIZED   = CAS_ERROR_BASE - 4,
+    ERROR_CAS_DECRYPT                        = CAS_ERROR_BASE - 5,
+    ERROR_CAS_CANNOT_HANDLE                  = CAS_ERROR_BASE - 6,
+    ERROR_CAS_TAMPER_DETECTED                = CAS_ERROR_BASE - 7,
+    ERROR_CAS_NOT_PROVISIONED                = CAS_ERROR_BASE - 8,
+    ERROR_CAS_DEVICE_REVOKED                 = CAS_ERROR_BASE - 9,
+    ERROR_CAS_RESOURCE_BUSY                  = CAS_ERROR_BASE - 10,
+    ERROR_CAS_INSUFFICIENT_OUTPUT_PROTECTION = CAS_ERROR_BASE - 11,
+    ERROR_CAS_LAST_USED_ERRORCODE            = CAS_ERROR_BASE - 11,
+
+    ERROR_CAS_VENDOR_MAX                     = CAS_ERROR_BASE - 500,
+    ERROR_CAS_VENDOR_MIN                     = CAS_ERROR_BASE - 999,
+
     // NDK Error codes
     // frameworks/av/include/ndk/NdkMediaError.h
     // from -10000 (0xFFFFD8F0 - 0xFFFFD8EC)
diff --git a/media/libstagefright/include/media/stagefright/MediaExtractor.h b/media/libstagefright/include/media/stagefright/MediaExtractor.h
index a856b2b..f12160b 100644
--- a/media/libstagefright/include/media/stagefright/MediaExtractor.h
+++ b/media/libstagefright/include/media/stagefright/MediaExtractor.h
@@ -23,10 +23,6 @@
 #include <media/MediaAnalyticsItem.h>
 
 namespace android {
-namespace media {
-class ICas;
-};
-using namespace media;
 class DataSource;
 struct MediaSource;
 class MetaData;
@@ -70,7 +66,7 @@
     }
     virtual void setUID(uid_t /*uid*/) {
     }
-    virtual status_t setMediaCas(const sp<ICas>& /*cas*/) override {
+    virtual status_t setMediaCas(const HInterfaceToken &/*casToken*/) override {
         return INVALID_OPERATION;
     }
 
diff --git a/media/libstagefright/include/media/stagefright/NuMediaExtractor.h b/media/libstagefright/include/media/stagefright/NuMediaExtractor.h
index 3e3cc17..6a93bd5 100644
--- a/media/libstagefright/include/media/stagefright/NuMediaExtractor.h
+++ b/media/libstagefright/include/media/stagefright/NuMediaExtractor.h
@@ -28,10 +28,6 @@
 #include <utils/Vector.h>
 
 namespace android {
-namespace media {
-class ICas;
-}
-using namespace media;
 
 struct ABuffer;
 struct AMessage;
@@ -64,7 +60,7 @@
 
     status_t setDataSource(const sp<DataSource> &datasource);
 
-    status_t setMediaCas(const sp<ICas> &cas);
+    status_t setMediaCas(const HInterfaceToken &casToken);
 
     size_t countTracks() const;
     status_t getTrackFormat(size_t index, sp<AMessage> *format, uint32_t flags = 0) const;
@@ -115,7 +111,7 @@
     sp<DataSource> mDataSource;
 
     sp<IMediaExtractor> mImpl;
-    sp<ICas> mCas;
+    HInterfaceToken mCasToken;
 
     Vector<TrackInfo> mSelectedTracks;
     int64_t mTotalBitrate;  // in bits/sec
diff --git a/media/libstagefright/mpeg2ts/ATSParser.cpp b/media/libstagefright/mpeg2ts/ATSParser.cpp
index 31edb21..a256a4d 100644
--- a/media/libstagefright/mpeg2ts/ATSParser.cpp
+++ b/media/libstagefright/mpeg2ts/ATSParser.cpp
@@ -23,8 +23,8 @@
 #include "ESQueue.h"
 #include "include/avc_utils.h"
 
-#include <android/media/IDescrambler.h>
-#include <binder/MemoryDealer.h>
+#include <android/hardware/cas/native/1.0/IDescrambler.h>
+#include <cutils/native_handle.h>
 #include <media/stagefright/foundation/ABitReader.h>
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
@@ -41,8 +41,12 @@
 #include <inttypes.h>
 
 namespace android {
-using binder::Status;
-using MediaDescrambler::DescrambleInfo;
+using hardware::hidl_handle;
+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;
 
 // I want the expression "y" evaluated even if verbose logging is off.
 #define MY_LOGV(x, y) \
@@ -203,6 +207,7 @@
     sp<AMessage> mSampleAesKeyItem;
     sp<IMemory> mMem;
     sp<MemoryDealer> mDealer;
+    hardware::cas::native::V1_0::SharedBuffer mDescramblerSrcBuffer;
     sp<ABuffer> mDescrambledBuffer;
     List<SubSampleInfo> mSubSamples;
     sp<IDescrambler> mDescrambler;
@@ -235,7 +240,7 @@
 
     // Ensure internal buffers can hold specified size, and will re-allocate
     // as needed.
-    void ensureBufferCapacity(size_t size);
+    bool ensureBufferCapacity(size_t size);
 
     DISALLOW_EVIL_CONSTRUCTORS(Stream);
 };
@@ -807,9 +812,9 @@
     mQueue = NULL;
 }
 
-void ATSParser::Stream::ensureBufferCapacity(size_t neededSize) {
+bool ATSParser::Stream::ensureBufferCapacity(size_t neededSize) {
     if (mBuffer != NULL && mBuffer->capacity() >= neededSize) {
-        return;
+        return true;
     }
 
     ALOGV("ensureBufferCapacity: current size %zu, new size %zu, scrambled %d",
@@ -837,6 +842,26 @@
         mMem = newMem;
         mDealer = newDealer;
         mDescrambledBuffer = newScrambledBuffer;
+
+        ssize_t offset;
+        size_t size;
+        sp<IMemoryHeap> heap = newMem->getMemory(&offset, &size);
+        if (heap == NULL) {
+            return false;
+        }
+        native_handle_t* nativeHandle = native_handle_create(1, 0);
+        if (!nativeHandle) {
+            ALOGE("[stream %d] failed to create native handle", mElementaryPID);
+            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;
+
+        ALOGD("[stream %d] created shared buffer for descrambling, offset %zd, size %zu",
+                mElementaryPID, offset, size);
     } else {
         // Align to multiples of 64K.
         neededSize = (neededSize + 65535) & ~65535;
@@ -850,6 +875,7 @@
         newBuffer->setRange(0, 0);
     }
     mBuffer = newBuffer;
+    return true;
 }
 
 status_t ATSParser::Stream::parse(
@@ -923,7 +949,9 @@
     }
 
     size_t neededSize = mBuffer->size() + payloadSizeBits / 8;
-    ensureBufferCapacity(neededSize);
+    if (!ensureBufferCapacity(neededSize)) {
+        return NO_MEMORY;
+    }
 
     memcpy(mBuffer->data() + mBuffer->size(), br->data(), payloadSizeBits / 8);
     mBuffer->setRange(0, mBuffer->size() + payloadSizeBits / 8);
@@ -1365,47 +1393,59 @@
         memcpy(mDescrambledBuffer->data(), mBuffer->data(), descrambleBytes);
         mDescrambledBuffer->setRange(0, descrambleBytes);
 
-        sp<ABuffer> subSamples = new ABuffer(
-                sizeof(DescramblerPlugin::SubSample) * descrambleSubSamples);
-
-        DescrambleInfo info;
-        info.dstType = DescrambleInfo::kDestinationTypeVmPointer;
-        info.scramblingControl = (DescramblerPlugin::ScramblingControl)sctrl;
-        info.numSubSamples = descrambleSubSamples;
-        info.subSamples = (DescramblerPlugin::SubSample *)subSamples->data();
-        info.srcMem = mMem;
-        info.srcOffset = 0;
-        info.dstPtr = NULL; // in-place descrambling into srcMem
-        info.dstOffset = 0;
+        hidl_vec<SubSample> subSamples;
+        subSamples.resize(descrambleSubSamples);
 
         int32_t i = 0;
         for (auto it = mSubSamples.begin();
                 it != mSubSamples.end() && i < descrambleSubSamples; it++, i++) {
             if (it->transport_scrambling_mode != 0 || pesScramblingControl != 0) {
-                info.subSamples[i].mNumBytesOfClearData = 0;
-                info.subSamples[i].mNumBytesOfEncryptedData = it->subSampleSize;
+                subSamples[i].numBytesOfClearData = 0;
+                subSamples[i].numBytesOfEncryptedData = it->subSampleSize;
             } else {
-                info.subSamples[i].mNumBytesOfClearData = it->subSampleSize;
-                info.subSamples[i].mNumBytesOfEncryptedData = 0;
+                subSamples[i].numBytesOfClearData = it->subSampleSize;
+                subSamples[i].numBytesOfEncryptedData = 0;
             }
         }
+
+        uint64_t srcOffset = 0, dstOffset = 0;
         // If scrambled at PES-level, PES header should be skipped
         if (pesScramblingControl != 0) {
-            info.srcOffset = info.dstOffset = pesOffset;
-            info.subSamples[0].mNumBytesOfEncryptedData -= pesOffset;
+            srcOffset = dstOffset = pesOffset;
+            subSamples[0].numBytesOfEncryptedData -= pesOffset;
         }
 
-        int32_t result;
-        Status status = mDescrambler->descramble(info, &result);
+        Status status = Status::OK;
+        uint32_t bytesWritten = 0;
+        hidl_string detailedError;
 
-        if (!status.isOk()) {
-            ALOGE("[stream %d] descramble failed, exceptionCode=%d",
-                    mElementaryPID, status.exceptionCode());
+        DestinationBuffer dstBuffer;
+        dstBuffer.type = BufferType::SHARED_MEMORY;
+        dstBuffer.nonsecureMemory = mDescramblerSrcBuffer;
+
+        auto returnVoid = mDescrambler->descramble(
+                (ScramblingControl) sctrl,
+                subSamples,
+                mDescramblerSrcBuffer,
+                srcOffset,
+                dstBuffer,
+                dstOffset,
+                [&status, &bytesWritten, &detailedError] (
+                        Status _status, uint32_t _bytesWritten,
+                        const hidl_string& _detailedError) {
+                    status = _status;
+                    bytesWritten = _bytesWritten;
+                    detailedError = _detailedError;
+                });
+
+        if (!returnVoid.isOk()) {
+            ALOGE("[stream %d] descramble failed, trans=%s",
+                    mElementaryPID, returnVoid.description().c_str());
             return UNKNOWN_ERROR;
         }
 
         ALOGV("[stream %d] descramble succeeded, %d bytes",
-                mElementaryPID, result);
+                mElementaryPID, bytesWritten);
         memcpy(mBuffer->data(), mDescrambledBuffer->data(), descrambleBytes);
     }
 
diff --git a/media/libstagefright/mpeg2ts/ATSParser.h b/media/libstagefright/mpeg2ts/ATSParser.h
index 374e011..41c19cd 100644
--- a/media/libstagefright/mpeg2ts/ATSParser.h
+++ b/media/libstagefright/mpeg2ts/ATSParser.h
@@ -29,11 +29,13 @@
 #include <vector>
 
 namespace android {
-namespace media {
-class ICas;
-class IDescrambler;
-};
-using namespace media;
+namespace hardware {
+namespace cas {
+namespace V1_0 {
+struct ICas;
+}}}
+using hardware::cas::V1_0::ICas;
+
 class ABitReader;
 struct ABuffer;
 struct AnotherPacketSource;
diff --git a/media/libstagefright/mpeg2ts/Android.bp b/media/libstagefright/mpeg2ts/Android.bp
index 96eb5bf..21259c4 100644
--- a/media/libstagefright/mpeg2ts/Android.bp
+++ b/media/libstagefright/mpeg2ts/Android.bp
@@ -35,5 +35,8 @@
     shared_libs: [
         "libcrypto",
         "libmedia",
+        "libhidlmemory",
+        "android.hardware.cas.native@1.0",
+        "android.hidl.memory@1.0",
     ],
 }
diff --git a/media/libstagefright/mpeg2ts/CasManager.cpp b/media/libstagefright/mpeg2ts/CasManager.cpp
index 047b1b3..9ff4521 100644
--- a/media/libstagefright/mpeg2ts/CasManager.cpp
+++ b/media/libstagefright/mpeg2ts/CasManager.cpp
@@ -18,15 +18,19 @@
 #define LOG_TAG "CasManager"
 #include "CasManager.h"
 
-#include <android/media/ICas.h>
-#include <android/media/IDescrambler.h>
-#include <android/media/IMediaCasService.h>
-#include <binder/IServiceManager.h>
+#include <android/hardware/cas/1.0/ICas.h>
+#include <android/hardware/cas/1.0/IMediaCasService.h>
+#include <android/hardware/cas/native/1.0/IDescrambler.h>
+#include <hidl/HidlSupport.h>
 #include <media/stagefright/foundation/ABitReader.h>
 #include <utils/Log.h>
 
 namespace android {
-using binder::Status;
+
+using hardware::hidl_vec;
+using hardware::Return;
+using namespace hardware::cas::V1_0;
+using namespace hardware::cas::native::V1_0;
 
 struct ATSParser::CasManager::ProgramCasManager : public RefBase {
     ProgramCasManager(unsigned programNumber, const CADescriptor &descriptor);
@@ -125,45 +129,60 @@
          const sp<ICas>& cas,
          PidToSessionMap &sessionMap,
          CasSession *session) {
-    sp<IServiceManager> sm = defaultServiceManager();
-    sp<IBinder> casServiceBinder = sm->getService(String16("media.cas"));
-    sp<IMediaCasService> casService =
-            interface_cast<IMediaCasService>(casServiceBinder);
-
+    sp<IMediaCasService> casService = IMediaCasService::getService("default");
     if (casService == NULL) {
         ALOGE("Cannot obtain IMediaCasService");
         return NO_INIT;
     }
 
+    Status status;
     sp<IDescrambler> descrambler;
+    sp<IDescramblerBase> descramblerBase;
+    Return<Status> returnStatus(Status::OK);
+    Return<sp<IDescramblerBase> > returnDescrambler(NULL);
     std::vector<uint8_t> sessionId;
     const CADescriptor &descriptor = session->mCADescriptor;
 
-    Status status = cas->openSession(&sessionId);
-    if (!status.isOk()) {
-        ALOGE("Failed to open session: exception=%d, error=%d",
-                status.exceptionCode(), status.serviceSpecificErrorCode());
+    auto returnVoid = cas->openSession(
+            [&status, &sessionId] (Status _status, const hidl_vec<uint8_t>& _sessionId) {
+                status = _status;
+                sessionId = _sessionId;
+            });
+    if (!returnVoid.isOk() || status != Status::OK) {
+        ALOGE("Failed to open session: trans=%s, status=%d",
+                returnVoid.description().c_str(), status);
         goto l_fail;
     }
 
-    cas->setSessionPrivateData(sessionId, descriptor.mPrivateData);
-    if (!status.isOk()) {
-        ALOGE("Failed to set private data: exception=%d, error=%d",
-                status.exceptionCode(), status.serviceSpecificErrorCode());
+    returnStatus = cas->setSessionPrivateData(sessionId, descriptor.mPrivateData);
+    if (!returnStatus.isOk() || returnStatus != Status::OK) {
+        ALOGE("Failed to set private data: trans=%s, status=%d",
+                returnStatus.description().c_str(), (Status)returnStatus);
         goto l_fail;
     }
 
-    status = casService->createDescrambler(descriptor.mSystemID, &descrambler);
-    if (!status.isOk() || descrambler == NULL) {
-        ALOGE("Failed to create descrambler: : exception=%d, error=%d",
-                status.exceptionCode(), status.serviceSpecificErrorCode());
+    returnDescrambler = casService->createDescrambler(descriptor.mSystemID);
+    if (!returnDescrambler.isOk()) {
+        ALOGE("Failed to create descrambler: trans=%s",
+                returnDescrambler.description().c_str());
+        goto l_fail;
+    }
+    descramblerBase = (sp<IDescramblerBase>) returnDescrambler;
+    if (descramblerBase == NULL) {
+        ALOGE("Failed to create descrambler: null ptr");
         goto l_fail;
     }
 
-    status = descrambler->setMediaCasSession(sessionId);
-    if (!status.isOk()) {
-        ALOGE("Failed to init descrambler: : exception=%d, error=%d",
-                status.exceptionCode(), status.serviceSpecificErrorCode());
+    returnStatus = descramblerBase->setMediaCasSession(sessionId);
+    if (!returnStatus.isOk() || (Status) returnStatus != Status::OK) {
+        ALOGE("Failed to init descrambler: : trans=%s, status=%d",
+                returnStatus.description().c_str(), (Status) returnStatus);
+        goto l_fail;
+    }
+
+    descrambler = IDescrambler::castFrom(descramblerBase);
+    if (descrambler == NULL) {
+        ALOGE("Failed to cast from IDescramblerBase to IDescrambler");
         goto l_fail;
     }
 
@@ -177,8 +196,8 @@
     if (!sessionId.empty()) {
         cas->closeSession(sessionId);
     }
-    if (descrambler != NULL) {
-        descrambler->release();
+    if (descramblerBase != NULL) {
+        descramblerBase->release();
     }
     return NO_INIT;
 }
@@ -316,11 +335,12 @@
     if (index < 0) {
         return false;
     }
-    MediaCas::ParcelableCasData ecm(br->data(), br->numBitsLeft() / 8);
-    Status status = mICas->processEcm(mCAPidToSessionIdMap[index], ecm);
-    if (!status.isOk()) {
-        ALOGE("Failed to process ECM: exception=%d, error=%d",
-                status.exceptionCode(), status.serviceSpecificErrorCode());
+    hidl_vec<uint8_t> ecm;
+    ecm.setToExternal((uint8_t*)br->data(), br->numBitsLeft() / 8);
+    auto returnStatus = mICas->processEcm(mCAPidToSessionIdMap[index], ecm);
+    if (!returnStatus.isOk() || (Status) returnStatus != Status::OK) {
+        ALOGE("Failed to process ECM: trans=%s, status=%d",
+                returnStatus.description().c_str(), (Status) returnStatus);
     }
     return true; // handled
 }
diff --git a/media/libstagefright/mpeg2ts/CasManager.h b/media/libstagefright/mpeg2ts/CasManager.h
index 8088dec..81f6546 100644
--- a/media/libstagefright/mpeg2ts/CasManager.h
+++ b/media/libstagefright/mpeg2ts/CasManager.h
@@ -21,10 +21,13 @@
 #include <set>
 
 namespace android {
-namespace media {
-class ICas;
-class IDescrambler;
-}
+namespace hardware {
+namespace cas {
+namespace native {
+namespace V1_0 {
+struct IDescrambler;
+}}}}
+using hardware::cas::native::V1_0::IDescrambler;
 
 struct ATSParser::CasManager : public RefBase {
     CasManager();
diff --git a/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp b/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp
index c3f1274..9d684e0 100644
--- a/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp
+++ b/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp
@@ -38,8 +38,13 @@
 #include "AnotherPacketSource.h"
 #include "ATSParser.h"
 
+#include <hidl/HybridInterface.h>
+#include <android/hardware/cas/1.0/ICas.h>
+
 namespace android {
 
+using hardware::cas::V1_0::ICas;
+
 static const size_t kTSPacketSize = 188;
 static const int kMaxDurationReadSize = 250000LL;
 static const int kMaxDurationRetry = 6;
@@ -156,7 +161,10 @@
                     || !strcasecmp(MEDIA_MIMETYPE_AUDIO_SCRAMBLED, mime));
 }
 
-status_t MPEG2TSExtractor::setMediaCas(const sp<ICas> &cas) {
+status_t MPEG2TSExtractor::setMediaCas(const HInterfaceToken &casToken) {
+    HalToken halToken;
+    halToken.setToExternal((uint8_t*)casToken.data(), casToken.size());
+    sp<ICas> cas = ICas::castFrom(retrieveHalInterface(halToken));
     ALOGD("setMediaCas: %p", cas.get());
 
     status_t err = mParser->setMediaCas(cas);