1030 lines
39 KiB
C++
1030 lines
39 KiB
C++
/*
|
|
* Copyright (C) 2021 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_TAG "clearkey-DrmPlugin"
|
|
|
|
#include <aidl/android/hardware/drm/DrmMetric.h>
|
|
#include <utils/Log.h>
|
|
|
|
#include <inttypes.h>
|
|
#include <stdio.h>
|
|
#include <chrono>
|
|
#include <set>
|
|
|
|
#include "AidlUtils.h"
|
|
#include "ClearKeyDrmProperties.h"
|
|
#include "DrmPlugin.h"
|
|
#include "Session.h"
|
|
#include "Utils.h"
|
|
#include "AidlClearKeryProperties.h"
|
|
|
|
namespace {
|
|
const std::string kKeySetIdPrefix("ckid");
|
|
const int kKeySetIdLength = 16;
|
|
const int kSecureStopIdStart = 100;
|
|
const std::string kOfflineLicense("\"type\":\"persistent-license\"");
|
|
const std::string kStreaming("Streaming");
|
|
const std::string kTemporaryLicense("\"type\":\"temporary\"");
|
|
const std::string kTrue("True");
|
|
|
|
const std::string kQueryKeyLicenseType("LicenseType");
|
|
// Value: "Streaming" or "Offline"
|
|
const std::string kQueryKeyPlayAllowed("PlayAllowed");
|
|
// Value: "True" or "False"
|
|
const std::string kQueryKeyRenewAllowed("RenewAllowed");
|
|
// Value: "True" or "False"
|
|
|
|
const int kSecureStopIdSize = 10;
|
|
|
|
std::vector<uint8_t> uint32ToVector(uint32_t value) {
|
|
// 10 bytes to display max value 4294967295 + one byte null terminator
|
|
char buffer[kSecureStopIdSize];
|
|
memset(buffer, 0, kSecureStopIdSize);
|
|
snprintf(buffer, kSecureStopIdSize, "%" PRIu32, value);
|
|
return std::vector<uint8_t>(buffer, buffer + sizeof(buffer));
|
|
}
|
|
|
|
}; // unnamed namespace
|
|
|
|
namespace aidl {
|
|
namespace android {
|
|
namespace hardware {
|
|
namespace drm {
|
|
namespace clearkey {
|
|
|
|
using ::android::Mutex;
|
|
|
|
DrmPlugin::DrmPlugin(SessionLibrary* sessionLibrary)
|
|
: mSessionLibrary(sessionLibrary),
|
|
mOpenSessionOkCount(0),
|
|
mCloseSessionOkCount(0),
|
|
mCloseSessionNotOpenedCount(0),
|
|
mNextSecureStopId(kSecureStopIdStart),
|
|
mMockError(Status::OK) {
|
|
mPlayPolicy.clear();
|
|
initProperties();
|
|
mSecureStops.clear();
|
|
mReleaseKeysMap.clear();
|
|
std::srand(std::time(nullptr));
|
|
}
|
|
|
|
void DrmPlugin::initProperties() {
|
|
mStringProperties.clear();
|
|
mStringProperties[kVendorKey] = kAidlVendorValue;
|
|
mStringProperties[kVersionKey] = kAidlVersionValue;
|
|
mStringProperties[kPluginDescriptionKey] = kAidlPluginDescriptionValue;
|
|
mStringProperties[kAlgorithmsKey] = kAidlAlgorithmsValue;
|
|
mStringProperties[kListenerTestSupportKey] = kAidlListenerTestSupportValue;
|
|
mStringProperties[kDrmErrorTestKey] = kAidlDrmErrorTestValue;
|
|
mStringProperties[kAidlVersionKey] = kAidlVersionValue;
|
|
|
|
std::vector<uint8_t> valueVector;
|
|
valueVector.clear();
|
|
valueVector.insert(valueVector.end(), kTestDeviceIdData,
|
|
kTestDeviceIdData + sizeof(kTestDeviceIdData) / sizeof(uint8_t));
|
|
mByteArrayProperties[kDeviceIdKey] = valueVector;
|
|
|
|
valueVector.clear();
|
|
valueVector.insert(valueVector.end(), kMetricsData,
|
|
kMetricsData + sizeof(kMetricsData) / sizeof(uint8_t));
|
|
mByteArrayProperties[kMetricsKey] = valueVector;
|
|
}
|
|
|
|
// The secure stop in ClearKey implementation is not installed securely.
|
|
// This function merely creates a test environment for testing secure stops APIs.
|
|
// The content in this secure stop is implementation dependent, the clearkey
|
|
// secureStop does not serve as a reference implementation.
|
|
void DrmPlugin::installSecureStop(const std::vector<uint8_t>& sessionId) {
|
|
::android::Mutex::Autolock lock(mSecureStopLock);
|
|
|
|
ClearkeySecureStop clearkeySecureStop;
|
|
clearkeySecureStop.id = uint32ToVector(++mNextSecureStopId);
|
|
clearkeySecureStop.data.assign(sessionId.begin(), sessionId.end());
|
|
|
|
mSecureStops.insert(std::pair<std::vector<uint8_t>, ClearkeySecureStop>(clearkeySecureStop.id,
|
|
clearkeySecureStop));
|
|
}
|
|
|
|
::ndk::ScopedAStatus DrmPlugin::closeSession(const std::vector<uint8_t>& in_sessionId) {
|
|
if (in_sessionId.size() == 0) {
|
|
return toNdkScopedAStatus(Status::BAD_VALUE);
|
|
}
|
|
|
|
::android::sp<Session> session = mSessionLibrary->findSession(in_sessionId);
|
|
if (session.get()) {
|
|
mSessionLibrary->destroySession(session);
|
|
if (session->getMockError() != clearkeydrm::OK) {
|
|
sendSessionLostState(in_sessionId);
|
|
return toNdkScopedAStatus(Status::ERROR_DRM_INVALID_STATE);
|
|
}
|
|
mCloseSessionOkCount++;
|
|
return toNdkScopedAStatus(Status::OK);
|
|
}
|
|
mCloseSessionNotOpenedCount++;
|
|
return toNdkScopedAStatus(Status::ERROR_DRM_SESSION_NOT_OPENED);
|
|
}
|
|
|
|
::ndk::ScopedAStatus DrmPlugin::decrypt(const std::vector<uint8_t>& in_sessionId,
|
|
const std::vector<uint8_t>& in_keyId,
|
|
const std::vector<uint8_t>& in_input,
|
|
const std::vector<uint8_t>& in_iv,
|
|
std::vector<uint8_t>* _aidl_return) {
|
|
*_aidl_return = {};
|
|
if (in_sessionId.size() == 0 || in_keyId.size() == 0 || in_input.size() == 0 ||
|
|
in_iv.size() == 0) {
|
|
return toNdkScopedAStatus(Status::BAD_VALUE);
|
|
}
|
|
return toNdkScopedAStatus(Status::ERROR_DRM_CANNOT_HANDLE);
|
|
}
|
|
|
|
::ndk::ScopedAStatus DrmPlugin::encrypt(const std::vector<uint8_t>& in_sessionId,
|
|
const std::vector<uint8_t>& in_keyId,
|
|
const std::vector<uint8_t>& in_input,
|
|
const std::vector<uint8_t>& in_iv,
|
|
std::vector<uint8_t>* _aidl_return) {
|
|
*_aidl_return = {};
|
|
if (in_sessionId.size() == 0 || in_keyId.size() == 0 || in_input.size() == 0 ||
|
|
in_iv.size() == 0) {
|
|
return toNdkScopedAStatus(Status::BAD_VALUE);
|
|
}
|
|
return toNdkScopedAStatus(Status::ERROR_DRM_CANNOT_HANDLE);
|
|
}
|
|
|
|
::ndk::ScopedAStatus DrmPlugin::getHdcpLevels(
|
|
::aidl::android::hardware::drm::HdcpLevels* _aidl_return) {
|
|
_aidl_return->connectedLevel = HdcpLevel::HDCP_NONE;
|
|
_aidl_return->maxLevel = HdcpLevel::HDCP_NO_OUTPUT;
|
|
return toNdkScopedAStatus(Status::OK);
|
|
}
|
|
|
|
::ndk::ScopedAStatus DrmPlugin::getKeyRequest(
|
|
const std::vector<uint8_t>& in_scope, const std::vector<uint8_t>& in_initData,
|
|
const std::string& in_mimeType, ::aidl::android::hardware::drm::KeyType in_keyType,
|
|
const std::vector<::aidl::android::hardware::drm::KeyValue>& in_optionalParameters,
|
|
::aidl::android::hardware::drm::KeyRequest* _aidl_return) {
|
|
UNUSED(in_optionalParameters);
|
|
|
|
KeyRequestType keyRequestType = KeyRequestType::UNKNOWN;
|
|
std::string defaultUrl("https://default.url");
|
|
|
|
_aidl_return->request = {};
|
|
_aidl_return->requestType = keyRequestType;
|
|
_aidl_return->defaultUrl = defaultUrl;
|
|
|
|
if (in_scope.size() == 0 ||
|
|
(in_keyType != KeyType::STREAMING && in_keyType != KeyType::OFFLINE &&
|
|
in_keyType != KeyType::RELEASE)) {
|
|
return toNdkScopedAStatus(Status::BAD_VALUE);
|
|
}
|
|
|
|
const std::vector<uint8_t> scopeId = in_scope;
|
|
::android::sp<Session> session;
|
|
std::set<KeyType> init_types{KeyType::STREAMING, KeyType::OFFLINE};
|
|
if (init_types.count(in_keyType)) {
|
|
std::vector<uint8_t> sessionId(scopeId.begin(), scopeId.end());
|
|
session = mSessionLibrary->findSession(sessionId);
|
|
if (!session.get()) {
|
|
return toNdkScopedAStatus(Status::ERROR_DRM_SESSION_NOT_OPENED);
|
|
} else if (session->getMockError() != clearkeydrm::OK) {
|
|
return toNdkScopedAStatus(session->getMockError());
|
|
}
|
|
keyRequestType = KeyRequestType::INITIAL;
|
|
}
|
|
|
|
std::vector<uint8_t> request = {};
|
|
auto keyType = static_cast<CdmKeyType>(in_keyType);
|
|
auto status = session->getKeyRequest(in_initData, in_mimeType, keyType, &request);
|
|
|
|
if (in_keyType == KeyType::RELEASE) {
|
|
std::vector<uint8_t> keySetId(scopeId.begin(), scopeId.end());
|
|
std::string requestString(request.begin(), request.end());
|
|
if (requestString.find(kOfflineLicense) != std::string::npos) {
|
|
std::string emptyResponse;
|
|
std::string keySetIdString(keySetId.begin(), keySetId.end());
|
|
if (!mFileHandle.StoreLicense(keySetIdString, DeviceFiles::kLicenseStateReleasing,
|
|
emptyResponse)) {
|
|
ALOGE("Problem releasing offline license");
|
|
return toNdkScopedAStatus(Status::ERROR_DRM_UNKNOWN);
|
|
}
|
|
if (mReleaseKeysMap.find(keySetIdString) == mReleaseKeysMap.end()) {
|
|
::android::sp<Session> session = mSessionLibrary->createSession();
|
|
mReleaseKeysMap[keySetIdString] = session->sessionId();
|
|
} else {
|
|
ALOGI("key is in use, ignore release request");
|
|
}
|
|
} else {
|
|
ALOGE("Offline license not found, nothing to release");
|
|
}
|
|
keyRequestType = KeyRequestType::RELEASE;
|
|
}
|
|
_aidl_return->request = request;
|
|
_aidl_return->requestType = keyRequestType;
|
|
_aidl_return->defaultUrl = defaultUrl;
|
|
return toNdkScopedAStatus(status);
|
|
}
|
|
|
|
::ndk::ScopedAStatus DrmPlugin::getLogMessages(
|
|
std::vector<::aidl::android::hardware::drm::LogMessage>* _aidl_return) {
|
|
using std::chrono::duration_cast;
|
|
using std::chrono::milliseconds;
|
|
using std::chrono::system_clock;
|
|
|
|
auto timeMillis = duration_cast<milliseconds>(system_clock::now().time_since_epoch()).count();
|
|
|
|
std::vector<::aidl::android::hardware::drm::LogMessage> logs = {
|
|
{timeMillis, ::aidl::android::hardware::drm::LogPriority::ERROR,
|
|
std::string("Not implemented")}};
|
|
*_aidl_return = logs;
|
|
return toNdkScopedAStatus(Status::OK);
|
|
}
|
|
|
|
::ndk::ScopedAStatus DrmPlugin::getMetrics(
|
|
std::vector<::aidl::android::hardware::drm::DrmMetricGroup>* _aidl_return) {
|
|
// Set the open session count metric.
|
|
DrmMetricNamedValue openSessionOkAttribute = {"status", static_cast<int64_t>(Status::OK)};
|
|
DrmMetricNamedValue openSessionMetricValue = {"count", mOpenSessionOkCount};
|
|
DrmMetric openSessionMetric = {
|
|
"open_session", {openSessionOkAttribute}, {openSessionMetricValue}};
|
|
|
|
// Set the close session count metric.
|
|
DrmMetricNamedValue closeSessionOkAttribute = {"status", static_cast<int64_t>(Status::OK)};
|
|
DrmMetricNamedValue closeSessionMetricValue = {"count", mCloseSessionOkCount};
|
|
DrmMetric closeSessionMetric = {
|
|
"close_session", {closeSessionOkAttribute}, {closeSessionMetricValue}};
|
|
|
|
// Set the close session, not opened metric.
|
|
DrmMetricNamedValue closeSessionNotOpenedAttribute = {"status",
|
|
static_cast<int64_t>(Status::ERROR_DRM_SESSION_NOT_OPENED)};
|
|
DrmMetricNamedValue closeSessionNotOpenedMetricValue = {"count", mCloseSessionNotOpenedCount};
|
|
DrmMetric closeSessionNotOpenedMetric = {
|
|
"close_session", {closeSessionNotOpenedAttribute}, {closeSessionNotOpenedMetricValue}};
|
|
|
|
// Set the setPlaybackId metric.
|
|
std::vector<DrmMetricNamedValue> sids = {};
|
|
std::vector<DrmMetricNamedValue> playbackIds = {};
|
|
for (const auto& [key, value] : mPlaybackId) {
|
|
std::string sid(key.begin(), key.end());
|
|
DrmMetricNamedValue sessionIdAttribute = {"sid", sid};
|
|
sids.push_back(sessionIdAttribute);
|
|
|
|
DrmMetricNamedValue playbackIdMetricValue = {"playbackId", value};
|
|
playbackIds.push_back(playbackIdMetricValue);
|
|
}
|
|
DrmMetric setPlaybackIdMetric = {"set_playback_id", sids, playbackIds};
|
|
|
|
DrmMetricGroup metrics = {{openSessionMetric, closeSessionMetric, closeSessionNotOpenedMetric,
|
|
setPlaybackIdMetric}};
|
|
|
|
*_aidl_return = {metrics};
|
|
return toNdkScopedAStatus(Status::OK);
|
|
}
|
|
|
|
::ndk::ScopedAStatus DrmPlugin::getNumberOfSessions(
|
|
::aidl::android::hardware::drm::NumberOfSessions* _aidl_return) {
|
|
_aidl_return->currentSessions = mSessionLibrary->numOpenSessions();
|
|
_aidl_return->maxSessions = 10;
|
|
return toNdkScopedAStatus(Status::OK);
|
|
}
|
|
|
|
::ndk::ScopedAStatus DrmPlugin::getOfflineLicenseKeySetIds(
|
|
std::vector<::aidl::android::hardware::drm::KeySetId>* _aidl_return) {
|
|
std::vector<std::string> licenseNames = mFileHandle.ListLicenses();
|
|
std::vector<KeySetId> keySetIds = {};
|
|
if (mMockError != Status::OK) {
|
|
*_aidl_return = keySetIds;
|
|
return toNdkScopedAStatus(toMockStatus(mMockError));
|
|
}
|
|
for (const auto& name : licenseNames) {
|
|
std::vector<uint8_t> keySetId(name.begin(), name.end());
|
|
KeySetId id = {};
|
|
id.keySetId = keySetId;
|
|
keySetIds.push_back(id);
|
|
}
|
|
*_aidl_return = keySetIds;
|
|
return toNdkScopedAStatus(Status::OK);
|
|
}
|
|
|
|
::ndk::ScopedAStatus DrmPlugin::getOfflineLicenseState(
|
|
const ::aidl::android::hardware::drm::KeySetId& in_keySetId,
|
|
::aidl::android::hardware::drm::OfflineLicenseState* _aidl_return) {
|
|
std::string licenseName(in_keySetId.keySetId.begin(), in_keySetId.keySetId.end());
|
|
DeviceFiles::LicenseState state;
|
|
std::string license;
|
|
OfflineLicenseState licenseState = OfflineLicenseState::UNKNOWN;
|
|
Status status = Status::OK;
|
|
if (mMockError != Status::OK) {
|
|
*_aidl_return = licenseState;
|
|
return toNdkScopedAStatus(toMockStatus(mMockError));
|
|
} else if (mFileHandle.RetrieveLicense(licenseName, &state, &license)) {
|
|
switch (state) {
|
|
case DeviceFiles::kLicenseStateActive:
|
|
licenseState = OfflineLicenseState::USABLE;
|
|
break;
|
|
case DeviceFiles::kLicenseStateReleasing:
|
|
licenseState = OfflineLicenseState::INACTIVE;
|
|
break;
|
|
case DeviceFiles::kLicenseStateUnknown:
|
|
licenseState = OfflineLicenseState::UNKNOWN;
|
|
break;
|
|
}
|
|
} else {
|
|
status = Status::BAD_VALUE;
|
|
}
|
|
*_aidl_return = licenseState;
|
|
return toNdkScopedAStatus(status);
|
|
}
|
|
|
|
::ndk::ScopedAStatus DrmPlugin::getPropertyByteArray(const std::string& in_propertyName,
|
|
std::vector<uint8_t>* _aidl_return) {
|
|
std::map<std::string, std::vector<uint8_t>>::iterator itr =
|
|
mByteArrayProperties.find(std::string(in_propertyName.c_str()));
|
|
Status status = Status::OK;
|
|
if (itr != mByteArrayProperties.end()) {
|
|
*_aidl_return = itr->second;
|
|
} else {
|
|
ALOGE("App requested unknown property: %s", in_propertyName.c_str());
|
|
status = Status::BAD_VALUE;
|
|
*_aidl_return = {};
|
|
}
|
|
return toNdkScopedAStatus(status);
|
|
}
|
|
|
|
::ndk::ScopedAStatus DrmPlugin::getPropertyString(const std::string& in_propertyName,
|
|
std::string* _aidl_return) {
|
|
std::string name(in_propertyName.c_str());
|
|
std::string value;
|
|
Status status = Status::OK;
|
|
|
|
if (name == kVendorKey) {
|
|
value = mStringProperties[kVendorKey];
|
|
} else if (name == kVersionKey) {
|
|
value = mStringProperties[kVersionKey];
|
|
} else if (name == kPluginDescriptionKey) {
|
|
value = mStringProperties[kPluginDescriptionKey];
|
|
} else if (name == kAlgorithmsKey) {
|
|
value = mStringProperties[kAlgorithmsKey];
|
|
} else if (name == kListenerTestSupportKey) {
|
|
value = mStringProperties[kListenerTestSupportKey];
|
|
} else if (name == kDrmErrorTestKey) {
|
|
value = mStringProperties[kDrmErrorTestKey];
|
|
} else if (name == kAidlVersionKey) {
|
|
value = mStringProperties[kAidlVersionKey];
|
|
} else {
|
|
ALOGE("App requested unknown string property %s", name.c_str());
|
|
status = Status::ERROR_DRM_CANNOT_HANDLE;
|
|
}
|
|
*_aidl_return = value;
|
|
return toNdkScopedAStatus(status);
|
|
}
|
|
|
|
::ndk::ScopedAStatus DrmPlugin::getProvisionRequest(
|
|
const std::string& in_certificateType, const std::string& in_certificateAuthority,
|
|
::aidl::android::hardware::drm::ProvisionRequest* _aidl_return) {
|
|
UNUSED(in_certificateType);
|
|
UNUSED(in_certificateAuthority);
|
|
_aidl_return->request = {};
|
|
_aidl_return->defaultUrl = {};
|
|
return toNdkScopedAStatus(Status::ERROR_DRM_CANNOT_HANDLE);
|
|
}
|
|
|
|
::ndk::ScopedAStatus DrmPlugin::getSecureStop(
|
|
const ::aidl::android::hardware::drm::SecureStopId& in_secureStopId,
|
|
::aidl::android::hardware::drm::SecureStop* _aidl_return) {
|
|
std::vector<uint8_t> stop = {};
|
|
|
|
mSecureStopLock.lock();
|
|
auto itr = mSecureStops.find(in_secureStopId.secureStopId);
|
|
if (itr != mSecureStops.end()) {
|
|
ClearkeySecureStop clearkeyStop = itr->second;
|
|
stop.insert(stop.end(), clearkeyStop.id.begin(), clearkeyStop.id.end());
|
|
stop.insert(stop.end(), clearkeyStop.data.begin(), clearkeyStop.data.end());
|
|
}
|
|
mSecureStopLock.unlock();
|
|
|
|
SecureStop secureStop = {};
|
|
Status status = Status::OK;
|
|
if (!stop.empty()) {
|
|
secureStop.opaqueData = stop;
|
|
} else {
|
|
status = Status::BAD_VALUE;
|
|
}
|
|
*_aidl_return = secureStop;
|
|
return toNdkScopedAStatus(status);
|
|
}
|
|
|
|
::ndk::ScopedAStatus DrmPlugin::getSecureStopIds(
|
|
std::vector<::aidl::android::hardware::drm::SecureStopId>* _aidl_return) {
|
|
mSecureStopLock.lock();
|
|
std::vector<::aidl::android::hardware::drm::SecureStopId> ids;
|
|
for (auto itr = mSecureStops.begin(); itr != mSecureStops.end(); ++itr) {
|
|
SecureStopId id;
|
|
id.secureStopId = itr->first;
|
|
ids.push_back(id);
|
|
}
|
|
mSecureStopLock.unlock();
|
|
|
|
*_aidl_return = ids;
|
|
return toNdkScopedAStatus(Status::OK);
|
|
}
|
|
|
|
::ndk::ScopedAStatus DrmPlugin::getSecureStops(
|
|
std::vector<::aidl::android::hardware::drm::SecureStop>* _aidl_return) {
|
|
mSecureStopLock.lock();
|
|
std::vector<::aidl::android::hardware::drm::SecureStop> stops;
|
|
for (auto itr = mSecureStops.begin(); itr != mSecureStops.end(); ++itr) {
|
|
ClearkeySecureStop clearkeyStop = itr->second;
|
|
std::vector<uint8_t> stop{};
|
|
stop.insert(stop.end(), clearkeyStop.id.begin(), clearkeyStop.id.end());
|
|
stop.insert(stop.end(), clearkeyStop.data.begin(), clearkeyStop.data.end());
|
|
|
|
SecureStop secureStop;
|
|
secureStop.opaqueData = stop;
|
|
stops.push_back(secureStop);
|
|
}
|
|
mSecureStopLock.unlock();
|
|
|
|
*_aidl_return = stops;
|
|
return toNdkScopedAStatus(Status::OK);
|
|
}
|
|
|
|
::ndk::ScopedAStatus DrmPlugin::getSecurityLevel(
|
|
const std::vector<uint8_t>& in_sessionId,
|
|
::aidl::android::hardware::drm::SecurityLevel* _aidl_return) {
|
|
if (in_sessionId.size() == 0) {
|
|
*_aidl_return = ::aidl::android::hardware::drm::SecurityLevel::UNKNOWN;
|
|
return toNdkScopedAStatus(Status::BAD_VALUE);
|
|
}
|
|
|
|
std::vector<uint8_t> sid = in_sessionId;
|
|
::android::sp<Session> session = mSessionLibrary->findSession(sid);
|
|
if (!session.get()) {
|
|
*_aidl_return = SecurityLevel::UNKNOWN;
|
|
return toNdkScopedAStatus(Status::ERROR_DRM_SESSION_NOT_OPENED);
|
|
}
|
|
|
|
std::map<std::vector<uint8_t>, ::aidl::android::hardware::drm::SecurityLevel>::iterator itr =
|
|
mSecurityLevel.find(sid);
|
|
if (itr == mSecurityLevel.end()) {
|
|
ALOGE("Session id not found");
|
|
*_aidl_return = SecurityLevel::UNKNOWN;
|
|
return toNdkScopedAStatus(Status::ERROR_DRM_INVALID_STATE);
|
|
}
|
|
|
|
*_aidl_return = SecurityLevel::SW_SECURE_CRYPTO;
|
|
return toNdkScopedAStatus(Status::OK);
|
|
}
|
|
|
|
::ndk::ScopedAStatus DrmPlugin::openSession(
|
|
::aidl::android::hardware::drm::SecurityLevel in_securityLevel,
|
|
std::vector<uint8_t>* _aidl_return) {
|
|
::android::sp<Session> session = mSessionLibrary->createSession();
|
|
processMockError(session);
|
|
std::vector<uint8_t> sessionId = session->sessionId();
|
|
|
|
Status status = setSecurityLevel(sessionId, in_securityLevel);
|
|
if (status == Status::OK) {
|
|
mOpenSessionOkCount++;
|
|
} else {
|
|
mSessionLibrary->destroySession(session);
|
|
sessionId.clear();
|
|
}
|
|
*_aidl_return = sessionId;
|
|
return toNdkScopedAStatus(status);
|
|
}
|
|
|
|
::ndk::ScopedAStatus DrmPlugin::provideKeyResponse(
|
|
const std::vector<uint8_t>& in_scope, const std::vector<uint8_t>& in_response,
|
|
::aidl::android::hardware::drm::KeySetId* _aidl_return) {
|
|
if (in_scope.size() == 0 || in_response.size() == 0) {
|
|
// Returns empty keySetId
|
|
*_aidl_return = {};
|
|
return toNdkScopedAStatus(Status::BAD_VALUE);
|
|
}
|
|
|
|
std::string responseString(reinterpret_cast<const char*>(in_response.data()),
|
|
in_response.size());
|
|
const std::vector<uint8_t> scopeId = in_scope;
|
|
std::vector<uint8_t> sessionId = {};
|
|
std::string keySetId;
|
|
|
|
bool isOfflineLicense = responseString.find(kOfflineLicense) != std::string::npos;
|
|
if (scopeId.size() < kKeySetIdPrefix.size()) {
|
|
android_errorWriteLog(0x534e4554, "144507096");
|
|
*_aidl_return = {};
|
|
return toNdkScopedAStatus(Status::ERROR_DRM_CANNOT_HANDLE);
|
|
}
|
|
bool isRelease = (memcmp(scopeId.data(), kKeySetIdPrefix.data(), kKeySetIdPrefix.size()) == 0);
|
|
if (isRelease) {
|
|
keySetId.assign(scopeId.begin(), scopeId.end());
|
|
|
|
auto iter = mReleaseKeysMap.find(std::string(keySetId.begin(), keySetId.end()));
|
|
if (iter != mReleaseKeysMap.end()) {
|
|
sessionId.assign(iter->second.begin(), iter->second.end());
|
|
}
|
|
} else {
|
|
sessionId.assign(scopeId.begin(), scopeId.end());
|
|
// non offline license returns empty keySetId
|
|
keySetId.clear();
|
|
}
|
|
|
|
::android::sp<Session> session = mSessionLibrary->findSession(sessionId);
|
|
if (!session.get()) {
|
|
*_aidl_return = {};
|
|
return toNdkScopedAStatus(Status::ERROR_DRM_SESSION_NOT_OPENED);
|
|
}
|
|
setPlayPolicy();
|
|
|
|
auto res = session->provideKeyResponse(in_response);
|
|
if (res == clearkeydrm::OK) {
|
|
if (isOfflineLicense) {
|
|
if (isRelease) {
|
|
mFileHandle.DeleteLicense(keySetId);
|
|
mSessionLibrary->destroySession(session);
|
|
} else {
|
|
if (!makeKeySetId(&keySetId)) {
|
|
*_aidl_return = {};
|
|
return toNdkScopedAStatus(Status::ERROR_DRM_UNKNOWN);
|
|
}
|
|
|
|
bool ok = mFileHandle.StoreLicense(
|
|
keySetId, DeviceFiles::kLicenseStateActive,
|
|
std::string(in_response.begin(), in_response.end()));
|
|
if (!ok) {
|
|
ALOGE("Failed to store offline license");
|
|
}
|
|
}
|
|
}
|
|
|
|
// Test calling AMediaDrm listeners.
|
|
sendEvent(EventType::VENDOR_DEFINED, sessionId, sessionId);
|
|
|
|
sendExpirationUpdate(sessionId, 100);
|
|
|
|
std::vector<KeyStatus> keysStatus = {};
|
|
KeyStatus keyStatus;
|
|
|
|
std::vector<uint8_t> keyId1 = {0xA, 0xB, 0xC};
|
|
keyStatus.keyId = keyId1;
|
|
keyStatus.type = KeyStatusType::USABLE;
|
|
keysStatus.push_back(keyStatus);
|
|
|
|
std::vector<uint8_t> keyId2 = {0xD, 0xE, 0xF};
|
|
keyStatus.keyId = keyId2;
|
|
keyStatus.type = KeyStatusType::EXPIRED;
|
|
keysStatus.push_back(keyStatus);
|
|
|
|
std::vector<uint8_t> keyId3 = {0x0, 0x1, 0x2};
|
|
keyStatus.keyId = keyId3;
|
|
keyStatus.type = KeyStatusType::USABLE_IN_FUTURE;
|
|
keysStatus.push_back(keyStatus);
|
|
|
|
sendKeysChange(sessionId, keysStatus, true);
|
|
|
|
installSecureStop(sessionId);
|
|
} else {
|
|
ALOGE("provideKeyResponse returns error=%d", res);
|
|
}
|
|
|
|
std::vector<uint8_t> keySetIdVec(keySetId.begin(), keySetId.end());
|
|
_aidl_return->keySetId = keySetIdVec;
|
|
return toNdkScopedAStatus(res);
|
|
}
|
|
|
|
::ndk::ScopedAStatus DrmPlugin::provideProvisionResponse(
|
|
const std::vector<uint8_t>& in_response,
|
|
::aidl::android::hardware::drm::ProvideProvisionResponseResult* _aidl_return) {
|
|
Status status = Status::ERROR_DRM_CANNOT_HANDLE;
|
|
_aidl_return->certificate = {};
|
|
_aidl_return->wrappedKey = {};
|
|
if (in_response.size() == 0) {
|
|
status = Status::BAD_VALUE;
|
|
}
|
|
return toNdkScopedAStatus(status);
|
|
}
|
|
|
|
::ndk::ScopedAStatus DrmPlugin::queryKeyStatus(
|
|
const std::vector<uint8_t>& in_sessionId,
|
|
std::vector<::aidl::android::hardware::drm::KeyValue>* _aidl_return) {
|
|
if (in_sessionId.size() == 0) {
|
|
// Returns empty key status KeyValue pair
|
|
*_aidl_return = {};
|
|
return toNdkScopedAStatus(Status::BAD_VALUE);
|
|
}
|
|
|
|
std::vector<KeyValue> infoMap = {};
|
|
mPlayPolicyLock.lock();
|
|
KeyValue keyValuePair;
|
|
for (size_t i = 0; i < mPlayPolicy.size(); ++i) {
|
|
keyValuePair.key = mPlayPolicy[i].key;
|
|
keyValuePair.value = mPlayPolicy[i].value;
|
|
infoMap.push_back(keyValuePair);
|
|
}
|
|
mPlayPolicyLock.unlock();
|
|
*_aidl_return = infoMap;
|
|
return toNdkScopedAStatus(Status::OK);
|
|
}
|
|
|
|
::ndk::ScopedAStatus DrmPlugin::releaseAllSecureStops() {
|
|
Status status = Status::OK;
|
|
const auto res = removeAllSecureStops();
|
|
if (!res.isOk() && res.getExceptionCode() == EX_SERVICE_SPECIFIC) {
|
|
status = static_cast<Status>(res.getServiceSpecificError());
|
|
}
|
|
return toNdkScopedAStatus(status);
|
|
}
|
|
|
|
::ndk::ScopedAStatus DrmPlugin::releaseSecureStop(
|
|
const ::aidl::android::hardware::drm::SecureStopId& in_secureStopId) {
|
|
Status status = Status::OK;
|
|
const auto res = removeSecureStop(in_secureStopId);
|
|
if (!res.isOk() && res.getExceptionCode() == EX_SERVICE_SPECIFIC) {
|
|
status = static_cast<Status>(res.getServiceSpecificError());
|
|
}
|
|
return toNdkScopedAStatus(status);
|
|
}
|
|
|
|
::ndk::ScopedAStatus DrmPlugin::releaseSecureStops(
|
|
const ::aidl::android::hardware::drm::OpaqueData& in_ssRelease) {
|
|
// OpaqueData starts with 4 byte decimal integer string
|
|
const size_t kFourBytesOffset = 4;
|
|
if (in_ssRelease.opaqueData.size() < kFourBytesOffset) {
|
|
ALOGE("Invalid secureStopRelease length");
|
|
return toNdkScopedAStatus(Status::BAD_VALUE);
|
|
}
|
|
|
|
Status status = Status::OK;
|
|
std::vector<uint8_t> input = in_ssRelease.opaqueData;
|
|
|
|
if (input.size() < kSecureStopIdSize + kFourBytesOffset) {
|
|
// The minimum size of secure stop has to contain
|
|
// a 4 bytes count and one secureStop id
|
|
ALOGE("Total size of secureStops is too short");
|
|
return toNdkScopedAStatus(Status::BAD_VALUE);
|
|
}
|
|
|
|
// The format of opaqueData is shared between the server
|
|
// and the drm service. The clearkey implementation consists of:
|
|
// count - number of secure stops
|
|
// list of fixed length secure stops
|
|
size_t countBufferSize = sizeof(uint32_t);
|
|
if (input.size() < countBufferSize) {
|
|
// SafetyNet logging
|
|
android_errorWriteLog(0x534e4554, "144766455");
|
|
return toNdkScopedAStatus(Status::BAD_VALUE);
|
|
}
|
|
uint32_t count = 0;
|
|
sscanf(reinterpret_cast<char*>(input.data()), "%04" PRIu32, &count);
|
|
|
|
// Avoid divide by 0 below.
|
|
if (count == 0) {
|
|
ALOGE("Invalid 0 secureStop count");
|
|
return toNdkScopedAStatus(Status::BAD_VALUE);
|
|
}
|
|
|
|
// Computes the fixed length secureStop size
|
|
size_t secureStopSize = (input.size() - kFourBytesOffset) / count;
|
|
if (secureStopSize < kSecureStopIdSize) {
|
|
// A valid secureStop contains the id plus data
|
|
ALOGE("Invalid secureStop size");
|
|
return toNdkScopedAStatus(Status::BAD_VALUE);
|
|
}
|
|
uint8_t* buffer = new uint8_t[secureStopSize];
|
|
size_t offset = kFourBytesOffset; // skip the count
|
|
for (size_t i = 0; i < count; ++i, offset += secureStopSize) {
|
|
memcpy(buffer, input.data() + offset, secureStopSize);
|
|
|
|
// A secureStop contains id+data, we only use the id for removal
|
|
std::vector<uint8_t> id(buffer, buffer + kSecureStopIdSize);
|
|
::aidl::android::hardware::drm::SecureStopId secureStopId{id};
|
|
const auto res = removeSecureStop(secureStopId);
|
|
if (!res.isOk() && res.getExceptionCode() == EX_SERVICE_SPECIFIC) {
|
|
status = static_cast<Status>(res.getServiceSpecificError());
|
|
}
|
|
if (Status::OK != status) break;
|
|
}
|
|
|
|
delete[] buffer;
|
|
return toNdkScopedAStatus(status);
|
|
}
|
|
|
|
::ndk::ScopedAStatus DrmPlugin::removeAllSecureStops() {
|
|
Mutex::Autolock lock(mSecureStopLock);
|
|
|
|
mSecureStops.clear();
|
|
mNextSecureStopId = kSecureStopIdStart;
|
|
return toNdkScopedAStatus(Status::OK);
|
|
}
|
|
|
|
::ndk::ScopedAStatus DrmPlugin::removeKeys(const std::vector<uint8_t>& in_sessionId) {
|
|
Status status = Status::ERROR_DRM_CANNOT_HANDLE;
|
|
if (in_sessionId.size() == 0) {
|
|
status = Status::BAD_VALUE;
|
|
}
|
|
return toNdkScopedAStatus(status);
|
|
}
|
|
|
|
::ndk::ScopedAStatus DrmPlugin::removeOfflineLicense(
|
|
const ::aidl::android::hardware::drm::KeySetId& in_keySetId) {
|
|
if (mMockError != Status::OK) {
|
|
return toNdkScopedAStatus(toMockStatus(mMockError));
|
|
}
|
|
Status status = Status::BAD_VALUE;
|
|
std::string licenseName(in_keySetId.keySetId.begin(), in_keySetId.keySetId.end());
|
|
if (mFileHandle.DeleteLicense(licenseName)) {
|
|
status = Status::OK;
|
|
}
|
|
return toNdkScopedAStatus(status);
|
|
}
|
|
|
|
::ndk::ScopedAStatus DrmPlugin::removeSecureStop(
|
|
const ::aidl::android::hardware::drm::SecureStopId& in_secureStopId) {
|
|
Mutex::Autolock lock(mSecureStopLock);
|
|
|
|
Status status = Status::OK;
|
|
if (1 != mSecureStops.erase(in_secureStopId.secureStopId)) {
|
|
status = Status::BAD_VALUE;
|
|
}
|
|
return toNdkScopedAStatus(status);
|
|
}
|
|
|
|
::ndk::ScopedAStatus DrmPlugin::requiresSecureDecoder(
|
|
const std::string& in_mime, ::aidl::android::hardware::drm::SecurityLevel in_level,
|
|
bool* _aidl_return) {
|
|
UNUSED(in_mime);
|
|
UNUSED(in_level);
|
|
*_aidl_return = false;
|
|
return ::ndk::ScopedAStatus::ok();
|
|
}
|
|
|
|
::ndk::ScopedAStatus DrmPlugin::restoreKeys(
|
|
const std::vector<uint8_t>& in_sessionId,
|
|
const ::aidl::android::hardware::drm::KeySetId& in_keySetId) {
|
|
if (in_sessionId.size() == 0 || in_keySetId.keySetId.size() == 0) {
|
|
return toNdkScopedAStatus(Status::BAD_VALUE);
|
|
}
|
|
|
|
DeviceFiles::LicenseState licenseState;
|
|
std::string offlineLicense;
|
|
if (!mFileHandle.RetrieveLicense(
|
|
std::string(in_keySetId.keySetId.begin(), in_keySetId.keySetId.end()),
|
|
&licenseState, &offlineLicense)) {
|
|
ALOGE("Failed to restore offline license");
|
|
return toNdkScopedAStatus(Status::ERROR_DRM_NO_LICENSE);
|
|
}
|
|
|
|
if (DeviceFiles::kLicenseStateUnknown == licenseState ||
|
|
DeviceFiles::kLicenseStateReleasing == licenseState) {
|
|
ALOGE("Invalid license state=%d", licenseState);
|
|
return toNdkScopedAStatus(Status::ERROR_DRM_NO_LICENSE);
|
|
}
|
|
|
|
::android::sp<Session> session = mSessionLibrary->findSession(in_sessionId);
|
|
if (!session.get()) {
|
|
return toNdkScopedAStatus(Status::ERROR_DRM_SESSION_NOT_OPENED);
|
|
}
|
|
auto res = session->provideKeyResponse(
|
|
std::vector<uint8_t>(offlineLicense.begin(), offlineLicense.end()));
|
|
if (res != clearkeydrm::OK) {
|
|
ALOGE("Failed to restore keys");
|
|
}
|
|
return toNdkScopedAStatus(res);
|
|
}
|
|
|
|
void DrmPlugin::sendEvent(::aidl::android::hardware::drm::EventType in_eventType,
|
|
const std::vector<uint8_t>& in_sessionId,
|
|
const std::vector<uint8_t>& in_data) {
|
|
if (mListener != nullptr) {
|
|
mListener->onEvent(in_eventType, in_sessionId, in_data);
|
|
} else {
|
|
ALOGE("Null event listener, event not sent");
|
|
}
|
|
return;
|
|
}
|
|
|
|
void DrmPlugin::sendExpirationUpdate(const std::vector<uint8_t>& in_sessionId,
|
|
int64_t in_expiryTimeInMS) {
|
|
if (mListener != nullptr) {
|
|
mListener->onExpirationUpdate(in_sessionId, in_expiryTimeInMS);
|
|
} else {
|
|
ALOGE("Null event listener, event not sent");
|
|
}
|
|
return;
|
|
}
|
|
|
|
void DrmPlugin::sendKeysChange(
|
|
const std::vector<uint8_t>& in_sessionId,
|
|
const std::vector<::aidl::android::hardware::drm::KeyStatus>& in_keyStatusList,
|
|
bool in_hasNewUsableKey) {
|
|
if (mListener != nullptr) {
|
|
mListener->onKeysChange(in_sessionId, in_keyStatusList, in_hasNewUsableKey);
|
|
} else {
|
|
ALOGE("Null event listener, event not sent");
|
|
}
|
|
return;
|
|
}
|
|
|
|
void DrmPlugin::sendSessionLostState(const std::vector<uint8_t>& in_sessionId) {
|
|
if (mListener != nullptr) {
|
|
mListener->onSessionLostState(in_sessionId);
|
|
}
|
|
return;
|
|
}
|
|
|
|
::ndk::ScopedAStatus DrmPlugin::setCipherAlgorithm(const std::vector<uint8_t>& /*in_sessionId*/,
|
|
const std::string& /*in_algorithm*/) {
|
|
return toNdkScopedAStatus(Status::ERROR_DRM_CANNOT_HANDLE);
|
|
}
|
|
|
|
::ndk::ScopedAStatus DrmPlugin::setListener(
|
|
const std::shared_ptr<
|
|
::aidl::android::hardware::drm::IDrmPluginListener>& in_listener) {
|
|
mListener = in_listener;
|
|
return toNdkScopedAStatus(Status::OK);
|
|
}
|
|
|
|
::ndk::ScopedAStatus DrmPlugin::setMacAlgorithm(const std::vector<uint8_t>& /*in_sessionId*/,
|
|
const std::string& /*in_algorithm*/) {
|
|
return toNdkScopedAStatus(Status::ERROR_DRM_CANNOT_HANDLE);
|
|
}
|
|
|
|
::ndk::ScopedAStatus DrmPlugin::setPlaybackId(const std::vector<uint8_t>& in_sessionId,
|
|
const std::string& in_playbackId) {
|
|
if (in_sessionId.size() == 0) {
|
|
ALOGE("Invalid empty session id");
|
|
return toNdkScopedAStatus(Status::BAD_VALUE);
|
|
}
|
|
|
|
std::vector<uint8_t> sid = in_sessionId;
|
|
mPlaybackId[sid] = in_playbackId;
|
|
return toNdkScopedAStatus(Status::OK);
|
|
}
|
|
|
|
::ndk::ScopedAStatus DrmPlugin::setPropertyByteArray(const std::string& in_propertyName,
|
|
const std::vector<uint8_t>& in_value) {
|
|
if (in_propertyName == kDeviceIdKey) {
|
|
ALOGD("Cannot set immutable property: %s", in_propertyName.c_str());
|
|
return toNdkScopedAStatus(Status::BAD_VALUE);
|
|
} else if (in_propertyName == kClientIdKey) {
|
|
mByteArrayProperties[kClientIdKey] = in_value;
|
|
return toNdkScopedAStatus(Status::OK);
|
|
}
|
|
|
|
// Setting of undefined properties is not supported
|
|
ALOGE("Failed to set property byte array, key=%s", in_propertyName.c_str());
|
|
return toNdkScopedAStatus(Status::ERROR_DRM_CANNOT_HANDLE);
|
|
}
|
|
|
|
::ndk::ScopedAStatus DrmPlugin::setPropertyString(const std::string& in_propertyName,
|
|
const std::string& in_value) {
|
|
std::string immutableKeys;
|
|
immutableKeys.append(kAlgorithmsKey + ",");
|
|
immutableKeys.append(kPluginDescriptionKey + ",");
|
|
immutableKeys.append(kVendorKey + ",");
|
|
immutableKeys.append(kVersionKey + ",");
|
|
|
|
std::string key = std::string(in_propertyName.c_str());
|
|
if (immutableKeys.find(key) != std::string::npos) {
|
|
ALOGD("Cannot set immutable property: %s", key.c_str());
|
|
return toNdkScopedAStatus(Status::BAD_VALUE);
|
|
}
|
|
|
|
std::map<std::string, std::string>::iterator itr = mStringProperties.find(key);
|
|
if (itr == mStringProperties.end()) {
|
|
ALOGE("Cannot set undefined property string, key=%s", key.c_str());
|
|
return toNdkScopedAStatus(Status::BAD_VALUE);
|
|
}
|
|
|
|
if (in_propertyName == kDrmErrorTestKey) {
|
|
if (in_value == kResourceContentionValue) {
|
|
mMockError = Status::ERROR_DRM_RESOURCE_CONTENTION;
|
|
} else if (in_value == kLostStateValue) {
|
|
mMockError = Status::ERROR_DRM_SESSION_LOST_STATE;
|
|
} else if (in_value == kFrameTooLargeValue) {
|
|
mMockError = Status::ERROR_DRM_FRAME_TOO_LARGE;
|
|
} else if (in_value == kInvalidStateValue) {
|
|
mMockError = Status::ERROR_DRM_INVALID_STATE;
|
|
} else {
|
|
mMockError = Status::ERROR_DRM_UNKNOWN;
|
|
}
|
|
}
|
|
|
|
mStringProperties[key] = std::string(in_value.c_str());
|
|
return toNdkScopedAStatus(Status::OK);
|
|
}
|
|
|
|
::ndk::ScopedAStatus DrmPlugin::sign(const std::vector<uint8_t>& /*in_sessionId*/,
|
|
const std::vector<uint8_t>& /*in_keyId*/,
|
|
const std::vector<uint8_t>& /*in_message*/,
|
|
std::vector<uint8_t>* _aidl_return) {
|
|
*_aidl_return = {};
|
|
return toNdkScopedAStatus(Status::ERROR_DRM_CANNOT_HANDLE);
|
|
}
|
|
|
|
::ndk::ScopedAStatus DrmPlugin::signRSA(const std::vector<uint8_t>& /*in_sessionId*/,
|
|
const std::string& /*in_algorithm*/,
|
|
const std::vector<uint8_t>& /*in_message*/,
|
|
const std::vector<uint8_t>& /*in_wrappedkey*/,
|
|
std::vector<uint8_t>* _aidl_return) {
|
|
*_aidl_return = {};
|
|
return toNdkScopedAStatus(Status::ERROR_DRM_CANNOT_HANDLE);
|
|
}
|
|
|
|
::ndk::ScopedAStatus DrmPlugin::verify(const std::vector<uint8_t>& /*in_sessionId*/,
|
|
const std::vector<uint8_t>& /*in_keyId*/,
|
|
const std::vector<uint8_t>& /*in_message*/,
|
|
const std::vector<uint8_t>& /*in_signature*/,
|
|
bool* _aidl_return) {
|
|
*_aidl_return = false;
|
|
return toNdkScopedAStatus(Status::ERROR_DRM_CANNOT_HANDLE);
|
|
}
|
|
|
|
// Private methods below.
|
|
void DrmPlugin::setPlayPolicy() {
|
|
::android::Mutex::Autolock lock(mPlayPolicyLock);
|
|
mPlayPolicy.clear();
|
|
|
|
KeyValue policy;
|
|
policy.key = kQueryKeyLicenseType;
|
|
policy.value = kStreaming;
|
|
mPlayPolicy.push_back(policy);
|
|
|
|
policy.key = kQueryKeyPlayAllowed;
|
|
policy.value = kTrue;
|
|
mPlayPolicy.push_back(policy);
|
|
|
|
policy.key = kQueryKeyRenewAllowed;
|
|
mPlayPolicy.push_back(policy);
|
|
}
|
|
|
|
bool DrmPlugin::makeKeySetId(std::string* keySetId) {
|
|
if (!keySetId) {
|
|
ALOGE("keySetId destination not provided");
|
|
return false;
|
|
}
|
|
std::vector<uint8_t> ksid(kKeySetIdPrefix.begin(), kKeySetIdPrefix.end());
|
|
ksid.resize(kKeySetIdLength);
|
|
std::vector<uint8_t> randomData((kKeySetIdLength - kKeySetIdPrefix.size()) / 2, 0);
|
|
|
|
while (keySetId->empty()) {
|
|
for (auto itr = randomData.begin(); itr != randomData.end(); ++itr) {
|
|
*itr = std::rand() % 0xff;
|
|
}
|
|
auto id = reinterpret_cast<const uint8_t*>(randomData.data());
|
|
*keySetId = kKeySetIdPrefix + ::android::ByteArrayToHexString(id, randomData.size());
|
|
if (mFileHandle.LicenseExists(*keySetId)) {
|
|
// collision, regenerate
|
|
ALOGV("Retry generating KeySetId");
|
|
keySetId->clear();
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
Status DrmPlugin::setSecurityLevel(const std::vector<uint8_t>& sessionId, SecurityLevel level) {
|
|
if (sessionId.size() == 0) {
|
|
ALOGE("Invalid empty session id");
|
|
return Status::BAD_VALUE;
|
|
}
|
|
|
|
if (level != SecurityLevel::DEFAULT && level != SecurityLevel::SW_SECURE_CRYPTO) {
|
|
ALOGE("Cannot set security level > max");
|
|
return Status::ERROR_DRM_CANNOT_HANDLE;
|
|
}
|
|
|
|
std::vector<uint8_t> sid = sessionId;
|
|
::android::sp<Session> session = mSessionLibrary->findSession(sid);
|
|
if (!session.get()) {
|
|
return Status::ERROR_DRM_SESSION_NOT_OPENED;
|
|
}
|
|
|
|
std::map<std::vector<uint8_t>, SecurityLevel>::iterator itr = mSecurityLevel.find(sid);
|
|
if (itr != mSecurityLevel.end()) {
|
|
mSecurityLevel[sid] = level;
|
|
} else {
|
|
if (!mSecurityLevel.insert(std::pair<std::vector<uint8_t>, SecurityLevel>(sid, level))
|
|
.second) {
|
|
ALOGE("Failed to set security level");
|
|
return Status::ERROR_DRM_INVALID_STATE;
|
|
}
|
|
}
|
|
return Status::OK;
|
|
}
|
|
|
|
} // namespace clearkey
|
|
} // namespace drm
|
|
} // namespace hardware
|
|
} // namespace android
|
|
} // namespace aidl
|