OSDN Git Service

Load crypto plugins from additional shared libraries
authorJeff Tinker <jtinker@google.com>
Fri, 22 Mar 2013 22:26:39 +0000 (15:26 -0700)
committerJeff Tinker <jtinker@google.com>
Fri, 22 Mar 2013 22:26:39 +0000 (15:26 -0700)
Currently crypto plugins are expected to be in libdrmdecrypt.so.
When there are multiple plugins supporting different schemes,
this approach requires source code integration across
vendors which is unmanagable.  Also, for integration with
MediaDrm where the crypto keys are obtained from a drm server,
the MediaCrypto plugin needs to interoperate with the MediaDrm
plugin. This change allows {MediaCrypto, MediaDrm} pairs that
are logically related to be implemented in a common shared
library.

Change-Id: I7f6638f29171f91609fc2d944396365568630b56

include/media/ICrypto.h
media/libmedia/ICrypto.cpp
media/libmediaplayerservice/Crypto.cpp
media/libmediaplayerservice/Crypto.h

index 61059bd..9dcb8d9 100644 (file)
@@ -31,7 +31,7 @@ struct ICrypto : public IInterface {
 
     virtual status_t initCheck() const = 0;
 
-    virtual bool isCryptoSchemeSupported(const uint8_t uuid[16]) const = 0;
+    virtual bool isCryptoSchemeSupported(const uint8_t uuid[16]) = 0;
 
     virtual status_t createPlugin(
             const uint8_t uuid[16], const void *data, size_t size) = 0;
index 2defc2d..98b183a 100644 (file)
@@ -48,7 +48,7 @@ struct BpCrypto : public BpInterface<ICrypto> {
         return reply.readInt32();
     }
 
-    virtual bool isCryptoSchemeSupported(const uint8_t uuid[16]) const {
+    virtual bool isCryptoSchemeSupported(const uint8_t uuid[16]) {
         Parcel data, reply;
         data.writeInterfaceToken(ICrypto::getInterfaceDescriptor());
         data.write(uuid, 16);
index 0e8f913..ae4d845 100644 (file)
@@ -17,6 +17,8 @@
 //#define LOG_NDEBUG 0
 #define LOG_TAG "Crypto"
 #include <utils/Log.h>
+#include <dirent.h>
+#include <dlfcn.h>
 
 #include "Crypto.h"
 
 #include <media/stagefright/foundation/hexdump.h>
 #include <media/stagefright/MediaErrors.h>
 
-#include <dlfcn.h>
-
 namespace android {
 
+KeyedVector<Vector<uint8_t>, String8> Crypto::mUUIDToLibraryPathMap;
+KeyedVector<String8, wp<SharedLibrary> > Crypto::mLibraryPathToOpenLibraryMap;
+Mutex Crypto::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;
+}
+
 Crypto::Crypto()
     : mInitCheck(NO_INIT),
-      mLibHandle(NULL),
       mFactory(NULL),
       mPlugin(NULL) {
-    mInitCheck = init();
 }
 
 Crypto::~Crypto() {
     delete mPlugin;
     mPlugin = NULL;
+    closeFactory();
+}
 
+void Crypto::closeFactory() {
     delete mFactory;
     mFactory = NULL;
-
-    if (mLibHandle != NULL) {
-        dlclose(mLibHandle);
-        mLibHandle = NULL;
-    }
+    mLibrary.clear();
 }
 
 status_t Crypto::initCheck() const {
     return mInitCheck;
 }
 
-status_t Crypto::init() {
-    mLibHandle = dlopen("libdrmdecrypt.so", RTLD_NOW);
+/*
+ * 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 Crypto::findFactoryForScheme(const uint8_t uuid[16]) {
 
-    if (mLibHandle == NULL) {
-        ALOGE("Unable to locate libdrmdecrypt.so");
+    closeFactory();
 
-        return ERROR_UNSUPPORTED;
+    // 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;
+        }
     }
 
-    typedef CryptoFactory *(*CreateCryptoFactoryFunc)();
-    CreateCryptoFactoryFunc createCryptoFactory =
-        (CreateCryptoFactoryFunc)dlsym(mLibHandle, "createCryptoFactory");
+    // no luck, have to search
+    String8 dirPath("/vendor/lib/mediadrm");
+    String8 pluginPath;
 
-    if (createCryptoFactory == NULL
-            || ((mFactory = createCryptoFactory()) == NULL)) {
-        if (createCryptoFactory == NULL) {
-            ALOGE("Unable to find symbol 'createCryptoFactory'.");
-        } else {
-            ALOGE("createCryptoFactory() failed.");
+    DIR* pDir = opendir(dirPath.string());
+    if (pDir) {
+        struct dirent* pEntry;
+        while ((pEntry = readdir(pDir))) {
+
+            pluginPath = dirPath + "/" + pEntry->d_name;
+
+            if (pluginPath.getPathExtension() == ".so") {
+
+                if (loadLibraryForScheme(pluginPath, uuid)) {
+                    mUUIDToLibraryPathMap.add(uuidVector, pluginPath);
+                    mInitCheck = OK;
+                    closedir(pDir);
+                    return;
+                }
+            }
         }
 
-        dlclose(mLibHandle);
-        mLibHandle = NULL;
+        closedir(pDir);
+    }
 
-        return ERROR_UNSUPPORTED;
+    // try the legacy libdrmdecrypt.so
+    pluginPath = "libdrmdecrypt.so";
+    if (loadLibraryForScheme(pluginPath, uuid)) {
+        mUUIDToLibraryPathMap.add(uuidVector, pluginPath);
+        mInitCheck = OK;
+        return;
     }
 
-    return OK;
+    ALOGE("Failed to find crypto plugin");
+    mInitCheck = ERROR_UNSUPPORTED;
 }
 
-bool Crypto::isCryptoSchemeSupported(const uint8_t uuid[16]) const {
-    Mutex::Autolock autoLock(mLock);
+bool Crypto::loadLibraryForScheme(const String8 &path, const uint8_t uuid[16]) {
 
-    if (mInitCheck != OK) {
+    // 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 CryptoFactory *(*CreateCryptoFactoryFunc)();
+
+    CreateCryptoFactoryFunc createCryptoFactory =
+        (CreateCryptoFactoryFunc)mLibrary->lookup("createCryptoFactory");
+
+    if (createCryptoFactory == NULL ||
+        (mFactory = createCryptoFactory()) == NULL ||
+        !mFactory->isCryptoSchemeSupported(uuid)) {
+        closeFactory();
         return false;
     }
+    return true;
+}
 
-    return mFactory->isCryptoSchemeSupported(uuid);
+bool Crypto::isCryptoSchemeSupported(const uint8_t uuid[16]) {
+    Mutex::Autolock autoLock(mLock);
+
+    if (mFactory && mFactory->isCryptoSchemeSupported(uuid)) {
+        return true;
+    }
+
+    findFactoryForScheme(uuid);
+    return (mInitCheck == OK);
 }
 
 status_t Crypto::createPlugin(
         const uint8_t uuid[16], const void *data, size_t size) {
     Mutex::Autolock autoLock(mLock);
 
-    if (mInitCheck != OK) {
-        return mInitCheck;
-    }
-
     if (mPlugin != NULL) {
         return -EINVAL;
     }
 
+    if (!mFactory || !mFactory->isCryptoSchemeSupported(uuid)) {
+        findFactoryForScheme(uuid);
+    }
+
+    if (mInitCheck != OK) {
+        return mInitCheck;
+    }
+
     return mFactory->createPlugin(uuid, data, size, &mPlugin);
 }
 
index d066774..c44ae34 100644 (file)
@@ -20,6 +20,9 @@
 
 #include <media/ICrypto.h>
 #include <utils/threads.h>
+#include <utils/KeyedVector.h>
+
+#include "SharedLibrary.h"
 
 namespace android {
 
@@ -32,7 +35,7 @@ struct Crypto : public BnCrypto {
 
     virtual status_t initCheck() const;
 
-    virtual bool isCryptoSchemeSupported(const uint8_t uuid[16]) const;
+    virtual bool isCryptoSchemeSupported(const uint8_t uuid[16]);
 
     virtual status_t createPlugin(
             const uint8_t uuid[16], const void *data, size_t size);
@@ -56,11 +59,17 @@ private:
     mutable Mutex mLock;
 
     status_t mInitCheck;
-    void *mLibHandle;
+    sp<SharedLibrary> mLibrary;
     CryptoFactory *mFactory;
     CryptoPlugin *mPlugin;
 
-    status_t init();
+    static KeyedVector<Vector<uint8_t>, String8> mUUIDToLibraryPathMap;
+    static KeyedVector<String8, wp<SharedLibrary> > mLibraryPathToOpenLibraryMap;
+    static Mutex mMapLock;
+
+    void findFactoryForScheme(const uint8_t uuid[16]);
+    bool loadLibraryForScheme(const String8 &path, const uint8_t uuid[16]);
+    void closeFactory();
 
     DISALLOW_EVIL_CONSTRUCTORS(Crypto);
 };