From 34486800a022857b45c3882624449980c5cb6907 Mon Sep 17 00:00:00 2001 From: Jeff Tinker Date: Wed, 11 Sep 2013 18:40:44 -0700 Subject: 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 --- drm/mediadrm/plugins/mock/Android.mk | 38 ++ drm/mediadrm/plugins/mock/MockDrmCryptoPlugin.cpp | 705 ++++++++++++++++++++++ drm/mediadrm/plugins/mock/MockDrmCryptoPlugin.h | 156 +++++ 3 files changed, 899 insertions(+) create mode 100644 drm/mediadrm/plugins/mock/Android.mk create mode 100644 drm/mediadrm/plugins/mock/MockDrmCryptoPlugin.cpp create mode 100644 drm/mediadrm/plugins/mock/MockDrmCryptoPlugin.h (limited to 'drm') 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 + + +#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 &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 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 const &sessionId, + Vector const &initData, + String8 const &mimeType, KeyType keyType, + KeyedVector const &optionalParameters, + Vector &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 const &sessionId, + Vector const &response, + Vector &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 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 const &sessionId, + Vector 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 const &sessionId, + KeyedVector &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 &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 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 > &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 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 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 &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 const *pSessionId = NULL; + ssize_t index = mByteArrayProperties.indexOfKey(String8("mock-event-session-id")); + if (index >= 0) { + pSessionId = &mByteArrayProperties[index]; + } + + Vector 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 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 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 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 const &sessionId, + Vector const &keyId, + Vector const &input, + Vector const &iv, + Vector &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 const &sessionId, + Vector const &keyId, + Vector const &input, + Vector const &iv, + Vector &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 const &sessionId, + Vector const &keyId, + Vector const &message, + Vector &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 const &sessionId, + Vector const &keyId, + Vector const &message, + Vector 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 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 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 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 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 const &lhs, Vector 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 + +#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 &sessionId); + status_t closeSession(Vector const &sessionId); + + status_t getKeyRequest(Vector const &sessionId, + Vector const &initData, + String8 const &mimeType, KeyType keyType, + KeyedVector const &optionalParameters, + Vector &request, String8 &defaultUrl); + + status_t provideKeyResponse(Vector const &sessionId, + Vector const &response, + Vector &keySetId); + + status_t removeKeys(Vector const &keySetId); + + status_t restoreKeys(Vector const &sessionId, + Vector const &keySetId); + + status_t queryKeyStatus(Vector const &sessionId, + KeyedVector &infoMap) const; + + status_t getProvisionRequest(Vector &request, + String8 &defaultUrl); + + status_t provideProvisionResponse(Vector const &response); + + status_t getSecureStops(List > &secureStops); + status_t releaseSecureStops(Vector const &ssRelease); + + status_t getPropertyString(String8 const &name, String8 &value ) const; + status_t getPropertyByteArray(String8 const &name, + Vector &value ) const; + + status_t setPropertyString(String8 const &name, + String8 const &value ); + status_t setPropertyByteArray(String8 const &name, + Vector const &value ); + + status_t setCipherAlgorithm(Vector const &sessionId, + String8 const &algorithm); + + status_t setMacAlgorithm(Vector const &sessionId, + String8 const &algorithm); + + status_t encrypt(Vector const &sessionId, + Vector const &keyId, + Vector const &input, + Vector const &iv, + Vector &output); + + status_t decrypt(Vector const &sessionId, + Vector const &keyId, + Vector const &input, + Vector const &iv, + Vector &output); + + status_t sign(Vector const &sessionId, + Vector const &keyId, + Vector const &message, + Vector &signature); + + status_t verify(Vector const &sessionId, + Vector const &keyId, + Vector const &message, + Vector const &signature, + bool &match); + + private: + String8 vectorToString(Vector const &vector) const; + String8 arrayToString(uint8_t const *array, size_t len) const; + String8 stringMapToString(KeyedVector map) const; + + SortedVector > mSessions; + SortedVector > mKeySets; + + static const ssize_t kNotFound = -1; + ssize_t findSession(Vector const &sessionId) const; + ssize_t findKeySet(Vector const &keySetId) const; + + Mutex mLock; + KeyedVector mStringProperties; + KeyedVector > 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; + }; +}; -- cgit v1.1