* Copyright (c) 2023 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <hdf_base.h>
#include <hdf_log.h>
#include "v1_0/media_key_system_service.h"
#include "v1_0/media_key_session_service.h"
#include "base64_utils.h"
#include "data_parser.h"
#include "securec.h"
#define HDF_LOG_TAG media_key_system_service
namespace OHOS {
namespace HDI {
namespace Drm {
namespace V1_0 {
MediaKeySystemService::~MediaKeySystemService()
{
HDF_LOGI("%{public}s: start", __func__);
mediaKeySessionMutex_.lock();
while (mediaKeySessionMap_.size() > 0) {
sptr<OHOS::HDI::Drm::V1_0::MediaKeySessionService> keySession = mediaKeySessionMap_.begin()->first;
mediaKeySessionMutex_.unlock();
CloseKeySessionService(keySession);
mediaKeySessionMutex_.lock();
}
mediaKeySessionMutex_.unlock();
HDF_LOGI("%{public}s: end", __func__);
}
int32_t MediaKeySystemService::GetConfigurationString(const std::string &name, std::string &value)
{
HDF_LOGI("%{public}s: start", __func__);
if (configurationString_.find(name) == configurationString_.end()) {
HDF_LOGE("%{public}s: do not find value, name: %{public}s", __func__, name.c_str());
return HDF_ERR_INVALID_PARAM;
}
value = configurationString_[name];
HDF_LOGI("%{public}s: end", __func__);
return HDF_SUCCESS;
}
int32_t MediaKeySystemService::SetConfigurationString(const std::string &name, const std::string &value)
{
HDF_LOGI("%{public}s: start", __func__);
configurationString_[name] = value;
HDF_LOGI("%{public}s: end", __func__);
return HDF_SUCCESS;
}
int32_t MediaKeySystemService::GetConfigurationByteArray(const std::string &name, std::vector<uint8_t> &value)
{
HDF_LOGI("%{public}s: start", __func__);
if (configuration_.find(name) == configuration_.end()) {
HDF_LOGE("%{public}s: do not find value, name: %{public}s", __func__, name.c_str());
return HDF_ERR_INVALID_PARAM;
}
value = configuration_[name];
HDF_LOGI("%{public}s: end", __func__);
return HDF_SUCCESS;
}
int32_t MediaKeySystemService::SetConfigurationByteArray(const std::string &name, const std::vector<uint8_t> &value)
{
HDF_LOGI("%{public}s: start", __func__);
configuration_[name] = value;
HDF_LOGI("%{public}s: end", __func__);
return HDF_SUCCESS;
}
void MediaKeySystemService::GetDecryptTimeAsString(std::vector<std::vector<double>> &topThreeTimes,
std::string &decryptTimes)
{
for (auto &time : topThreeTimes) {
if (!decryptTimes.empty()) {
decryptTimes.append(";");
}
for (auto it = time.begin(); it != time.end(); ++it) {
if (it != time.begin()) {
decryptTimes.append(",");
}
decryptTimes.append(std::to_string(*it));
}
}
}
int32_t MediaKeySystemService::GetStatistics(std::map<std::string, std::string> &statistics)
{
HDF_LOGI("%{public}s: start", __func__);
mediaKeySessionMutex_.lock();
int sessionNum = mediaKeySessionMap_.size();
int decryptNumber = 0;
int errorDecryptNumber = 0;
std::vector<std::vector<double>> topThreeTimes;
std::string decryptTimes;
for (auto &pair : mediaKeySessionMap_) {
decryptNumber += pair.first->GetDecryptNumber();
errorDecryptNumber += pair.first->GetErrorDecryptNumber();
std::vector<double> topThreeTime;
pair.first->GetDecryptTimes(topThreeTime);
topThreeTimes.push_back(topThreeTime);
}
GetDecryptTimeAsString(topThreeTimes, decryptTimes);
mediaKeySessionMutex_.unlock();
statistics[versionName] = "clearplay";
statistics[currentSessionNumName] = std::to_string(sessionNum);
statistics[decryptNumberName] = std::to_string(decryptNumber);
statistics[errorDecryptNumberName] = std::to_string(errorDecryptNumber);
statistics[decryptTime] = decryptTimes;
HDF_LOGI("%{public}s: end", __func__);
return HDF_SUCCESS;
}
int32_t MediaKeySystemService::GetMaxContentProtectionLevel(ContentProtectionLevel &level)
{
HDF_LOGI("%{public}s: start", __func__);
level = OHOS::HDI::Drm::V1_0::ContentProtectionLevel::SW_SECURE_CRYPTO;
HDF_LOGI("%{public}s: end", __func__);
return HDF_SUCCESS;
}
int32_t MediaKeySystemService::GenerateKeySystemRequest(std::string &defaultUrl, std::vector<uint8_t> &request)
{
HDF_LOGI("%{public}s: start", __func__);
defaultUrl = "http://default.com";
std::string requestData = "{\"signedRequest\":\"KEYREQUESTTYPE_DOWNLOADCERT\"}";
size_t requestDataLen = requestData.size();
request.assign(requestData.c_str(), requestData.c_str() + requestDataLen);
if (vdiCallbackObj != nullptr) {
std::string eventData = "PROVISIONRE QUIRED";
std::vector<uint8_t> data(eventData.begin(), eventData.end());
vdiCallbackObj->SendEvent(EVENTTYPE_PROVISIONREQUIRED, 0, data);
}
HDF_LOGI("%{public}s: end", __func__);
return HDF_SUCCESS;
}
int32_t MediaKeySystemService::ProcessKeySystemResponse(const std::vector<uint8_t> &response)
{
HDF_LOGI("%{public}s: start", __func__);
std::string responseData(response.begin(), response.end());
HDF_LOGI("%{public}s: response: %{public}s", __func__, responseData.c_str());
HDF_LOGI("%{public}s: end", __func__);
return HDF_SUCCESS;
}
int32_t MediaKeySystemService::CreateMediaKeySession(ContentProtectionLevel level,
sptr<OHOS::HDI::Drm::V1_0::IMediaKeySession> &keySession)
{
HDF_LOGI("%{public}s: start", __func__);
HDF_LOGI("%{public}s: start, level: %d", __func__, level);
sptr<MediaKeySessionService> keySessionService = nullptr;
keySessionService = new (std::nothrow) MediaKeySessionService(level);
if (keySessionService == nullptr) {
HDF_LOGE("MediaKeySystemService::CreateKeySession allocation failed");
return HDF_ERR_MALLOC_FAIL;
}
if (keySessionService->Init() != HDF_SUCCESS) {
HDF_LOGE("keySessionService::Init() failed");
delete keySessionService;
return HDF_ERR_MALLOC_FAIL;
}
keySessionService->SetKeySessionServiceCallback(this);
mediaKeySessionMutex_.lock();
mediaKeySessionMap_[keySessionService] = true;
mediaKeySessionMutex_.unlock();
keySession = keySessionService;
HDF_LOGI("%{public}s: end", __func__);
return HDF_SUCCESS;
}
int32_t MediaKeySystemService::GetOfflineMediaKeyIds(std::vector<std::vector<uint8_t>> &licenseIds)
{
HDF_LOGI("%{public}s: start", __func__);
offlineKeyMutex_.lock();
int32_t ret = GetOfflineKeyFromFile();
if (ret != HDF_SUCCESS) {
offlineKeyMutex_.unlock();
return ret;
}
for (auto &keyIdValueBase64Pair : offlineKeyIdAndKeyValueBase64_) {
std::string keyIdString = Decode(keyIdValueBase64Pair.first);
std::vector<uint8_t> keyId(keyIdString.begin(), keyIdString.end());
licenseIds.push_back(keyId);
}
offlineKeyIdAndKeyValueBase64_.clear();
offlineKeyMutex_.unlock();
HDF_LOGI("%{public}s: end", __func__);
return HDF_SUCCESS;
}
int32_t MediaKeySystemService::GetOfflineMediaKeyStatus(const std::vector<uint8_t> &licenseId,
OfflineMediaKeyStatus &licenseStatus)
{
HDF_LOGI("%{public}s: start", __func__);
offlineKeyMutex_.lock();
std::string keyIdString(licenseId.begin(), licenseId.end());
std::string keyIdBase64 = Encode(keyIdString);
int32_t ret = GetOfflineKeyFromFile();
if (ret != HDF_SUCCESS) {
offlineKeyMutex_.unlock();
return HDF_FAILURE;
}
keyIdBase64.erase(std::remove(keyIdBase64.begin(), keyIdBase64.end(), '\0'), keyIdBase64.end());
if (offlineKeyIdAndKeyValueBase64_.find(keyIdBase64) == offlineKeyIdAndKeyValueBase64_.end()) {
offlineKeyMutex_.unlock();
return HDF_FAILURE;
}
for (auto it = mediaKeySessionMap_.begin(); it != mediaKeySessionMap_.end(); ++it) {
if (it->second == false) {
continue;
}
licenseStatus = it->first->session_->keyIdStatusMap[licenseId];
}
offlineKeyMutex_.unlock();
HDF_LOGI("%{public}s: end", __func__);
return HDF_SUCCESS;
}
int32_t MediaKeySystemService::ClearOfflineMediaKeys(const std::vector<uint8_t> &licenseId)
{
HDF_LOGI("%{public}s: start", __func__);
offlineKeyMutex_.lock();
int32_t ret = GetOfflineKeyFromFile();
if (ret != HDF_SUCCESS) {
offlineKeyMutex_.unlock();
return ret;
}
std::string keyIdString(licenseId.begin(), licenseId.end());
std::string keyIdBase64 = Encode(keyIdString);
auto it = offlineKeyIdAndKeyValueBase64_.find(keyIdBase64);
if (it != offlineKeyIdAndKeyValueBase64_.end()) {
offlineKeyIdAndKeyValueBase64_.erase(it);
ret = SetOfflineKeyToFile();
if (ret != HDF_SUCCESS) {
offlineKeyMutex_.unlock();
return ret;
}
for (auto it = mediaKeySessionMap_.begin(); it != mediaKeySessionMap_.end(); ++it) {
if (it->second == false) {
continue;
}
it->first->session_->keyIdStatusMap[licenseId] = OFFLINE_MEDIA_KEY_STATUS_UNKNOWN;
}
offlineKeyMutex_.unlock();
HDF_LOGI("%{public}s: end", __func__);
return HDF_SUCCESS;
}
offlineKeyMutex_.unlock();
HDF_LOGI("%{public}s: do not find offline license, keyId: %{public}s", __func__, licenseId.data());
return HDF_FAILURE;
}
int32_t MediaKeySystemService::GetOemCertificate(sptr<OHOS::HDI::Drm::V1_0::IOemCertificate> &oemCert)
{
HDF_LOGI("%{public}s: start", __func__);
HDF_LOGI("%{public}s: end", __func__);
return HDF_SUCCESS;
}
int32_t MediaKeySystemService::GetOemCertificateStatus(CertificateStatus &status)
{
HDF_LOGI("%{public}s: start", __func__);
HDF_LOGI("%{public}s: end", __func__);
return HDF_SUCCESS;
}
int32_t MediaKeySystemService::SetCallback(const sptr<OHOS::HDI::Drm::V1_0::IMediaKeySystemCallback> &systemCallback)
{
vdiCallbackObj = new (std::nothrow) MediaKeySystemCallbackService(systemCallback);
if (vdiCallbackObj == nullptr) {
HDF_LOGE("new MediaKeySystemCallbackService() failed");
return HDF_ERR_MALLOC_FAIL;
}
return HDF_SUCCESS;
}
int32_t MediaKeySystemService::Destroy()
{
HDF_LOGI("%{public}s: start", __func__);
if (systemCallback_ != nullptr) {
systemCallback_->CloseMediaKeySystemService(this);
}
systemCallback_ = nullptr;
HDF_LOGI("%{public}s: end", __func__);
return HDF_SUCCESS;
}
int32_t MediaKeySystemService::CloseKeySessionService(sptr<MediaKeySessionService> mediaKeySession)
{
HDF_LOGI("%{public}s: start", __func__);
mediaKeySessionMutex_.lock();
auto it = mediaKeySessionMap_.find(mediaKeySession);
if (it == mediaKeySessionMap_.end()) {
mediaKeySessionMutex_.unlock();
return HDF_FAILURE;
}
mediaKeySessionMap_.erase(it);
mediaKeySessionMutex_.unlock();
HDF_LOGI("%{public}s: end", __func__);
return HDF_SUCCESS;
}
int32_t MediaKeySystemService::SetKeySystemServiceCallback(sptr<MediaKeySystemServiceCallback> callback)
{
HDF_LOGI("%{public}s: start", __func__);
if (callback == nullptr) {
HDF_LOGE("MediaKeySystemServiceCallback callback is null");
return HDF_ERR_INVALID_PARAM;
}
systemCallback_ = callback;
HDF_LOGI("%{public}s: end", __func__);
return HDF_SUCCESS;
}
int32_t MediaKeySystemService::GetOfflineKeyFromFile()
{
HDF_LOGI("%{public}s: start", __func__);
FILE *offlineKeyFile = fopen(offlineKeyFileName, "r+");
if (offlineKeyFile == NULL) {
HDF_LOGE("%{public}s: open: \"%{public}s\" failed", __func__, offlineKeyFileName);
return HDF_SUCCESS;
}
char keyIdBase64Chars[keyIdMaxLength];
char keyValueBase64Chars[keyIdMaxLength];
while (fscanf_s(offlineKeyFile, "%s %s", keyIdBase64Chars, sizeof(keyIdBase64Chars), keyValueBase64Chars, sizeof(keyValueBase64Chars)) != EOF) {
std::string tempKeyIdBase64 = keyIdBase64Chars;
std::string tempKeyValueBase64 = keyValueBase64Chars;
tempKeyIdBase64.erase(std::remove(tempKeyIdBase64.begin(), tempKeyIdBase64.end(), '\0'), tempKeyIdBase64.end());
offlineKeyIdAndKeyValueBase64_[tempKeyIdBase64] = tempKeyValueBase64;
}
fclose(offlineKeyFile);
HDF_LOGI("%{public}s: end", __func__);
return HDF_SUCCESS;
}
int32_t MediaKeySystemService::SetOfflineKeyToFile()
{
HDF_LOGI("%{public}s: start", __func__);
FILE *offlineKeyFile = fopen(offlineKeyFileName, "w+");
if (offlineKeyFile == NULL) {
offlineKeyIdAndKeyValueBase64_.clear();
HDF_LOGE("%{public}s: create failed, ret: %{public}s", __func__, strerror(errno));
return HDF_FAILURE;
}
for (auto &keyIdValueBase64Pair : offlineKeyIdAndKeyValueBase64_) {
fprintf(offlineKeyFile, "%s %s\n", keyIdValueBase64Pair.first.c_str(), keyIdValueBase64Pair.second.c_str());
}
offlineKeyIdAndKeyValueBase64_.clear();
fclose(offlineKeyFile);
HDF_LOGI("%{public}s: end", __func__);
return HDF_SUCCESS;
}
}
}
}
}