Files
android/libwvdrmengine/cdm/core/src/cdm_engine.cpp
Rahul Frias 6d617e2be4 Implement Cdm::listStoredLicenses()
[ Merge of http://go/wvgerrit/23600 ]

This adds a new entry to IStorage:: -

  bool list(std::vector<std::string> file_names)

It returns the name of each file in the (origin-specific) file system.

b/34628115

Uses the current file system (origin-specific) bound to the CDM. Returns
the list of stored licenses (key_set_ids) in vector output parameter.

Test: verified by unittests on angler.

Change-Id: I988556b27c2a4b75f52b59bcd78cfeaddd649acd
2017-02-07 13:28:05 -08:00

1707 lines
53 KiB
C++

// Copyright 2013 Google Inc. All Rights Reserved.
#include "cdm_engine.h"
#include <assert.h>
#include <stdlib.h>
#include <iostream>
#include <sstream>
#include "cdm_session.h"
#include "clock.h"
#include "device_files.h"
#include "file_store.h"
#include "license_protocol.pb.h"
#include "log.h"
#include "metrics_front_end.h"
#include "properties.h"
#include "string_conversions.h"
#include "wv_cdm_constants.h"
#include "wv_cdm_event_listener.h"
namespace {
const uint64_t kReleaseSessionTimeToLive = 60; // seconds
const uint32_t kUpdateUsageInformationPeriod = 60; // seconds
const size_t kUsageReportsPerRequest = 1;
} // namespace
namespace wvcdm {
class UsagePropertySet : public CdmClientPropertySet {
public:
UsagePropertySet() {}
virtual ~UsagePropertySet() {}
void set_security_level(SecurityLevel security_level) {
if (kLevel3 == security_level)
security_level_ = QUERY_VALUE_SECURITY_LEVEL_L3;
else
security_level_.clear();
}
virtual const std::string& security_level() const { return security_level_; }
virtual bool use_privacy_mode() const { return false; }
virtual const std::string& service_certificate() const { return empty_; }
virtual void set_service_certificate(const std::string&) {}
virtual const std::string& device_provisioning_service_certificate() const {
return empty_;
}
virtual void set_device_provisioning_service_certificate(const std::string&) {
}
virtual bool is_session_sharing_enabled() const { return false; }
virtual uint32_t session_sharing_id() const { return 0; }
virtual void set_session_sharing_id(uint32_t /* id */) {}
virtual const std::string& app_id() const { return app_id_; }
void set_app_id(const std::string& appId) { app_id_ = appId; }
private:
std::string app_id_;
std::string security_level_;
const std::string empty_;
};
bool CdmEngine::seeded_ = false;
CdmEngine::CdmEngine(FileSystem* file_system, const std::string& spoid)
: cert_provisioning_(NULL),
cert_provisioning_requested_security_level_(kLevelDefault),
file_system_(file_system),
spoid_(spoid),
usage_session_(NULL),
last_usage_information_update_time_(0) {
assert(file_system);
Properties::Init();
if (!seeded_) {
srand(clock_.GetCurrentTime());
seeded_ = true;
}
life_span_.Start();
}
CdmEngine::~CdmEngine() {
AutoLock lock(session_list_lock_);
CdmSessionMap::iterator i(sessions_.begin());
for (; i != sessions_.end(); ++i) {
delete i->second;
}
sessions_.clear();
M_RECORD(&metrics_, cdm_engine_life_span_, life_span_.AsMs());
}
CdmResponseType CdmEngine::OpenSession(const CdmKeySystem& key_system,
CdmClientPropertySet* property_set,
const CdmSessionId& forced_session_id,
WvCdmEventListener* event_listener) {
return OpenSession(key_system, property_set, event_listener,
&forced_session_id, NULL);
}
CdmResponseType CdmEngine::OpenSession(const CdmKeySystem& key_system,
CdmClientPropertySet* property_set,
WvCdmEventListener* event_listener,
CdmSessionId* session_id) {
return OpenSession(key_system, property_set, event_listener, NULL,
session_id);
}
CdmResponseType CdmEngine::OpenSession(const CdmKeySystem& key_system,
CdmClientPropertySet* property_set,
WvCdmEventListener* event_listener,
const CdmSessionId* forced_session_id,
CdmSessionId* session_id) {
LOGI("CdmEngine::OpenSession");
if (!ValidateKeySystem(key_system)) {
LOGI("CdmEngine::OpenSession: invalid key_system = %s", key_system.c_str());
return INVALID_KEY_SYSTEM;
}
if (!session_id && !forced_session_id) {
LOGE("CdmEngine::OpenSession: no (forced/)session ID destination provided");
return INVALID_PARAMETERS_ENG_1;
}
if (forced_session_id) {
if (sessions_.find(*forced_session_id) != sessions_.end()) {
return DUPLICATE_SESSION_ID_SPECIFIED;
}
}
CloseExpiredReleaseSessions();
scoped_ptr<CdmSession> new_session(new CdmSession(file_system_));
CdmResponseType sts = new_session->Init(property_set, forced_session_id,
event_listener);
if (sts != NO_ERROR) {
if (sts == NEED_PROVISIONING) {
cert_provisioning_requested_security_level_ =
new_session->GetRequestedSecurityLevel();
// Reserve a session ID so the CDM can return success.
if (session_id)
*session_id = new_session->GenerateSessionId();
} else {
LOGE("CdmEngine::OpenSession: bad session init: %d", sts);
}
return sts;
}
CdmSessionId id = new_session->session_id();
AutoLock lock(session_list_lock_);
sessions_[id] = new_session.release();
if (session_id) *session_id = id;
return NO_ERROR;
}
CdmResponseType CdmEngine::OpenKeySetSession(
const CdmKeySetId& key_set_id, CdmClientPropertySet* property_set,
WvCdmEventListener* event_listener) {
LOGI("CdmEngine::OpenKeySetSession");
if (key_set_id.empty()) {
LOGE("CdmEngine::OpenKeySetSession: invalid key set id");
return EMPTY_KEYSET_ID_ENG_1;
}
// If in-use, release key set before re-opening, to avoid leaking
// resources (CryptoSession etc).
bool key_set_in_use = false;
{
AutoLock lock(release_key_sets_lock_);
key_set_in_use =
release_key_sets_.find(key_set_id) != release_key_sets_.end();
}
if (key_set_in_use)
CloseKeySetSession(key_set_id);
CdmSessionId session_id;
CdmResponseType sts = OpenSession(KEY_SYSTEM, property_set, event_listener,
NULL /* forced_session_id */, &session_id);
if (sts != NO_ERROR) return sts;
AutoLock lock(release_key_sets_lock_);
release_key_sets_[key_set_id] = std::make_pair(session_id,
clock_.GetCurrentTime() + kReleaseSessionTimeToLive);
return NO_ERROR;
}
CdmResponseType CdmEngine::CloseSession(const CdmSessionId& session_id) {
LOGI("CdmEngine::CloseSession");
AutoLock lock(session_list_lock_);
CdmSessionMap::iterator iter = sessions_.find(session_id);
if (iter == sessions_.end()) {
LOGE("CdmEngine::CloseSession: session not found = %s", session_id.c_str());
return SESSION_NOT_FOUND_1;
}
CdmSession* session = iter->second;
sessions_.erase(session_id);
delete session;
return NO_ERROR;
}
CdmResponseType CdmEngine::CloseKeySetSession(const CdmKeySetId& key_set_id) {
LOGI("CdmEngine::CloseKeySetSession");
CdmSessionId session_id;
{
AutoLock lock(release_key_sets_lock_);
CdmReleaseKeySetMap::iterator iter = release_key_sets_.find(key_set_id);
if (iter == release_key_sets_.end()) {
LOGE("CdmEngine::CloseKeySetSession: key set id not found = %s",
key_set_id.c_str());
return KEYSET_ID_NOT_FOUND_1;
}
session_id = iter->second.first;
}
CdmResponseType sts = CloseSession(session_id);
AutoLock lock(release_key_sets_lock_);
CdmReleaseKeySetMap::iterator iter = release_key_sets_.find(key_set_id);
if (iter != release_key_sets_.end()) {
release_key_sets_.erase(iter);
}
return sts;
}
bool CdmEngine::IsOpenSession(const CdmSessionId& session_id) {
AutoLock lock(session_list_lock_);
CdmSessionMap::iterator iter = sessions_.find(session_id);
return iter != sessions_.end();
}
CdmResponseType CdmEngine::GenerateKeyRequest(
const CdmSessionId& session_id, const CdmKeySetId& key_set_id,
const InitializationData& init_data, const CdmLicenseType license_type,
CdmAppParameterMap& app_parameters, CdmKeyRequest* key_request) {
LOGI("CdmEngine::GenerateKeyRequest");
CdmSessionId id = session_id;
CdmResponseType sts;
// NOTE: If AlwaysUseKeySetIds() is true, there is no need to consult the
// release_key_sets_ map for release licenses.
if (license_type == kLicenseTypeRelease &&
!Properties::AlwaysUseKeySetIds()) {
if (key_set_id.empty()) {
LOGE("CdmEngine::GenerateKeyRequest: invalid key set ID");
return EMPTY_KEYSET_ID_ENG_2;
}
if (!session_id.empty()) {
LOGE("CdmEngine::GenerateKeyRequest: invalid session ID = %s",
session_id.c_str());
return INVALID_SESSION_ID;
}
AutoLock lock(release_key_sets_lock_);
CdmReleaseKeySetMap::iterator iter = release_key_sets_.find(key_set_id);
if (iter == release_key_sets_.end()) {
LOGE("CdmEngine::GenerateKeyRequest: key set ID not found = %s",
key_set_id.c_str());
return KEYSET_ID_NOT_FOUND_2;
}
id = iter->second.first;
}
CdmSessionMap::iterator iter = sessions_.find(id);
if (iter == sessions_.end()) {
LOGE("CdmEngine::GenerateKeyRequest: session_id not found = %s",
id.c_str());
return SESSION_NOT_FOUND_2;
}
if (!key_request) {
LOGE("CdmEngine::GenerateKeyRequest: output destination provided");
return INVALID_PARAMETERS_ENG_2;
}
key_request->message.clear();
if (license_type == kLicenseTypeRelease &&
!iter->second->license_received()) {
M_TIME(
sts = iter->second->RestoreOfflineSession(
key_set_id,
kLicenseTypeRelease),
iter->second->GetMetrics(),
cdm_session_restore_offline_session_,
sts);
if (sts != KEY_ADDED) {
LOGE("CdmEngine::GenerateKeyRequest: key release restoration failed,"
"sts = %d", static_cast<int>(sts));
return sts;
}
}
M_TIME(
sts = iter->second->GenerateKeyRequest(
init_data,
license_type,
app_parameters,
key_request),
iter->second->GetMetrics(),
cdm_session_generate_key_request_,
sts);
if (KEY_MESSAGE != sts) {
if (sts == NEED_PROVISIONING) {
M_TIME(
cert_provisioning_requested_security_level_ =
iter->second->GetRequestedSecurityLevel(),
iter->second->GetMetrics(),
cdm_session_get_requested_security_level_,
cert_provisioning_requested_security_level_);
}
LOGE("CdmEngine::GenerateKeyRequest: key request generation failed, "
"sts = %d", static_cast<int>(sts));
return sts;
}
if (license_type == kLicenseTypeRelease) {
OnKeyReleaseEvent(key_set_id);
}
return KEY_MESSAGE;
}
CdmResponseType CdmEngine::AddKey(const CdmSessionId& session_id,
const CdmKeyResponse& key_data,
CdmKeySetId* key_set_id) {
LOGI("CdmEngine::AddKey");
CdmSessionId id = session_id;
bool license_type_release = session_id.empty();
if (license_type_release) {
if (!key_set_id) {
LOGE("CdmEngine::AddKey: no key set id provided");
return INVALID_PARAMETERS_ENG_3;
}
if (key_set_id->empty()) {
LOGE("CdmEngine::AddKey: invalid key set id");
return EMPTY_KEYSET_ID_ENG_3;
}
AutoLock lock(release_key_sets_lock_);
CdmReleaseKeySetMap::iterator iter = release_key_sets_.find(*key_set_id);
if (iter == release_key_sets_.end()) {
LOGE("CdmEngine::AddKey: key set id not found = %s", key_set_id->c_str());
return KEYSET_ID_NOT_FOUND_3;
}
id = iter->second.first;
}
CdmSessionMap::iterator iter = sessions_.find(id);
if (iter == sessions_.end()) {
LOGE("CdmEngine::AddKey: session id not found = %s", id.c_str());
return SESSION_NOT_FOUND_3;
}
if (key_data.empty()) {
LOGE("CdmEngine::AddKey: no key_data");
return EMPTY_KEY_DATA_1;
}
CdmResponseType sts;
M_TIME(
sts = iter->second->AddKey(
key_data),
iter->second->GetMetrics(),
cdm_session_add_key_,
sts);
if (key_set_id) {
*key_set_id = iter->second->key_set_id();
}
switch (sts) {
case KEY_ADDED:
break;
case NEED_KEY:
LOGI("CdmEngine::AddKey: service certificate loaded, no key added");
break;
default:
LOGE("CdmEngine::AddKey: keys not added, result = %d", sts);
break;
}
return sts;
}
CdmResponseType CdmEngine::RestoreKey(const CdmSessionId& session_id,
const CdmKeySetId& key_set_id) {
LOGI("CdmEngine::RestoreKey");
if (key_set_id.empty()) {
LOGI("CdmEngine::RestoreKey: invalid key set id");
return EMPTY_KEYSET_ID_ENG_4;
}
CdmSessionMap::iterator iter = sessions_.find(session_id);
if (iter == sessions_.end()) {
LOGE("CdmEngine::RestoreKey: session_id not found = %s ",
session_id.c_str());
return SESSION_NOT_FOUND_4;
}
CdmResponseType sts;
M_TIME(
sts = iter->second->RestoreOfflineSession(
key_set_id,
kLicenseTypeOffline),
iter->second->GetMetrics(),
cdm_session_restore_offline_session_,
sts);
if (sts == NEED_PROVISIONING) {
M_TIME(
cert_provisioning_requested_security_level_ =
iter->second->GetRequestedSecurityLevel(),
iter->second->GetMetrics(),
cdm_session_get_requested_security_level_,
cert_provisioning_requested_security_level_);
}
if (sts != KEY_ADDED && sts != GET_RELEASED_LICENSE_ERROR) {
LOGE("CdmEngine::RestoreKey: restore offline session failed = %d", sts);
}
return sts;
}
CdmResponseType CdmEngine::RemoveKeys(const CdmSessionId& session_id) {
LOGI("CdmEngine::RemoveKeys");
CdmSessionMap::iterator iter = sessions_.find(session_id);
if (iter == sessions_.end()) {
LOGE("CdmEngine::RemoveKeys: session_id not found = %s",
session_id.c_str());
return SESSION_NOT_FOUND_5;
}
M_TIME(
iter->second->ReleaseCrypto(),
iter->second->GetMetrics(),
cdm_session_release_crypto_);
return NO_ERROR;
}
CdmResponseType CdmEngine::GenerateRenewalRequest(
const CdmSessionId& session_id, CdmKeyRequest* key_request) {
LOGI("CdmEngine::GenerateRenewalRequest");
CdmSessionMap::iterator iter = sessions_.find(session_id);
if (iter == sessions_.end()) {
LOGE("CdmEngine::GenerateRenewalRequest: session_id not found = %s",
session_id.c_str());
return SESSION_NOT_FOUND_6;
}
if (!key_request) {
LOGE("CdmEngine::GenerateRenewalRequest: no request destination");
return INVALID_PARAMETERS_ENG_4;
}
key_request->message.clear();
CdmResponseType sts;
M_TIME(
sts= iter->second->GenerateRenewalRequest(
key_request),
iter->second->GetMetrics(),
cdm_session_generate_renewal_request_,
sts);
if (KEY_MESSAGE != sts) {
LOGE("CdmEngine::GenerateRenewalRequest: key request gen. failed, sts=%d",
sts);
return sts;
}
return KEY_MESSAGE;
}
CdmResponseType CdmEngine::RenewKey(const CdmSessionId& session_id,
const CdmKeyResponse& key_data) {
LOGI("CdmEngine::RenewKey");
CdmSessionMap::iterator iter = sessions_.find(session_id);
if (iter == sessions_.end()) {
LOGE("CdmEngine::RenewKey: session_id not found = %s", session_id.c_str());
return SESSION_NOT_FOUND_7;
}
if (key_data.empty()) {
LOGE("CdmEngine::RenewKey: no key_data");
return EMPTY_KEY_DATA_2;
}
CdmResponseType sts;
M_TIME(
sts = iter->second->RenewKey(
key_data),
iter->second->GetMetrics(),
cdm_session_renew_key_,
sts);
if (KEY_ADDED != sts) {
LOGE("CdmEngine::RenewKey: keys not added, sts=%d", static_cast<int>(sts));
return sts;
}
return KEY_ADDED;
}
CdmResponseType CdmEngine::QueryStatus(SecurityLevel security_level,
const std::string& query_token,
std::string* query_response) {
LOGI("CdmEngine::QueryStatus");
CryptoSession crypto_session(&metrics_);
if (security_level == kLevel3) {
CdmResponseType status;
M_TIME(
status = crypto_session.Open(
kLevel3),
&metrics_,
crypto_session_open_,
status,
kLevel3);
if (NO_ERROR != status) return INVALID_QUERY_STATUS;
}
if (!query_response) {
LOGE("CdmEngine::QueryStatus: no query response destination");
return INVALID_PARAMETERS_ENG_6;
}
if (query_token == QUERY_KEY_SECURITY_LEVEL) {
CdmSecurityLevel security_level;
M_TIME(
security_level = crypto_session.GetSecurityLevel(),
&metrics_,
crypto_session_get_security_level_,
security_level);
switch (security_level) {
case kSecurityLevelL1:
*query_response = QUERY_VALUE_SECURITY_LEVEL_L1;
break;
case kSecurityLevelL2:
*query_response = QUERY_VALUE_SECURITY_LEVEL_L2;
break;
case kSecurityLevelL3:
*query_response = QUERY_VALUE_SECURITY_LEVEL_L3;
break;
case kSecurityLevelUninitialized:
case kSecurityLevelUnknown:
*query_response = QUERY_VALUE_SECURITY_LEVEL_UNKNOWN;
break;
default:
LOGW("CdmEngine::QueryStatus: Unknown security level: %d",
security_level);
return UNKNOWN_ERROR;
}
} else if (query_token == QUERY_KEY_DEVICE_ID) {
std::string deviceId;
bool got_id;
M_TIME(
got_id = crypto_session.GetDeviceUniqueId(
&deviceId),
&metrics_,
crypto_session_get_device_unique_id_,
got_id);
if (!got_id) {
LOGW("CdmEngine::QueryStatus: QUERY_KEY_DEVICE_ID unknown failure");
return UNKNOWN_ERROR;
}
*query_response = deviceId;
} else if (query_token == QUERY_KEY_SYSTEM_ID) {
uint32_t system_id;
bool got_id;
M_TIME(
got_id = crypto_session.GetSystemId(
&system_id),
&metrics_,
crypto_session_get_system_id_,
got_id,
system_id);
if (!got_id) {
LOGW("CdmEngine::QueryStatus: QUERY_KEY_SYSTEM_ID unknown failure");
return UNKNOWN_ERROR;
}
std::ostringstream system_id_stream;
system_id_stream << system_id;
*query_response = system_id_stream.str();
} else if (query_token == QUERY_KEY_PROVISIONING_ID) {
std::string provisioning_id;
bool got_id;
M_TIME(
got_id = crypto_session.GetProvisioningId(
&provisioning_id),
&metrics_,
crypto_session_get_provisioning_id_,
got_id);
if (!got_id) {
LOGW("CdmEngine::QueryStatus: GetProvisioningId failed");
return UNKNOWN_ERROR;
}
*query_response = provisioning_id;
} else if (query_token == QUERY_KEY_CURRENT_HDCP_LEVEL ||
query_token == QUERY_KEY_MAX_HDCP_LEVEL) {
CryptoSession::HdcpCapability current_hdcp;
CryptoSession::HdcpCapability max_hdcp;
bool got_hdcp;
M_TIME(
got_hdcp = crypto_session.GetHdcpCapabilities(
&current_hdcp,
&max_hdcp),
&metrics_,
crypto_session_get_hdcp_capabilities_,
got_hdcp);
if (!got_hdcp) {
LOGW("CdmEngine::QueryStatus: GetHdcpCapabilities failed");
return UNKNOWN_ERROR;
}
*query_response =
MapHdcpVersion(query_token == QUERY_KEY_CURRENT_HDCP_LEVEL ?
current_hdcp : max_hdcp);
} else if (query_token == QUERY_KEY_USAGE_SUPPORT) {
bool supports_usage_reporting;
bool got_info;
M_TIME(
got_info = crypto_session.UsageInformationSupport(
&supports_usage_reporting),
&metrics_,
crypto_session_usage_information_support_,
got_info);
if (!got_info) {
LOGW("CdmEngine::QueryStatus: UsageInformationSupport failed");
return UNKNOWN_ERROR;
}
*query_response =
supports_usage_reporting ? QUERY_VALUE_TRUE : QUERY_VALUE_FALSE;
} else if (query_token == QUERY_KEY_NUMBER_OF_OPEN_SESSIONS) {
size_t number_of_open_sessions;
bool got_num;
M_TIME(
got_num = crypto_session.GetNumberOfOpenSessions(
&number_of_open_sessions),
&metrics_,
crypto_session_get_number_of_open_sessions_,
got_num);
if (!got_num) {
LOGW("CdmEngine::QueryStatus: GetNumberOfOpenSessions failed");
return UNKNOWN_ERROR;
}
std::ostringstream open_sessions_stream;
open_sessions_stream << number_of_open_sessions;
*query_response = open_sessions_stream.str();
} else if (query_token == QUERY_KEY_MAX_NUMBER_OF_SESSIONS) {
size_t maximum_number_of_sessions;
bool got_num;
M_TIME(
got_num = crypto_session.GetMaxNumberOfSessions(
&maximum_number_of_sessions),
&metrics_,
crypto_session_get_max_number_of_sessions_,
got_num);
if (!got_num) {
LOGW("CdmEngine::QueryStatus: GetMaxNumberOfOpenSessions failed");
return UNKNOWN_ERROR;
}
std::ostringstream max_sessions_stream;
max_sessions_stream << maximum_number_of_sessions;
*query_response = max_sessions_stream.str();
} else if (query_token == QUERY_KEY_OEMCRYPTO_API_VERSION) {
uint32_t api_version;
bool got_version;
M_TIME(
got_version = crypto_session.GetApiVersion(
&api_version),
&metrics_,
crypto_session_get_api_version_,
got_version);
if (!got_version) {
LOGW("CdmEngine::QueryStatus: GetApiVersion failed");
return UNKNOWN_ERROR;
}
std::ostringstream api_version_stream;
api_version_stream << api_version;
*query_response = api_version_stream.str();
} else {
LOGW("CdmEngine::QueryStatus: Unknown status requested, token = %s",
query_token.c_str());
return INVALID_QUERY_KEY;
}
return NO_ERROR;
}
CdmResponseType CdmEngine::QuerySessionStatus(const CdmSessionId& session_id,
CdmQueryMap* query_response) {
LOGI("CdmEngine::QuerySessionStatus");
CdmSessionMap::iterator iter = sessions_.find(session_id);
if (iter == sessions_.end()) {
LOGE("CdmEngine::QuerySessionStatus: session_id not found = %s",
session_id.c_str());
return SESSION_NOT_FOUND_8;
}
CdmResponseType sts;
M_TIME(
sts = iter->second->QueryStatus(
query_response),
iter->second->GetMetrics(),
cdm_session_query_status_,
sts);
return sts;
}
bool CdmEngine::IsReleaseSession(const CdmSessionId& session_id) {
LOGI("CdmEngine::IsReleaseSession");
CdmSessionMap::iterator iter = sessions_.find(session_id);
if (iter == sessions_.end()) {
LOGE("CdmEngine::IsReleaseSession: session_id not found = %s",
session_id.c_str());
return false;
}
return iter->second->is_release();
}
bool CdmEngine::IsOfflineSession(const CdmSessionId& session_id) {
LOGI("CdmEngine::IsOfflineSession");
CdmSessionMap::iterator iter = sessions_.find(session_id);
if (iter == sessions_.end()) {
LOGE("CdmEngine::IsOfflineSession: session_id not found = %s",
session_id.c_str());
return false;
}
return iter->second->is_offline();
}
CdmResponseType CdmEngine::QueryKeyStatus(const CdmSessionId& session_id,
CdmQueryMap* query_response) {
LOGI("CdmEngine::QueryKeyStatus");
CdmSessionMap::iterator iter = sessions_.find(session_id);
if (iter == sessions_.end()) {
LOGE("CdmEngine::QueryKeyStatus: session_id not found = %s",
session_id.c_str());
return SESSION_NOT_FOUND_9;
}
CdmResponseType sts;
M_TIME(
sts = iter->second->QueryKeyStatus(
query_response),
iter->second->GetMetrics(),
cdm_session_query_key_status_,
sts);
return sts;
}
CdmResponseType CdmEngine::QueryKeyAllowedUsage(const CdmSessionId& session_id,
const std::string& key_id,
CdmKeyAllowedUsage* key_usage) {
LOGI("CdmEngine::QueryKeyAllowedUsage");
if (!key_usage) {
LOGE("CdmEngine::QueryKeyAllowedUsage: no response destination");
return INVALID_PARAMETERS_ENG_12;
}
CdmSessionMap::iterator iter = sessions_.find(session_id);
if (iter == sessions_.end()) {
LOGE("CdmEngine::QueryKeyAllowedUsage: session_id not found = %s",
session_id.c_str());
return SESSION_NOT_FOUND_12;
}
CdmResponseType sts;
M_TIME(
sts = iter->second->QueryKeyAllowedUsage(
key_id,
key_usage),
iter->second->GetMetrics(),
cdm_session_query_key_allowed_usage_,
sts);
return sts;
}
CdmResponseType CdmEngine::QueryKeyAllowedUsage(const std::string& key_id,
CdmKeyAllowedUsage* key_usage) {
LOGI("CdmEngine::QueryKeyAllowedUsage (all sessions)");
CdmResponseType session_sts;
CdmKeyAllowedUsage found_in_this_session;
bool found = false;
if (!key_usage) {
LOGE("CdmEngine::QueryKeyAllowedUsage: no response destination");
return INVALID_PARAMETERS_ENG_7;
}
key_usage->Clear();
for (CdmSessionMap::iterator iter = sessions_.begin();
iter != sessions_.end(); ++iter) {
M_TIME(
session_sts = iter->second->QueryKeyAllowedUsage(
key_id,
&found_in_this_session),
iter->second->GetMetrics(),
cdm_session_query_key_allowed_usage_,
session_sts);
if (session_sts == NO_ERROR) {
if (found) {
// Found another key. If usage settings do not match, fail.
if (!key_usage->Equals(found_in_this_session)) {
key_usage->Clear();
return KEY_CONFLICT_1;
}
} else {
*key_usage = found_in_this_session;
found = true;
}
} else if (session_sts != KEY_NOT_FOUND_1) {
LOGE("CdmEngine::QueryKeyAllowedUsage (all sessions) FAILED = %d",
session_sts);
key_usage->Clear();
return session_sts;
}
}
return (found) ? NO_ERROR : KEY_NOT_FOUND_2;
}
CdmResponseType CdmEngine::QueryOemCryptoSessionId(
const CdmSessionId& session_id, CdmQueryMap* query_response) {
LOGI("CdmEngine::QueryOemCryptoSessionId");
CdmSessionMap::iterator iter = sessions_.find(session_id);
if (iter == sessions_.end()) {
LOGE("CdmEngine::QueryOemCryptoSessionId: session_id not found = %s",
session_id.c_str());
return SESSION_NOT_FOUND_10;
}
CdmResponseType sts;
M_TIME(
sts = iter->second->QueryOemCryptoSessionId(
query_response),
iter->second->GetMetrics(),
cdm_session_query_oemcrypto_session_id_,
sts);
return sts;
}
/*
* Composes a device provisioning request and output the request in JSON format
* in *request. It also returns the default url for the provisioning server
* in *default_url.
*
* Returns NO_ERROR for success and CdmResponseType error code if fails.
*/
CdmResponseType CdmEngine::GetProvisioningRequest(
CdmCertificateType cert_type, const std::string& cert_authority,
CdmProvisioningRequest* request, std::string* default_url) {
if (!request) {
LOGE("CdmEngine::GetProvisioningRequest: invalid output parameters");
return INVALID_PROVISIONING_REQUEST_PARAM_1;
}
if (!default_url) {
LOGE("CdmEngine::GetProvisioningRequest: invalid output parameters");
return INVALID_PROVISIONING_REQUEST_PARAM_2;
}
DeleteAllUsageReportsUponFactoryReset();
if (NULL == cert_provisioning_.get()) {
cert_provisioning_.reset(new CertificateProvisioning(&metrics_));
}
CdmResponseType ret = cert_provisioning_->GetProvisioningRequest(
cert_provisioning_requested_security_level_, cert_type, cert_authority,
file_system_->origin(), spoid_, request, default_url);
if (ret != NO_ERROR) {
cert_provisioning_.reset(NULL); // Release resources.
}
return ret;
}
/*
* The response message consists of a device certificate and the device RSA key.
* The device RSA key is stored in the T.E.E. The device certificate is stored
* in the device.
*
* Returns NO_ERROR for success and CdmResponseType error code if fails.
*/
CdmResponseType CdmEngine::HandleProvisioningResponse(
const CdmProvisioningResponse& response, std::string* cert,
std::string* wrapped_key) {
if (response.empty()) {
LOGE("CdmEngine::HandleProvisioningResponse: Empty provisioning response.");
cert_provisioning_.reset(NULL);
return EMPTY_PROVISIONING_RESPONSE;
}
if (NULL == cert) {
LOGE(
"CdmEngine::HandleProvisioningResponse: invalid certificate "
"destination");
cert_provisioning_.reset(NULL);
return INVALID_PROVISIONING_PARAMETERS_1;
}
if (NULL == wrapped_key) {
LOGE("CdmEngine::HandleProvisioningResponse: invalid wrapped key "
"destination");
cert_provisioning_.reset(NULL);
return INVALID_PROVISIONING_PARAMETERS_2;
}
if (NULL == cert_provisioning_.get()) {
// Certificate provisioning object has been released. Check if a concurrent
// provisioning attempt has succeeded before declaring failure.
CryptoSession crypto_session(&metrics_);
CdmResponseType status;
M_TIME(
status = crypto_session.Open(
cert_provisioning_requested_security_level_),
&metrics_,
crypto_session_open_,
status,
cert_provisioning_requested_security_level_);
if (NO_ERROR != status) {
LOGE(
"CdmEngine::HandleProvisioningResponse: provisioning object "
"missing and crypto session open failed.");
return EMPTY_PROVISIONING_CERTIFICATE_2;
}
CdmSecurityLevel security_level;
M_TIME(
security_level = crypto_session.GetSecurityLevel(),
&metrics_,
crypto_session_get_security_level_,
security_level);
if (!IsProvisioned(security_level)) {
LOGE(
"CdmEngine::HandleProvisioningResponse: provisioning object "
"missing.");
return EMPTY_PROVISIONING_CERTIFICATE_1;
}
return NO_ERROR;
}
CdmResponseType ret = cert_provisioning_->HandleProvisioningResponse(
file_system_, response, cert, wrapped_key);
// Release resources only on success. It is possible that a provisioning
// attempt was made after this one was requested but before the response was
// received, which will cause this attempt to fail. Not releasing will
// allow for the possibility that the later attempt succeeds.
if (NO_ERROR == ret) cert_provisioning_.reset(NULL);
return ret;
}
bool CdmEngine::IsProvisioned(CdmSecurityLevel security_level) {
DeviceFiles handle(file_system_);
if (!handle.Init(security_level)) {
LOGE("CdmEngine::IsProvisioned: unable to initialize device files");
return false;
}
return handle.HasCertificate();
}
CdmResponseType CdmEngine::Unprovision(CdmSecurityLevel security_level) {
DeviceFiles handle(file_system_);
if (!handle.Init(security_level)) {
LOGE("CdmEngine::Unprovision: unable to initialize device files");
return UNPROVISION_ERROR_1;
}
if (!file_system_->IsGlobal()) {
if (!handle.RemoveCertificate()) {
LOGE("CdmEngine::Unprovision: unable to delete certificate");
return UNPROVISION_ERROR_2;
}
return NO_ERROR;
} else {
if (!handle.DeleteAllFiles()) {
LOGE("CdmEngine::Unprovision: unable to delete files");
return UNPROVISION_ERROR_3;
}
CryptoSession crypto_session(&metrics_);
CdmResponseType status;
M_TIME(
status = crypto_session.Open(
security_level == kSecurityLevelL3 ?
kLevel3 :
kLevelDefault),
&metrics_,
crypto_session_open_,
status,
security_level == kSecurityLevelL3 ? kLevel3 : kLevelDefault);
if (NO_ERROR != status) {
LOGE("CdmEngine::Unprovision: error opening crypto session: %d", status);
return UNPROVISION_ERROR_4;
}
M_TIME(
status = crypto_session.DeleteAllUsageReports(),
&metrics_,
crypto_session_delete_all_usage_reports_,
status);
if (status != NO_ERROR) {
LOGE("CdmEngine::Unprovision: error deleteing usage reports: %d", status);
}
return status;
}
}
CdmResponseType CdmEngine::ListStoredLicenses(
CdmSecurityLevel security_level, std::vector<std::string>* key_set_ids) {
DeviceFiles handle(file_system_);
if (!key_set_ids) {
LOGE("CdmEngine::QueryStoredLicenses: no response destination");
return INVALID_PARAMETERS_ENG_22;
}
if (!handle.Init(security_level)) {
LOGE("CdmEngine::ListStoredLicenses: unable to initialize device files");
return STORE_LICENSE_ERROR_4;
}
if (!handle.ListLicenses(key_set_ids)) {
return LIST_LICENSES_ERROR;
}
return NO_ERROR;
}
CdmResponseType CdmEngine::GetUsageInfo(const std::string& app_id,
const CdmSecureStopId& ssid,
CdmUsageInfo* usage_info) {
if (NULL == usage_property_set_.get()) {
usage_property_set_.reset(new UsagePropertySet());
}
if (!usage_info) {
LOGE("CdmEngine::GetUsageInfo: no usage info destination");
return INVALID_PARAMETERS_ENG_8;
}
usage_property_set_->set_security_level(kLevelDefault);
usage_property_set_->set_app_id(app_id);
usage_session_.reset(new CdmSession(file_system_));
CdmResponseType status = usage_session_->Init(usage_property_set_.get());
if (NO_ERROR != status) {
LOGE("CdmEngine::GetUsageInfo: session init error");
return status;
}
DeviceFiles handle(file_system_);
if (!handle.Init(usage_session_->GetSecurityLevel())) {
LOGE("CdmEngine::GetUsageInfo: device file init error");
return GET_USAGE_INFO_ERROR_1;
}
CdmKeyMessage license_request;
CdmKeyResponse license_response;
std::string usage_entry;
if (!handle.RetrieveUsageInfo(app_id, ssid, &license_request,
&license_response, &usage_entry)) {
usage_property_set_->set_security_level(kLevel3);
usage_property_set_->set_app_id(app_id);
usage_session_.reset(new CdmSession(file_system_));
status = usage_session_->Init(usage_property_set_.get());
if (NO_ERROR != status) {
LOGE("CdmEngine::GetUsageInfo: session init error");
return status;
}
if (!handle.Reset(usage_session_->GetSecurityLevel())) {
LOGE("CdmEngine::GetUsageInfo: device file init error");
return GET_USAGE_INFO_ERROR_2;
}
if (!handle.RetrieveUsageInfo(app_id, ssid, &license_request,
&license_response, &usage_entry)) {
// No entry found for that ssid.
return USAGE_INFO_NOT_FOUND;
}
}
status =
usage_session_->RestoreUsageSession(license_request,license_response);
if (KEY_ADDED != status) {
LOGE("CdmEngine::GetUsageInfo: restore usage session error %d", status);
usage_info->clear();
return status;
}
CdmKeyRequest request;
status = usage_session_->GenerateReleaseRequest(&request);
usage_info->clear();
usage_info->push_back(request.message);
if (KEY_MESSAGE != status) {
LOGE("CdmEngine::GetUsageInfo: generate release request error: %d", status);
usage_info->clear();
return status;
}
return KEY_MESSAGE;
}
CdmResponseType CdmEngine::GetUsageInfo(const std::string& app_id,
CdmUsageInfo* usage_info) {
// Return a random usage report from a random security level
SecurityLevel security_level = ((rand() % 2) == 0) ? kLevelDefault : kLevel3;
CdmResponseType status = UNKNOWN_ERROR;
if (!usage_info) {
LOGE("CdmEngine::GetUsageInfo: no usage info destination");
return INVALID_PARAMETERS_ENG_9;
}
do {
status = GetUsageInfo(app_id, security_level, usage_info);
if (KEY_MESSAGE == status && !usage_info->empty()) return status;
} while (KEY_CANCELED == status);
security_level = (kLevel3 == security_level) ? kLevelDefault : kLevel3;
do {
status = GetUsageInfo(app_id, security_level, usage_info);
if (NEED_PROVISIONING == status)
return NO_ERROR; // Valid scenario that one of the security
// levels has not been provisioned
} while (KEY_CANCELED == status);
return status;
}
CdmResponseType CdmEngine::GetUsageInfo(const std::string& app_id,
SecurityLevel requested_security_level,
CdmUsageInfo* usage_info) {
if (NULL == usage_property_set_.get()) {
usage_property_set_.reset(new UsagePropertySet());
}
usage_property_set_->set_security_level(requested_security_level);
usage_property_set_->set_app_id(app_id);
usage_session_.reset(new CdmSession(file_system_));
CdmResponseType status = usage_session_->Init(usage_property_set_.get());
if (NO_ERROR != status) {
LOGE("CdmEngine::GetUsageInfo: session init error");
return status;
}
DeviceFiles handle(file_system_);
if (!handle.Init(usage_session_->GetSecurityLevel())) {
LOGE("CdmEngine::GetUsageInfo: unable to initialize device files");
return GET_USAGE_INFO_ERROR_3;
}
std::vector<std::pair<CdmKeyMessage, CdmKeyResponse> > license_info;
if (!handle.RetrieveUsageInfo(app_id, &license_info)) {
LOGE("CdmEngine::GetUsageInfo: unable to read usage information");
return GET_USAGE_INFO_ERROR_4;
}
if (!usage_info) {
LOGE("CdmEngine::GetUsageInfo: no usage info destination");
return INVALID_PARAMETERS_ENG_10;
}
if (0 == license_info.size()) {
usage_info->resize(0);
return NO_ERROR;
}
usage_info->resize(kUsageReportsPerRequest);
uint32_t index = rand() % license_info.size();
status = usage_session_->RestoreUsageSession(license_info[index].first,
license_info[index].second);
if (KEY_ADDED != status) {
LOGE("CdmEngine::GetUsageInfo: restore usage session (%d) error %ld", index,
status);
usage_info->clear();
return status;
}
CdmKeyRequest request;
status = usage_session_->GenerateReleaseRequest(&request);
usage_info->clear();
usage_info->push_back(request.message);
switch (status) {
case KEY_MESSAGE:
break;
case KEY_CANCELED: // usage information not present in
usage_session_->DeleteLicense(); // OEMCrypto, delete and try again
usage_info->clear();
break;
default:
LOGE("CdmEngine::GetUsageInfo: generate release request error: %d",
status);
usage_info->clear();
break;
}
return status;
}
CdmResponseType CdmEngine::ReleaseAllUsageInfo(const std::string& app_id) {
if (NULL == usage_property_set_.get()) {
usage_property_set_.reset(new UsagePropertySet());
}
usage_property_set_->set_app_id(app_id);
CdmResponseType status = NO_ERROR;
for (int j = kSecurityLevelL1; j < kSecurityLevelUnknown; ++j) {
DeviceFiles handle(file_system_);
if (handle.Init(static_cast<CdmSecurityLevel>(j))) {
std::vector<std::string> provider_session_tokens;
if (!handle.DeleteAllUsageInfoForApp(app_id, &provider_session_tokens)) {
LOGE("CdmEngine::ReleaseAllUsageInfo: failed to delete L%d secure"
"stops", j);
status = RELEASE_ALL_USAGE_INFO_ERROR_1;
} else {
SecurityLevel security_level =
static_cast<CdmSecurityLevel>(j) == kSecurityLevelL3
? kLevel3
: kLevelDefault;
usage_property_set_->set_security_level(security_level);
usage_session_.reset(new CdmSession(file_system_));
usage_session_->Init(usage_property_set_.get());
CdmResponseType status2 = usage_session_->
DeleteMultipleUsageInformation(provider_session_tokens);
if (status2 != NO_ERROR) {
status = status2;
}
}
} else {
LOGE("CdmEngine::ReleaseAllUsageInfo: failed to initialize L%d device"
"files", j);
status = RELEASE_ALL_USAGE_INFO_ERROR_2;
}
}
usage_session_.reset(NULL);
return status;
}
CdmResponseType CdmEngine::ReleaseUsageInfo(
const CdmUsageInfoReleaseMessage& message) {
if (NULL == usage_session_.get()) {
LOGE("CdmEngine::ReleaseUsageInfo: cdm session not initialized");
return RELEASE_USAGE_INFO_ERROR;
}
CdmResponseType status = usage_session_->ReleaseKey(message);
usage_session_.reset(NULL);
if (NO_ERROR != status) {
LOGE("CdmEngine::ReleaseUsageInfo: release key error: %d", status);
}
return status;
}
CdmResponseType CdmEngine::LoadUsageSession(const CdmKeySetId& key_set_id,
CdmKeyMessage* release_message) {
LOGI("CdmEngine::LoadUsageSession");
// This method is currently only used by the CE CDM, in which all session IDs
// are key set IDs.
assert(Properties::AlwaysUseKeySetIds());
if (key_set_id.empty()) {
LOGE("CdmEngine::LoadUsageSession: invalid key set id");
return EMPTY_KEYSET_ID_ENG_5;
}
CdmSessionMap::iterator iter = sessions_.find(key_set_id);
if (iter == sessions_.end()) {
LOGE("CdmEngine::LoadUsageSession: session_id not found = %s ",
key_set_id.c_str());
return SESSION_NOT_FOUND_11;
}
if (!release_message) {
LOGE("CdmEngine::LoadUsageSession: no release message destination");
return INVALID_PARAMETERS_ENG_11;
}
DeviceFiles handle(file_system_);
if (!handle.Init(iter->second->GetSecurityLevel())) {
LOGE("CdmEngine::LoadUsageSession: unable to initialize device files");
return LOAD_USAGE_INFO_FILE_ERROR;
}
std::string app_id;
iter->second->GetApplicationId(&app_id);
CdmKeyMessage key_message;
CdmKeyResponse key_response;
std::string usage_entry;
if (!handle.RetrieveUsageInfoByKeySetId(app_id, key_set_id, &key_message,
&key_response, &usage_entry)) {
LOGE("CdmEngine::LoadUsageSession: unable to find usage information");
return LOAD_USAGE_INFO_MISSING;
}
CdmResponseType status;
M_TIME(
status = iter->second->RestoreUsageSession(
key_message,
key_response),
iter->second->GetMetrics(),
cdm_session_restore_usage_session_,
status);
if (KEY_ADDED != status) {
LOGE("CdmEngine::LoadUsageSession: usage session error %ld", status);
return status;
}
CdmKeyRequest request;
M_TIME(
status = iter->second->GenerateReleaseRequest(
&request),
iter->second->GetMetrics(),
cdm_session_generate_release_request_,
status);
*release_message = request.message;
switch (status) {
case KEY_MESSAGE:
break;
case KEY_CANCELED:
/* usage information not present in OEMCrypto, delete and try again */
M_TIME(
iter->second->DeleteLicense(),
iter->second->GetMetrics(),
cdm_session_delete_license_);
break;
default:
LOGE("CdmEngine::LoadUsageSession: generate release request error: %d",
status);
break;
}
return status;
}
CdmResponseType CdmEngine::Decrypt(const CdmSessionId& session_id,
const CdmDecryptionParameters& parameters) {
if (parameters.key_id == NULL) {
LOGE("CdmEngine::Decrypt: no key_id");
return INVALID_DECRYPT_PARAMETERS_ENG_1;
}
if (parameters.encrypt_buffer == NULL) {
LOGE("CdmEngine::Decrypt: no src encrypt buffer");
return INVALID_DECRYPT_PARAMETERS_ENG_2;
}
if (parameters.iv == NULL) {
LOGE("CdmEngine::Decrypt: no iv");
return INVALID_DECRYPT_PARAMETERS_ENG_3;
}
if (parameters.decrypt_buffer == NULL) {
if (!parameters.is_secure &&
!Properties::Properties::oem_crypto_use_fifo()) {
LOGE("CdmEngine::Decrypt: no dest decrypt buffer");
return INVALID_DECRYPT_PARAMETERS_ENG_4;
}
// else we must be level 1 direct and we don't need to return a buffer.
}
CdmSessionMap::iterator session_iter = sessions_.end();
if (session_id.empty()) {
// Loop through the sessions to find the session containing the key_id
// with the longest remaining license validity.
int64_t seconds_remaining = 0;
for (CdmSessionMap::iterator iter = sessions_.begin();
iter != sessions_.end(); ++iter) {
bool is_key_loaded;
M_TIME(
is_key_loaded = iter->second->IsKeyLoaded(
*parameters.key_id),
iter->second->GetMetrics(),
cdm_session_is_key_loaded_,
is_key_loaded);
if (is_key_loaded) {
int64_t duration = iter->second->GetDurationRemaining();
if (duration > seconds_remaining) {
session_iter = iter;
seconds_remaining = duration;
}
}
}
} else {
session_iter = sessions_.find(session_id);
}
if (session_iter == sessions_.end()) {
LOGE("CdmEngine::Decrypt: session not found: id=%s, id size=%d",
session_id.c_str(), session_id.size());
return SESSION_NOT_FOUND_FOR_DECRYPT;
}
CdmResponseType decrypt_sts;
M_TIME(
decrypt_sts = session_iter->second->Decrypt(
parameters),
session_iter->second->GetMetrics(),
cdm_session_decrypt_,
decrypt_sts);
return decrypt_sts;
}
CdmResponseType CdmEngine::GenericEncrypt(
const std::string& session_id, const std::string& in_buffer,
const std::string& key_id, const std::string& iv,
CdmEncryptionAlgorithm algorithm, std::string* out_buffer) {
CdmSessionMap::iterator iter = sessions_.find(session_id);
if (iter == sessions_.end()) {
LOGE("CdmEngine::GenericEncrypt: session_id not found = %s ",
session_id.c_str());
return SESSION_NOT_FOUND_13;
}
CdmResponseType sts;
M_TIME(
sts = iter->second->GenericEncrypt(
in_buffer,
key_id,
iv,
algorithm,
out_buffer),
iter->second->GetMetrics(),
cdm_session_generic_encrypt_,
sts,
metrics::Pow2Bucket(in_buffer.size()),
algorithm);
return sts;
}
CdmResponseType CdmEngine::GenericDecrypt(
const std::string& session_id, const std::string& in_buffer,
const std::string& key_id, const std::string& iv,
CdmEncryptionAlgorithm algorithm,
std::string* out_buffer) {
CdmSessionMap::iterator iter = sessions_.find(session_id);
if (iter == sessions_.end()) {
LOGE("CdmEngine::GenericDecrypt: session_id not found = %s ",
session_id.c_str());
return SESSION_NOT_FOUND_14;
}
CdmResponseType sts;
M_TIME(
sts = iter->second->GenericDecrypt(
in_buffer,
key_id,
iv,
algorithm,
out_buffer),
iter->second->GetMetrics(),
cdm_session_generic_decrypt_,
sts,
metrics::Pow2Bucket(in_buffer.size()),
algorithm);
return sts;
}
CdmResponseType CdmEngine::GenericSign(
const std::string& session_id, const std::string& message,
const std::string& key_id, CdmSigningAlgorithm algorithm,
std::string* signature) {
CdmSessionMap::iterator iter = sessions_.find(session_id);
if (iter == sessions_.end()) {
LOGE("CdmEngine::GenericSign: session_id not found = %s ",
session_id.c_str());
return SESSION_NOT_FOUND_15;
}
CdmResponseType sts;
M_TIME(
sts = iter->second->GenericSign(
message,
key_id,
algorithm,
signature),
iter->second->GetMetrics(),
cdm_session_generic_sign_,
sts,
metrics::Pow2Bucket(message.size()),
algorithm);
return sts;
}
CdmResponseType CdmEngine::GenericVerify(
const std::string& session_id, const std::string& message,
const std::string& key_id, CdmSigningAlgorithm algorithm,
const std::string& signature) {
CdmSessionMap::iterator iter = sessions_.find(session_id);
if (iter == sessions_.end()) {
LOGE("CdmEngine::GenericVerify: session_id not found = %s ",
session_id.c_str());
return SESSION_NOT_FOUND_16;
}
CdmResponseType sts;
M_TIME(
sts = iter->second->GenericVerify(
message,
key_id,
algorithm,
signature),
iter->second->GetMetrics(),
cdm_session_generic_verify_,
sts,
metrics::Pow2Bucket(message.size()),
algorithm);
return sts;
}
bool CdmEngine::IsKeyLoaded(const KeyId& key_id) {
for (CdmSessionMap::iterator iter = sessions_.begin();
iter != sessions_.end(); ++iter) {
if (iter->second->IsKeyLoaded(key_id)) {
return true;
}
}
return false;
}
bool CdmEngine::FindSessionForKey(const KeyId& key_id,
CdmSessionId* session_id) {
if (NULL == session_id) {
LOGE("CdmEngine::FindSessionForKey: session id not provided");
return false;
}
uint32_t session_sharing_id = Properties::GetSessionSharingId(*session_id);
CdmSessionMap::iterator session_iter = sessions_.end();
int64_t seconds_remaining = 0;
for (CdmSessionMap::iterator iter = sessions_.begin();
iter != sessions_.end(); ++iter) {
CdmSessionId local_session_id = iter->second->session_id();
if (Properties::GetSessionSharingId(local_session_id) ==
session_sharing_id) {
if (iter->second->IsKeyLoaded(key_id)) {
int64_t duration = iter->second->GetDurationRemaining();
if (duration > seconds_remaining) {
session_iter = iter;
seconds_remaining = duration;
}
}
}
}
if (session_iter != sessions_.end()) {
*session_id = session_iter->second->session_id();
return true;
}
return false;
}
bool CdmEngine::NotifyResolution(const CdmSessionId& session_id, uint32_t width,
uint32_t height) {
CdmSessionMap::iterator iter = sessions_.find(session_id);
if (iter != sessions_.end()) {
iter->second->NotifyResolution(width, height);
return true;
}
return false;
}
bool CdmEngine::ValidateKeySystem(const CdmKeySystem& key_system) {
return (key_system.find("widevine") != std::string::npos);
}
void CdmEngine::OnTimerEvent() {
Clock clock;
uint64_t current_time = clock.GetCurrentTime();
bool usage_update_period_expired = false;
if (current_time - last_usage_information_update_time_ >
kUpdateUsageInformationPeriod) {
usage_update_period_expired = true;
last_usage_information_update_time_ = current_time;
}
bool is_initial_usage_update = false;
bool is_usage_update_needed = false;
AutoLock lock(session_list_lock_);
for (CdmSessionMap::iterator iter = sessions_.begin();
iter != sessions_.end(); ++iter) {
is_initial_usage_update =
is_initial_usage_update || iter->second->is_initial_usage_update();
is_usage_update_needed =
is_usage_update_needed || iter->second->is_usage_update_needed();
iter->second->OnTimerEvent(usage_update_period_expired);
}
if (is_usage_update_needed &&
(usage_update_period_expired || is_initial_usage_update)) {
bool has_usage_been_updated = false;
for (CdmSessionMap::iterator iter = sessions_.begin();
iter != sessions_.end(); ++iter) {
iter->second->reset_usage_flags();
if (!has_usage_been_updated) {
// usage is updated for all sessions so this needs to be
// called only once per update usage information period
CdmResponseType status;
M_TIME(
status = iter->second->UpdateUsageInformation(),
iter->second->GetMetrics(),
cdm_session_update_usage_information_,
status);
if (NO_ERROR != status) {
LOGW("Update usage information failed: %d", status);
} else {
has_usage_been_updated = true;
}
}
}
}
CloseExpiredReleaseSessions();
}
void CdmEngine::OnKeyReleaseEvent(const CdmKeySetId& key_set_id) {
AutoLock lock(session_list_lock_);
for (CdmSessionMap::iterator iter = sessions_.begin();
iter != sessions_.end(); ++iter) {
iter->second->OnKeyReleaseEvent(key_set_id);
}
}
std::string CdmEngine::MapHdcpVersion(
CryptoSession::HdcpCapability version) {
switch (version) {
case HDCP_NONE:
return QUERY_VALUE_UNPROTECTED;
case HDCP_V1:
return QUERY_VALUE_HDCP_V1;
case HDCP_V2:
return QUERY_VALUE_HDCP_V2_0;
case HDCP_V2_1:
return QUERY_VALUE_HDCP_V2_1;
case HDCP_V2_2:
return QUERY_VALUE_HDCP_V2_2;
case HDCP_NO_DIGITAL_OUTPUT:
return QUERY_VALUE_DISCONNECTED;
}
return "";
}
void CdmEngine::CloseExpiredReleaseSessions() {
int64_t current_time = clock_.GetCurrentTime();
std::set<CdmSessionId> close_session_set;
{
AutoLock lock(release_key_sets_lock_);
for (CdmReleaseKeySetMap::iterator iter = release_key_sets_.begin();
iter != release_key_sets_.end();) {
if (iter->second.second < current_time) {
close_session_set.insert(iter->second.first);
release_key_sets_.erase(iter++);
} else {
++iter;
}
}
}
for (std::set<CdmSessionId>::iterator iter = close_session_set.begin();
iter != close_session_set.end(); ++iter) {
CloseSession(*iter);
}
}
void CdmEngine::DeleteAllUsageReportsUponFactoryReset() {
std::string device_base_path_level1 = "";
std::string device_base_path_level3 = "";
Properties::GetDeviceFilesBasePath(kSecurityLevelL1,
&device_base_path_level1);
Properties::GetDeviceFilesBasePath(kSecurityLevelL3,
&device_base_path_level3);
if (!file_system_->Exists(device_base_path_level1) &&
!file_system_->Exists(device_base_path_level3)) {
scoped_ptr<CryptoSession> crypto_session(new CryptoSession(&metrics_));
CdmResponseType status;
M_TIME(
status = crypto_session->Open(
cert_provisioning_requested_security_level_),
&metrics_,
crypto_session_open_,
status,
cert_provisioning_requested_security_level_);
if (NO_ERROR == status) {
M_TIME(
status = crypto_session->DeleteAllUsageReports(),
&metrics_,
crypto_session_delete_all_usage_reports_,
status);
if (NO_ERROR != status) {
LOGW(
"CdmEngine::GetProvisioningRequest: "
"Fails to delete usage reports: %d", status);
}
} else {
LOGW(
"CdmEngine::GetProvisioningRequest: "
"Fails to open crypto session: error=%d.\n"
"Usage reports are not removed after factory reset.", status);
}
}
}
} // namespace wvcdm