Implementing MediaDrm APIs

Change-Id: I9ff8eeb7d0c383b5c0c68cd54eb54ce7d2d22fe6
diff --git a/media/libmediaplayerservice/Drm.cpp b/media/libmediaplayerservice/Drm.cpp
new file mode 100644
index 0000000..6ac7530
--- /dev/null
+++ b/media/libmediaplayerservice/Drm.cpp
@@ -0,0 +1,423 @@
+/*
+ * Copyright (C) 2013 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 "Drm"
+#include <utils/Log.h>
+
+#include <dirent.h>
+#include <dlfcn.h>
+
+#include "Drm.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>
+
+namespace android {
+
+KeyedVector<Vector<uint8_t>, String8> Drm::mUUIDToLibraryPathMap;
+KeyedVector<String8, wp<SharedLibrary> > Drm::mLibraryPathToOpenLibraryMap;
+Mutex Drm::mMapLock;
+
+static bool operator<(const Vector<uint8_t> &lhs, const Vector<uint8_t> &rhs) {
+    if (lhs.size() < rhs.size()) {
+        return true;
+    } else if (lhs.size() > rhs.size()) {
+        return false;
+    }
+
+    return memcmp((void *)lhs.array(), (void *)rhs.array(), rhs.size()) < 0;
+}
+
+Drm::Drm()
+    : mInitCheck(NO_INIT),
+      mFactory(NULL),
+      mPlugin(NULL) {
+}
+
+Drm::~Drm() {
+    delete mPlugin;
+    mPlugin = NULL;
+    closeFactory();
+}
+
+void Drm::closeFactory() {
+    delete mFactory;
+    mFactory = NULL;
+    mLibrary.clear();
+}
+
+status_t Drm::initCheck() const {
+    return mInitCheck;
+}
+
+
+/*
+ * Search the plugins directory for a plugin that supports the scheme
+ * specified by uuid
+ *
+ * If found:
+ *    mLibrary holds a strong pointer to the dlopen'd library
+ *    mFactory is set to the library's factory method
+ *    mInitCheck is set to OK
+ *
+ * If not found:
+ *    mLibrary is cleared and mFactory are set to NULL
+ *    mInitCheck is set to an error (!OK)
+ */
+void Drm::findFactoryForScheme(const uint8_t uuid[16]) {
+
+    closeFactory();
+
+    // lock static maps
+    Mutex::Autolock autoLock(mMapLock);
+
+    // first check cache
+    Vector<uint8_t> uuidVector;
+    uuidVector.appendArray(uuid, sizeof(uuid));
+    ssize_t index = mUUIDToLibraryPathMap.indexOfKey(uuidVector);
+    if (index >= 0) {
+        if (loadLibraryForScheme(mUUIDToLibraryPathMap[index], uuid)) {
+            mInitCheck = OK;
+            return;
+        } else {
+            ALOGE("Failed to load from cached library path!");
+            mInitCheck = ERROR_UNSUPPORTED;
+            return;
+        }
+    }
+
+    // no luck, have to search
+    String8 dirPath("/vendor/lib/mediadrm");
+    DIR* pDir = opendir(dirPath.string());
+
+    if (pDir == NULL) {
+        mInitCheck = ERROR_UNSUPPORTED;
+        ALOGE("Failed to open plugin directory %s", dirPath.string());
+        return;
+    }
+
+
+    struct dirent* pEntry;
+    while ((pEntry = readdir(pDir))) {
+
+        String8 pluginPath = dirPath + "/" + pEntry->d_name;
+
+        if (pluginPath.getPathExtension() == ".so") {
+
+            if (loadLibraryForScheme(pluginPath, uuid)) {
+                mUUIDToLibraryPathMap.add(uuidVector, pluginPath);
+                mInitCheck = OK;
+                closedir(pDir);
+                return;
+            }
+        }
+    }
+
+    closedir(pDir);
+
+    ALOGE("Failed to find drm plugin");
+    mInitCheck = ERROR_UNSUPPORTED;
+}
+
+bool Drm::loadLibraryForScheme(const String8 &path, const uint8_t uuid[16]) {
+
+    // get strong pointer to open shared library
+    ssize_t index = mLibraryPathToOpenLibraryMap.indexOfKey(path);
+    if (index >= 0) {
+        mLibrary = mLibraryPathToOpenLibraryMap[index].promote();
+    } else {
+        index = mLibraryPathToOpenLibraryMap.add(path, NULL);
+    }
+
+    if (!mLibrary.get()) {
+        mLibrary = new SharedLibrary(path);
+        if (!*mLibrary) {
+            return false;
+        }
+
+        mLibraryPathToOpenLibraryMap.replaceValueAt(index, mLibrary);
+    }
+
+    typedef DrmFactory *(*CreateDrmFactoryFunc)();
+
+    CreateDrmFactoryFunc createDrmFactory =
+        (CreateDrmFactoryFunc)mLibrary->lookup("createDrmFactory");
+
+    if (createDrmFactory == NULL ||
+        (mFactory = createDrmFactory()) == NULL ||
+        !mFactory->isCryptoSchemeSupported(uuid)) {
+        closeFactory();
+        return false;
+    }
+    return true;
+}
+
+bool Drm::isCryptoSchemeSupported(const uint8_t uuid[16]) {
+    Mutex::Autolock autoLock(mLock);
+
+    if (mFactory && mFactory->isCryptoSchemeSupported(uuid)) {
+        return true;
+    }
+
+    findFactoryForScheme(uuid);
+    return (mInitCheck == OK);
+}
+
+status_t Drm::createPlugin(const uint8_t uuid[16]) {
+    Mutex::Autolock autoLock(mLock);
+
+    if (mPlugin != NULL) {
+        return -EINVAL;
+    }
+
+    if (!mFactory || !mFactory->isCryptoSchemeSupported(uuid)) {
+        findFactoryForScheme(uuid);
+    }
+
+    if (mInitCheck != OK) {
+        return mInitCheck;
+    }
+
+    return mFactory->createDrmPlugin(uuid, &mPlugin);
+}
+
+status_t Drm::destroyPlugin() {
+    Mutex::Autolock autoLock(mLock);
+
+    if (mInitCheck != OK) {
+        return mInitCheck;
+    }
+
+    if (mPlugin == NULL) {
+        return -EINVAL;
+    }
+
+    delete mPlugin;
+    mPlugin = NULL;
+
+    return OK;
+}
+
+status_t Drm::openSession(Vector<uint8_t> &sessionId) {
+    Mutex::Autolock autoLock(mLock);
+
+    if (mInitCheck != OK) {
+        return mInitCheck;
+    }
+
+    if (mPlugin == NULL) {
+        return -EINVAL;
+    }
+
+    return mPlugin->openSession(sessionId);
+}
+
+status_t Drm::closeSession(Vector<uint8_t> const &sessionId) {
+    Mutex::Autolock autoLock(mLock);
+
+    if (mInitCheck != OK) {
+        return mInitCheck;
+    }
+
+    if (mPlugin == NULL) {
+        return -EINVAL;
+    }
+
+    return mPlugin->closeSession(sessionId);
+}
+
+status_t Drm::getLicenseRequest(Vector<uint8_t> const &sessionId,
+                                Vector<uint8_t> const &initData,
+                                String8 const &mimeType, DrmPlugin::LicenseType licenseType,
+                                KeyedVector<String8, String8> const &optionalParameters,
+                                Vector<uint8_t> &request, String8 &defaultUrl) {
+    Mutex::Autolock autoLock(mLock);
+
+    if (mInitCheck != OK) {
+        return mInitCheck;
+    }
+
+    if (mPlugin == NULL) {
+        return -EINVAL;
+    }
+
+    return mPlugin->getLicenseRequest(sessionId, initData, mimeType, licenseType,
+                                      optionalParameters, request, defaultUrl);
+}
+
+status_t Drm::provideLicenseResponse(Vector<uint8_t> const &sessionId,
+                                     Vector<uint8_t> const &response) {
+    Mutex::Autolock autoLock(mLock);
+
+    if (mInitCheck != OK) {
+        return mInitCheck;
+    }
+
+    if (mPlugin == NULL) {
+        return -EINVAL;
+    }
+
+    return mPlugin->provideLicenseResponse(sessionId, response);
+}
+
+status_t Drm::removeLicense(Vector<uint8_t> const &sessionId) {
+    Mutex::Autolock autoLock(mLock);
+
+    if (mInitCheck != OK) {
+        return mInitCheck;
+    }
+
+    if (mPlugin == NULL) {
+        return -EINVAL;
+    }
+
+    return mPlugin->removeLicense(sessionId);
+}
+
+status_t Drm::queryLicenseStatus(Vector<uint8_t> const &sessionId,
+                                 KeyedVector<String8, String8> &infoMap) const {
+    Mutex::Autolock autoLock(mLock);
+
+    if (mInitCheck != OK) {
+        return mInitCheck;
+    }
+
+    if (mPlugin == NULL) {
+        return -EINVAL;
+    }
+
+    return mPlugin->queryLicenseStatus(sessionId, infoMap);
+}
+
+status_t Drm::getProvisionRequest(Vector<uint8_t> &request, String8 &defaultUrl) {
+    Mutex::Autolock autoLock(mLock);
+
+    if (mInitCheck != OK) {
+        return mInitCheck;
+    }
+
+    if (mPlugin == NULL) {
+        return -EINVAL;
+    }
+
+    return mPlugin->getProvisionRequest(request, defaultUrl);
+}
+
+status_t Drm::provideProvisionResponse(Vector<uint8_t> const &response) {
+    Mutex::Autolock autoLock(mLock);
+
+    if (mInitCheck != OK) {
+        return mInitCheck;
+    }
+
+    if (mPlugin == NULL) {
+        return -EINVAL;
+    }
+
+    return mPlugin->provideProvisionResponse(response);
+}
+
+
+status_t Drm::getSecureStops(List<Vector<uint8_t> > &secureStops) {
+    Mutex::Autolock autoLock(mLock);
+
+    if (mInitCheck != OK) {
+        return mInitCheck;
+    }
+
+    if (mPlugin == NULL) {
+        return -EINVAL;
+    }
+
+    return mPlugin->getSecureStops(secureStops);
+}
+
+status_t Drm::releaseSecureStops(Vector<uint8_t> const &ssRelease) {
+    Mutex::Autolock autoLock(mLock);
+
+    if (mInitCheck != OK) {
+        return mInitCheck;
+    }
+
+    if (mPlugin == NULL) {
+        return -EINVAL;
+    }
+
+    return mPlugin->releaseSecureStops(ssRelease);
+}
+
+status_t Drm::getPropertyString(String8 const &name, String8 &value ) const {
+    Mutex::Autolock autoLock(mLock);
+
+    if (mInitCheck != OK) {
+        return mInitCheck;
+    }
+
+    if (mPlugin == NULL) {
+        return -EINVAL;
+    }
+
+    return mPlugin->getPropertyString(name, value);
+}
+
+status_t Drm::getPropertyByteArray(String8 const &name, Vector<uint8_t> &value ) const {
+    Mutex::Autolock autoLock(mLock);
+
+    if (mInitCheck != OK) {
+        return mInitCheck;
+    }
+
+    if (mPlugin == NULL) {
+        return -EINVAL;
+    }
+
+    return mPlugin->getPropertyByteArray(name, value);
+}
+
+status_t Drm::setPropertyString(String8 const &name, String8 const &value ) const {
+    Mutex::Autolock autoLock(mLock);
+
+    if (mInitCheck != OK) {
+        return mInitCheck;
+    }
+
+    if (mPlugin == NULL) {
+        return -EINVAL;
+    }
+
+    return mPlugin->setPropertyString(name, value);
+}
+
+status_t Drm::setPropertyByteArray(String8 const &name,
+                                   Vector<uint8_t> const &value ) const {
+    Mutex::Autolock autoLock(mLock);
+
+    if (mInitCheck != OK) {
+        return mInitCheck;
+    }
+
+    if (mPlugin == NULL) {
+        return -EINVAL;
+    }
+
+    return mPlugin->setPropertyByteArray(name, value);
+}
+
+}  // namespace android