From cc82dc6d500023eba6048616301a4b12682458db Mon Sep 17 00:00:00 2001 From: Jeff Tinker Date: Fri, 8 Feb 2013 10:18:35 -0800 Subject: Implementing MediaDrm APIs Change-Id: I9ff8eeb7d0c383b5c0c68cd54eb54ce7d2d22fe6 --- media/libmediaplayerservice/Android.mk | 2 + media/libmediaplayerservice/Drm.cpp | 423 +++++++++++++++++++++ media/libmediaplayerservice/Drm.h | 100 +++++ media/libmediaplayerservice/MediaPlayerService.cpp | 5 + media/libmediaplayerservice/MediaPlayerService.h | 1 + media/libmediaplayerservice/SharedLibrary.cpp | 49 +++ media/libmediaplayerservice/SharedLibrary.h | 39 ++ 7 files changed, 619 insertions(+) create mode 100644 media/libmediaplayerservice/Drm.cpp create mode 100644 media/libmediaplayerservice/Drm.h create mode 100644 media/libmediaplayerservice/SharedLibrary.cpp create mode 100644 media/libmediaplayerservice/SharedLibrary.h (limited to 'media/libmediaplayerservice') diff --git a/media/libmediaplayerservice/Android.mk b/media/libmediaplayerservice/Android.mk index 48f48e4..2a6f3c7 100644 --- a/media/libmediaplayerservice/Android.mk +++ b/media/libmediaplayerservice/Android.mk @@ -9,6 +9,7 @@ include $(CLEAR_VARS) LOCAL_SRC_FILES:= \ ActivityManager.cpp \ Crypto.cpp \ + Drm.cpp \ HDCP.cpp \ MediaPlayerFactory.cpp \ MediaPlayerService.cpp \ @@ -17,6 +18,7 @@ LOCAL_SRC_FILES:= \ MidiFile.cpp \ MidiMetadataRetriever.cpp \ RemoteDisplay.cpp \ + SharedLibrary.cpp \ StagefrightPlayer.cpp \ StagefrightRecorder.cpp \ TestPlayerStub.cpp \ diff --git a/media/libmediaplayerservice/Drm.cpp b/media/libmediaplayerservice/Drm.cpp new file mode 100644 index 0000000..6ac7530 --- /dev/null +++ b/media/libmediaplayerservice/Drm.cpp @@ -0,0 +1,423 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +//#define LOG_NDEBUG 0 +#define LOG_TAG "Drm" +#include + +#include +#include + +#include "Drm.h" + +#include +#include +#include +#include +#include + +namespace android { + +KeyedVector, String8> Drm::mUUIDToLibraryPathMap; +KeyedVector > Drm::mLibraryPathToOpenLibraryMap; +Mutex Drm::mMapLock; + +static bool operator<(const Vector &lhs, const Vector &rhs) { + if (lhs.size() < rhs.size()) { + return true; + } else if (lhs.size() > rhs.size()) { + return false; + } + + return memcmp((void *)lhs.array(), (void *)rhs.array(), rhs.size()) < 0; +} + +Drm::Drm() + : mInitCheck(NO_INIT), + mFactory(NULL), + mPlugin(NULL) { +} + +Drm::~Drm() { + delete mPlugin; + mPlugin = NULL; + closeFactory(); +} + +void Drm::closeFactory() { + delete mFactory; + mFactory = NULL; + mLibrary.clear(); +} + +status_t Drm::initCheck() const { + return mInitCheck; +} + + +/* + * Search the plugins directory for a plugin that supports the scheme + * specified by uuid + * + * If found: + * mLibrary holds a strong pointer to the dlopen'd library + * mFactory is set to the library's factory method + * mInitCheck is set to OK + * + * If not found: + * mLibrary is cleared and mFactory are set to NULL + * mInitCheck is set to an error (!OK) + */ +void Drm::findFactoryForScheme(const uint8_t uuid[16]) { + + closeFactory(); + + // lock static maps + Mutex::Autolock autoLock(mMapLock); + + // first check cache + Vector uuidVector; + uuidVector.appendArray(uuid, sizeof(uuid)); + ssize_t index = mUUIDToLibraryPathMap.indexOfKey(uuidVector); + if (index >= 0) { + if (loadLibraryForScheme(mUUIDToLibraryPathMap[index], uuid)) { + mInitCheck = OK; + return; + } else { + ALOGE("Failed to load from cached library path!"); + mInitCheck = ERROR_UNSUPPORTED; + return; + } + } + + // no luck, have to search + String8 dirPath("/vendor/lib/mediadrm"); + DIR* pDir = opendir(dirPath.string()); + + if (pDir == NULL) { + mInitCheck = ERROR_UNSUPPORTED; + ALOGE("Failed to open plugin directory %s", dirPath.string()); + return; + } + + + struct dirent* pEntry; + while ((pEntry = readdir(pDir))) { + + String8 pluginPath = dirPath + "/" + pEntry->d_name; + + if (pluginPath.getPathExtension() == ".so") { + + if (loadLibraryForScheme(pluginPath, uuid)) { + mUUIDToLibraryPathMap.add(uuidVector, pluginPath); + mInitCheck = OK; + closedir(pDir); + return; + } + } + } + + closedir(pDir); + + ALOGE("Failed to find drm plugin"); + mInitCheck = ERROR_UNSUPPORTED; +} + +bool Drm::loadLibraryForScheme(const String8 &path, const uint8_t uuid[16]) { + + // get strong pointer to open shared library + ssize_t index = mLibraryPathToOpenLibraryMap.indexOfKey(path); + if (index >= 0) { + mLibrary = mLibraryPathToOpenLibraryMap[index].promote(); + } else { + index = mLibraryPathToOpenLibraryMap.add(path, NULL); + } + + if (!mLibrary.get()) { + mLibrary = new SharedLibrary(path); + if (!*mLibrary) { + return false; + } + + mLibraryPathToOpenLibraryMap.replaceValueAt(index, mLibrary); + } + + typedef DrmFactory *(*CreateDrmFactoryFunc)(); + + CreateDrmFactoryFunc createDrmFactory = + (CreateDrmFactoryFunc)mLibrary->lookup("createDrmFactory"); + + if (createDrmFactory == NULL || + (mFactory = createDrmFactory()) == NULL || + !mFactory->isCryptoSchemeSupported(uuid)) { + closeFactory(); + return false; + } + return true; +} + +bool Drm::isCryptoSchemeSupported(const uint8_t uuid[16]) { + Mutex::Autolock autoLock(mLock); + + if (mFactory && mFactory->isCryptoSchemeSupported(uuid)) { + return true; + } + + findFactoryForScheme(uuid); + return (mInitCheck == OK); +} + +status_t Drm::createPlugin(const uint8_t uuid[16]) { + Mutex::Autolock autoLock(mLock); + + if (mPlugin != NULL) { + return -EINVAL; + } + + if (!mFactory || !mFactory->isCryptoSchemeSupported(uuid)) { + findFactoryForScheme(uuid); + } + + if (mInitCheck != OK) { + return mInitCheck; + } + + return mFactory->createDrmPlugin(uuid, &mPlugin); +} + +status_t Drm::destroyPlugin() { + Mutex::Autolock autoLock(mLock); + + if (mInitCheck != OK) { + return mInitCheck; + } + + if (mPlugin == NULL) { + return -EINVAL; + } + + delete mPlugin; + mPlugin = NULL; + + return OK; +} + +status_t Drm::openSession(Vector &sessionId) { + Mutex::Autolock autoLock(mLock); + + if (mInitCheck != OK) { + return mInitCheck; + } + + if (mPlugin == NULL) { + return -EINVAL; + } + + return mPlugin->openSession(sessionId); +} + +status_t Drm::closeSession(Vector const &sessionId) { + Mutex::Autolock autoLock(mLock); + + if (mInitCheck != OK) { + return mInitCheck; + } + + if (mPlugin == NULL) { + return -EINVAL; + } + + return mPlugin->closeSession(sessionId); +} + +status_t Drm::getLicenseRequest(Vector const &sessionId, + Vector const &initData, + String8 const &mimeType, DrmPlugin::LicenseType licenseType, + KeyedVector const &optionalParameters, + Vector &request, String8 &defaultUrl) { + Mutex::Autolock autoLock(mLock); + + if (mInitCheck != OK) { + return mInitCheck; + } + + if (mPlugin == NULL) { + return -EINVAL; + } + + return mPlugin->getLicenseRequest(sessionId, initData, mimeType, licenseType, + optionalParameters, request, defaultUrl); +} + +status_t Drm::provideLicenseResponse(Vector const &sessionId, + Vector const &response) { + Mutex::Autolock autoLock(mLock); + + if (mInitCheck != OK) { + return mInitCheck; + } + + if (mPlugin == NULL) { + return -EINVAL; + } + + return mPlugin->provideLicenseResponse(sessionId, response); +} + +status_t Drm::removeLicense(Vector const &sessionId) { + Mutex::Autolock autoLock(mLock); + + if (mInitCheck != OK) { + return mInitCheck; + } + + if (mPlugin == NULL) { + return -EINVAL; + } + + return mPlugin->removeLicense(sessionId); +} + +status_t Drm::queryLicenseStatus(Vector const &sessionId, + KeyedVector &infoMap) const { + Mutex::Autolock autoLock(mLock); + + if (mInitCheck != OK) { + return mInitCheck; + } + + if (mPlugin == NULL) { + return -EINVAL; + } + + return mPlugin->queryLicenseStatus(sessionId, infoMap); +} + +status_t Drm::getProvisionRequest(Vector &request, String8 &defaultUrl) { + Mutex::Autolock autoLock(mLock); + + if (mInitCheck != OK) { + return mInitCheck; + } + + if (mPlugin == NULL) { + return -EINVAL; + } + + return mPlugin->getProvisionRequest(request, defaultUrl); +} + +status_t Drm::provideProvisionResponse(Vector const &response) { + Mutex::Autolock autoLock(mLock); + + if (mInitCheck != OK) { + return mInitCheck; + } + + if (mPlugin == NULL) { + return -EINVAL; + } + + return mPlugin->provideProvisionResponse(response); +} + + +status_t Drm::getSecureStops(List > &secureStops) { + Mutex::Autolock autoLock(mLock); + + if (mInitCheck != OK) { + return mInitCheck; + } + + if (mPlugin == NULL) { + return -EINVAL; + } + + return mPlugin->getSecureStops(secureStops); +} + +status_t Drm::releaseSecureStops(Vector const &ssRelease) { + Mutex::Autolock autoLock(mLock); + + if (mInitCheck != OK) { + return mInitCheck; + } + + if (mPlugin == NULL) { + return -EINVAL; + } + + return mPlugin->releaseSecureStops(ssRelease); +} + +status_t Drm::getPropertyString(String8 const &name, String8 &value ) const { + Mutex::Autolock autoLock(mLock); + + if (mInitCheck != OK) { + return mInitCheck; + } + + if (mPlugin == NULL) { + return -EINVAL; + } + + return mPlugin->getPropertyString(name, value); +} + +status_t Drm::getPropertyByteArray(String8 const &name, Vector &value ) const { + Mutex::Autolock autoLock(mLock); + + if (mInitCheck != OK) { + return mInitCheck; + } + + if (mPlugin == NULL) { + return -EINVAL; + } + + return mPlugin->getPropertyByteArray(name, value); +} + +status_t Drm::setPropertyString(String8 const &name, String8 const &value ) const { + Mutex::Autolock autoLock(mLock); + + if (mInitCheck != OK) { + return mInitCheck; + } + + if (mPlugin == NULL) { + return -EINVAL; + } + + return mPlugin->setPropertyString(name, value); +} + +status_t Drm::setPropertyByteArray(String8 const &name, + Vector const &value ) const { + Mutex::Autolock autoLock(mLock); + + if (mInitCheck != OK) { + return mInitCheck; + } + + if (mPlugin == NULL) { + return -EINVAL; + } + + return mPlugin->setPropertyByteArray(name, value); +} + +} // namespace android diff --git a/media/libmediaplayerservice/Drm.h b/media/libmediaplayerservice/Drm.h new file mode 100644 index 0000000..1b10958 --- /dev/null +++ b/media/libmediaplayerservice/Drm.h @@ -0,0 +1,100 @@ +/* + * 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. + */ + +#ifndef DRM_H_ + +#define DRM_H_ + +#include "SharedLibrary.h" + +#include +#include + +namespace android { + +struct DrmFactory; +struct DrmPlugin; + +struct Drm : public BnDrm { + Drm(); + virtual ~Drm(); + + virtual status_t initCheck() const; + + virtual bool isCryptoSchemeSupported(const uint8_t uuid[16]); + + virtual status_t createPlugin(const uint8_t uuid[16]); + + virtual status_t destroyPlugin(); + + virtual status_t openSession(Vector &sessionId); + + virtual status_t closeSession(Vector const &sessionId); + + virtual status_t + getLicenseRequest(Vector const &sessionId, + Vector const &initData, + String8 const &mimeType, DrmPlugin::LicenseType licenseType, + KeyedVector const &optionalParameters, + Vector &request, String8 &defaultUrl); + + virtual status_t provideLicenseResponse(Vector const &sessionId, + Vector const &response); + + virtual status_t removeLicense(Vector const &sessionId); + + virtual status_t queryLicenseStatus(Vector const &sessionId, + KeyedVector &infoMap) const; + + virtual status_t getProvisionRequest(Vector &request, + String8 &defaulUrl); + + virtual status_t provideProvisionResponse(Vector const &response); + + virtual status_t getSecureStops(List > &secureStops); + + virtual status_t releaseSecureStops(Vector const &ssRelease); + + virtual status_t getPropertyString(String8 const &name, String8 &value ) const; + virtual status_t getPropertyByteArray(String8 const &name, + Vector &value ) const; + virtual status_t setPropertyString(String8 const &name, String8 const &value ) const; + virtual status_t setPropertyByteArray(String8 const &name, + Vector const &value ) const; + +private: + mutable Mutex mLock; + + status_t mInitCheck; + sp mLibrary; + DrmFactory *mFactory; + DrmPlugin *mPlugin; + + static KeyedVector, String8> mUUIDToLibraryPathMap; + static KeyedVector > 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(Drm); +}; + +} // namespace android + +#endif // CRYPTO_H_ diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp index 16f1317..ec6ace1 100644 --- a/media/libmediaplayerservice/MediaPlayerService.cpp +++ b/media/libmediaplayerservice/MediaPlayerService.cpp @@ -72,6 +72,7 @@ #include #include "Crypto.h" +#include "Drm.h" #include "HDCP.h" #include "RemoteDisplay.h" @@ -285,6 +286,10 @@ sp MediaPlayerService::makeCrypto() { return new Crypto; } +sp MediaPlayerService::makeDrm() { + return new Drm; +} + sp MediaPlayerService::makeHDCP(bool createEncryptionModule) { return new HDCP(createEncryptionModule); } diff --git a/media/libmediaplayerservice/MediaPlayerService.h b/media/libmediaplayerservice/MediaPlayerService.h index 2d2a09d..82dc29b 100644 --- a/media/libmediaplayerservice/MediaPlayerService.h +++ b/media/libmediaplayerservice/MediaPlayerService.h @@ -249,6 +249,7 @@ public: virtual sp decode(int fd, int64_t offset, int64_t length, uint32_t *pSampleRate, int* pNumChannels, audio_format_t* pFormat); virtual sp getOMX(); virtual sp makeCrypto(); + virtual sp makeDrm(); virtual sp makeHDCP(bool createEncryptionModule); virtual sp listenForRemoteDisplay(const sp& client, diff --git a/media/libmediaplayerservice/SharedLibrary.cpp b/media/libmediaplayerservice/SharedLibrary.cpp new file mode 100644 index 0000000..178e15d --- /dev/null +++ b/media/libmediaplayerservice/SharedLibrary.cpp @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +//#define LOG_NDEBUG 0 +#define LOG_TAG "Drm" +#include +#include + +#include + +#include "SharedLibrary.h" + +namespace android { + + SharedLibrary::SharedLibrary(const String8 &path) { + mLibHandle = dlopen(path.string(), RTLD_NOW); + } + + SharedLibrary::~SharedLibrary() { + if (mLibHandle != NULL) { + dlclose(mLibHandle); + mLibHandle = NULL; + } + } + + bool SharedLibrary::operator!() const { + return mLibHandle == NULL; + } + + void *SharedLibrary::lookup(const char *symbol) const { + if (!mLibHandle) { + return NULL; + } + return dlsym(mLibHandle, symbol); + } +}; diff --git a/media/libmediaplayerservice/SharedLibrary.h b/media/libmediaplayerservice/SharedLibrary.h new file mode 100644 index 0000000..5353642 --- /dev/null +++ b/media/libmediaplayerservice/SharedLibrary.h @@ -0,0 +1,39 @@ +/* + * 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. + */ + +#ifndef SHARED_LIBRARY_H_ +#define SHARED_LIBRARY_H_ + +#include +#include +#include + +namespace android { + class SharedLibrary : public RefBase { + public: + SharedLibrary(const String8 &path); + ~SharedLibrary(); + + bool operator!() const; + void *lookup(const char *symbol) const; + + private: + void *mLibHandle; + DISALLOW_EVIL_CONSTRUCTORS(SharedLibrary); + }; +}; + +#endif // SHARED_LIBRARY_H_ -- cgit v1.1