/* * Copyright (C) 2014 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 "ClearKeyDrmPlugin" #include #include #include #include "DrmPlugin.h" #include "ClearKeyDrmProperties.h" #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(); initProperties(); } void DrmPlugin::initProperties() { mStringProperties.clear(); mStringProperties.add(kVendorKey, kVendorValue); mStringProperties.add(kVersionKey, kVersionValue); mStringProperties.add(kPluginDescriptionKey, kPluginDescriptionValue); mStringProperties.add(kAlgorithmsKey, kAlgorithmsValue); mStringProperties.add(kListenerTestSupportKey, kListenerTestSupportValue); Vector testDeviceId; testDeviceId.appendArray(kTestDeviceIdData, sizeof(kTestDeviceIdData) / sizeof(uint8_t)); mByteArrayProperties.add(kDeviceIdKey, testDeviceId); } status_t DrmPlugin::openSession(Vector& sessionId) { sp session = mSessionLibrary->createSession(); sessionId = session->sessionId(); return android::OK; } status_t DrmPlugin::closeSession(const Vector& sessionId) { sp session = mSessionLibrary->findSession(sessionId); if (sessionId.size() == 0) { return android::BAD_VALUE; } if (session.get()) { mSessionLibrary->destroySession(session); return android::OK; } return android::ERROR_DRM_SESSION_NOT_OPENED; } status_t DrmPlugin::getKeyRequest( const Vector& scope, const Vector& initData, const String8& mimeType, KeyType keyType, const KeyedVector& optionalParameters, Vector& request, String8& defaultUrl, DrmPlugin::KeyRequestType *keyRequestType) { UNUSED(optionalParameters); 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 = mSessionLibrary->findSession(scope); if (!session.get()) { return android::ERROR_DRM_SESSION_NOT_OPENED; } return session->getKeyRequest(initData, mimeType, &request); } void DrmPlugin::setPlayPolicy() { android::Mutex::Autolock lock(mPlayPolicyLock); mPlayPolicy.clear(); mPlayPolicy.add(kQueryKeyLicenseType, kStreaming); mPlayPolicy.add(kQueryKeyPlayAllowed, kTrue); mPlayPolicy.add(kQueryKeyRenewAllowed, kTrue); } status_t DrmPlugin::provideKeyResponse( const Vector& scope, const Vector& response, Vector& keySetId) { if (scope.size() == 0 || response.size() == 0) { return android::BAD_VALUE; } sp session = mSessionLibrary->findSession(scope); 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. sendEvent(kDrmPluginEventVendorDefined, 0, &scope, NULL); keySetId.clear(); } return res; } status_t DrmPlugin::getPropertyByteArray( const String8& name, Vector& value) const { ssize_t index = mByteArrayProperties.indexOfKey(name); if (index < 0) { ALOGE("App requested unknown property: %s", name.string()); return android::ERROR_DRM_CANNOT_HANDLE; } value = mByteArrayProperties.valueAt(index); return android::OK; } status_t DrmPlugin::setPropertyByteArray( const String8& name, const Vector& value) { UNUSED(value); if (0 == name.compare(kDeviceIdKey)) { ALOGD("Cannot set immutable property: %s", name.string()); return android::ERROR_DRM_CANNOT_HANDLE; } // Setting of undefined properties is not supported ALOGE("Failed to set property byte array, key=%s", name.string()); return android::ERROR_DRM_CANNOT_HANDLE; } status_t DrmPlugin::getPropertyString( const String8& name, String8& value) const { ssize_t index = mStringProperties.indexOfKey(name); if (index < 0) { ALOGE("App requested unknown property: %s", name.string()); return android::ERROR_DRM_CANNOT_HANDLE; } value = mStringProperties.valueAt(index); return android::OK; } status_t DrmPlugin::setPropertyString( const String8& name, const String8& value) { String8 immutableKeys; immutableKeys.appendFormat("%s,%s,%s,%s", kAlgorithmsKey.string(), kPluginDescriptionKey.string(), kVendorKey.string(), kVersionKey.string()); if (immutableKeys.contains(name.string())) { ALOGD("Cannot set immutable property: %s", name.string()); return android::ERROR_DRM_CANNOT_HANDLE; } ssize_t index = mStringProperties.indexOfKey(name); if (index < 0) { ALOGE("Cannot set undefined property string, key=%s", name.string()); return android::ERROR_DRM_CANNOT_HANDLE; } if (mStringProperties.add(name, value) < 0) { ALOGE("Failed to set property string, key=%s", name.string()); return android::ERROR_DRM_UNKNOWN; } return android::OK; } status_t DrmPlugin::queryKeyStatus( const Vector& sessionId, KeyedVector& infoMap) const { if (sessionId.size() == 0) { return android::BAD_VALUE; } infoMap.clear(); android::Mutex::Autolock lock(mPlayPolicyLock); for (size_t i = 0; i < mPlayPolicy.size(); ++i) { infoMap.add(mPlayPolicy.keyAt(i), mPlayPolicy.valueAt(i)); } return android::OK; } } // namespace clearkeydrm