summaryrefslogtreecommitdiffstats
path: root/drm
diff options
context:
space:
mode:
authorJeff Tinker <jtinker@google.com>2013-09-11 18:40:44 -0700
committerJeff Tinker <jtinker@google.com>2013-09-11 18:40:44 -0700
commit34486800a022857b45c3882624449980c5cb6907 (patch)
tree06e1a76a831666df008d5ba344b2c8e34bce27ef /drm
parentfe346c707f59d763ded93bc3d27b51f0c0408258 (diff)
downloadframeworks_av-34486800a022857b45c3882624449980c5cb6907.zip
frameworks_av-34486800a022857b45c3882624449980c5cb6907.tar.gz
frameworks_av-34486800a022857b45c3882624449980c5cb6907.tar.bz2
Fix MediaDrm cts tests
Moving the build of the mock MediaDrm plugin back to frameworks/av since it can't be installed by cts. b/10668350 Change-Id: Id662bdb0775389b458f86a299392217f2d959422
Diffstat (limited to 'drm')
-rw-r--r--drm/mediadrm/plugins/mock/Android.mk38
-rw-r--r--drm/mediadrm/plugins/mock/MockDrmCryptoPlugin.cpp705
-rw-r--r--drm/mediadrm/plugins/mock/MockDrmCryptoPlugin.h156
3 files changed, 899 insertions, 0 deletions
diff --git a/drm/mediadrm/plugins/mock/Android.mk b/drm/mediadrm/plugins/mock/Android.mk
new file mode 100644
index 0000000..ada23a2
--- /dev/null
+++ b/drm/mediadrm/plugins/mock/Android.mk
@@ -0,0 +1,38 @@
+#
+# 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.
+#
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+ MockDrmCryptoPlugin.cpp
+
+LOCAL_MODULE := libmockdrmcryptoplugin
+
+LOCAL_MODULE_PATH := $(TARGET_OUT_VENDOR_SHARED_LIBRARIES)/mediadrm
+
+LOCAL_SHARED_LIBRARIES := \
+ libutils liblog
+
+LOCAL_C_INCLUDES += \
+ $(TOP)/frameworks/av/include \
+ $(TOP)/frameworks/native/include/media
+
+# Set the following flag to enable the decryption passthru flow
+#LOCAL_CFLAGS += -DENABLE_PASSTHRU_DECRYPTION
+
+LOCAL_MODULE_TAGS := optional
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/drm/mediadrm/plugins/mock/MockDrmCryptoPlugin.cpp b/drm/mediadrm/plugins/mock/MockDrmCryptoPlugin.cpp
new file mode 100644
index 0000000..f2cadf7
--- /dev/null
+++ b/drm/mediadrm/plugins/mock/MockDrmCryptoPlugin.cpp
@@ -0,0 +1,705 @@
+/*
+ * 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 "MockDrmCryptoPlugin"
+#include <utils/Log.h>
+
+
+#include "drm/DrmAPI.h"
+#include "MockDrmCryptoPlugin.h"
+#include "media/stagefright/MediaErrors.h"
+
+using namespace android;
+
+// Shared library entry point
+DrmFactory *createDrmFactory()
+{
+ return new MockDrmFactory();
+}
+
+// Shared library entry point
+CryptoFactory *createCryptoFactory()
+{
+ return new MockCryptoFactory();
+}
+
+const uint8_t mock_uuid[16] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
+ 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10};
+
+namespace android {
+
+ // MockDrmFactory
+ bool MockDrmFactory::isCryptoSchemeSupported(const uint8_t uuid[16])
+ {
+ return (!memcmp(uuid, mock_uuid, sizeof(uuid)));
+ }
+
+ bool MockDrmFactory::isContentTypeSupported(const String8 &mimeType)
+ {
+ if (mimeType != "video/mp4") {
+ return false;
+ }
+ return true;
+ }
+
+ status_t MockDrmFactory::createDrmPlugin(const uint8_t uuid[16], DrmPlugin **plugin)
+ {
+ *plugin = new MockDrmPlugin();
+ return OK;
+ }
+
+ // MockCryptoFactory
+ bool MockCryptoFactory::isCryptoSchemeSupported(const uint8_t uuid[16]) const
+ {
+ return (!memcmp(uuid, mock_uuid, sizeof(uuid)));
+ }
+
+ status_t MockCryptoFactory::createPlugin(const uint8_t uuid[16], const void *data,
+ size_t size, CryptoPlugin **plugin)
+ {
+ *plugin = new MockCryptoPlugin();
+ return OK;
+ }
+
+
+ // MockDrmPlugin methods
+
+ status_t MockDrmPlugin::openSession(Vector<uint8_t> &sessionId)
+ {
+ const size_t kSessionIdSize = 8;
+
+ Mutex::Autolock lock(mLock);
+ for (size_t i = 0; i < kSessionIdSize / sizeof(long); i++) {
+ long r = random();
+ sessionId.appendArray((uint8_t *)&r, sizeof(long));
+ }
+ mSessions.add(sessionId);
+
+ ALOGD("MockDrmPlugin::openSession() -> %s", vectorToString(sessionId).string());
+ return OK;
+ }
+
+ status_t MockDrmPlugin::closeSession(Vector<uint8_t> const &sessionId)
+ {
+ Mutex::Autolock lock(mLock);
+ ALOGD("MockDrmPlugin::closeSession(%s)", vectorToString(sessionId).string());
+ ssize_t index = findSession(sessionId);
+ if (index == kNotFound) {
+ ALOGD("Invalid sessionId");
+ return BAD_VALUE;
+ }
+ mSessions.removeAt(index);
+ return OK;
+ }
+
+
+ status_t MockDrmPlugin::getKeyRequest(Vector<uint8_t> const &sessionId,
+ Vector<uint8_t> const &initData,
+ String8 const &mimeType, KeyType keyType,
+ KeyedVector<String8, String8> const &optionalParameters,
+ Vector<uint8_t> &request, String8 &defaultUrl)
+ {
+ Mutex::Autolock lock(mLock);
+ ALOGD("MockDrmPlugin::getKeyRequest(sessionId=%s, initData=%s, mimeType=%s"
+ ", keyType=%d, optionalParameters=%s))",
+ vectorToString(sessionId).string(), vectorToString(initData).string(), mimeType.string(),
+ keyType, stringMapToString(optionalParameters).string());
+
+ ssize_t index = findSession(sessionId);
+ if (index == kNotFound) {
+ ALOGD("Invalid sessionId");
+ return BAD_VALUE;
+ }
+
+ // Properties used in mock test, set by mock plugin and verifed cts test app
+ // byte[] initData -> mock-initdata
+ // string mimeType -> mock-mimetype
+ // string keyType -> mock-keytype
+ // string optionalParameters -> mock-optparams formatted as {key1,value1},{key2,value2}
+
+ mByteArrayProperties.add(String8("mock-initdata"), initData);
+ mStringProperties.add(String8("mock-mimetype"), mimeType);
+
+ String8 keyTypeStr;
+ keyTypeStr.appendFormat("%d", (int)keyType);
+ mStringProperties.add(String8("mock-keytype"), keyTypeStr);
+
+ String8 params;
+ for (size_t i = 0; i < optionalParameters.size(); i++) {
+ params.appendFormat("%s{%s,%s}", i ? "," : "",
+ optionalParameters.keyAt(i).string(),
+ optionalParameters.valueAt(i).string());
+ }
+ mStringProperties.add(String8("mock-optparams"), params);
+
+ // Properties used in mock test, set by cts test app returned from mock plugin
+ // byte[] mock-request -> request
+ // string mock-default-url -> defaultUrl
+
+ index = mByteArrayProperties.indexOfKey(String8("mock-request"));
+ if (index < 0) {
+ ALOGD("Missing 'mock-request' parameter for mock");
+ return BAD_VALUE;
+ } else {
+ request = mByteArrayProperties.valueAt(index);
+ }
+
+ index = mStringProperties.indexOfKey(String8("mock-defaultUrl"));
+ if (index < 0) {
+ ALOGD("Missing 'mock-defaultUrl' parameter for mock");
+ return BAD_VALUE;
+ } else {
+ defaultUrl = mStringProperties.valueAt(index);
+ }
+ return OK;
+ }
+
+ status_t MockDrmPlugin::provideKeyResponse(Vector<uint8_t> const &sessionId,
+ Vector<uint8_t> const &response,
+ Vector<uint8_t> &keySetId)
+ {
+ Mutex::Autolock lock(mLock);
+ ALOGD("MockDrmPlugin::provideKeyResponse(sessionId=%s, response=%s)",
+ vectorToString(sessionId).string(), vectorToString(response).string());
+ ssize_t index = findSession(sessionId);
+ if (index == kNotFound) {
+ ALOGD("Invalid sessionId");
+ return BAD_VALUE;
+ }
+ if (response.size() == 0) {
+ return BAD_VALUE;
+ }
+
+ // Properties used in mock test, set by mock plugin and verifed cts test app
+ // byte[] response -> mock-response
+ mByteArrayProperties.add(String8("mock-response"), response);
+
+ const size_t kKeySetIdSize = 8;
+
+ for (size_t i = 0; i < kKeySetIdSize / sizeof(long); i++) {
+ long r = random();
+ keySetId.appendArray((uint8_t *)&r, sizeof(long));
+ }
+ mKeySets.add(keySetId);
+
+ return OK;
+ }
+
+ status_t MockDrmPlugin::removeKeys(Vector<uint8_t> const &keySetId)
+ {
+ Mutex::Autolock lock(mLock);
+ ALOGD("MockDrmPlugin::removeKeys(keySetId=%s)",
+ vectorToString(keySetId).string());
+
+ ssize_t index = findKeySet(keySetId);
+ if (index == kNotFound) {
+ ALOGD("Invalid keySetId");
+ return BAD_VALUE;
+ }
+ mKeySets.removeAt(index);
+
+ return OK;
+ }
+
+ status_t MockDrmPlugin::restoreKeys(Vector<uint8_t> const &sessionId,
+ Vector<uint8_t> const &keySetId)
+ {
+ Mutex::Autolock lock(mLock);
+ ALOGD("MockDrmPlugin::restoreKeys(sessionId=%s, keySetId=%s)",
+ vectorToString(sessionId).string(),
+ vectorToString(keySetId).string());
+ ssize_t index = findSession(sessionId);
+ if (index == kNotFound) {
+ ALOGD("Invalid sessionId");
+ return BAD_VALUE;
+ }
+
+ index = findKeySet(keySetId);
+ if (index == kNotFound) {
+ ALOGD("Invalid keySetId");
+ return BAD_VALUE;
+ }
+
+ return OK;
+ }
+
+ status_t MockDrmPlugin::queryKeyStatus(Vector<uint8_t> const &sessionId,
+ KeyedVector<String8, String8> &infoMap) const
+ {
+ ALOGD("MockDrmPlugin::queryKeyStatus(sessionId=%s)",
+ vectorToString(sessionId).string());
+
+ ssize_t index = findSession(sessionId);
+ if (index == kNotFound) {
+ ALOGD("Invalid sessionId");
+ return BAD_VALUE;
+ }
+
+ infoMap.add(String8("purchaseDuration"), String8("1000"));
+ infoMap.add(String8("licenseDuration"), String8("100"));
+ return OK;
+ }
+
+ status_t MockDrmPlugin::getProvisionRequest(Vector<uint8_t> &request,
+ String8 &defaultUrl)
+ {
+ Mutex::Autolock lock(mLock);
+ ALOGD("MockDrmPlugin::getProvisionRequest()");
+
+ // Properties used in mock test, set by cts test app returned from mock plugin
+ // byte[] mock-request -> request
+ // string mock-default-url -> defaultUrl
+
+ ssize_t index = mByteArrayProperties.indexOfKey(String8("mock-request"));
+ if (index < 0) {
+ ALOGD("Missing 'mock-request' parameter for mock");
+ return BAD_VALUE;
+ } else {
+ request = mByteArrayProperties.valueAt(index);
+ }
+
+ index = mStringProperties.indexOfKey(String8("mock-defaultUrl"));
+ if (index < 0) {
+ ALOGD("Missing 'mock-defaultUrl' parameter for mock");
+ return BAD_VALUE;
+ } else {
+ defaultUrl = mStringProperties.valueAt(index);
+ }
+ return OK;
+ }
+
+ status_t MockDrmPlugin::provideProvisionResponse(Vector<uint8_t> const &response)
+ {
+ Mutex::Autolock lock(mLock);
+ ALOGD("MockDrmPlugin::provideProvisionResponse(%s)",
+ vectorToString(response).string());
+
+ // Properties used in mock test, set by mock plugin and verifed cts test app
+ // byte[] response -> mock-response
+
+ mByteArrayProperties.add(String8("mock-response"), response);
+ return OK;
+ }
+
+ status_t MockDrmPlugin::getSecureStops(List<Vector<uint8_t> > &secureStops)
+ {
+ Mutex::Autolock lock(mLock);
+ ALOGD("MockDrmPlugin::getSecureStops()");
+
+ // Properties used in mock test, set by cts test app returned from mock plugin
+ // byte[] mock-secure-stop1 -> first secure stop in list
+ // byte[] mock-secure-stop2 -> second secure stop in list
+
+ Vector<uint8_t> ss1, ss2;
+ ssize_t index = mByteArrayProperties.indexOfKey(String8("mock-secure-stop1"));
+ if (index < 0) {
+ ALOGD("Missing 'mock-secure-stop1' parameter for mock");
+ return BAD_VALUE;
+ } else {
+ ss1 = mByteArrayProperties.valueAt(index);
+ }
+
+ index = mByteArrayProperties.indexOfKey(String8("mock-secure-stop2"));
+ if (index < 0) {
+ ALOGD("Missing 'mock-secure-stop2' parameter for mock");
+ return BAD_VALUE;
+ } else {
+ ss2 = mByteArrayProperties.valueAt(index);
+ }
+
+ secureStops.push_back(ss1);
+ secureStops.push_back(ss2);
+ return OK;
+ }
+
+ status_t MockDrmPlugin::releaseSecureStops(Vector<uint8_t> const &ssRelease)
+ {
+ Mutex::Autolock lock(mLock);
+ ALOGD("MockDrmPlugin::releaseSecureStops(%s)",
+ vectorToString(ssRelease).string());
+
+ // Properties used in mock test, set by mock plugin and verifed cts test app
+ // byte[] secure-stop-release -> mock-ssrelease
+ mByteArrayProperties.add(String8("mock-ssrelease"), ssRelease);
+
+ return OK;
+ }
+
+ status_t MockDrmPlugin::getPropertyString(String8 const &name, String8 &value) const
+ {
+ ALOGD("MockDrmPlugin::getPropertyString(name=%s)", name.string());
+ ssize_t index = mStringProperties.indexOfKey(name);
+ if (index < 0) {
+ ALOGD("no property for '%s'", name.string());
+ return BAD_VALUE;
+ }
+ value = mStringProperties.valueAt(index);
+ return OK;
+ }
+
+ status_t MockDrmPlugin::getPropertyByteArray(String8 const &name,
+ Vector<uint8_t> &value) const
+ {
+ ALOGD("MockDrmPlugin::getPropertyByteArray(name=%s)", name.string());
+ ssize_t index = mByteArrayProperties.indexOfKey(name);
+ if (index < 0) {
+ ALOGD("no property for '%s'", name.string());
+ return BAD_VALUE;
+ }
+ value = mByteArrayProperties.valueAt(index);
+ return OK;
+ }
+
+ status_t MockDrmPlugin::setPropertyString(String8 const &name,
+ String8 const &value)
+ {
+ Mutex::Autolock lock(mLock);
+ ALOGD("MockDrmPlugin::setPropertyString(name=%s, value=%s)",
+ name.string(), value.string());
+
+ if (name == "mock-send-event") {
+ unsigned code, extra;
+ sscanf(value.string(), "%d %d", &code, &extra);
+ DrmPlugin::EventType eventType = (DrmPlugin::EventType)code;
+
+ Vector<uint8_t> const *pSessionId = NULL;
+ ssize_t index = mByteArrayProperties.indexOfKey(String8("mock-event-session-id"));
+ if (index >= 0) {
+ pSessionId = &mByteArrayProperties[index];
+ }
+
+ Vector<uint8_t> const *pData = NULL;
+ index = mByteArrayProperties.indexOfKey(String8("mock-event-data"));
+ if (index >= 0) {
+ pData = &mByteArrayProperties[index];
+ }
+ ALOGD("sending event from mock drm plugin: %d %d %s %s",
+ (int)code, extra, pSessionId ? vectorToString(*pSessionId) : "{}",
+ pData ? vectorToString(*pData) : "{}");
+
+ sendEvent(eventType, extra, pSessionId, pData);
+ } else {
+ mStringProperties.add(name, value);
+ }
+ return OK;
+ }
+
+ status_t MockDrmPlugin::setPropertyByteArray(String8 const &name,
+ Vector<uint8_t> const &value)
+ {
+ Mutex::Autolock lock(mLock);
+ ALOGD("MockDrmPlugin::setPropertyByteArray(name=%s, value=%s)",
+ name.string(), vectorToString(value).string());
+ mByteArrayProperties.add(name, value);
+ return OK;
+ }
+
+ status_t MockDrmPlugin::setCipherAlgorithm(Vector<uint8_t> const &sessionId,
+ String8 const &algorithm)
+ {
+ Mutex::Autolock lock(mLock);
+
+ ALOGD("MockDrmPlugin::setCipherAlgorithm(sessionId=%s, algorithm=%s)",
+ vectorToString(sessionId).string(), algorithm.string());
+
+ ssize_t index = findSession(sessionId);
+ if (index == kNotFound) {
+ ALOGD("Invalid sessionId");
+ return BAD_VALUE;
+ }
+
+ if (algorithm == "AES/CBC/NoPadding") {
+ return OK;
+ }
+ return BAD_VALUE;
+ }
+
+ status_t MockDrmPlugin::setMacAlgorithm(Vector<uint8_t> const &sessionId,
+ String8 const &algorithm)
+ {
+ Mutex::Autolock lock(mLock);
+
+ ALOGD("MockDrmPlugin::setMacAlgorithm(sessionId=%s, algorithm=%s)",
+ vectorToString(sessionId).string(), algorithm.string());
+
+ ssize_t index = findSession(sessionId);
+ if (index == kNotFound) {
+ ALOGD("Invalid sessionId");
+ return BAD_VALUE;
+ }
+
+ if (algorithm == "HmacSHA256") {
+ return OK;
+ }
+ return BAD_VALUE;
+ }
+
+ status_t MockDrmPlugin::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 lock(mLock);
+ ALOGD("MockDrmPlugin::encrypt(sessionId=%s, keyId=%s, input=%s, iv=%s)",
+ vectorToString(sessionId).string(),
+ vectorToString(keyId).string(),
+ vectorToString(input).string(),
+ vectorToString(iv).string());
+
+ ssize_t index = findSession(sessionId);
+ if (index == kNotFound) {
+ ALOGD("Invalid sessionId");
+ return BAD_VALUE;
+ }
+
+ // Properties used in mock test, set by mock plugin and verifed cts test app
+ // byte[] keyId -> mock-keyid
+ // byte[] input -> mock-input
+ // byte[] iv -> mock-iv
+ mByteArrayProperties.add(String8("mock-keyid"), keyId);
+ mByteArrayProperties.add(String8("mock-input"), input);
+ mByteArrayProperties.add(String8("mock-iv"), iv);
+
+ // Properties used in mock test, set by cts test app returned from mock plugin
+ // byte[] mock-output -> output
+ index = mByteArrayProperties.indexOfKey(String8("mock-output"));
+ if (index < 0) {
+ ALOGD("Missing 'mock-request' parameter for mock");
+ return BAD_VALUE;
+ } else {
+ output = mByteArrayProperties.valueAt(index);
+ }
+ return OK;
+ }
+
+ status_t MockDrmPlugin::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 lock(mLock);
+ ALOGD("MockDrmPlugin::decrypt(sessionId=%s, keyId=%s, input=%s, iv=%s)",
+ vectorToString(sessionId).string(),
+ vectorToString(keyId).string(),
+ vectorToString(input).string(),
+ vectorToString(iv).string());
+
+ ssize_t index = findSession(sessionId);
+ if (index == kNotFound) {
+ ALOGD("Invalid sessionId");
+ return BAD_VALUE;
+ }
+
+ // Properties used in mock test, set by mock plugin and verifed cts test app
+ // byte[] keyId -> mock-keyid
+ // byte[] input -> mock-input
+ // byte[] iv -> mock-iv
+ mByteArrayProperties.add(String8("mock-keyid"), keyId);
+ mByteArrayProperties.add(String8("mock-input"), input);
+ mByteArrayProperties.add(String8("mock-iv"), iv);
+
+ // Properties used in mock test, set by cts test app returned from mock plugin
+ // byte[] mock-output -> output
+ index = mByteArrayProperties.indexOfKey(String8("mock-output"));
+ if (index < 0) {
+ ALOGD("Missing 'mock-request' parameter for mock");
+ return BAD_VALUE;
+ } else {
+ output = mByteArrayProperties.valueAt(index);
+ }
+ return OK;
+ }
+
+ status_t MockDrmPlugin::sign(Vector<uint8_t> const &sessionId,
+ Vector<uint8_t> const &keyId,
+ Vector<uint8_t> const &message,
+ Vector<uint8_t> &signature)
+ {
+ Mutex::Autolock lock(mLock);
+ ALOGD("MockDrmPlugin::sign(sessionId=%s, keyId=%s, message=%s)",
+ vectorToString(sessionId).string(),
+ vectorToString(keyId).string(),
+ vectorToString(message).string());
+
+ ssize_t index = findSession(sessionId);
+ if (index == kNotFound) {
+ ALOGD("Invalid sessionId");
+ return BAD_VALUE;
+ }
+
+ // Properties used in mock test, set by mock plugin and verifed cts test app
+ // byte[] keyId -> mock-keyid
+ // byte[] message -> mock-message
+ mByteArrayProperties.add(String8("mock-keyid"), keyId);
+ mByteArrayProperties.add(String8("mock-message"), message);
+
+ // Properties used in mock test, set by cts test app returned from mock plugin
+ // byte[] mock-signature -> signature
+ index = mByteArrayProperties.indexOfKey(String8("mock-signature"));
+ if (index < 0) {
+ ALOGD("Missing 'mock-request' parameter for mock");
+ return BAD_VALUE;
+ } else {
+ signature = mByteArrayProperties.valueAt(index);
+ }
+ return OK;
+ }
+
+ status_t MockDrmPlugin::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 lock(mLock);
+ ALOGD("MockDrmPlugin::verify(sessionId=%s, keyId=%s, message=%s, signature=%s)",
+ vectorToString(sessionId).string(),
+ vectorToString(keyId).string(),
+ vectorToString(message).string(),
+ vectorToString(signature).string());
+
+ ssize_t index = findSession(sessionId);
+ if (index == kNotFound) {
+ ALOGD("Invalid sessionId");
+ return BAD_VALUE;
+ }
+
+ // Properties used in mock test, set by mock plugin and verifed cts test app
+ // byte[] keyId -> mock-keyid
+ // byte[] message -> mock-message
+ // byte[] signature -> mock-signature
+ mByteArrayProperties.add(String8("mock-keyid"), keyId);
+ mByteArrayProperties.add(String8("mock-message"), message);
+ mByteArrayProperties.add(String8("mock-signature"), signature);
+
+ // Properties used in mock test, set by cts test app returned from mock plugin
+ // String mock-match "1" or "0" -> match
+ index = mStringProperties.indexOfKey(String8("mock-match"));
+ if (index < 0) {
+ ALOGD("Missing 'mock-request' parameter for mock");
+ return BAD_VALUE;
+ } else {
+ match = atol(mStringProperties.valueAt(index).string());
+ }
+ return OK;
+ }
+
+ ssize_t MockDrmPlugin::findSession(Vector<uint8_t> const &sessionId) const
+ {
+ ALOGD("findSession: nsessions=%d, size=%d", mSessions.size(), sessionId.size());
+ for (size_t i = 0; i < mSessions.size(); ++i) {
+ if (memcmp(mSessions[i].array(), sessionId.array(), sessionId.size()) == 0) {
+ return i;
+ }
+ }
+ return kNotFound;
+ }
+
+ ssize_t MockDrmPlugin::findKeySet(Vector<uint8_t> const &keySetId) const
+ {
+ ALOGD("findKeySet: nkeySets=%d, size=%d", mKeySets.size(), keySetId.size());
+ for (size_t i = 0; i < mKeySets.size(); ++i) {
+ if (memcmp(mKeySets[i].array(), keySetId.array(), keySetId.size()) == 0) {
+ return i;
+ }
+ }
+ return kNotFound;
+ }
+
+
+ // Conversion utilities
+ String8 MockDrmPlugin::vectorToString(Vector<uint8_t> const &vector) const
+ {
+ return arrayToString(vector.array(), vector.size());
+ }
+
+ String8 MockDrmPlugin::arrayToString(uint8_t const *array, size_t len) const
+ {
+ String8 result("{ ");
+ for (size_t i = 0; i < len; i++) {
+ result.appendFormat("0x%02x ", array[i]);
+ }
+ result += "}";
+ return result;
+ }
+
+ String8 MockDrmPlugin::stringMapToString(KeyedVector<String8, String8> map) const
+ {
+ String8 result("{ ");
+ for (size_t i = 0; i < map.size(); i++) {
+ result.appendFormat("%s{name=%s, value=%s}", i > 0 ? ", " : "",
+ map.keyAt(i).string(), map.valueAt(i).string());
+ }
+ return result + " }";
+ }
+
+ bool operator<(Vector<uint8_t> const &lhs, Vector<uint8_t> const &rhs) {
+ return lhs.size() < rhs.size() || (memcmp(lhs.array(), rhs.array(), lhs.size()) < 0);
+ }
+
+ //
+ // Crypto Plugin
+ //
+
+ bool MockCryptoPlugin::requiresSecureDecoderComponent(const char *mime) const
+ {
+ ALOGD("MockCryptoPlugin::requiresSecureDecoderComponent(mime=%s)", mime);
+ return false;
+ }
+
+ ssize_t
+ MockCryptoPlugin::decrypt(bool secure, const uint8_t key[16], const uint8_t iv[16],
+ Mode mode, const void *srcPtr, const SubSample *subSamples,
+ size_t numSubSamples, void *dstPtr, AString *errorDetailMsg)
+ {
+ ALOGD("MockCryptoPlugin::decrypt(secure=%d, key=%s, iv=%s, mode=%d, src=%p, "
+ "subSamples=%s, dst=%p)",
+ (int)secure,
+ arrayToString(key, sizeof(key)).string(),
+ arrayToString(iv, sizeof(iv)).string(),
+ (int)mode, srcPtr,
+ subSamplesToString(subSamples, numSubSamples).string(),
+ dstPtr);
+ return OK;
+ }
+
+ // Conversion utilities
+ String8 MockCryptoPlugin::arrayToString(uint8_t const *array, size_t len) const
+ {
+ String8 result("{ ");
+ for (size_t i = 0; i < len; i++) {
+ result.appendFormat("0x%02x ", array[i]);
+ }
+ result += "}";
+ return result;
+ }
+
+ String8 MockCryptoPlugin::subSamplesToString(SubSample const *subSamples,
+ size_t numSubSamples) const
+ {
+ String8 result;
+ for (size_t i = 0; i < numSubSamples; i++) {
+ result.appendFormat("[%d] {clear:%d, encrypted:%d} ", i,
+ subSamples[i].mNumBytesOfClearData,
+ subSamples[i].mNumBytesOfEncryptedData);
+ }
+ return result;
+ }
+
+};
diff --git a/drm/mediadrm/plugins/mock/MockDrmCryptoPlugin.h b/drm/mediadrm/plugins/mock/MockDrmCryptoPlugin.h
new file mode 100644
index 0000000..2297f9b
--- /dev/null
+++ b/drm/mediadrm/plugins/mock/MockDrmCryptoPlugin.h
@@ -0,0 +1,156 @@
+/*
+ * 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.
+ */
+
+#include <utils/Mutex.h>
+
+#include "drm/DrmAPI.h"
+#include "hardware/CryptoAPI.h"
+
+extern "C" {
+ android::DrmFactory *createDrmFactory();
+ android::CryptoFactory *createCryptoFactory();
+}
+
+namespace android {
+
+ class MockDrmFactory : public DrmFactory {
+ public:
+ MockDrmFactory() {}
+ virtual ~MockDrmFactory() {}
+
+ bool isCryptoSchemeSupported(const uint8_t uuid[16]);
+ bool isContentTypeSupported(const String8 &mimeType);
+ status_t createDrmPlugin(const uint8_t uuid[16], DrmPlugin **plugin);
+ };
+
+ class MockCryptoFactory : public CryptoFactory {
+ public:
+ MockCryptoFactory() {}
+ virtual ~MockCryptoFactory() {}
+
+ bool isCryptoSchemeSupported(const uint8_t uuid[16]) const;
+ status_t createPlugin(
+ const uint8_t uuid[16], const void *data, size_t size,
+ CryptoPlugin **plugin);
+ };
+
+
+
+ class MockDrmPlugin : public DrmPlugin {
+ public:
+ MockDrmPlugin() {}
+ virtual ~MockDrmPlugin() {}
+
+ // from DrmPlugin
+ status_t openSession(Vector<uint8_t> &sessionId);
+ status_t closeSession(Vector<uint8_t> const &sessionId);
+
+ status_t getKeyRequest(Vector<uint8_t> const &sessionId,
+ Vector<uint8_t> const &initData,
+ String8 const &mimeType, KeyType keyType,
+ KeyedVector<String8, String8> const &optionalParameters,
+ Vector<uint8_t> &request, String8 &defaultUrl);
+
+ status_t provideKeyResponse(Vector<uint8_t> const &sessionId,
+ Vector<uint8_t> const &response,
+ Vector<uint8_t> &keySetId);
+
+ status_t removeKeys(Vector<uint8_t> const &keySetId);
+
+ status_t restoreKeys(Vector<uint8_t> const &sessionId,
+ Vector<uint8_t> const &keySetId);
+
+ status_t queryKeyStatus(Vector<uint8_t> const &sessionId,
+ KeyedVector<String8, String8> &infoMap) const;
+
+ status_t getProvisionRequest(Vector<uint8_t> &request,
+ String8 &defaultUrl);
+
+ status_t provideProvisionResponse(Vector<uint8_t> const &response);
+
+ status_t getSecureStops(List<Vector<uint8_t> > &secureStops);
+ status_t releaseSecureStops(Vector<uint8_t> const &ssRelease);
+
+ status_t getPropertyString(String8 const &name, String8 &value ) const;
+ status_t getPropertyByteArray(String8 const &name,
+ Vector<uint8_t> &value ) const;
+
+ status_t setPropertyString(String8 const &name,
+ String8 const &value );
+ status_t setPropertyByteArray(String8 const &name,
+ Vector<uint8_t> const &value );
+
+ status_t setCipherAlgorithm(Vector<uint8_t> const &sessionId,
+ String8 const &algorithm);
+
+ status_t setMacAlgorithm(Vector<uint8_t> const &sessionId,
+ String8 const &algorithm);
+
+ status_t 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);
+
+ status_t 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);
+
+ status_t sign(Vector<uint8_t> const &sessionId,
+ Vector<uint8_t> const &keyId,
+ Vector<uint8_t> const &message,
+ Vector<uint8_t> &signature);
+
+ status_t verify(Vector<uint8_t> const &sessionId,
+ Vector<uint8_t> const &keyId,
+ Vector<uint8_t> const &message,
+ Vector<uint8_t> const &signature,
+ bool &match);
+
+ private:
+ String8 vectorToString(Vector<uint8_t> const &vector) const;
+ String8 arrayToString(uint8_t const *array, size_t len) const;
+ String8 stringMapToString(KeyedVector<String8, String8> map) const;
+
+ SortedVector<Vector<uint8_t> > mSessions;
+ SortedVector<Vector<uint8_t> > mKeySets;
+
+ static const ssize_t kNotFound = -1;
+ ssize_t findSession(Vector<uint8_t> const &sessionId) const;
+ ssize_t findKeySet(Vector<uint8_t> const &keySetId) const;
+
+ Mutex mLock;
+ KeyedVector<String8, String8> mStringProperties;
+ KeyedVector<String8, Vector<uint8_t> > mByteArrayProperties;
+ };
+
+
+ class MockCryptoPlugin : public CryptoPlugin {
+
+ bool requiresSecureDecoderComponent(const char *mime) const;
+
+ ssize_t decrypt(bool secure,
+ const uint8_t key[16], const uint8_t iv[16],
+ Mode mode, const void *srcPtr,
+ const SubSample *subSamples, size_t numSubSamples,
+ void *dstPtr, AString *errorDetailMsg);
+ private:
+ String8 subSamplesToString(CryptoPlugin::SubSample const *subSamples, size_t numSubSamples) const;
+ String8 arrayToString(uint8_t const *array, size_t len) const;
+ };
+};