New Crypto services talking to the new crypto "HAL".

Change-Id: I69ed31e7a8b4d69d1209d2d516f94d258f072566
related-to-bug: 6275919
diff --git a/cmds/stagefright/SimplePlayer.cpp b/cmds/stagefright/SimplePlayer.cpp
index 0cfeb3e..7636906 100644
--- a/cmds/stagefright/SimplePlayer.cpp
+++ b/cmds/stagefright/SimplePlayer.cpp
@@ -22,6 +22,7 @@
 
 #include <gui/SurfaceTextureClient.h>
 #include <media/AudioTrack.h>
+#include <media/ICrypto.h>
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/AMessage.h>
@@ -318,7 +319,9 @@
         CHECK(state->mCodec != NULL);
 
         err = state->mCodec->configure(
-                format, mNativeWindow->getSurfaceTextureClient(),
+                format,
+                mNativeWindow->getSurfaceTextureClient(),
+                NULL /* crypto */,
                 0 /* flags */);
 
         CHECK_EQ(err, (status_t)OK);
diff --git a/cmds/stagefright/codec.cpp b/cmds/stagefright/codec.cpp
index cf2909e..5cbfbfe 100644
--- a/cmds/stagefright/codec.cpp
+++ b/cmds/stagefright/codec.cpp
@@ -20,8 +20,10 @@
 
 #include "SimplePlayer.h"
 
+#include <binder/IServiceManager.h>
 #include <binder/ProcessState.h>
-
+#include <media/ICrypto.h>
+#include <media/IMediaPlayerService.h>
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/ALooper.h>
@@ -59,6 +61,33 @@
     bool mIsAudio;
 };
 
+static sp<ICrypto> makeCrypto(
+        const uint8_t uuid[16], const void *data, size_t size) {
+    sp<IServiceManager> sm = defaultServiceManager();
+
+    sp<IBinder> binder =
+        sm->getService(String16("media.player"));
+
+    sp<IMediaPlayerService> service =
+        interface_cast<IMediaPlayerService>(binder);
+
+    CHECK(service != NULL);
+
+    sp<ICrypto> crypto = service->makeCrypto();
+
+    if (crypto == NULL || crypto->initCheck() != OK) {
+        return NULL;
+    }
+
+    status_t err = crypto->createPlugin(uuid, data, size);
+
+    if (err != OK) {
+        return NULL;
+    }
+
+    return crypto;
+}
+
 }  // namespace android
 
 static int decode(
@@ -78,6 +107,8 @@
         return 1;
     }
 
+    sp<ICrypto> crypto;
+
     KeyedVector<size_t, CodecState> stateByTrack;
 
     bool haveAudio = false;
@@ -113,7 +144,38 @@
         state->mNumBuffersDecoded = 0;
         state->mIsAudio = isAudio;
 
