Implement client code to use Drm and Crypto HALs

This change adds DrmHal & CryptoHal classes that connect to the Treble
HAL interfaces for drm.  These classes mirror the existing Drm and
Crypto classes that connect to the DrmPlugin and CryptoPlugin
interfaces. Having both allows mediadrmserver to run in either mode
while the HAL is stabilized.

The shared memory interfaces between mediaserver's ACodecBufferChannel
and ICrypto had to be reworked to use the Treble HALs. Specifically,
the shared memory path for returning decrypted buffers in the
non-secure case had to become separate instead of piggy-backing on the
source shared memory buffer. A separate shared memory destination
buffer is now allocated on the buffer channel. An abstraction for a
decrypt destination buffer was also introduced to clarify ICrypto's
decrypt method.

Tests: Playback using Play Movies and ExoPlayer works on angler
with and without the treble hal enabled.

bug: 32815560
Change-Id: I5a3dc84f99902eb8cf8eabab9ad074d307744950
diff --git a/drm/libmediadrm/DrmHal.cpp b/drm/libmediadrm/DrmHal.cpp
new file mode 100644
index 0000000..304cdaf
--- /dev/null
+++ b/drm/libmediadrm/DrmHal.cpp
@@ -0,0 +1,950 @@
+/*
+ * Copyright (C) 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 "DrmHal"
+#include <utils/Log.h>
+
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+#include <dirent.h>
+#include <dlfcn.h>
+
+#include <android/hardware/drm/1.0/IDrmFactory.h>
+#include <android/hardware/drm/1.0/IDrmPlugin.h>
+#include <android/hardware/drm/1.0/types.h>
+
+#include <media/DrmHal.h>
+#include <media/DrmSessionClientInterface.h>
+#include <media/DrmSessionManager.h>
+#include <media/drm/DrmAPI.h>
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/AString.h>
+#include <media/stagefright/foundation/hexdump.h>
+#include <media/stagefright/MediaErrors.h>
+
+using ::android::hardware::drm::V1_0::EventType;
+using ::android::hardware::drm::V1_0::IDrmFactory;
+using ::android::hardware::drm::V1_0::IDrmPlugin;
+using ::android::hardware::drm::V1_0::KeyedVector;
+using ::android::hardware::drm::V1_0::KeyRequestType;
+using ::android::hardware::drm::V1_0::KeyStatus;
+using ::android::hardware::drm::V1_0::KeyStatusType;
+using ::android::hardware::drm::V1_0::KeyType;
+using ::android::hardware::drm::V1_0::KeyValue;
+using ::android::hardware::drm::V1_0::SecureStop;
+using ::android::hardware::drm::V1_0::Status;
+using ::android::hardware::hidl_array;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::sp;
+
+namespace android {
+
+static inline int getCallingPid() {
+    return IPCThreadState::self()->getCallingPid();
+}
+
+static bool checkPermission(const char* permissionString) {
+    if (getpid() == IPCThreadState::self()->getCallingPid()) return true;
+    bool ok = checkCallingPermission(String16(permissionString));
+    if (!ok) ALOGE("Request requires %s", permissionString);
+    return ok;
+}
+
+static const Vector<uint8_t> toVector(const hidl_vec<uint8_t> &vec) {
+    Vector<uint8_t> vector;
+    vector.appendArray(vec.data(), vec.size());
+    return *const_cast<const Vector<uint8_t> *>(&vector);
+}
+
+static hidl_vec<uint8_t> toHidlVec(const Vector<uint8_t> &vector) {
+    hidl_vec<uint8_t> vec;
+    vec.setToExternal(const_cast<uint8_t *>(vector.array()), vector.size());
+    return vec;
+}
+
+static String8 toString8(const hidl_string &string) {
+    return String8(string.c_str());
+}
+
+static hidl_string toHidlString(const String8& string) {
+    return hidl_string(string.string());
+}
+
+
+static ::KeyedVector toHidlKeyedVector(const KeyedVector<String8, String8>&
+        keyedVector) {
+    std::vector<KeyValue> stdKeyedVector;
+    for (size_t i = 0; i < keyedVector.size(); i++) {
+        KeyValue keyValue;
+        keyValue.key = toHidlString(keyedVector.keyAt(i));
+        keyValue.value = toHidlString(keyedVector.valueAt(i));
+        stdKeyedVector.push_back(keyValue);
+    }
+    return ::KeyedVector(stdKeyedVector);
+}
+
+static KeyedVector<String8, String8> toKeyedVector(const ::KeyedVector&
+        hKeyedVector) {
+    KeyedVector<String8, String8> keyedVector;
+    for (size_t i = 0; i < hKeyedVector.size(); i++) {
+        keyedVector.add(toString8(hKeyedVector[i].key),
+                toString8(hKeyedVector[i].value));
+    }
+    return keyedVector;
+}
+
+static List<Vector<uint8_t> > toSecureStops(const hidl_vec<SecureStop>&
+        hSecureStops) {
+    List<Vector<uint8_t> > secureStops;
+    for (size_t i = 0; i < hSecureStops.size(); i++) {
+        secureStops.push_back(toVector(hSecureStops[i].opaqueData));
+    }
+    return secureStops;
+}
+
+static status_t toStatusT(Status status) {
+    switch (status) {
+    case Status::OK:
+        return OK;
+        break;
+    case Status::ERROR_DRM_NO_LICENSE:
+        return ERROR_DRM_NO_LICENSE;
+        break;
+    case Status::ERROR_DRM_LICENSE_EXPIRED:
+        return ERROR_DRM_LICENSE_EXPIRED;
+        break;
+    case Status::ERROR_DRM_SESSION_NOT_OPENED:
+        return ERROR_DRM_SESSION_NOT_OPENED;
+        break;
+    case Status::ERROR_DRM_CANNOT_HANDLE:
+        return ERROR_DRM_CANNOT_HANDLE;
+        break;
+    case Status::ERROR_DRM_INVALID_STATE:
+        return ERROR_DRM_TAMPER_DETECTED;
+        break;
+    case Status::BAD_VALUE:
+        return BAD_VALUE;
+        break;
+    case Status::ERROR_DRM_NOT_PROVISIONED:
+        return ERROR_DRM_NOT_PROVISIONED;
+        break;
+    case Status::ERROR_DRM_RESOURCE_BUSY:
+        return ERROR_DRM_RESOURCE_BUSY;
+        break;
+    case Status::ERROR_DRM_DEVICE_REVOKED:
+        return ERROR_DRM_DEVICE_REVOKED;
+        break;
+    case Status::ERROR_DRM_UNKNOWN:
+    default:
+        return ERROR_DRM_UNKNOWN;
+        break;
+    }
+}
+
+
+Mutex DrmHal::mLock;
+
+struct DrmSessionClient : public DrmSessionClientInterface {
+    explicit DrmSessionClient(DrmHal* drm) : mDrm(drm) {}
+
+    virtual bool reclaimSession(const Vector<uint8_t>& sessionId) {
+        sp<DrmHal> drm = mDrm.promote();
+        if (drm == NULL) {
+            return true;
+        }
+        status_t err = drm->closeSession(sessionId);
+        if (err != OK) {
+            return false;
+        }
+        drm->sendEvent(EventType::SESSION_RECLAIMED,
+                toHidlVec(sessionId), hidl_vec<uint8_t>());
+        return true;
+    }
+
+protected:
+    virtual ~DrmSessionClient() {}
+
+private:
+    wp<DrmHal> mDrm;
+
+    DISALLOW_EVIL_CONSTRUCTORS(DrmSessionClient);
+};
+
+DrmHal::DrmHal()
+   : mDrmSessionClient(new DrmSessionClient(this)),
+     mFactory(makeDrmFactory()),
+     mInitCheck((mFactory == NULL) ? ERROR_UNSUPPORTED : NO_INIT) {
+}
+
+DrmHal::~DrmHal() {
+    DrmSessionManager::Instance()->removeDrm(mDrmSessionClient);
+}
+
+sp<IDrmFactory> DrmHal::makeDrmFactory() {
+    sp<IDrmFactory> factory = IDrmFactory::getService("drm");
+    if (factory == NULL) {
+        ALOGE("Failed to make drm factory");
+    }
+    return factory;
+}
+
+sp<IDrmPlugin> DrmHal::makeDrmPlugin(const uint8_t uuid[16]) {
+    if (mFactory == NULL){
+        return NULL;
+    }
+
+    sp<IDrmPlugin> plugin;
+    Return<void> hResult = mFactory->createPlugin(uuid,
+            [&](Status status, const sp<IDrmPlugin>& hPlugin) {
+                if (status != Status::OK) {
+                    ALOGD("Failed to make drm plugin");
+                    return;
+                }
+                plugin = hPlugin;
+            }
+        );
+    return plugin;
+}
+
+status_t DrmHal::initCheck() const {
+    return mInitCheck;
+}
+
+status_t DrmHal::setListener(const sp<IDrmClient>& listener)
+{
+    Mutex::Autolock lock(mEventLock);
+    if (mListener != NULL){
+        IInterface::asBinder(mListener)->unlinkToDeath(this);
+    }
+    if (listener != NULL) {
+        IInterface::asBinder(listener)->linkToDeath(this);
+    }
+    mListener = listener;
+    return NO_ERROR;
+}
+
+Return<void> DrmHal::sendEvent(EventType hEventType,
+        const hidl_vec<uint8_t>& sessionId, const hidl_vec<uint8_t>& data) {
+
+    mEventLock.lock();
+    sp<IDrmClient> listener = mListener;
+    mEventLock.unlock();
+
+    if (listener != NULL) {
+        Parcel obj;
+        writeByteArray(obj, sessionId);
+        writeByteArray(obj, data);
+
+        Mutex::Autolock lock(mNotifyLock);
+        DrmPlugin::EventType eventType;
+        switch(hEventType) {
+        case EventType::PROVISION_REQUIRED:
+            eventType = DrmPlugin::kDrmPluginEventProvisionRequired;
+            break;
+        case EventType::KEY_NEEDED:
+            eventType = DrmPlugin::kDrmPluginEventKeyNeeded;
+            break;
+        case EventType::KEY_EXPIRED:
+            eventType = DrmPlugin::kDrmPluginEventKeyExpired;
+            break;
+        case EventType::VENDOR_DEFINED:
+            eventType = DrmPlugin::kDrmPluginEventVendorDefined;
+            break;
+        default:
+            return Void();
+        }
+        listener->notify(eventType, 0, &obj);
+    }
+    return Void();
+}
+
+Return<void> DrmHal::sendExpirationUpdate(const hidl_vec<uint8_t>& sessionId,
+        int64_t expiryTimeInMS) {
+
+    mEventLock.lock();
+    sp<IDrmClient> listener = mListener;
+    mEventLock.unlock();
+
+    if (listener != NULL) {
+        Parcel obj;
+        writeByteArray(obj, sessionId);
+        obj.writeInt64(expiryTimeInMS);
+
+        Mutex::Autolock lock(mNotifyLock);
+        listener->notify(DrmPlugin::kDrmPluginEventExpirationUpdate, 0, &obj);
+    }
+    return Void();
+}
+
+Return<void> DrmHal::sendKeysChange(const hidl_vec<uint8_t>& sessionId,
+        const hidl_vec<KeyStatus>& keyStatusList, bool hasNewUsableKey) {
+
+    mEventLock.lock();
+    sp<IDrmClient> listener = mListener;
+    mEventLock.unlock();
+
+    if (listener != NULL) {
+        Parcel obj;
+        writeByteArray(obj, sessionId);
+
+        size_t nKeys = keyStatusList.size();
+        obj.writeInt32(nKeys);
+        for (size_t i = 0; i < nKeys; ++i) {
+            const KeyStatus &keyStatus = keyStatusList[i];
+            writeByteArray(obj, keyStatus.keyId);
+            uint32_t type;
+            switch(keyStatus.type) {
+            case KeyStatusType::USABLE:
+                type = DrmPlugin::kKeyStatusType_Usable;
+                break;
+            case KeyStatusType::EXPIRED:
+                type = DrmPlugin::kKeyStatusType_Expired;
+                break;
+            case KeyStatusType::OUTPUTNOTALLOWED:
+                type = DrmPlugin::kKeyStatusType_OutputNotAllowed;
+                break;
+            case KeyStatusType::STATUSPENDING:
+                type = DrmPlugin::kKeyStatusType_StatusPending;
+                break;
+            case KeyStatusType::INTERNALERROR:
+            default:
+                type = DrmPlugin::kKeyStatusType_InternalError;
+                break;
+            }
+            obj.writeInt32(type);
+        }
+        obj.writeInt32(hasNewUsableKey);
+
+        Mutex::Autolock lock(mNotifyLock);
+        listener->notify(DrmPlugin::kDrmPluginEventKeysChange, 0, &obj);
+    }
+    return Void();
+}
+
+bool DrmHal::isCryptoSchemeSupported(const uint8_t uuid[16], const String8 &mimeType) {
+    Mutex::Autolock autoLock(mLock);
+    bool result = false;
+
+    if (mFactory != NULL && mFactory->isCryptoSchemeSupported(uuid)) {
+        if (mimeType != "") {
+            result = mFactory->isContentTypeSupported(mimeType.string());
+        }
+    }
+    return result;
+}
+
+status_t DrmHal::createPlugin(const uint8_t uuid[16]) {
+    Mutex::Autolock autoLock(mLock);
+
+    mPlugin = makeDrmPlugin(uuid);
+
+    if (mPlugin == NULL) {
+        mInitCheck = ERROR_UNSUPPORTED;
+    } else {
+        mInitCheck = OK;
+        mPlugin->setListener(this);
+    }
+
+    return mInitCheck;
+}
+
+status_t DrmHal::destroyPlugin() {
+    Mutex::Autolock autoLock(mLock);
+
+    if (mInitCheck != OK) {
+        return mInitCheck;
+    }
+
+    setListener(NULL);
+    mPlugin.clear();
+
+    return OK;
+}
+
+status_t DrmHal::openSession(Vector<uint8_t> &sessionId) {
+    Mutex::Autolock autoLock(mLock);
+
+    if (mInitCheck != OK) {
+        return mInitCheck;
+    }
+
+    status_t  err = UNKNOWN_ERROR;
+
+    bool retry = true;
+    do {
+        hidl_vec<uint8_t> hSessionId;
+
+        Return<void> hResult = mPlugin->openSession(
+                [&](Status status, const hidl_vec<uint8_t>& id) {
+                    if (status == Status::OK) {
+                        sessionId = toVector(id);
+                    }
+                    err = toStatusT(status);
+                }
+            );
+
+        if (!hResult.isOk()) {
+            err = DEAD_OBJECT;
+        }
+
+        if (err == ERROR_DRM_RESOURCE_BUSY && retry) {
+            mLock.unlock();
+            // reclaimSession may call back to closeSession, since mLock is
+            // shared between Drm instances, we should unlock here to avoid
+            // deadlock.
+            retry = DrmSessionManager::Instance()->reclaimSession(getCallingPid());
+            mLock.lock();
+        } else {
+            retry = false;
+        }
+    } while (retry);
+
+    if (err == OK) {
+        DrmSessionManager::Instance()->addSession(getCallingPid(),
+                mDrmSessionClient, sessionId);
+    }
+    return err;
+}
+
+status_t DrmHal::closeSession(Vector<uint8_t> const &sessionId) {
+    Mutex::Autolock autoLock(mLock);
+
+    if (mInitCheck != OK) {
+        return mInitCheck;
+    }
+
+    Status status = mPlugin->closeSession(toHidlVec(sessionId));
+    if (status == Status::OK) {
+        DrmSessionManager::Instance()->removeSession(sessionId);
+    }
+    return toStatusT(status);
+}
+
+status_t DrmHal::getKeyRequest(Vector<uint8_t> const &sessionId,
+        Vector<uint8_t> const &initData, String8 const &mimeType,
+        DrmPlugin::KeyType keyType, KeyedVector<String8,
+        String8> const &optionalParameters, Vector<uint8_t> &request,
+        String8 &defaultUrl, DrmPlugin::KeyRequestType *keyRequestType) {
+    Mutex::Autolock autoLock(mLock);
+
+    if (mInitCheck != OK) {
+        return mInitCheck;
+    }
+
+    DrmSessionManager::Instance()->useSession(sessionId);
+
+    KeyType hKeyType;
+    if (keyType == DrmPlugin::kKeyType_Streaming) {
+        hKeyType = KeyType::STREAMING;
+    } else if (keyType == DrmPlugin::kKeyType_Offline) {
+        hKeyType = KeyType::OFFLINE;
+    } else if (keyType == DrmPlugin::kKeyType_Release) {
+        hKeyType = KeyType::RELEASE;
+    } else {
+        return BAD_VALUE;
+    }
+
+    ::KeyedVector hOptionalParameters = toHidlKeyedVector(optionalParameters);
+
+    status_t err = UNKNOWN_ERROR;
+
+    Return<void> hResult = mPlugin->getKeyRequest(toHidlVec(sessionId),
+            toHidlVec(initData), toHidlString(mimeType), hKeyType, hOptionalParameters,
+            [&](Status status, const hidl_vec<uint8_t>& hRequest,
+                    KeyRequestType hKeyRequestType, const hidl_string& hDefaultUrl) {
+
+                if (status == Status::OK) {
+                    request = toVector(hRequest);
+                    defaultUrl = toString8(hDefaultUrl);
+
+                    switch (hKeyRequestType) {
+                    case KeyRequestType::INITIAL:
+                        *keyRequestType = DrmPlugin::kKeyRequestType_Initial;
+                        break;
+                    case KeyRequestType::RENEWAL:
+                        *keyRequestType = DrmPlugin::kKeyRequestType_Renewal;
+                        break;
+                    case KeyRequestType::RELEASE:
+                        *keyRequestType = DrmPlugin::kKeyRequestType_Release;
+                        break;
+                    default:
+                        *keyRequestType = DrmPlugin::kKeyRequestType_Unknown;
+                        break;
+                    }
+                    err = toStatusT(status);
+                }
+            });
+
+    return hResult.isOk() ? err : DEAD_OBJECT;
+}
+
+status_t DrmHal::provideKeyResponse(Vector<uint8_t> const &sessionId,
+        Vector<uint8_t> const &response, Vector<uint8_t> &keySetId) {
+    Mutex::Autolock autoLock(mLock);
+
+    if (mInitCheck != OK) {
+        return mInitCheck;
+    }
+
+    DrmSessionManager::Instance()->useSession(sessionId);
+
+    status_t err = UNKNOWN_ERROR;
+
+    Return<void> hResult = mPlugin->provideKeyResponse(toHidlVec(sessionId),
+            toHidlVec(response),
+            [&](Status status, const hidl_vec<uint8_t>& hKeySetId) {
+                if (status == Status::OK) {
+                    keySetId = toVector(hKeySetId);
+                }
+                err = toStatusT(status);
+            }
+        );
+
+    return hResult.isOk() ? err : DEAD_OBJECT;
+}
+
+status_t DrmHal::removeKeys(Vector<uint8_t> const &keySetId) {
+    Mutex::Autolock autoLock(mLock);
+
+    if (mInitCheck != OK) {
+        return mInitCheck;
+    }
+
+    return toStatusT(mPlugin->removeKeys(toHidlVec(keySetId)));
+}
+
+status_t DrmHal::restoreKeys(Vector<uint8_t> const &sessionId,
+        Vector<uint8_t> const &keySetId) {
+    Mutex::Autolock autoLock(mLock);
+
+    if (mInitCheck != OK) {
+        return mInitCheck;
+    }
+
+    DrmSessionManager::Instance()->useSession(sessionId);
+
+    return toStatusT(mPlugin->restoreKeys(toHidlVec(sessionId),
+                    toHidlVec(keySetId)));
+}
+
+status_t DrmHal::queryKeyStatus(Vector<uint8_t> const &sessionId,
+        KeyedVector<String8, String8> &infoMap) const {
+    Mutex::Autolock autoLock(mLock);
+
+    if (mInitCheck != OK) {
+        return mInitCheck;
+    }
+
+    DrmSessionManager::Instance()->useSession(sessionId);
+
+    ::KeyedVector hInfoMap;
+
+    status_t err = UNKNOWN_ERROR;
+
+    Return<void> hResult = mPlugin->queryKeyStatus(toHidlVec(sessionId),
+            [&](Status status, const hidl_vec<KeyValue>& map) {
+                if (status == Status::OK) {
+                    infoMap = toKeyedVector(map);
+                }
+                err = toStatusT(status);
+            }
+        );
+
+    return hResult.isOk() ? err : DEAD_OBJECT;
+}
+
+status_t DrmHal::getProvisionRequest(String8 const &certType,
+        String8 const &certAuthority, Vector<uint8_t> &request,
+        String8 &defaultUrl) {
+    Mutex::Autolock autoLock(mLock);
+
+    if (mInitCheck != OK) {
+        return mInitCheck;
+    }
+
+    status_t err = UNKNOWN_ERROR;
+
+    Return<void> hResult = mPlugin->getProvisionRequest(
+            toHidlString(certType), toHidlString(certAuthority),
+            [&](Status status, const hidl_vec<uint8_t>& hRequest,
+                    const hidl_string& hDefaultUrl) {
+                if (status == Status::OK) {
+                    request = toVector(hRequest);
+                    defaultUrl = toString8(hDefaultUrl);
+                }
+                err = toStatusT(status);
+            }
+        );
+
+    return hResult.isOk() ? err : DEAD_OBJECT;
+}
+
+status_t DrmHal::provideProvisionResponse(Vector<uint8_t> const &response,
+                                       Vector<uint8_t> &certificate,
+                                       Vector<uint8_t> &wrappedKey) {
+    Mutex::Autolock autoLock(mLock);
+
+    if (mInitCheck != OK) {
+        return mInitCheck;
+    }
+
+    status_t err = UNKNOWN_ERROR;
+
+    Return<void> hResult = mPlugin->provideProvisionResponse(toHidlVec(response),
+            [&](Status status, const hidl_vec<uint8_t>& hCertificate,
+                    const hidl_vec<uint8_t>& hWrappedKey) {
+                if (status == Status::OK) {
+                    certificate = toVector(hCertificate);
+                    wrappedKey = toVector(hWrappedKey);
+                }
+                err = toStatusT(status);
+            }
+        );
+
+    return hResult.isOk() ? err : DEAD_OBJECT;
+}
+
+status_t DrmHal::getSecureStops(List<Vector<uint8_t> > &secureStops) {
+    Mutex::Autolock autoLock(mLock);
+
+    if (mInitCheck != OK) {
+        return mInitCheck;
+    }
+
+    status_t err = UNKNOWN_ERROR;
+
+    Return<void> hResult = mPlugin->getSecureStops(
+            [&](Status status, const hidl_vec<SecureStop>& hSecureStops) {
+                if (status == Status::OK) {
+                    secureStops = toSecureStops(hSecureStops);
+                }
+                err = toStatusT(status);
+            }
+    );
+
+    return hResult.isOk() ? err : DEAD_OBJECT;
+}
+
+
+status_t DrmHal::getSecureStop(Vector<uint8_t> const &ssid, Vector<uint8_t> &secureStop) {
+    Mutex::Autolock autoLock(mLock);
+
+    if (mInitCheck != OK) {
+        return mInitCheck;
+    }
+
+    status_t err = UNKNOWN_ERROR;
+
+    Return<void> hResult = mPlugin->getSecureStop(toHidlVec(ssid),
+            [&](Status status, const SecureStop& hSecureStop) {
+                if (status == Status::OK) {
+                    secureStop = toVector(hSecureStop.opaqueData);
+                }
+                err = toStatusT(status);
+            }
+    );
+
+    return hResult.isOk() ? err : DEAD_OBJECT;
+}
+
+status_t DrmHal::releaseSecureStops(Vector<uint8_t> const &ssRelease) {
+    Mutex::Autolock autoLock(mLock);
+
+    if (mInitCheck != OK) {
+        return mInitCheck;
+    }
+
+    return toStatusT(mPlugin->releaseSecureStop(toHidlVec(ssRelease)));
+}
+
+status_t DrmHal::releaseAllSecureStops() {
+    Mutex::Autolock autoLock(mLock);
+
+    if (mInitCheck != OK) {
+        return mInitCheck;
+    }
+
+    return toStatusT(mPlugin->releaseAllSecureStops());
+}
+
+status_t DrmHal::getPropertyString(String8 const &name, String8 &value ) const {
+    Mutex::Autolock autoLock(mLock);
+
+    if (mInitCheck != OK) {
+        return mInitCheck;
+    }
+
+    status_t err = UNKNOWN_ERROR;
+
+    Return<void> hResult = mPlugin->getPropertyString(toHidlString(name),
+            [&](Status status, const hidl_string& hValue) {
+                if (status == Status::OK) {
+                    value = toString8(hValue);
+                }
+                err = toStatusT(status);
+            }
+    );
+
+    return hResult.isOk() ? err : DEAD_OBJECT;
+}
+
+status_t DrmHal::getPropertyByteArray(String8 const &name, Vector<uint8_t> &value ) const {
+    Mutex::Autolock autoLock(mLock);
+
+    if (mInitCheck != OK) {
+        return mInitCheck;
+    }
+
+    status_t err = UNKNOWN_ERROR;
+
+    Return<void> hResult = mPlugin->getPropertyByteArray(toHidlString(name),
+            [&](Status status, const hidl_vec<uint8_t>& hValue) {
+                if (status == Status::OK) {
+                    value = toVector(hValue);
+                }
+                err = toStatusT(status);
+            }
+    );
+
+    return hResult.isOk() ? err : DEAD_OBJECT;
+}
+
+status_t DrmHal::setPropertyString(String8 const &name, String8 const &value ) const {
+    Mutex::Autolock autoLock(mLock);
+
+    if (mInitCheck != OK) {
+        return mInitCheck;
+    }
+
+    Status status =  mPlugin->setPropertyString(toHidlString(name),
+            toHidlString(value));
+    return toStatusT(status);
+}
+
+status_t DrmHal::setPropertyByteArray(String8 const &name,
+                                   Vector<uint8_t> const &value ) const {
+    Mutex::Autolock autoLock(mLock);
+
+    if (mInitCheck != OK) {
+        return mInitCheck;
+    }
+
+    Status status = mPlugin->setPropertyByteArray(toHidlString(name),
+            toHidlVec(value));
+    return toStatusT(status);
+}
+
+
+status_t DrmHal::setCipherAlgorithm(Vector<uint8_t> const &sessionId,
+                                 String8 const &algorithm) {
+    Mutex::Autolock autoLock(mLock);
+
+    if (mInitCheck != OK) {
+        return mInitCheck;
+    }
+
+    DrmSessionManager::Instance()->useSession(sessionId);
+
+    Status status = mPlugin->setCipherAlgorithm(toHidlVec(sessionId),
+            toHidlString(algorithm));
+    return toStatusT(status);
+}
+
+status_t DrmHal::setMacAlgorithm(Vector<uint8_t> const &sessionId,
+                              String8 const &algorithm) {
+    Mutex::Autolock autoLock(mLock);
+
+    if (mInitCheck != OK) {
+        return mInitCheck;
+    }
+
+    DrmSessionManager::Instance()->useSession(sessionId);
+
+    Status status = mPlugin->setMacAlgorithm(toHidlVec(sessionId),
+            toHidlString(algorithm));
+    return toStatusT(status);
+}
+
+status_t DrmHal::encrypt(Vector<uint8_t> const &sessionId,
+                      Vector<uint8_t> const &keyId,
+                      Vector<uint8_t> const &input,
+                      Vector<uint8_t> const &iv,
+                      Vector<uint8_t> &output) {
+    Mutex::Autolock autoLock(mLock);
+
+    if (mInitCheck != OK) {
+        return mInitCheck;
+    }
+
+    DrmSessionManager::Instance()->useSession(sessionId);
+
+    status_t err = UNKNOWN_ERROR;
+
+    Return<void> hResult = mPlugin->encrypt(toHidlVec(sessionId),
+            toHidlVec(keyId), toHidlVec(input), toHidlVec(iv),
+            [&](Status status, const hidl_vec<uint8_t>& hOutput) {
+                if (status == Status::OK) {
+                    output = toVector(hOutput);
+                }
+                err = toStatusT(status);
+            }
+    );
+
+    return hResult.isOk() ? err : DEAD_OBJECT;
+}
+
+status_t DrmHal::decrypt(Vector<uint8_t> const &sessionId,
+                      Vector<uint8_t> const &keyId,
+                      Vector<uint8_t> const &input,
+                      Vector<uint8_t> const &iv,
+                      Vector<uint8_t> &output) {
+    Mutex::Autolock autoLock(mLock);
+
+    if (mInitCheck != OK) {
+        return mInitCheck;
+    }
+
+    DrmSessionManager::Instance()->useSession(sessionId);
+
+    status_t  err = UNKNOWN_ERROR;
+
+    Return<void> hResult = mPlugin->decrypt(toHidlVec(sessionId),
+            toHidlVec(keyId), toHidlVec(input), toHidlVec(iv),
+            [&](Status status, const hidl_vec<uint8_t>& hOutput) {
+                if (status == Status::OK) {
+                    output = toVector(hOutput);
+                }
+                err = toStatusT(status);
+            }
+    );
+
+    return hResult.isOk() ? err : DEAD_OBJECT;
+}
+
+status_t DrmHal::sign(Vector<uint8_t> const &sessionId,
+                   Vector<uint8_t> const &keyId,
+                   Vector<uint8_t> const &message,
+                   Vector<uint8_t> &signature) {
+    Mutex::Autolock autoLock(mLock);
+
+    if (mInitCheck != OK) {
+        return mInitCheck;
+    }
+
+    DrmSessionManager::Instance()->useSession(sessionId);
+
+    status_t err = UNKNOWN_ERROR;
+
+    Return<void> hResult = mPlugin->sign(toHidlVec(sessionId),
+            toHidlVec(keyId), toHidlVec(message),
+            [&](Status status, const hidl_vec<uint8_t>& hSignature)  {
+                if (status == Status::OK) {
+                    signature = toVector(hSignature);
+                }
+                err = toStatusT(status);
+            }
+    );
+
+    return hResult.isOk() ? err : DEAD_OBJECT;
+}
+
+status_t DrmHal::verify(Vector<uint8_t> const &sessionId,
+                     Vector<uint8_t> const &keyId,
+                     Vector<uint8_t> const &message,
+                     Vector<uint8_t> const &signature,
+                     bool &match) {
+    Mutex::Autolock autoLock(mLock);
+
+    if (mInitCheck != OK) {
+        return mInitCheck;
+    }
+
+    DrmSessionManager::Instance()->useSession(sessionId);
+
+    status_t err = UNKNOWN_ERROR;
+
+    Return<void> hResult = mPlugin->verify(toHidlVec(sessionId),toHidlVec(keyId),
+            toHidlVec(message), toHidlVec(signature),
+            [&](Status status, bool hMatch) {
+                if (status == Status::OK) {
+                    match = hMatch;
+                } else {
+                    match = false;
+                }
+                err = toStatusT(status);
+            }
+    );
+
+    return hResult.isOk() ? err : DEAD_OBJECT;
+}
+
+status_t DrmHal::signRSA(Vector<uint8_t> const &sessionId,
+                      String8 const &algorithm,
+                      Vector<uint8_t> const &message,
+                      Vector<uint8_t> const &wrappedKey,
+                      Vector<uint8_t> &signature) {
+    Mutex::Autolock autoLock(mLock);
+
+    if (mInitCheck != OK) {
+        return mInitCheck;
+    }
+
+    if (!checkPermission("android.permission.ACCESS_DRM_CERTIFICATES")) {
+        return -EPERM;
+    }
+
+    DrmSessionManager::Instance()->useSession(sessionId);
+
+    status_t err = UNKNOWN_ERROR;
+
+    Return<void> hResult = mPlugin->signRSA(toHidlVec(sessionId),
+            toHidlString(algorithm), toHidlVec(message), toHidlVec(wrappedKey),
+            [&](Status status, const hidl_vec<uint8_t>& hSignature) {
+                if (status == Status::OK) {
+                    signature = toVector(hSignature);
+                }
+                err = toStatusT(status);
+            }
+        );
+
+    return hResult.isOk() ? err : DEAD_OBJECT;
+}
+
+void DrmHal::binderDied(const wp<IBinder> &the_late_who __unused)
+{
+    mEventLock.lock();
+    mListener.clear();
+    mEventLock.unlock();
+
+    Mutex::Autolock autoLock(mLock);
+    mPlugin.clear();
+}
+
+void DrmHal::writeByteArray(Parcel &obj, hidl_vec<uint8_t> const &vec)
+{
+    if (vec.size()) {
+        obj.writeInt32(vec.size());
+        obj.write(vec.data(), vec.size());
+    } else {
+        obj.writeInt32(0);
+    }
+}
+
+}  // namespace android