diff options
Diffstat (limited to 'drm')
28 files changed, 335 insertions, 770 deletions
diff --git a/drm/OWNERS b/drm/OWNERS new file mode 100644 index 0000000000..e788754d4e --- /dev/null +++ b/drm/OWNERS @@ -0,0 +1 @@ +jtinker@google.com diff --git a/drm/libmediadrm/Android.bp b/drm/libmediadrm/Android.bp index 66f5fc24ce..f90656434d 100644 --- a/drm/libmediadrm/Android.bp +++ b/drm/libmediadrm/Android.bp @@ -5,36 +5,31 @@ cc_library_shared { name: "libmediadrm", - aidl: { - local_include_dirs: ["aidl"], - export_aidl_headers: true, - }, srcs: [ - "aidl/android/media/ICas.aidl", - "aidl/android/media/ICasListener.aidl", - "aidl/android/media/IDescrambler.aidl", - "aidl/android/media/IMediaCasService.aidl", - - "CasImpl.cpp", - "DescramblerImpl.cpp", "DrmPluginPath.cpp", "DrmSessionManager.cpp", "ICrypto.cpp", "IDrm.cpp", "IDrmClient.cpp", "IMediaDrmService.cpp", - "MediaCasDefs.cpp", + "PluginMetricsReporting.cpp", "SharedLibrary.cpp", "DrmHal.cpp", "CryptoHal.cpp", + "protos/plugin_metrics.proto", ], + proto: { + type: "lite", + }, + shared_libs: [ "libbinder", "libcutils", "libdl", "liblog", + "libmediametrics", "libmediautils", "libstagefright_foundation", "libutils", diff --git a/drm/libmediadrm/CasImpl.cpp b/drm/libmediadrm/CasImpl.cpp deleted file mode 100644 index 1a33bb01f4..0000000000 --- a/drm/libmediadrm/CasImpl.cpp +++ /dev/null @@ -1,224 +0,0 @@ - -/* - * Copyright (C) 2017 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 "CasImpl" - -#include <android/media/ICasListener.h> -#include <media/cas/CasAPI.h> -#include <media/CasImpl.h> -#include <media/SharedLibrary.h> -#include <utils/Log.h> - -namespace android { - -static Status getBinderStatus(status_t err) { - if (err == OK) { - return Status::ok(); - } - if (err == BAD_VALUE) { - return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT); - } - if (err == INVALID_OPERATION) { - return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE); - } - return Status::fromServiceSpecificError(err); -} - -static String8 sessionIdToString(const CasSessionId &sessionId) { - String8 result; - for (size_t i = 0; i < sessionId.size(); i++) { - result.appendFormat("%02x ", sessionId[i]); - } - if (result.isEmpty()) { - result.append("(null)"); - } - return result; -} - -struct CasImpl::PluginHolder : public RefBase { -public: - explicit PluginHolder(CasPlugin *plugin) : mPlugin(plugin) {} - ~PluginHolder() { if (mPlugin != NULL) delete mPlugin; } - CasPlugin* get() { return mPlugin; } - -private: - CasPlugin *mPlugin; - DISALLOW_EVIL_CONSTRUCTORS(PluginHolder); -}; - -CasImpl::CasImpl(const sp<ICasListener> &listener) - : mPluginHolder(NULL), mListener(listener) { - ALOGV("CTOR"); -} - -CasImpl::~CasImpl() { - ALOGV("DTOR"); - release(); -} - -//static -void CasImpl::OnEvent( - void *appData, - int32_t event, - int32_t arg, - uint8_t *data, - size_t size) { - if (appData == NULL) { - ALOGE("Invalid appData!"); - return; - } - CasImpl *casImpl = static_cast<CasImpl *>(appData); - casImpl->onEvent(event, arg, data, size); -} - -void CasImpl::init(const sp<SharedLibrary>& library, CasPlugin *plugin) { - mLibrary = library; - mPluginHolder = new PluginHolder(plugin); -} - -void CasImpl::onEvent( - int32_t event, int32_t arg, uint8_t *data, size_t size) { - if (mListener == NULL) { - return; - } - - std::unique_ptr<CasData> eventData; - if (data != NULL && size > 0) { - eventData.reset(new CasData(data, data + size)); - } - - mListener->onEvent(event, arg, eventData); -} - -Status CasImpl::setPrivateData(const CasData& pvtData) { - ALOGV("setPrivateData"); - sp<PluginHolder> holder = mPluginHolder; - if (holder == NULL) { - return getBinderStatus(INVALID_OPERATION); - } - return getBinderStatus(holder->get()->setPrivateData(pvtData)); -} - -Status CasImpl::openSession(CasSessionId* sessionId) { - ALOGV("openSession"); - sp<PluginHolder> holder = mPluginHolder; - if (holder == NULL) { - return getBinderStatus(INVALID_OPERATION); - } - status_t err = holder->get()->openSession(sessionId); - - ALOGV("openSession: session opened, sessionId=%s", - sessionIdToString(*sessionId).string()); - - return getBinderStatus(err); -} - -Status CasImpl::setSessionPrivateData( - const CasSessionId &sessionId, const CasData& pvtData) { - ALOGV("setSessionPrivateData: sessionId=%s", - sessionIdToString(sessionId).string()); - sp<PluginHolder> holder = mPluginHolder; - if (holder == NULL) { - return getBinderStatus(INVALID_OPERATION); - } - return getBinderStatus(holder->get()->setSessionPrivateData(sessionId, pvtData)); -} - -Status CasImpl::closeSession(const CasSessionId &sessionId) { - ALOGV("closeSession: sessionId=%s", - sessionIdToString(sessionId).string()); - sp<PluginHolder> holder = mPluginHolder; - if (holder == NULL) { - return getBinderStatus(INVALID_OPERATION); - } - return getBinderStatus(holder->get()->closeSession(sessionId)); -} - -Status CasImpl::processEcm(const CasSessionId &sessionId, const ParcelableCasData& ecm) { - ALOGV("processEcm: sessionId=%s", - sessionIdToString(sessionId).string()); - sp<PluginHolder> holder = mPluginHolder; - if (holder == NULL) { - return getBinderStatus(INVALID_OPERATION); - } - - return getBinderStatus(holder->get()->processEcm(sessionId, ecm)); -} - -Status CasImpl::processEmm(const ParcelableCasData& emm) { - ALOGV("processEmm"); - sp<PluginHolder> holder = mPluginHolder; - if (holder == NULL) { - return getBinderStatus(INVALID_OPERATION); - } - - return getBinderStatus(holder->get()->processEmm(emm)); -} - -Status CasImpl::sendEvent( - int32_t event, int32_t arg, const ::std::unique_ptr<CasData> &eventData) { - ALOGV("sendEvent"); - sp<PluginHolder> holder = mPluginHolder; - if (holder == NULL) { - return getBinderStatus(INVALID_OPERATION); - } - - status_t err; - if (eventData == nullptr) { - err = holder->get()->sendEvent(event, arg, CasData()); - } else { - err = holder->get()->sendEvent(event, arg, *eventData); - } - return getBinderStatus(err); -} - -Status CasImpl::provision(const String16& provisionString) { - ALOGV("provision: provisionString=%s", String8(provisionString).string()); - sp<PluginHolder> holder = mPluginHolder; - if (holder == NULL) { - return getBinderStatus(INVALID_OPERATION); - } - - return getBinderStatus(holder->get()->provision(String8(provisionString))); -} - -Status CasImpl::refreshEntitlements( - int32_t refreshType, const ::std::unique_ptr<CasData> &refreshData) { - ALOGV("refreshEntitlements"); - sp<PluginHolder> holder = mPluginHolder; - if (holder == NULL) { - return getBinderStatus(INVALID_OPERATION); - } - - status_t err; - if (refreshData == nullptr) { - err = holder->get()->refreshEntitlements(refreshType, CasData()); - } else { - err = holder->get()->refreshEntitlements(refreshType, *refreshData); - } - return getBinderStatus(err); -} - -Status CasImpl::release() { - ALOGV("release: plugin=%p", - mPluginHolder == NULL ? mPluginHolder->get() : NULL); - mPluginHolder.clear(); - return Status::ok(); -} - -} // namespace android - diff --git a/drm/libmediadrm/DescramblerImpl.cpp b/drm/libmediadrm/DescramblerImpl.cpp deleted file mode 100644 index 5764669c81..0000000000 --- a/drm/libmediadrm/DescramblerImpl.cpp +++ /dev/null @@ -1,154 +0,0 @@ - -/* - * Copyright (C) 2017 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 "DescramblerImpl" - -#include <media/cas/DescramblerAPI.h> -#include <media/DescramblerImpl.h> -#include <media/SharedLibrary.h> -#include <media/stagefright/foundation/AUtils.h> -#include <binder/IMemory.h> -#include <utils/Log.h> - -namespace android { - -static Status getBinderStatus(status_t err) { - if (err == OK) { - return Status::ok(); - } - if (err == BAD_VALUE) { - return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT); - } - if (err == INVALID_OPERATION) { - return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE); - } - return Status::fromServiceSpecificError(err); -} - -static String8 sessionIdToString(const CasSessionId &sessionId) { - String8 result; - for (size_t i = 0; i < sessionId.size(); i++) { - result.appendFormat("%02x ", sessionId[i]); - } - if (result.isEmpty()) { - result.append("(null)"); - } - return result; -} - -DescramblerImpl::DescramblerImpl( - const sp<SharedLibrary>& library, DescramblerPlugin *plugin) : - mLibrary(library), mPlugin(plugin) { - ALOGV("CTOR: mPlugin=%p", mPlugin); -} - -DescramblerImpl::~DescramblerImpl() { - ALOGV("DTOR: mPlugin=%p", mPlugin); - release(); -} - -Status DescramblerImpl::setMediaCasSession(const CasSessionId& sessionId) { - ALOGV("setMediaCasSession: sessionId=%s", - sessionIdToString(sessionId).string()); - - return getBinderStatus(mPlugin->setMediaCasSession(sessionId)); -} - -Status DescramblerImpl::requiresSecureDecoderComponent( - const String16& mime, bool *result) { - *result = mPlugin->requiresSecureDecoderComponent(String8(mime)); - - return getBinderStatus(OK); -} - -static inline bool validateRangeForSize( - uint64_t offset, uint64_t length, uint64_t size) { - return isInRange<uint64_t, uint64_t>(0, size, offset, length); -} - -Status DescramblerImpl::descramble( - const DescrambleInfo& info, int32_t *result) { - ALOGV("descramble"); - - if (info.srcMem == NULL || info.srcMem->pointer() == NULL) { - ALOGE("srcMem is invalid"); - return getBinderStatus(BAD_VALUE); - } - - // use 64-bit here to catch bad subsample size that might be overflowing. - uint64_t totalBytesInSubSamples = 0; - for (size_t i = 0; i < info.numSubSamples; i++) { - totalBytesInSubSamples += (uint64_t)info.subSamples[i].mNumBytesOfClearData + - info.subSamples[i].mNumBytesOfEncryptedData; - } - // validate if the specified srcOffset and requested total subsample size - // is consistent with the source shared buffer size. - if (!validateRangeForSize(info.srcOffset, totalBytesInSubSamples, info.srcMem->size())) { - ALOGE("Invalid srcOffset and subsample size: " - "srcOffset %llu, totalBytesInSubSamples %llu, srcMem size %llu", - (unsigned long long) info.srcOffset, - (unsigned long long) totalBytesInSubSamples, - (unsigned long long) info.srcMem->size()); - android_errorWriteLog(0x534e4554, "67962232"); - return getBinderStatus(BAD_VALUE); - } - void *dstPtr = NULL; - if (info.dstType == DescrambleInfo::kDestinationTypeVmPointer) { - // When using shared memory, src buffer is also used as dst - dstPtr = info.srcMem->pointer(); - - // In this case the dst and src would be the same buffer, need to validate - // dstOffset against the buffer size too. - if (!validateRangeForSize(info.dstOffset, totalBytesInSubSamples, info.srcMem->size())) { - ALOGE("Invalid dstOffset and subsample size: " - "dstOffset %llu, totalBytesInSubSamples %llu, srcBuffer size %llu", - (unsigned long long) info.dstOffset, - (unsigned long long) totalBytesInSubSamples, - (unsigned long long) info.srcMem->size()); - android_errorWriteLog(0x534e4554, "67962232"); - return getBinderStatus(BAD_VALUE); - } - } else { - dstPtr = info.dstPtr; - } - - *result = mPlugin->descramble( - info.dstType != DescrambleInfo::kDestinationTypeVmPointer, - info.scramblingControl, - info.numSubSamples, - info.subSamples, - info.srcMem->pointer(), - info.srcOffset, - dstPtr, - info.dstOffset, - NULL); - - return getBinderStatus(*result >= 0 ? OK : *result); -} - -Status DescramblerImpl::release() { - ALOGV("release: mPlugin=%p", mPlugin); - - if (mPlugin != NULL) { - delete mPlugin; - mPlugin = NULL; - } - return Status::ok(); -} - -} // namespace android - diff --git a/drm/libmediadrm/DrmHal.cpp b/drm/libmediadrm/DrmHal.cpp index 074489a93f..bc37557ed5 100644 --- a/drm/libmediadrm/DrmHal.cpp +++ b/drm/libmediadrm/DrmHal.cpp @@ -30,6 +30,7 @@ #include <media/DrmHal.h> #include <media/DrmSessionClientInterface.h> #include <media/DrmSessionManager.h> +#include <media/PluginMetricsReporting.h> #include <media/drm/DrmAPI.h> #include <media/stagefright/foundation/ADebug.h> #include <media/stagefright/foundation/AString.h> @@ -194,7 +195,18 @@ DrmHal::DrmHal() mInitCheck((mFactories.size() == 0) ? ERROR_UNSUPPORTED : NO_INIT) { } +void DrmHal::closeOpenSessions() { + if (mPlugin != NULL) { + for (size_t i = 0; i < mOpenSessions.size(); i++) { + mPlugin->closeSession(toHidlVec(mOpenSessions[i])); + DrmSessionManager::Instance()->removeSession(mOpenSessions[i]); + } + } + mOpenSessions.clear(); +} + DrmHal::~DrmHal() { + closeOpenSessions(); DrmSessionManager::Instance()->removeDrm(mDrmSessionClient); } @@ -413,11 +425,12 @@ status_t DrmHal::createPlugin(const uint8_t uuid[16], status_t DrmHal::destroyPlugin() { Mutex::Autolock autoLock(mLock); - if (mInitCheck != OK) { return mInitCheck; } + closeOpenSessions(); + reportMetrics(); setListener(NULL); mInitCheck = NO_INIT; @@ -471,6 +484,7 @@ status_t DrmHal::openSession(Vector<uint8_t> &sessionId) { if (err == OK) { DrmSessionManager::Instance()->addSession(getCallingPid(), mDrmSessionClient, sessionId); + mOpenSessions.push(sessionId); } return err; } @@ -486,7 +500,14 @@ status_t DrmHal::closeSession(Vector<uint8_t> const &sessionId) { if (status.isOk()) { if (status == Status::OK) { DrmSessionManager::Instance()->removeSession(sessionId); + for (size_t i = 0; i < mOpenSessions.size(); i++) { + if (mOpenSessions[i] == sessionId) { + mOpenSessions.removeAt(i); + break; + } + } } + reportMetrics(); return toStatusT(status); } return DEAD_OBJECT; @@ -740,6 +761,12 @@ status_t DrmHal::releaseAllSecureStops() { status_t DrmHal::getPropertyString(String8 const &name, String8 &value ) const { Mutex::Autolock autoLock(mLock); + return getPropertyStringInternal(name, value); +} + +status_t DrmHal::getPropertyStringInternal(String8 const &name, String8 &value) const { + // This function is internal to the class and should only be called while + // mLock is already held. if (mInitCheck != OK) { return mInitCheck; @@ -761,6 +788,12 @@ status_t DrmHal::getPropertyString(String8 const &name, String8 &value ) const { status_t DrmHal::getPropertyByteArray(String8 const &name, Vector<uint8_t> &value ) const { Mutex::Autolock autoLock(mLock); + return getPropertyByteArrayInternal(name, value); +} + +status_t DrmHal::getPropertyByteArrayInternal(String8 const &name, Vector<uint8_t> &value ) const { + // This function is internal to the class and should only be called while + // mLock is already held. if (mInitCheck != OK) { return mInitCheck; @@ -975,7 +1008,7 @@ status_t DrmHal::signRSA(Vector<uint8_t> const &sessionId, void DrmHal::binderDied(const wp<IBinder> &the_late_who __unused) { Mutex::Autolock autoLock(mLock); - + closeOpenSessions(); setListener(NULL); mInitCheck = NO_INIT; @@ -997,4 +1030,20 @@ void DrmHal::writeByteArray(Parcel &obj, hidl_vec<uint8_t> const &vec) } } +void DrmHal::reportMetrics() const +{ + Vector<uint8_t> metrics; + String8 vendor; + String8 description; + if (getPropertyStringInternal(String8("vendor"), vendor) == OK && + getPropertyStringInternal(String8("description"), description) == OK && + getPropertyByteArrayInternal(String8("metrics"), metrics) == OK) { + status_t res = android::reportDrmPluginMetrics( + metrics, vendor, description); + if (res != OK) { + ALOGE("Metrics were retrieved but could not be reported: %i", res); + } + } +} + } // namespace android diff --git a/drm/libmediadrm/MediaCasDefs.cpp b/drm/libmediadrm/MediaCasDefs.cpp deleted file mode 100644 index 9c2ba38fde..0000000000 --- a/drm/libmediadrm/MediaCasDefs.cpp +++ /dev/null @@ -1,184 +0,0 @@ -/* - * Copyright (C) 2017 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 "MediaCas" - -#include <media/MediaCasDefs.h> -#include <utils/Log.h> -#include <binder/IMemory.h> - -namespace android { -namespace media { - -/////////////////////////////////////////////////////////////////////////////// -namespace MediaCas { - -status_t ParcelableCasData::readFromParcel(const Parcel* parcel) { - return parcel->readByteVector(this); -} - -status_t ParcelableCasData::writeToParcel(Parcel* parcel) const { - return parcel->writeByteVector(*this); -} - -/////////////////////////////////////////////////////////////////////////////// - -status_t ParcelableCasPluginDescriptor::readFromParcel(const Parcel* /*parcel*/) { - ALOGE("CAPluginDescriptor::readFromParcel() shouldn't be called"); - return INVALID_OPERATION; -} - -status_t ParcelableCasPluginDescriptor::writeToParcel(Parcel* parcel) const { - status_t err = parcel->writeInt32(mCASystemId); - if (err != NO_ERROR) { - return err; - } - return parcel->writeString16(mName); -} - -} // namespace MediaCas -/////////////////////////////////////////////////////////////////////////////// - -namespace MediaDescrambler { - -DescrambleInfo::DescrambleInfo() {} - -DescrambleInfo::~DescrambleInfo() {} - -status_t DescrambleInfo::readFromParcel(const Parcel* parcel) { - status_t err = parcel->readInt32((int32_t*)&dstType); - if (err != OK) { - return err; - } - if (dstType != kDestinationTypeNativeHandle - && dstType != kDestinationTypeVmPointer) { - return BAD_VALUE; - } - - err = parcel->readInt32((int32_t*)&scramblingControl); - if (err != OK) { - return err; - } - - err = parcel->readUint32((uint32_t*)&numSubSamples); - if (err != OK) { - return err; - } - if (numSubSamples > 0xffff) { - return BAD_VALUE; - } - - subSamples = new DescramblerPlugin::SubSample[numSubSamples]; - if (subSamples == NULL) { - return NO_MEMORY; - } - - for (size_t i = 0; i < numSubSamples; i++) { - err = parcel->readUint32(&subSamples[i].mNumBytesOfClearData); - if (err != OK) { - return err; - } - err = parcel->readUint32(&subSamples[i].mNumBytesOfEncryptedData); - if (err != OK) { - return err; - } - } - - srcMem = interface_cast<IMemory>(parcel->readStrongBinder()); - if (srcMem == NULL) { - return BAD_VALUE; - } - - err = parcel->readInt32(&srcOffset); - if (err != OK) { - return err; - } - - native_handle_t *nativeHandle = NULL; - if (dstType == kDestinationTypeNativeHandle) { - nativeHandle = parcel->readNativeHandle(); - dstPtr = static_cast<void *>(nativeHandle); - } else { - dstPtr = NULL; - } - - err = parcel->readInt32(&dstOffset); - if (err != OK) { - return err; - } - - return OK; -} - -status_t DescrambleInfo::writeToParcel(Parcel* parcel) const { - if (dstType != kDestinationTypeNativeHandle - && dstType != kDestinationTypeVmPointer) { - return BAD_VALUE; - } - - status_t err = parcel->writeInt32((int32_t)dstType); - if (err != OK) { - return err; - } - - err = parcel->writeInt32(scramblingControl); - if (err != OK) { - return err; - } - - err = parcel->writeUint32(numSubSamples); - if (err != OK) { - return err; - } - - for (size_t i = 0; i < numSubSamples; i++) { - err = parcel->writeUint32(subSamples[i].mNumBytesOfClearData); - if (err != OK) { - return err; - } - err = parcel->writeUint32(subSamples[i].mNumBytesOfEncryptedData); - if (err != OK) { - return err; - } - } - - err = parcel->writeStrongBinder(IInterface::asBinder(srcMem)); - if (err != OK) { - return err; - } - - err = parcel->writeInt32(srcOffset); - if (err != OK) { - return err; - } - - if (dstType == kDestinationTypeNativeHandle) { - parcel->writeNativeHandle(static_cast<native_handle_t *>(dstPtr)); - } - - err = parcel->writeInt32(dstOffset); - if (err != OK) { - return err; - } - - return OK; -} - -} // namespace MediaDescrambler - -} // namespace media -} // namespace android - diff --git a/drm/libmediadrm/PluginMetricsReporting.cpp b/drm/libmediadrm/PluginMetricsReporting.cpp new file mode 100644 index 0000000000..57ff5b8207 --- /dev/null +++ b/drm/libmediadrm/PluginMetricsReporting.cpp @@ -0,0 +1,134 @@ +/* + * Copyright (C) 2017 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 "PluginMetricsReporting" +#include <utils/Log.h> + +#include <media/PluginMetricsReporting.h> + +#include <media/MediaAnalyticsItem.h> + +#include "protos/plugin_metrics.pb.h" + +namespace android { + +namespace { + +using android::drm_metrics::MetricsGroup; +using android::drm_metrics::MetricsGroup_Metric; +using android::drm_metrics::MetricsGroup_Metric_MetricValue; + +const char* const kParentAttribute = "/parent/external"; + +status_t reportMetricsGroup(const MetricsGroup& metricsGroup, + const String8& batchName, + const int64_t* parentId) { + MediaAnalyticsItem analyticsItem(batchName.c_str()); + analyticsItem.generateSessionID(); + int64_t sessionId = analyticsItem.getSessionID(); + if (parentId != NULL) { + analyticsItem.setInt64(kParentAttribute, *parentId); + } + + // Report the package name. + if (metricsGroup.has_app_package_name()) { + AString app_package_name(metricsGroup.app_package_name().c_str(), + metricsGroup.app_package_name().size()); + analyticsItem.setPkgName(app_package_name); + } + + for (int i = 0; i < metricsGroup.metric_size(); ++i) { + const MetricsGroup_Metric& metric = metricsGroup.metric(i); + if (!metric.has_name()) { + ALOGE("Metric with no name."); + return BAD_VALUE; + } + + if (!metric.has_value()) { + ALOGE("Metric with no value."); + return BAD_VALUE; + } + + const MetricsGroup_Metric_MetricValue& value = metric.value(); + if (value.has_int_value()) { + analyticsItem.setInt64(metric.name().c_str(), + value.int_value()); + } else if (value.has_double_value()) { + analyticsItem.setDouble(metric.name().c_str(), + value.double_value()); + } else if (value.has_string_value()) { + analyticsItem.setCString(metric.name().c_str(), + value.string_value().c_str()); + } else { + ALOGE("Metric Value with no actual value."); + return BAD_VALUE; + } + } + + analyticsItem.setFinalized(true); + if (!analyticsItem.selfrecord()) { + // Note the cast to int is because we build on 32 and 64 bit. + // The cast prevents a peculiar printf problem where one format cannot + // satisfy both. + ALOGE("selfrecord() returned false. sessioId %d", (int) sessionId); + } + + for (int i = 0; i < metricsGroup.metric_sub_group_size(); ++i) { + const MetricsGroup& subGroup = metricsGroup.metric_sub_group(i); + status_t res = reportMetricsGroup(subGroup, batchName, &sessionId); + if (res != OK) { + return res; + } + } + + return OK; +} + +String8 sanitize(const String8& input) { + // Filters the input string down to just alphanumeric characters. + String8 output; + for (size_t i = 0; i < input.size(); ++i) { + char candidate = input[i]; + if ((candidate >= 'a' && candidate <= 'z') || + (candidate >= 'A' && candidate <= 'Z') || + (candidate >= '0' && candidate <= '9')) { + output.append(&candidate, 1); + } + } + return output; +} + +} // namespace + +status_t reportDrmPluginMetrics(const Vector<uint8_t>& serializedMetrics, + const String8& vendor, + const String8& description) { + MetricsGroup root_metrics_group; + if (!root_metrics_group.ParseFromArray(serializedMetrics.array(), + serializedMetrics.size())) { + ALOGE("Failure to parse."); + return BAD_VALUE; + } + + String8 name = String8::format("drm.vendor.%s.%s", + sanitize(vendor).c_str(), + sanitize(description).c_str()); + + return reportMetricsGroup(root_metrics_group, name, NULL); +} + +} // namespace android diff --git a/drm/libmediadrm/aidl/android/media/ICas.aidl b/drm/libmediadrm/aidl/android/media/ICas.aidl deleted file mode 100644 index 97465937e6..0000000000 --- a/drm/libmediadrm/aidl/android/media/ICas.aidl +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (C) 2017 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. - */ - -package android.media; - -import android.media.MediaCas; - -/** @hide */ -interface ICas { - void setPrivateData(in byte[] pvtData); - byte[] openSession(); - void closeSession(in byte[] sessionId); - void setSessionPrivateData(in byte[] sessionId, in byte[] pvtData); - void processEcm(in byte[] sessionId, in MediaCas.ParcelableCasData ecm); - void processEmm(in MediaCas.ParcelableCasData emm); - void sendEvent(int event, int arg, in @nullable byte[] eventData); - void provision(String provisionString); - void refreshEntitlements(int refreshType, in @nullable byte[] refreshData); - void release(); -}
\ No newline at end of file diff --git a/drm/libmediadrm/aidl/android/media/ICasListener.aidl b/drm/libmediadrm/aidl/android/media/ICasListener.aidl deleted file mode 100644 index 01a5abc883..0000000000 --- a/drm/libmediadrm/aidl/android/media/ICasListener.aidl +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright (C) 2017 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. - */ - -package android.media; - -/** @hide */ -interface ICasListener { - void onEvent(int event, int arg, in @nullable byte[] data); -}
\ No newline at end of file diff --git a/drm/libmediadrm/aidl/android/media/IDescrambler.aidl b/drm/libmediadrm/aidl/android/media/IDescrambler.aidl deleted file mode 100644 index fdf99eba62..0000000000 --- a/drm/libmediadrm/aidl/android/media/IDescrambler.aidl +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright (C) 2017 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. - */ - -package android.media; - -import android.media.MediaDescrambler; - -/** @hide */ -interface IDescrambler { - void setMediaCasSession(in byte[] sessionId); - boolean requiresSecureDecoderComponent(String mime); - int descramble(in MediaDescrambler.DescrambleInfo descrambleInfo); - void release(); -}
\ No newline at end of file diff --git a/drm/libmediadrm/aidl/android/media/IMediaCasService.aidl b/drm/libmediadrm/aidl/android/media/IMediaCasService.aidl deleted file mode 100644 index 44f6825188..0000000000 --- a/drm/libmediadrm/aidl/android/media/IMediaCasService.aidl +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (C) 2017 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. - */ - -package android.media; - -import android.media.IDescrambler; -import android.media.ICas; -import android.media.ICasListener; -import android.media.MediaCas; - -/** @hide */ -interface IMediaCasService { - MediaCas.ParcelableCasPluginDescriptor[] enumeratePlugins(); - boolean isSystemIdSupported(int CA_system_id); - ICas createPlugin(int CA_system_id, ICasListener listener); - boolean isDescramblerSupported(int CA_system_id); - IDescrambler createDescrambler(int CA_system_id); -} - diff --git a/drm/libmediadrm/aidl/android/media/MediaCas.aidl b/drm/libmediadrm/aidl/android/media/MediaCas.aidl deleted file mode 100644 index cb8d0c65b0..0000000000 --- a/drm/libmediadrm/aidl/android/media/MediaCas.aidl +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright (C) 2017 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. - */ - -package android.media; - -/** @hide */ -parcelable MediaCas.ParcelableCasPluginDescriptor cpp_header "media/MediaCasDefs.h"; - -/** @hide */ -parcelable MediaCas.ParcelableCasData cpp_header "media/MediaCasDefs.h";
\ No newline at end of file diff --git a/drm/libmediadrm/aidl/android/media/MediaDescrambler.aidl b/drm/libmediadrm/aidl/android/media/MediaDescrambler.aidl deleted file mode 100644 index e7892442ef..0000000000 --- a/drm/libmediadrm/aidl/android/media/MediaDescrambler.aidl +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (C) 2017 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. - */ - -package android.media; - -/** @hide */ -parcelable MediaDescrambler.DescrambleInfo cpp_header "media/MediaCasDefs.h";
\ No newline at end of file diff --git a/drm/libmediadrm/protos/plugin_metrics.proto b/drm/libmediadrm/protos/plugin_metrics.proto new file mode 100644 index 0000000000..7e3bcf5304 --- /dev/null +++ b/drm/libmediadrm/protos/plugin_metrics.proto @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2017 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. + */ + +syntax = "proto2"; + +package android.drm_metrics; + +// need this if we are using libprotobuf-cpp-2.3.0-lite +option optimize_for = LITE_RUNTIME; + +// The MetricsGroup is a collection of metric name/value pair instances +// that can be serialized and provided to a caller. +message MetricsGroup { + message Metric { + message MetricValue { + // Exactly one of the following values must be set. + optional int64 int_value = 1; + optional double double_value = 2; + optional string string_value = 3; + } + + // The name of the metric. Must be valid UTF-8. Required. + optional string name = 1; + + // The value of the metric. Required. + optional MetricValue value = 2; + } + + // The list of name/value pairs of metrics. + repeated Metric metric = 1; + + // Allow multiple sub groups of metrics. + repeated MetricsGroup metric_sub_group = 2; + + // Name of the application package associated with the metrics. + optional string app_package_name = 3; +} diff --git a/drm/mediacas/plugins/clearkey/Android.mk b/drm/mediacas/plugins/clearkey/Android.mk index 8fd866ce8b..4b139a8fa7 100644 --- a/drm/mediacas/plugins/clearkey/Android.mk +++ b/drm/mediacas/plugins/clearkey/Android.mk @@ -28,8 +28,7 @@ LOCAL_SRC_FILES:= \ LOCAL_MODULE := libclearkeycasplugin -#TODO: move this back to /vendor/lib after conversion to treble -#LOCAL_PROPRIETARY_MODULE := true +LOCAL_PROPRIETARY_MODULE := true LOCAL_MODULE_RELATIVE_PATH := mediacas LOCAL_SHARED_LIBRARIES := \ @@ -39,6 +38,9 @@ LOCAL_SHARED_LIBRARIES := \ libstagefright_foundation \ libprotobuf-cpp-lite \ +LOCAL_HEADER_LIBRARIES := \ + media_plugin_headers + LOCAL_STATIC_LIBRARIES := \ libjsmn \ diff --git a/drm/mediacas/plugins/clearkey/ClearKeyCasPlugin.cpp b/drm/mediacas/plugins/clearkey/ClearKeyCasPlugin.cpp index 757219484c..50acc1dab5 100644 --- a/drm/mediacas/plugins/clearkey/ClearKeyCasPlugin.cpp +++ b/drm/mediacas/plugins/clearkey/ClearKeyCasPlugin.cpp @@ -121,7 +121,7 @@ status_t ClearKeyCasPlugin::closeSession(const CasSessionId &sessionId) { std::shared_ptr<ClearKeyCasSession> session = ClearKeySessionLibrary::get()->findSession(sessionId); if (session.get() == nullptr) { - return ERROR_DRM_SESSION_NOT_OPENED; + return ERROR_CAS_SESSION_NOT_OPENED; } ClearKeySessionLibrary::get()->destroySession(sessionId); @@ -135,7 +135,7 @@ status_t ClearKeyCasPlugin::setSessionPrivateData( std::shared_ptr<ClearKeyCasSession> session = ClearKeySessionLibrary::get()->findSession(sessionId); if (session.get() == nullptr) { - return ERROR_DRM_SESSION_NOT_OPENED; + return ERROR_CAS_SESSION_NOT_OPENED; } return OK; } @@ -146,7 +146,7 @@ status_t ClearKeyCasPlugin::processEcm( std::shared_ptr<ClearKeyCasSession> session = ClearKeySessionLibrary::get()->findSession(sessionId); if (session.get() == nullptr) { - return ERROR_DRM_SESSION_NOT_OPENED; + return ERROR_CAS_SESSION_NOT_OPENED; } Mutex::Autolock lock(mKeyFetcherLock); @@ -293,7 +293,7 @@ const static size_t kUserKeyLength = 16; status_t ClearKeyCasSession::updateECM( KeyFetcher *keyFetcher, void *ecm, size_t size) { if (keyFetcher == nullptr) { - return ERROR_DRM_NOT_PROVISIONED; + return ERROR_CAS_NOT_PROVISIONED; } if (size < kEcmHeaderLength) { @@ -344,7 +344,7 @@ ssize_t ClearKeyCasSession::decrypt( size_t numSubSamples, const DescramblerPlugin::SubSample *subSamples, const void *srcPtr, void *dstPtr, AString * /* errorDetailMsg */) { if (secure) { - return ERROR_DRM_CANNOT_HANDLE; + return ERROR_CAS_CANNOT_HANDLE; } AES_KEY contentKey; @@ -356,7 +356,7 @@ ssize_t ClearKeyCasSession::decrypt( int32_t keyIndex = (scramblingControl & 1); if (!mKeyInfo[keyIndex].valid) { ALOGE("decrypt: key %d is invalid", keyIndex); - return ERROR_DRM_DECRYPT; + return ERROR_CAS_DECRYPT; } contentKey = mKeyInfo[keyIndex].contentKey; } @@ -420,7 +420,7 @@ status_t ClearKeyDescramblerPlugin::setMediaCasSession( if (session.get() == nullptr) { ALOGE("ClearKeyDescramblerPlugin: session not found"); - return ERROR_DRM_SESSION_NOT_OPENED; + return ERROR_CAS_SESSION_NOT_OPENED; } std::atomic_store(&mCASSession, session); @@ -448,7 +448,7 @@ ssize_t ClearKeyDescramblerPlugin::descramble( if (session.get() == nullptr) { ALOGE("Uninitialized CAS session!"); - return ERROR_DRM_DECRYPT_UNIT_NOT_INITIALIZED; + return ERROR_CAS_DECRYPT_UNIT_NOT_INITIALIZED; } return session->decrypt( diff --git a/drm/mediacas/plugins/clearkey/JsonAssetLoader.cpp b/drm/mediacas/plugins/clearkey/JsonAssetLoader.cpp index 9cd77e9e41..6e1004caa1 100644 --- a/drm/mediacas/plugins/clearkey/JsonAssetLoader.cpp +++ b/drm/mediacas/plugins/clearkey/JsonAssetLoader.cpp @@ -48,24 +48,24 @@ JsonAssetLoader::~JsonAssetLoader() { * Extract a clear key asset from a JSON string. * * Returns OK if a clear key asset is extracted successfully, - * or ERROR_DRM_NO_LICENSE if the string doesn't contain a valid + * or ERROR_CAS_NO_LICENSE if the string doesn't contain a valid * clear key asset. */ status_t JsonAssetLoader::extractAssetFromString( const String8& jsonAssetString, Asset *asset) { if (!parseJsonAssetString(jsonAssetString, &mJsonObjects)) { - return ERROR_DRM_NO_LICENSE; + return ERROR_CAS_NO_LICENSE; } if (mJsonObjects.size() < 1) { - return ERROR_DRM_NO_LICENSE; + return ERROR_CAS_NO_LICENSE; } if (!parseJsonObject(mJsonObjects[0], &mTokens)) - return ERROR_DRM_NO_LICENSE; + return ERROR_CAS_NO_LICENSE; if (!findKey(mJsonObjects[0], asset)) { - return ERROR_DRM_NO_LICENSE; + return ERROR_CAS_NO_LICENSE; } return OK; } diff --git a/drm/mediacas/plugins/clearkey/ecm_generator.h b/drm/mediacas/plugins/clearkey/ecm_generator.h index 2ef06c4db8..5fbdea5870 100644 --- a/drm/mediacas/plugins/clearkey/ecm_generator.h +++ b/drm/mediacas/plugins/clearkey/ecm_generator.h @@ -29,7 +29,7 @@ using namespace std; namespace android { namespace clearkeycas { enum { - CLEARKEY_STATUS_BASE = ERROR_DRM_VENDOR_MAX, + CLEARKEY_STATUS_BASE = ERROR_CAS_VENDOR_MAX, CLEARKEY_STATUS_INVALIDASSETID = CLEARKEY_STATUS_BASE - 1, CLEARKEY_STATUS_INVALIDSYSTEMID = CLEARKEY_STATUS_BASE - 2, CLEARKEY_STATUS_INVALID_PARAMETER = CLEARKEY_STATUS_BASE - 3, diff --git a/drm/mediacas/plugins/clearkey/tests/Android.mk b/drm/mediacas/plugins/clearkey/tests/Android.mk index cbf7be73a7..e1545afe00 100644 --- a/drm/mediacas/plugins/clearkey/tests/Android.mk +++ b/drm/mediacas/plugins/clearkey/tests/Android.mk @@ -21,12 +21,13 @@ LOCAL_SRC_FILES := \ ClearKeyFetcherTest.cpp LOCAL_MODULE := ClearKeyFetcherTest +LOCAL_VENDOR_MODULE := true # LOCAL_LDFLAGS is needed here for the test to use the plugin, because # the plugin is not in standard library search path. Without this .so # loading fails at run-time (linking is okay). LOCAL_LDFLAGS := \ - -Wl,--rpath,\$${ORIGIN}/../../../system/lib/mediacas -Wl,--enable-new-dtags + -Wl,--rpath,\$${ORIGIN}/../../../system/vendor/lib/mediacas -Wl,--enable-new-dtags LOCAL_SHARED_LIBRARIES := \ libutils libclearkeycasplugin libstagefright_foundation libprotobuf-cpp-lite liblog diff --git a/drm/mediacas/plugins/mock/Android.mk b/drm/mediacas/plugins/mock/Android.mk index a97fac60cb..a1d61dae89 100644 --- a/drm/mediacas/plugins/mock/Android.mk +++ b/drm/mediacas/plugins/mock/Android.mk @@ -28,6 +28,8 @@ LOCAL_MODULE_RELATIVE_PATH := mediacas LOCAL_SHARED_LIBRARIES := \ libutils liblog +LOCAL_HEADER_LIBRARIES := media_plugin_headers + LOCAL_C_INCLUDES += \ $(TOP)/frameworks/av/include \ $(TOP)/frameworks/native/include/media \ diff --git a/drm/mediadrm/plugins/clearkey/ClearKeyUUID.cpp b/drm/mediadrm/plugins/clearkey/ClearKeyUUID.cpp index ed050f791a..0259a42a15 100644 --- a/drm/mediadrm/plugins/clearkey/ClearKeyUUID.cpp +++ b/drm/mediadrm/plugins/clearkey/ClearKeyUUID.cpp @@ -21,12 +21,19 @@ namespace clearkeydrm { bool isClearKeyUUID(const uint8_t uuid[16]) { - static const uint8_t kClearKeyUUID[16] = { + static const uint8_t kCommonPsshBoxUUID[16] = { 0x10,0x77,0xEF,0xEC,0xC0,0xB2,0x4D,0x02, 0xAC,0xE3,0x3C,0x1E,0x52,0xE2,0xFB,0x4B }; - return !memcmp(uuid, kClearKeyUUID, sizeof(kClearKeyUUID)); + // To be used in mpd to specify drm scheme for players + static const uint8_t kClearKeyUUID[16] = { + 0xE2,0x71,0x9D,0x58,0xA9,0x85,0xB3,0xC9, + 0x78,0x1A,0xB0,0x30,0xAF,0x78,0xD3,0x0E + }; + + return !memcmp(uuid, kCommonPsshBoxUUID, sizeof(kCommonPsshBoxUUID)) || + !memcmp(uuid, kClearKeyUUID, sizeof(kClearKeyUUID)); } } // namespace clearkeydrm diff --git a/drm/mediadrm/plugins/clearkey/DrmPlugin.cpp b/drm/mediadrm/plugins/clearkey/DrmPlugin.cpp index 5fdac5cadf..ec07d87b1c 100644 --- a/drm/mediadrm/plugins/clearkey/DrmPlugin.cpp +++ b/drm/mediadrm/plugins/clearkey/DrmPlugin.cpp @@ -25,10 +25,28 @@ #include "Session.h" +namespace { +const android::String8 kStreaming("Streaming"); +const android::String8 kOffline("Offline"); +const android::String8 kTrue("True"); + +const android::String8 kQueryKeyLicenseType("LicenseType"); + // Value: "Streaming" or "Offline" +const android::String8 kQueryKeyPlayAllowed("PlayAllowed"); + // Value: "True" or "False" +const android::String8 kQueryKeyRenewAllowed("RenewAllowed"); + // Value: "True" or "False" +}; + namespace clearkeydrm { using android::sp; +DrmPlugin::DrmPlugin(SessionLibrary* sessionLibrary) + : mSessionLibrary(sessionLibrary) { + mPlayPolicy.clear(); +} + status_t DrmPlugin::openSession(Vector<uint8_t>& sessionId) { sp<Session> session = mSessionLibrary->createSession(); sessionId = session->sessionId(); @@ -60,18 +78,28 @@ status_t DrmPlugin::getKeyRequest( if (scope.size() == 0) { return android::BAD_VALUE; } + if (keyType != kKeyType_Streaming) { return android::ERROR_DRM_CANNOT_HANDLE; } + *keyRequestType = DrmPlugin::kKeyRequestType_Initial; defaultUrl.clear(); sp<Session> session = mSessionLibrary->findSession(scope); if (!session.get()) { return android::ERROR_DRM_SESSION_NOT_OPENED; } + return session->getKeyRequest(initData, mimeType, &request); } +void DrmPlugin::setPlayPolicy() { + mPlayPolicy.clear(); + mPlayPolicy.add(kQueryKeyLicenseType, kStreaming); + mPlayPolicy.add(kQueryKeyPlayAllowed, kTrue); + mPlayPolicy.add(kQueryKeyRenewAllowed, kTrue); +} + status_t DrmPlugin::provideKeyResponse( const Vector<uint8_t>& scope, const Vector<uint8_t>& response, @@ -83,6 +111,8 @@ status_t DrmPlugin::provideKeyResponse( if (!session.get()) { return android::ERROR_DRM_SESSION_NOT_OPENED; } + + setPlayPolicy(); status_t res = session->provideKeyResponse(response); if (res == android::OK) { // This is for testing AMediaDrm_setOnEventListener only. @@ -111,4 +141,18 @@ status_t DrmPlugin::getPropertyString( return android::OK; } +status_t DrmPlugin::queryKeyStatus( + const Vector<uint8_t>& sessionId, + KeyedVector<String8, String8>& infoMap) const { + + if (sessionId.size() == 0) { + return android::BAD_VALUE; + } + + infoMap.clear(); + for (size_t i = 0; i < mPlayPolicy.size(); ++i) { + infoMap.add(mPlayPolicy.keyAt(i), mPlayPolicy.valueAt(i)); + } + return android::OK; +} } // namespace clearkeydrm diff --git a/drm/mediadrm/plugins/clearkey/DrmPlugin.h b/drm/mediadrm/plugins/clearkey/DrmPlugin.h index 58421b9d01..f37a70699a 100644 --- a/drm/mediadrm/plugins/clearkey/DrmPlugin.h +++ b/drm/mediadrm/plugins/clearkey/DrmPlugin.h @@ -39,8 +39,8 @@ using android::Vector; class DrmPlugin : public android::DrmPlugin { public: - explicit DrmPlugin(SessionLibrary* sessionLibrary) - : mSessionLibrary(sessionLibrary) {} + explicit DrmPlugin(SessionLibrary* sessionLibrary); + virtual ~DrmPlugin() {} virtual status_t openSession(Vector<uint8_t>& sessionId); @@ -81,13 +81,7 @@ public: virtual status_t queryKeyStatus( const Vector<uint8_t>& sessionId, - KeyedVector<String8, String8>& infoMap) const { - if (sessionId.size() == 0) { - return android::BAD_VALUE; - } - UNUSED(infoMap); - return android::ERROR_DRM_CANNOT_HANDLE; - } + KeyedVector<String8, String8>& infoMap) const; virtual status_t getProvisionRequest( const String8& cert_type, @@ -248,9 +242,12 @@ public: } private: - DISALLOW_EVIL_CONSTRUCTORS(DrmPlugin); + void setPlayPolicy(); + android::KeyedVector<android::String8, android::String8> mPlayPolicy; SessionLibrary* mSessionLibrary; + + DISALLOW_EVIL_CONSTRUCTORS(DrmPlugin); }; } // namespace clearkeydrm diff --git a/drm/mediadrm/plugins/clearkey/InitDataParser.cpp b/drm/mediadrm/plugins/clearkey/InitDataParser.cpp index 6a4f8d5695..caff3939be 100644 --- a/drm/mediadrm/plugins/clearkey/InitDataParser.cpp +++ b/drm/mediadrm/plugins/clearkey/InitDataParser.cpp @@ -136,7 +136,7 @@ String8 InitDataParser::generateRequest(const Vector<const uint8_t*>& keyIds) { AString encodedId; for (size_t i = 0; i < keyIds.size(); ++i) { encodedId.clear(); - android::encodeBase64(keyIds[i], kKeyIdSize, &encodedId); + android::encodeBase64Url(keyIds[i], kKeyIdSize, &encodedId); if (i != 0) { request.append(","); } diff --git a/drm/mediadrm/plugins/clearkey/tests/Android.bp b/drm/mediadrm/plugins/clearkey/tests/Android.bp index ac57d653c6..0fcfc6436b 100644 --- a/drm/mediadrm/plugins/clearkey/tests/Android.bp +++ b/drm/mediadrm/plugins/clearkey/tests/Android.bp @@ -34,4 +34,5 @@ cc_test { "libstagefright_foundation", "libutils", ], + header_libs: ["media_plugin_headers"], } diff --git a/drm/mediadrm/plugins/clearkey/tests/InitDataParserUnittest.cpp b/drm/mediadrm/plugins/clearkey/tests/InitDataParserUnittest.cpp index 84ed242246..8c496566cc 100644 --- a/drm/mediadrm/plugins/clearkey/tests/InitDataParserUnittest.cpp +++ b/drm/mediadrm/plugins/clearkey/tests/InitDataParserUnittest.cpp @@ -59,7 +59,7 @@ class InitDataParserTest : public ::testing::Test { (size_t)requestString.find(kRequestSuffix)); for (size_t i = 0; i < expectedKeys.size(); ++i) { AString encodedIdAString; - android::encodeBase64(expectedKeys[i], kKeyIdSize, + android::encodeBase64Url(expectedKeys[i], kKeyIdSize, &encodedIdAString); String8 encodedId(encodedIdAString.c_str()); encodedId.removeAll(kBase64Padding); @@ -231,5 +231,4 @@ TEST_F(InitDataParserTest, FailsForPsshBadKeyCount) { attemptParseExpectingFailure(initData, kCencMimeType); } - } // namespace clearkeydrm diff --git a/drm/mediadrm/plugins/clearkey/tests/JsonWebKeyUnittest.cpp b/drm/mediadrm/plugins/clearkey/tests/JsonWebKeyUnittest.cpp index c3b0d84c61..d9f3ea6703 100644 --- a/drm/mediadrm/plugins/clearkey/tests/JsonWebKeyUnittest.cpp +++ b/drm/mediadrm/plugins/clearkey/tests/JsonWebKeyUnittest.cpp @@ -284,14 +284,14 @@ TEST_F(JsonWebKeyTest, ExtractKeys) { "\"keys\":" "[{" "\"kid\":\"Y2xlYXJrZXlrZXlpZDAx\"" - "\"k\":\"SGVsbG8gRnJpZW5kISE\"" + "\"k\":\"SGVsbG8gRnJpZW5kICE-Pw\"" "\"kty\":\"oct\"" "\"alg\":\"A128KW1\"" "}" "{" "\"kty\":\"oct\"" "\"alg\":\"A128KW2\"" - "\"k\":\"SGVsbG8gRnJpZW5kIQ\"" + "\"k\":\"SGVsbG8gRnJpZW5kICE_\"" "\"kid\":\"Y2xlYXJrZXlrZXlpZDAy\"" "}" "{" @@ -303,7 +303,7 @@ TEST_F(JsonWebKeyTest, ExtractKeys) { "{" "\"alg\":\"A128KW3\"" "\"kid\":\"Y2xlYXJrZXlrZXlpZDAz\"" - "\"k\":\"R29vZCBkYXkh\"" + "\"k\":\"SGVsbG8gPz4-IEZyaWVuZCA_Pg\"" "\"kty\":\"oct\"" "}]" "}"); @@ -313,8 +313,8 @@ TEST_F(JsonWebKeyTest, ExtractKeys) { EXPECT_TRUE(keys.size() == 3); const String8 clearKeys[] = - { String8("Hello Friend!!"), String8("Hello Friend!"), - String8("Good day!") }; + { String8("Hello Friend !>?"), String8("Hello Friend !?"), + String8("Hello ?>> Friend ?>") }; verifyKeys(keys, clearKeys); } diff --git a/drm/mediadrm/plugins/mock/Android.bp b/drm/mediadrm/plugins/mock/Android.bp index 7f448195c5..abd18840f3 100644 --- a/drm/mediadrm/plugins/mock/Android.bp +++ b/drm/mediadrm/plugins/mock/Android.bp @@ -22,6 +22,8 @@ cc_library_shared { vendor: true, relative_install_path: "mediadrm", + header_libs: ["media_plugin_headers"], + shared_libs: [ "libutils", "liblog", |