-        if (decryptInputBuffers && !isAudio) {
+        if (decryptInputBuffers && crypto == NULL) {
+            sp<ABuffer> emm;
+            CHECK(format->findBuffer("emm", &emm));
+
+            sp<ABuffer> ecm;
+            CHECK(format->findBuffer("ecm", &ecm));
+
+            struct WVOpaqueInitData {
+                uint8_t mEMM[16];
+                uint8_t mECM[32];
+
+            } opaque;
+
+            CHECK_EQ(emm->size(), sizeof(opaque.mEMM));
+            memcpy(opaque.mEMM, emm->data(), emm->size());
+
+            CHECK_EQ(ecm->size(), 80u);
+            // bytes 16..47 of the original ecm stream data.
+            memcpy(opaque.mECM, ecm->data() + 16, 32);
+
+            static const uint8_t kUUIDWidevine[16] = {
+                0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+                0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+            };
+
+            crypto = makeCrypto(kUUIDWidevine, &opaque, sizeof(opaque));
+            CHECK(crypto != NULL);
+            CHECK_EQ(crypto->initCheck(), (status_t)OK);
+        }
+
+        if (decryptInputBuffers
+                && crypto->requiresSecureDecoderComponent(mime.c_str())) {
             static const MediaCodecList *list = MediaCodecList::getInstance();
 
             ssize_t index =
@@ -137,7 +199,8 @@
 
         err = state->mCodec->configure(
                 format, isVideo ? surface : NULL,
-                decryptInputBuffers ? MediaCodec::CONFIGURE_FLAG_SECURE : 0);
+                crypto,
+                0 /* flags */);
 
         CHECK_EQ(err, (status_t)OK);
 
diff --git a/include/media/ICrypto.h b/include/media/ICrypto.h
index 916abe0..376c326 100644
--- a/include/media/ICrypto.h
+++ b/include/media/ICrypto.h
@@ -16,6 +16,7 @@
 
 #include <binder/IInterface.h>
 #include <media/stagefright/foundation/ABase.h>
+#include <media/hardware/CryptoAPI.h>
 
 #ifndef ANDROID_ICRYPTO_H_
 
@@ -26,26 +27,26 @@
 struct ICrypto : public IInterface {
     DECLARE_META_INTERFACE(Crypto);
 
-    virtual status_t initialize() = 0;
-    virtual status_t terminate() = 0;
+    virtual status_t initCheck() const = 0;
 
-    virtual status_t setEntitlementKey(
-            const void *key, size_t keyLength) = 0;
+    virtual bool isCryptoSchemeSupported(const uint8_t uuid[16]) const = 0;
 
-    virtual status_t setEntitlementControlMessage(
-            const void *msg, size_t msgLength) = 0;
+    virtual status_t createPlugin(
+            const uint8_t uuid[16], const void *data, size_t size) = 0;
 
-    // "dstData" is in media_server's address space (but inaccessible).
-    virtual ssize_t decryptVideo(
-            const void *iv, size_t ivLength,
-            const void *srcData, size_t srcDataSize,
-            void *dstData, size_t dstDataOffset) = 0;
+    virtual status_t destroyPlugin() = 0;
 
-    // "dstData" is in the calling process' address space.
-    virtual ssize_t decryptAudio(
-            const void *iv, size_t ivLength,
-            const void *srcData, size_t srcDataSize,
-            void *dstData, size_t dstDataSize) = 0;
+    virtual bool requiresSecureDecoderComponent(
+            const char *mime) const = 0;
+
+    virtual status_t decrypt(
+            bool secure,
+            const uint8_t key[16],
+            const uint8_t iv[16],
+            CryptoPlugin::Mode mode,
+            const void *srcPtr,
+            const CryptoPlugin::SubSample *subSamples, size_t numSubSamples,
+            void *dstPtr) = 0;
 
 private:
     DISALLOW_EVIL_CONSTRUCTORS(ICrypto);
diff --git a/include/media/stagefright/MediaCodec.h b/include/media/stagefright/MediaCodec.h
index 0fc88e1..0b0d511 100644
--- a/include/media/stagefright/MediaCodec.h
+++ b/include/media/stagefright/MediaCodec.h
@@ -34,7 +34,6 @@
 struct MediaCodec : public AHandler {
     enum ConfigureFlags {
         CONFIGURE_FLAG_ENCODE   = 1,
-        CONFIGURE_FLAG_SECURE   = 2,
     };
 
     enum BufferFlags {
@@ -53,6 +52,7 @@
     status_t configure(
             const sp<AMessage> &format,
             const sp<SurfaceTextureClient> &nativeWindow,
+            const sp<ICrypto> &crypto,
             uint32_t flags);
 
     status_t start();
diff --git a/media/libmedia/ICrypto.cpp b/media/libmedia/ICrypto.cpp
index 827d7af..1fe6bed 100644
--- a/media/libmedia/ICrypto.cpp
+++ b/media/libmedia/ICrypto.cpp
@@ -25,12 +25,12 @@
 namespace android {
 
 enum {
-    INITIALIZE = IBinder::FIRST_CALL_TRANSACTION,
-    TERMINATE,
-    SET_ENTITLEMENT_KEY,
-    SET_ECM,
-    DECRYPT_VIDEO,
-    DECRYPT_AUDIO,
+    INIT_CHECK = IBinder::FIRST_CALL_TRANSACTION,
+    IS_CRYPTO_SUPPORTED,
+    CREATE_PLUGIN,
+    DESTROY_PLUGIN,
+    REQUIRES_SECURE_COMPONENT,
+    DECRYPT,
 };
 
 struct BpCrypto : public BpInterface<ICrypto> {
@@ -38,104 +38,97 @@
         : BpInterface<ICrypto>(impl) {
     }
 
-    virtual status_t initialize() {
+    virtual status_t initCheck() const {
         Parcel data, reply;
         data.writeInterfaceToken(ICrypto::getInterfaceDescriptor());
-        remote()->transact(INITIALIZE, data, &reply);
+        remote()->transact(INIT_CHECK, data, &reply);
 
         return reply.readInt32();
     }
 
-    virtual status_t terminate() {
+    virtual bool isCryptoSchemeSupported(const uint8_t uuid[16]) const {
         Parcel data, reply;
         data.writeInterfaceToken(ICrypto::getInterfaceDescriptor());
-        remote()->transact(TERMINATE, data, &reply);
+        data.write(uuid, 16);
+        remote()->transact(IS_CRYPTO_SUPPORTED, data, &reply);
+
+        return reply.readInt32() != 0;
+    }
+
+    virtual status_t createPlugin(
+            const uint8_t uuid[16], const void *opaqueData, size_t opaqueSize) {
+        Parcel data, reply;
+        data.writeInterfaceToken(ICrypto::getInterfaceDescriptor());
+        data.write(uuid, 16);
+        data.writeInt32(opaqueSize);
+        data.write(opaqueData, opaqueSize);
+        remote()->transact(CREATE_PLUGIN, data, &reply);
 
         return reply.readInt32();
     }
 
-    virtual status_t setEntitlementKey(
-            const void *key, size_t keyLength) {
+    virtual status_t destroyPlugin() {
         Parcel data, reply;
         data.writeInterfaceToken(ICrypto::getInterfaceDescriptor());
-        data.writeInt32(keyLength);
-        data.write(key, keyLength);
-        remote()->transact(SET_ENTITLEMENT_KEY, data, &reply);
+        remote()->transact(DESTROY_PLUGIN, data, &reply);
 
         return reply.readInt32();
     }
 
-    virtual status_t setEntitlementControlMessage(
-            const void *msg, size_t msgLength) {
+    virtual bool requiresSecureDecoderComponent(
+            const char *mime) const {
         Parcel data, reply;
         data.writeInterfaceToken(ICrypto::getInterfaceDescriptor());
-        data.writeInt32(msgLength);
-        data.write(msg, msgLength);
-        remote()->transact(SET_ECM, data, &reply);
+        data.writeCString(mime);
+        remote()->transact(REQUIRES_SECURE_COMPONENT, data, &reply);
 
-        return reply.readInt32();
+        return reply.readInt32() != 0;
     }
 
-    virtual ssize_t decryptVideo(
-            const void *iv, size_t ivLength,
-            const void *srcData, size_t srcDataSize,
-            void *dstData, size_t dstDataOffset) {
+    virtual status_t decrypt(
+            bool secure,
+            const uint8_t key[16],
+            const uint8_t iv[16],
+            CryptoPlugin::Mode mode,
+            const void *srcPtr,
+            const CryptoPlugin::SubSample *subSamples, size_t numSubSamples,
+            void *dstPtr) {
         Parcel data, reply;
         data.writeInterfaceToken(ICrypto::getInterfaceDescriptor());
-        if (iv == NULL) {
-            if (ivLength > 0) {
-                return -EINVAL;
-            }
+        data.writeInt32(secure);
+        data.writeInt32(mode);
+        data.write(key, 16);
+        data.write(iv, 16);
 
-            data.writeInt32(-1);
-        } else {
-            data.writeInt32(ivLength);
-            data.write(iv, ivLength);
+        size_t totalSize = 0;
+        for (size_t i = 0; i < numSubSamples; ++i) {
+            totalSize += subSamples[i].mNumBytesOfEncryptedData;
+            totalSize += subSamples[i].mNumBytesOfClearData;
         }
 
-        data.writeInt32(srcDataSize);
-        data.write(srcData, srcDataSize);
+        data.writeInt32(totalSize);
+        data.write(srcPtr, totalSize);
 
-        data.writeIntPtr((intptr_t)dstData);
-        data.writeInt32(dstDataOffset);
+        data.writeInt32(numSubSamples);
+        data.write(subSamples, sizeof(CryptoPlugin::SubSample) * numSubSamples);
 
-        remote()->transact(DECRYPT_VIDEO, data, &reply);
-
-        return reply.readInt32();
-    }
-
-    virtual ssize_t decryptAudio(
-            const void *iv, size_t ivLength,
-            const void *srcData, size_t srcDataSize,
-            void *dstData, size_t dstDataSize) {
-        Parcel data, reply;
-        data.writeInterfaceToken(ICrypto::getInterfaceDescriptor());
-        if (iv == NULL) {
-            if (ivLength > 0) {
-                return -EINVAL;
-            }
-
-            data.writeInt32(-1);
-        } else {
-            data.writeInt32(ivLength);
-            data.write(iv, ivLength);
+        if (secure) {
+            data.writeIntPtr((intptr_t)dstPtr);
         }
 
-        data.writeInt32(srcDataSize);
-        data.write(srcData, srcDataSize);
-        data.writeInt32(dstDataSize);
+        remote()->transact(DECRYPT, data, &reply);
 
-        remote()->transact(DECRYPT_AUDIO, data, &reply);
+        status_t result = reply.readInt32();
 
-        ssize_t res = reply.readInt32();
-
-        if (res <= 0) {
-            return res;
+        if (result != OK) {
+            return result;
         }
 
-        reply.read(dstData, res);
+        if (!secure) {
+            reply.read(dstPtr, totalSize);
+        }
 
-        return res;
+        return OK;
     }
 
 private:
@@ -149,138 +142,120 @@
 status_t BnCrypto::onTransact(
     uint32_t code, const Parcel &data, Parcel *reply, uint32_t flags) {
     switch (code) {
-        case INITIALIZE:
+        case INIT_CHECK:
         {
             CHECK_INTERFACE(ICrypto, data, reply);
-            reply->writeInt32(initialize());
+            reply->writeInt32(initCheck());
 
             return OK;
         }
 
-        case TERMINATE:
+        case IS_CRYPTO_SUPPORTED:
         {
             CHECK_INTERFACE(ICrypto, data, reply);
-            reply->writeInt32(terminate());
+            uint8_t uuid[16];
+            data.read(uuid, sizeof(uuid));
+            reply->writeInt32(isCryptoSchemeSupported(uuid));
 
             return OK;
         }
 
-        case SET_ENTITLEMENT_KEY:
+        case CREATE_PLUGIN:
         {
             CHECK_INTERFACE(ICrypto, data, reply);
 
-            size_t keyLength = data.readInt32();
-            void *key = malloc(keyLength);
-            data.read(key, keyLength);
+            uint8_t uuid[16];
+            data.read(uuid, sizeof(uuid));
 
-            reply->writeInt32(setEntitlementKey(key, keyLength));
+            size_t opaqueSize = data.readInt32();
+            void *opaqueData = malloc(opaqueSize);
+            data.read(opaqueData, opaqueSize);
 
-            free(key);
-            key = NULL;
+            reply->writeInt32(createPlugin(uuid, opaqueData, opaqueSize));
+
+            free(opaqueData);
+            opaqueData = NULL;
 
             return OK;
         }
 
-        case SET_ECM:
+        case DESTROY_PLUGIN:
         {
             CHECK_INTERFACE(ICrypto, data, reply);
-
-            size_t msgLength = data.readInt32();
-            void *msg = malloc(msgLength);
-            data.read(msg, msgLength);
-
-            reply->writeInt32(setEntitlementControlMessage(msg, msgLength));
-
-            free(msg);
-            msg = NULL;
+            reply->writeInt32(destroyPlugin());
 
             return OK;
         }
 
-        case DECRYPT_VIDEO:
+        case REQUIRES_SECURE_COMPONENT:
         {
             CHECK_INTERFACE(ICrypto, data, reply);
 
-            void *iv = NULL;
+            const char *mime = data.readCString();
+            reply->writeInt32(requiresSecureDecoderComponent(mime));
 
-            int32_t ivLength = data.readInt32();
-            if (ivLength >= 0) {
-                iv = malloc(ivLength);
-                data.read(iv, ivLength);
+            return OK;
+        }
+
+        case DECRYPT:
+        {
+            CHECK_INTERFACE(ICrypto, data, reply);
+
+            bool secure = data.readInt32() != 0;
+            CryptoPlugin::Mode mode = (CryptoPlugin::Mode)data.readInt32();
+
+            uint8_t key[16];
+            data.read(key, sizeof(key));
+
+            uint8_t iv[16];
+            data.read(iv, sizeof(iv));
+
+            size_t totalSize = data.readInt32();
+            void *srcData = malloc(totalSize);
+            data.read(srcData, totalSize);
+
+            int32_t numSubSamples = data.readInt32();
+
+            CryptoPlugin::SubSample *subSamples =
+                new CryptoPlugin::SubSample[numSubSamples];
+
+            data.read(
+                    subSamples,
+                    sizeof(CryptoPlugin::SubSample) * numSubSamples);
+
+            void *dstPtr;
+            if (secure) {
+                dstPtr = (void *)data.readIntPtr();
+            } else {
+                dstPtr = malloc(totalSize);
             }
 
-            size_t srcDataSize = data.readInt32();
-            void *srcData = malloc(srcDataSize);
-            data.read(srcData, srcDataSize);
+            status_t err = decrypt(
+                    secure,
+                    key,
+                    iv,
+                    mode,
+                    srcData,
+                    subSamples, numSubSamples,
+                    dstPtr);
 
-            void *dstData = (void *)data.readIntPtr();
-            size_t dstDataOffset = data.readInt32();
+            reply->writeInt32(err);
 
-            reply->writeInt32(
-                    decryptVideo(
-                        iv,
-                        ivLength < 0 ? 0 : ivLength,
-                        srcData,
-                        srcDataSize,
-                        dstData,
-                        dstDataOffset));
+            if (!secure) {
+                if (err == OK) {
+                    reply->write(dstPtr, totalSize);
+                }
+
+                free(dstPtr);
+                dstPtr = NULL;
+            }
+
+            delete[] subSamples;
+            subSamples = NULL;
 
             free(srcData);
             srcData = NULL;
 
-            if (iv != NULL) {
-                free(iv);
-                iv = NULL;
-            }
-
-            return OK;
-        }
-
-        case DECRYPT_AUDIO:
-        {
-            CHECK_INTERFACE(ICrypto, data, reply);
-
-            void *iv = NULL;
-
-            int32_t ivLength = data.readInt32();
-            if (ivLength >= 0) {
-                iv = malloc(ivLength);
-                data.read(iv, ivLength);
-            }
-
-            size_t srcDataSize = data.readInt32();
-            void *srcData = malloc(srcDataSize);
-            data.read(srcData, srcDataSize);
-
-            size_t dstDataSize = data.readInt32();
-            void *dstData = malloc(dstDataSize);
-
-            ssize_t res =
-                decryptAudio(
-                        iv,
-                        ivLength < 0 ? 0 : ivLength,
-                        srcData,
-                        srcDataSize,
-                        dstData,
-                        dstDataSize);
-
-            reply->writeInt32(res);
-
-            if (res > 0) {
-                reply->write(dstData, res);
-            }
-
-            free(dstData);
-            dstData = NULL;
-
-            free(srcData);
-            srcData = NULL;
-
-            if (iv != NULL) {
-                free(iv);
-                iv = NULL;
-            }
-
             return OK;
         }
 
diff --git a/media/libmediaplayerservice/Crypto.cpp b/media/libmediaplayerservice/Crypto.cpp
index e02035f..4491f2b 100644
--- a/media/libmediaplayerservice/Crypto.cpp
+++ b/media/libmediaplayerservice/Crypto.cpp
@@ -20,46 +20,137 @@
 
 #include "Crypto.h"
 
+#include <media/hardware/CryptoAPI.h>
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/hexdump.h>
 #include <media/stagefright/MediaErrors.h>
 
+#include <dlfcn.h>
+
 namespace android {
 
-Crypto::Crypto() {
+Crypto::Crypto()
+    : mInitCheck(NO_INIT),
+      mLibHandle(NULL),
+      mPlugin(NULL) {
+    mInitCheck = init();
 }
 
 Crypto::~Crypto() {
+    delete mPlugin;
+    mPlugin = NULL;
+
+    delete mFactory;
+    mFactory = NULL;
+
+    if (mLibHandle != NULL) {
+        dlclose(mLibHandle);
+        mLibHandle = NULL;
+    }
 }
 
-status_t Crypto::initialize() {
-    return ERROR_UNSUPPORTED;
+status_t Crypto::initCheck() const {
+    return mInitCheck;
 }
 
-status_t Crypto::terminate() {
-    return ERROR_UNSUPPORTED;
+status_t Crypto::init() {
+    mLibHandle = dlopen("libdrmdecrypt.so", RTLD_NOW);
+
+    if (mLibHandle == NULL) {
+        return ERROR_UNSUPPORTED;
+    }
+
+    typedef CryptoFactory *(*CreateCryptoFactoryFunc)();
+    CreateCryptoFactoryFunc createCryptoFactory =
+        (CreateCryptoFactoryFunc)dlsym(mLibHandle, "createCryptoFactory");
+
+    if (createCryptoFactory == NULL
+            || ((mFactory = createCryptoFactory()) == NULL)) {
+        dlclose(mLibHandle);
+        mLibHandle = NULL;
+
+        return ERROR_UNSUPPORTED;
+    }
+
+    return OK;
 }
 
-status_t Crypto::setEntitlementKey(
-        const void *key, size_t keyLength) {
-    return ERROR_UNSUPPORTED;
+bool Crypto::isCryptoSchemeSupported(const uint8_t uuid[16]) const {
+    Mutex::Autolock autoLock(mLock);
+
+    if (mInitCheck != OK) {
+        return false;
+    }
+
+    return mFactory->isCryptoSchemeSupported(uuid);
 }
 
-status_t Crypto::setEntitlementControlMessage(
-        const void *msg, size_t msgLength) {
-    return ERROR_UNSUPPORTED;
+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;
+    }
+
+    return mFactory->createPlugin(uuid, data, size, &mPlugin);
 }
 
-ssize_t Crypto::decryptVideo(
-        const void *iv, size_t ivLength,
-        const void *srcData, size_t srcDataSize,
-        void *dstData, size_t dstDataOffset) {
-    return ERROR_UNSUPPORTED;
+status_t Crypto::destroyPlugin() {
+    Mutex::Autolock autoLock(mLock);
+
+    if (mInitCheck != OK) {
+        return mInitCheck;
+    }
+
+    if (mPlugin == NULL) {
+        return -EINVAL;
+    }
+
+    delete mPlugin;
+    mPlugin = NULL;
+
+    return OK;
 }
 
-ssize_t Crypto::decryptAudio(
-        const void *iv, size_t ivLength,
-        const void *srcData, size_t srcDataSize,
-        void *dstData, size_t dstDataSize) {
-    return ERROR_UNSUPPORTED;
+bool Crypto::requiresSecureDecoderComponent(const char *mime) const {
+    Mutex::Autolock autoLock(mLock);
+
+    if (mInitCheck != OK) {
+        return mInitCheck;
+    }
+
+    if (mPlugin == NULL) {
+        return -EINVAL;
+    }
+
+    return mPlugin->requiresSecureDecoderComponent(mime);
+}
+
+status_t Crypto::decrypt(
+        bool secure,
+        const uint8_t key[16],
+        const uint8_t iv[16],
+        CryptoPlugin::Mode mode,
+        const void *srcPtr,
+        const CryptoPlugin::SubSample *subSamples, size_t numSubSamples,
+        void *dstPtr) {
+    Mutex::Autolock autoLock(mLock);
+
+    if (mInitCheck != OK) {
+        return mInitCheck;
+    }
+
+    if (mPlugin == NULL) {
+        return -EINVAL;
+    }
+
+    return mPlugin->decrypt(
+            secure, key, iv, mode, srcPtr, subSamples, numSubSamples, dstPtr);
 }
 
 }  // namespace android
diff --git a/media/libmediaplayerservice/Crypto.h b/media/libmediaplayerservice/Crypto.h
index 9855496..74de2b5 100644
--- a/media/libmediaplayerservice/Crypto.h
+++ b/media/libmediaplayerservice/Crypto.h
@@ -23,32 +23,44 @@
 
 namespace android {
 
+struct CryptoFactory;
+struct CryptoPlugin;
+
 struct Crypto : public BnCrypto {
     Crypto();
-
-    virtual status_t initialize();
-    virtual status_t terminate();
-
-    virtual status_t setEntitlementKey(
-            const void *key, size_t keyLength);
-
-    virtual status_t setEntitlementControlMessage(
-            const void *msg, size_t msgLength);
-
-    virtual ssize_t decryptVideo(
-            const void *iv, size_t ivLength,
-            const void *srcData, size_t srcDataSize,
-            void *dstData, size_t dstDataOffset);
-
-    virtual ssize_t decryptAudio(
-            const void *iv, size_t ivLength,
-            const void *srcData, size_t srcDataSize,
-            void *dstData, size_t dstDataSize);
-
-protected:
     virtual ~Crypto();
 
+    virtual status_t initCheck() const;
+
+    virtual bool isCryptoSchemeSupported(const uint8_t uuid[16]) const;
+
+    virtual status_t createPlugin(
+            const uint8_t uuid[16], const void *data, size_t size);
+
+    virtual status_t destroyPlugin();
+
+    virtual bool requiresSecureDecoderComponent(
+            const char *mime) const;
+
+    virtual status_t decrypt(
+            bool secure,
+            const uint8_t key[16],
+            const uint8_t iv[16],
+            CryptoPlugin::Mode mode,
+            const void *srcPtr,
+            const CryptoPlugin::SubSample *subSamples, size_t numSubSamples,
+            void *dstPtr);
+
 private:
+    mutable Mutex mLock;
+
+    status_t mInitCheck;
+    void *mLibHandle;
+    CryptoFactory *mFactory;
+    CryptoPlugin *mPlugin;
+
+    status_t init();
+
     DISALLOW_EVIL_CONSTRUCTORS(Crypto);
 };
 
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index a977337..7c3fb0d 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -294,13 +294,7 @@
 }
 
 sp<ICrypto> MediaPlayerService::makeCrypto() {
-    Mutex::Autolock autoLock(mLock);
-
-    if (mCrypto == NULL) {
-        mCrypto = new Crypto;
-    }
-
-    return mCrypto;
+    return new Crypto;
 }
 
 status_t MediaPlayerService::AudioCache::dump(int fd, const Vector<String16>& args) const
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index 42b5c7e..ced8368 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -22,10 +22,8 @@
 
 #include "include/SoftwareRenderer.h"
 
-#include <binder/IServiceManager.h>
 #include <gui/SurfaceTextureClient.h>
 #include <media/ICrypto.h>
-#include <media/IMediaPlayerService.h>
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/AMessage.h>
@@ -134,6 +132,7 @@
 status_t MediaCodec::configure(
         const sp<AMessage> &format,
         const sp<SurfaceTextureClient> &nativeWindow,
+        const sp<ICrypto> &crypto,
         uint32_t flags) {
     sp<AMessage> msg = new AMessage(kWhatConfigure, id());
 
@@ -141,13 +140,13 @@
     msg->setInt32("flags", flags);
 
     if (nativeWindow != NULL) {
-        if (!(mFlags & kFlagIsSoftwareCodec)) {
-            msg->setObject(
-                    "native-window",
-                    new NativeWindowWrapper(nativeWindow));
-        } else {
-            mNativeWindow = nativeWindow;
-        }
+        msg->setObject(
+                "native-window",
+                new NativeWindowWrapper(nativeWindow));
+    }
+
+    if (crypto != NULL) {
+        msg->setPointer("crypto", crypto.get());
     }
 
     sp<AMessage> response;
@@ -490,6 +489,12 @@
                         mFlags &= ~kFlagIsSoftwareCodec;
                     }
 
+                    if (componentName.endsWith(".secure")) {
+                        mFlags |= kFlagIsSecure;
+                    } else {
+                        mFlags &= ~kFlagIsSecure;
+                    }
+
                     (new AMessage)->postReply(mReplyID);
                     break;
                 }
@@ -532,8 +537,7 @@
                         info.mOwnedByClient = false;
                         CHECK(msg->findBuffer(name.c_str(), &info.mData));
 
-                        if (portIndex == kPortIndexInput
-                                && (mFlags & kFlagIsSecure)) {
+                        if (portIndex == kPortIndexInput && mCrypto != NULL) {
                             info.mEncryptedData =
                                 new ABuffer(info.mData->capacity());
                         }
@@ -743,8 +747,23 @@
 
             if (obj != NULL) {
                 format->setObject("native-window", obj);
+
+                if (mFlags & kFlagIsSoftwareCodec) {
+                    mNativeWindow =
+                        static_cast<NativeWindowWrapper *>(obj.get())
+                            ->getSurfaceTextureClient();
+                }
+            } else {
+                mNativeWindow.clear();
             }
 
+            void *crypto;
+            if (!msg->findPointer("crypto", &crypto)) {
+                crypto = NULL;
+            }
+
+            mCrypto = static_cast<ICrypto *>(crypto);
+
             uint32_t flags;
             CHECK(msg->findInt32("flags", (int32_t *)&flags));
 
@@ -752,59 +771,6 @@
                 format->setInt32("encoder", true);
             }
 
-            if (flags & CONFIGURE_FLAG_SECURE) {
-                mFlags |= kFlagIsSecure;
-
-                sp<IServiceManager> sm = defaultServiceManager();
-
-                sp<IBinder> binder =
-                    sm->getService(String16("media.player"));
-
-                sp<IMediaPlayerService> service =
-                    interface_cast<IMediaPlayerService>(binder);
-
-                CHECK(service != NULL);
-
-                mCrypto = service->makeCrypto();
-
-                status_t err = mCrypto->initialize();
-
-                if (err == OK) {
-                    sp<ABuffer> emm;
-                    if (format->findBuffer("emm", &emm)) {
-                        err = mCrypto->setEntitlementKey(
-                                emm->data(), emm->size());
-                    }
-                }
-
-                if (err == OK) {
-                    sp<ABuffer> ecm;
-                    if (format->findBuffer("ecm", &ecm)) {
-                        CHECK_EQ(ecm->size(), 80u);
-
-                        // bytes 16..47 of the original ecm stream data.
-                        err = mCrypto->setEntitlementControlMessage(
-                                ecm->data() + 16, 32);
-                    }
-                }
-
-                if (err != OK) {
-                    ALOGE("failed to instantiate crypto service.");
-
-                    mCrypto.clear();
-
-                    setState(INITIALIZED);
-
-                    sp<AMessage> response = new AMessage;
-                    response->setInt32("err", UNKNOWN_ERROR);
-
-                    response->postReply(mReplyID);
-                    break;
-                }
-            } else {
-                mFlags &= ~kFlagIsSecure;
-            }
-
             mCodec->initiateConfigureComponent(format);
             break;
         }
@@ -1047,8 +1013,7 @@
                 const BufferInfo &info = srcBuffers.itemAt(i);
 
                 dstBuffers->push_back(
-                        (portIndex == kPortIndexInput
-                            && (mFlags & kFlagIsSecure))
+                        (portIndex == kPortIndexInput && mCrypto != NULL)
                                 ? info.mEncryptedData : info.mData);
             }
 
@@ -1107,11 +1072,7 @@
         delete mSoftRenderer;
         mSoftRenderer = NULL;
 
-        if (mCrypto != NULL) {
-            mCrypto->terminate();
-            mCrypto.clear();
-        }
-
+        mCrypto.clear();
         mNativeWindow.clear();
 
         mOutputFormat.clear();
@@ -1221,39 +1182,41 @@
         info->mData->meta()->setInt32("csd", true);
     }
 
-    if (mFlags & kFlagIsSecure) {
-        uint8_t iv[16];
-        memset(iv, 0, sizeof(iv));
-
-        ssize_t outLength;
-
-        if (mFlags & kFlagIsSoftwareCodec) {
-            outLength = mCrypto->decryptAudio(
-                    (flags & BUFFER_FLAG_ENCRYPTED) ? iv : NULL,
-                    (flags & BUFFER_FLAG_ENCRYPTED) ? sizeof(iv) : 0,
-                        info->mEncryptedData->base() + offset,
-                        size,
-                        info->mData->base(),
-                        info->mData->capacity());
-        } else {
-            outLength = mCrypto->decryptVideo(
-                    (flags & BUFFER_FLAG_ENCRYPTED) ? iv : NULL,
-                    (flags & BUFFER_FLAG_ENCRYPTED) ? sizeof(iv) : 0,
-                        info->mEncryptedData->base() + offset,
-                        size,
-                        info->mData->base(),
-                        0  /* offset */);
-        }
-
-        if (outLength < 0) {
-            return outLength;
-        }
-
-        if ((size_t)outLength > info->mEncryptedData->capacity()) {
+    if (mCrypto != NULL) {
+        if (size > info->mEncryptedData->capacity()) {
             return -ERANGE;
         }
 
-        info->mData->setRange(0, outLength);
+        uint8_t key[16];
+        uint8_t iv[16];
+
+        CryptoPlugin::Mode mode;
+        CryptoPlugin::SubSample ss;
+        if (flags & BUFFER_FLAG_ENCRYPTED) {
+            mode = CryptoPlugin::kMode_AES_WV;
+            ss.mNumBytesOfClearData = 0;
+            ss.mNumBytesOfEncryptedData = size;
+        } else {
+            mode = CryptoPlugin::kMode_Unencrypted;
+            ss.mNumBytesOfClearData = size;
+            ss.mNumBytesOfEncryptedData = 0;
+        }
+
+        status_t err = mCrypto->decrypt(
+                (mFlags & kFlagIsSecure) != 0,
+                key,
+                iv,
+                mode,
+                info->mEncryptedData->base() + offset,
+                &ss,
+                1 /* numSubSamples */,
+                info->mData->base());
+
+        if (err != OK) {
+            return err;
+        }
+
+        info->mData->setRange(0, size);
     } else if (flags & BUFFER_FLAG_ENCRYPTED) {
         return -EINVAL;
     }