Source release 15.1.0
This commit is contained in:
@@ -325,8 +325,7 @@ class CdmEngine {
|
||||
// data. Returns true if the metrics data is populated, false otherwise.
|
||||
// |engine_metrics| is owned by the caller and must not be null.
|
||||
// The CdmEngine implementation is a placeholder. Just return false.
|
||||
virtual bool GetMetricsSnapshot(
|
||||
__attribute__((unused)) drm_metrics::WvCdmMetrics *metrics) {
|
||||
virtual bool GetMetricsSnapshot(drm_metrics::WvCdmMetrics* /* metrics */) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ class EntitlementKeySession : public ContentKeySession {
|
||||
metrics::CryptoMetrics* metrics);
|
||||
~EntitlementKeySession() override {}
|
||||
|
||||
KeySessionType Type() { return kEntitlement; }
|
||||
KeySessionType Type() override { return kEntitlement; }
|
||||
|
||||
// Load Keys for ContentKeySession
|
||||
OEMCryptoResult LoadKeys(const std::string& message,
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
namespace video_widevine {
|
||||
class SignedMessage;
|
||||
class LicenseRequest;
|
||||
class VersionInfo;
|
||||
} // namespace video_widevine
|
||||
|
||||
namespace wvcdm {
|
||||
@@ -29,6 +30,7 @@ class CryptoKey;
|
||||
|
||||
using ::google::protobuf::RepeatedPtrField;
|
||||
using video_widevine::License_KeyContainer;
|
||||
using video_widevine::VersionInfo;
|
||||
using video_widevine::WidevinePsshData_EntitledKey;
|
||||
|
||||
class CdmLicense {
|
||||
@@ -75,6 +77,10 @@ class CdmLicense {
|
||||
|
||||
virtual bool is_offline() { return is_offline_; }
|
||||
|
||||
virtual const VersionInfo& GetServiceVersion() {
|
||||
return latest_service_version_;
|
||||
}
|
||||
|
||||
static bool ExtractProviderSessionToken(
|
||||
const CdmKeyResponse& license_response,
|
||||
std::string* provider_session_token);
|
||||
@@ -152,6 +158,9 @@ class CdmLicense {
|
||||
RepeatedPtrField<License_KeyContainer> entitlement_keys_;
|
||||
|
||||
std::string provider_client_token_;
|
||||
// This is the latest version info extracted from the SignedMessage in
|
||||
// HandleKeyResponse
|
||||
VersionInfo latest_service_version_;
|
||||
|
||||
#if defined(UNIT_TEST)
|
||||
friend class CdmLicenseTestPeer;
|
||||
|
||||
@@ -68,7 +68,7 @@ class PolicyEngine {
|
||||
virtual void SetLicenseForRelease(const video_widevine::License& license);
|
||||
|
||||
// Call this on first decrypt to set the start of playback.
|
||||
virtual void BeginDecryption(void);
|
||||
virtual bool BeginDecryption(void);
|
||||
virtual void DecryptionEvent(void);
|
||||
|
||||
// UpdateLicense is used in handling a license response for a renewal request.
|
||||
|
||||
@@ -83,6 +83,7 @@ class UsageTableHeader {
|
||||
static int64_t GetRandomInRange(size_t upper_bound_exclusive);
|
||||
static int64_t GetRandomInRangeWithExclusion(size_t upper_bound_exclusive,
|
||||
size_t exclude);
|
||||
size_t size() { return usage_entry_info_.size(); }
|
||||
|
||||
private:
|
||||
CdmResponseType MoveEntry(uint32_t from /* usage entry number */,
|
||||
|
||||
@@ -87,6 +87,7 @@ static const std::string QUERY_KEY_DECRYPT_HASH_SUPPORT =
|
||||
|
||||
static const std::string QUERY_VALUE_TRUE = "True";
|
||||
static const std::string QUERY_VALUE_FALSE = "False";
|
||||
static const std::string QUERY_VALUE_NONE = "None";
|
||||
static const std::string QUERY_VALUE_STREAMING = "Streaming";
|
||||
static const std::string QUERY_VALUE_OFFLINE = "Offline";
|
||||
static const std::string QUERY_VALUE_SECURITY_LEVEL_L1 = "L1";
|
||||
|
||||
@@ -631,7 +631,10 @@ CdmResponseType CdmEngine::QueryStatus(SecurityLevel security_level,
|
||||
} else if (query_token == QUERY_KEY_CURRENT_SRM_VERSION) {
|
||||
uint16_t current_srm_version;
|
||||
status = crypto_session->GetSrmVersion(¤t_srm_version);
|
||||
if (status != NO_ERROR) {
|
||||
if (status == NOT_IMPLEMENTED_ERROR) {
|
||||
*query_response = QUERY_VALUE_NONE;
|
||||
return NO_ERROR;
|
||||
} else if (status != NO_ERROR) {
|
||||
LOGW("CdmEngine::QueryStatus: GetCurrentSRMVersion failed: %d", status);
|
||||
return status;
|
||||
}
|
||||
@@ -1098,24 +1101,7 @@ CdmResponseType CdmEngine::DeleteUsageRecord(const std::string& app_id,
|
||||
return DELETE_USAGE_ERROR_2;
|
||||
}
|
||||
|
||||
// Got provider token. Remove from OEMCrypto.
|
||||
std::unique_ptr<CryptoSession> crypto_session(
|
||||
CryptoSession::MakeCryptoSession(metrics_->GetCryptoMetrics()));
|
||||
CdmResponseType status = crypto_session->Open(
|
||||
security_level == kSecurityLevelL3 ? kLevel3 : kLevelDefault);
|
||||
if (status == NO_ERROR) {
|
||||
status = crypto_session->DeleteUsageInformation(provider_session_token);
|
||||
}
|
||||
if (status != NO_ERROR) {
|
||||
LOGE("CdmEngine::DeleteUsageRecord: OEMCrypto failure");
|
||||
}
|
||||
|
||||
// Remove from file system.
|
||||
if (!handle.DeleteUsageInfo(app_id, provider_session_token)) {
|
||||
LOGE("CdmEngine::DeleteUsageRecord: file system failure");
|
||||
return DELETE_USAGE_ERROR_3;
|
||||
}
|
||||
return status;
|
||||
return RemoveUsageInfo(app_id, provider_session_token);
|
||||
}
|
||||
|
||||
CdmResponseType CdmEngine::GetOfflineLicenseState(
|
||||
@@ -1389,129 +1375,98 @@ CdmResponseType CdmEngine::GetUsageInfo(const std::string& app_id,
|
||||
}
|
||||
|
||||
CdmResponseType CdmEngine::RemoveAllUsageInfo(
|
||||
const std::string& app_id, CdmSecurityLevel security_level) {
|
||||
const std::string& app_id, CdmSecurityLevel cdm_security_level) {
|
||||
LOGI("CdmEngine::RemoveAllUsageInfo: %s, security level: %d",
|
||||
app_id.c_str(), security_level);
|
||||
DeviceFiles handle(file_system_);
|
||||
if (!handle.Init(security_level)) {
|
||||
LOGE("CdmEngine::RemoveAllUsageInfo: unable to initialize device files");
|
||||
return REMOVE_ALL_USAGE_INFO_ERROR_6;
|
||||
}
|
||||
std::vector<std::string> provider_session_tokens;
|
||||
if (!handle.DeleteAllUsageInfoForApp(app_id, &provider_session_tokens)) {
|
||||
LOGE("CdmEngine::RemoveAllUsageInfo: failed to delete usage records");
|
||||
return REMOVE_ALL_USAGE_INFO_ERROR_7;
|
||||
}
|
||||
|
||||
if (provider_session_tokens.size() == 0UL) {
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
// Got at least one provider token. Remove from OEMCrypto.
|
||||
std::unique_ptr<CryptoSession> crypto_session(
|
||||
CryptoSession::MakeCryptoSession(metrics_->GetCryptoMetrics()));
|
||||
CdmResponseType status = crypto_session->Open(
|
||||
security_level == kSecurityLevelL3 ? kLevel3 : kLevelDefault);
|
||||
if (status == NO_ERROR) {
|
||||
status = crypto_session->
|
||||
DeleteMultipleUsageInformation(provider_session_tokens);
|
||||
}
|
||||
if (status != NO_ERROR) {
|
||||
LOGE("CdmEngine::RemoveAllUsageInfo: CryptoSession failure");
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
CdmResponseType CdmEngine::RemoveAllUsageInfo(const std::string& app_id) {
|
||||
LOGI("CdmEngine::RemoveAllUsageInfo: %s", app_id.c_str());
|
||||
if (NULL == usage_property_set_.get()) {
|
||||
app_id.c_str(), cdm_security_level);
|
||||
if (usage_property_set_.get() == nullptr) {
|
||||
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))) {
|
||||
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_, metrics_->AddSession()));
|
||||
usage_session_->Init(usage_property_set_.get());
|
||||
DeviceFiles handle(file_system_);
|
||||
if (handle.Init(cdm_security_level)) {
|
||||
SecurityLevel security_level =
|
||||
cdm_security_level == kSecurityLevelL3 ? kLevel3 : kLevelDefault;
|
||||
usage_property_set_->set_security_level(security_level);
|
||||
usage_session_.reset(new CdmSession(file_system_, metrics_->AddSession()));
|
||||
usage_session_->Init(usage_property_set_.get());
|
||||
|
||||
switch (usage_session_->get_usage_support_type()) {
|
||||
case kUsageEntrySupport: {
|
||||
std::vector<DeviceFiles::CdmUsageData> usage_data;
|
||||
// Retrieve all usage information but delete only one before
|
||||
// refetching. This is because deleting the usage entry
|
||||
// might cause other entries to be shifted and information updated.
|
||||
do {
|
||||
if (!handle.RetrieveUsageInfo(
|
||||
DeviceFiles::GetUsageInfoFileName(app_id),
|
||||
&usage_data)) {
|
||||
LOGW("CdmEngine::RemoveAllUsageInfo: failed to retrieve usage info");
|
||||
break;
|
||||
}
|
||||
|
||||
if (usage_data.empty()) break;
|
||||
|
||||
CdmResponseType res = usage_session_->DeleteUsageEntry(
|
||||
usage_data[0].usage_entry_number);
|
||||
|
||||
if (res != NO_ERROR) {
|
||||
LOGW("CdmEngine::RemoveAllUsageInfo: failed to delete usage "
|
||||
"entry: error: %d", res);
|
||||
break;
|
||||
}
|
||||
|
||||
if (!handle.DeleteUsageInfo(
|
||||
DeviceFiles::GetUsageInfoFileName(app_id),
|
||||
usage_data[0].provider_session_token)) {
|
||||
LOGW("CdmEngine::RemoveAllUsageInfo: failed to delete usage "
|
||||
"info");
|
||||
break;
|
||||
}
|
||||
} while (!usage_data.empty());
|
||||
|
||||
std::vector<std::string> provider_session_tokens;
|
||||
if (!handle.DeleteAllUsageInfoForApp(
|
||||
switch (usage_session_->get_usage_support_type()) {
|
||||
case kUsageEntrySupport: {
|
||||
std::vector<DeviceFiles::CdmUsageData> usage_data;
|
||||
// Retrieve all usage information but delete only one before
|
||||
// refetching. This is because deleting the usage entry
|
||||
// might cause other entries to be shifted and information updated.
|
||||
do {
|
||||
if (!handle.RetrieveUsageInfo(
|
||||
DeviceFiles::GetUsageInfoFileName(app_id),
|
||||
&provider_session_tokens)) {
|
||||
status = REMOVE_ALL_USAGE_INFO_ERROR_5;
|
||||
&usage_data)) {
|
||||
LOGW("CdmEngine::RemoveAllUsageInfo: failed to retrieve usage info");
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case kUsageTableSupport: {
|
||||
std::vector<std::string> provider_session_tokens;
|
||||
if (!handle.DeleteAllUsageInfoForApp(
|
||||
|
||||
if (usage_data.empty()) break;
|
||||
|
||||
CdmResponseType res = usage_session_->DeleteUsageEntry(
|
||||
usage_data[0].usage_entry_number);
|
||||
|
||||
if (res != NO_ERROR) {
|
||||
LOGW("CdmEngine::RemoveAllUsageInfo: failed to delete usage "
|
||||
"entry: error: %d", res);
|
||||
break;
|
||||
}
|
||||
|
||||
if (!handle.DeleteUsageInfo(
|
||||
DeviceFiles::GetUsageInfoFileName(app_id),
|
||||
&provider_session_tokens)) {
|
||||
LOGE("CdmEngine::RemoveAllUsageInfo: failed to delete %d secure"
|
||||
"stops", j);
|
||||
status = REMOVE_ALL_USAGE_INFO_ERROR_1;
|
||||
} else {
|
||||
CdmResponseType status2 = usage_session_->
|
||||
DeleteMultipleUsageInformation(provider_session_tokens);
|
||||
if (status2 != NO_ERROR) status = status2;
|
||||
usage_data[0].provider_session_token)) {
|
||||
LOGW("CdmEngine::RemoveAllUsageInfo: failed to delete usage "
|
||||
"info");
|
||||
break;
|
||||
}
|
||||
break;
|
||||
} while (!usage_data.empty());
|
||||
|
||||
std::vector<std::string> provider_session_tokens;
|
||||
if (!handle.DeleteAllUsageInfoForApp(
|
||||
DeviceFiles::GetUsageInfoFileName(app_id),
|
||||
&provider_session_tokens)) {
|
||||
status = REMOVE_ALL_USAGE_INFO_ERROR_5;
|
||||
}
|
||||
default:
|
||||
// Ignore
|
||||
break;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
LOGE("CdmEngine::RemoveAllUsageInfo: failed to initialize L%d device"
|
||||
"files", j);
|
||||
status = REMOVE_ALL_USAGE_INFO_ERROR_2;
|
||||
case kUsageTableSupport: {
|
||||
std::vector<std::string> provider_session_tokens;
|
||||
if (!handle.DeleteAllUsageInfoForApp(
|
||||
DeviceFiles::GetUsageInfoFileName(app_id),
|
||||
&provider_session_tokens)) {
|
||||
LOGE("CdmEngine::RemoveAllUsageInfo: failed to delete %d secure"
|
||||
"stops", cdm_security_level);
|
||||
status = REMOVE_ALL_USAGE_INFO_ERROR_1;
|
||||
} else {
|
||||
CdmResponseType status2 = usage_session_->
|
||||
DeleteMultipleUsageInformation(provider_session_tokens);
|
||||
if (status2 != NO_ERROR) status = status2;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
// Ignore
|
||||
break;
|
||||
}
|
||||
}
|
||||
usage_session_.reset(NULL);
|
||||
return status;
|
||||
}
|
||||
|
||||
CdmResponseType CdmEngine::RemoveAllUsageInfo(const std::string& app_id) {
|
||||
LOGI("CdmEngine::RemoveAllUsageInfo: %s", app_id.c_str());
|
||||
CdmResponseType status_l1, status_l3;
|
||||
status_l1 = status_l3 = NO_ERROR;
|
||||
status_l1 = RemoveAllUsageInfo(app_id, kSecurityLevelL1);
|
||||
status_l3 = RemoveAllUsageInfo(app_id, kSecurityLevelL3);
|
||||
return (status_l3 == NO_ERROR) ? status_l3 : status_l1;
|
||||
}
|
||||
|
||||
CdmResponseType CdmEngine::RemoveUsageInfo(
|
||||
const std::string& app_id,
|
||||
const CdmSecureStopId& provider_session_token) {
|
||||
@@ -1653,6 +1608,7 @@ CdmResponseType CdmEngine::LoadUsageSession(const CdmKeySetId& key_set_id,
|
||||
}
|
||||
|
||||
int error_detail = NO_ERROR;
|
||||
usage_data.key_set_id = key_set_id;
|
||||
CdmResponseType status = session->RestoreUsageSession(usage_data,
|
||||
&error_detail);
|
||||
session->GetMetrics()->cdm_session_restore_usage_session_.Increment(
|
||||
@@ -1854,7 +1810,7 @@ CdmResponseType CdmEngine::ParseDecryptHashString(
|
||||
return INVALID_DECRYPT_HASH_FORMAT;
|
||||
}
|
||||
|
||||
std::vector<uint8_t> hash_vec = wvcdm::Base64Decode(tokens[2]);
|
||||
std::vector<uint8_t> hash_vec = wvcdm::a2b_hex(tokens[2]);
|
||||
if (hash_vec.empty()) {
|
||||
LOGE("CdmEngine::ParseDecryptHashString: malformed hash: %s",
|
||||
hash_string.c_str());
|
||||
|
||||
@@ -267,6 +267,7 @@ CdmResponseType CdmSession::RestoreOfflineSession(
|
||||
} else {
|
||||
CdmResponseType sts = usage_table_header_->LoadEntry(
|
||||
crypto_session_.get(), usage_entry_, usage_entry_number_);
|
||||
crypto_metrics_->usage_table_header_load_entry_.Increment(sts);
|
||||
if (sts != NO_ERROR) {
|
||||
LOGE(
|
||||
"CdmSession::RestoreOfflineSession: failed to load usage entry = "
|
||||
@@ -341,6 +342,7 @@ CdmResponseType CdmSession::RestoreUsageSession(
|
||||
usage_table_header_ != NULL) {
|
||||
sts = usage_table_header_->LoadEntry(
|
||||
crypto_session_.get(), usage_entry_, usage_entry_number_);
|
||||
crypto_metrics_->usage_table_header_load_entry_.Increment(sts);
|
||||
if (sts != NO_ERROR) {
|
||||
LOGE("CdmSession::RestoreUsageSession: failed to load usage entry = %d",
|
||||
sts);
|
||||
@@ -504,17 +506,24 @@ CdmResponseType CdmSession::AddKeyInternal(const CdmKeyResponse& key_response) {
|
||||
sts = usage_table_header_->AddEntry(
|
||||
crypto_session_.get(), is_offline_, key_set_id_,
|
||||
DeviceFiles::GetUsageInfoFileName(app_id), &usage_entry_number_);
|
||||
crypto_metrics_->usage_table_header_add_entry_.Increment(sts);
|
||||
if (sts != NO_ERROR) return sts;
|
||||
}
|
||||
}
|
||||
sts = license_parser_->HandleKeyResponse(key_response);
|
||||
|
||||
// Update the license sdk and service versions.
|
||||
const VersionInfo& version_info = license_parser_->GetServiceVersion();
|
||||
metrics_->license_sdk_version_.Record(version_info.license_sdk_version());
|
||||
metrics_->license_sdk_version_.Record(version_info.license_service_version());
|
||||
|
||||
// Update or delete entry if usage table header+entries are supported
|
||||
if (usage_support_type_ == kUsageEntrySupport &&
|
||||
!provider_session_token.empty() && usage_table_header_ != NULL) {
|
||||
if (sts != KEY_ADDED) {
|
||||
CdmResponseType delete_sts = usage_table_header_->DeleteEntry(
|
||||
usage_entry_number_, file_handle_.get(), crypto_metrics_);
|
||||
crypto_metrics_->usage_table_header_delete_entry_.Increment(delete_sts);
|
||||
if (delete_sts != NO_ERROR) {
|
||||
LOGW("CdmSession::AddKey: Delete usage entry failed = %d",
|
||||
delete_sts);
|
||||
@@ -629,8 +638,7 @@ CdmResponseType CdmSession::Decrypt(const CdmDecryptionParameters& params) {
|
||||
|
||||
if (status == NO_ERROR) {
|
||||
if (is_initial_decryption_) {
|
||||
policy_engine_->BeginDecryption();
|
||||
is_initial_decryption_ = false;
|
||||
is_initial_decryption_ = !policy_engine_->BeginDecryption();
|
||||
}
|
||||
has_decrypted_since_last_report_ = true;
|
||||
if (!is_usage_update_needed_) {
|
||||
@@ -712,6 +720,7 @@ CdmResponseType CdmSession::GenerateReleaseRequest(CdmKeyRequest* key_request) {
|
||||
usage_support_type_ == kUsageEntrySupport) {
|
||||
status =
|
||||
usage_table_header_->UpdateEntry(crypto_session_.get(), &usage_entry_);
|
||||
|
||||
if (status != NO_ERROR) {
|
||||
LOGE(
|
||||
"CdmSession::GenerateReleaseRequest: Update usage entry failed = "
|
||||
@@ -765,6 +774,7 @@ CdmResponseType CdmSession::DeleteUsageEntry(uint32_t usage_entry_number) {
|
||||
|
||||
// The usage entry cannot be deleted if it has a crypto session handling
|
||||
// it, so close and reopen session.
|
||||
UpdateUsageEntryInformation();
|
||||
CdmResponseType sts;
|
||||
crypto_session_->Close();
|
||||
crypto_session_.reset(CryptoSession::MakeCryptoSession(crypto_metrics_));
|
||||
@@ -785,8 +795,10 @@ CdmResponseType CdmSession::DeleteUsageEntry(uint32_t usage_entry_number) {
|
||||
return INCORRECT_USAGE_SUPPORT_TYPE_1;
|
||||
}
|
||||
|
||||
return usage_table_header_->DeleteEntry(usage_entry_number,
|
||||
file_handle_.get(), crypto_metrics_);
|
||||
sts = usage_table_header_->DeleteEntry(usage_entry_number,
|
||||
file_handle_.get(), crypto_metrics_);
|
||||
crypto_metrics_->usage_table_header_delete_entry_.Increment(sts);
|
||||
return sts;
|
||||
}
|
||||
|
||||
bool CdmSession::IsKeyLoaded(const KeyId& key_id) {
|
||||
@@ -924,14 +936,14 @@ CdmResponseType CdmSession::RemoveKeys() {
|
||||
}
|
||||
|
||||
CdmResponseType CdmSession::RemoveLicense() {
|
||||
CdmResponseType sts = NO_ERROR;
|
||||
if (is_offline_ || has_provider_session_token()) {
|
||||
DeleteLicenseFile();
|
||||
|
||||
if (usage_support_type_ == kUsageEntrySupport &&
|
||||
has_provider_session_token()) {
|
||||
CdmResponseType sts = DeleteUsageEntry(usage_entry_number_);
|
||||
if (NO_ERROR != sts) return sts;
|
||||
sts = DeleteUsageEntry(usage_entry_number_);
|
||||
}
|
||||
DeleteLicenseFile();
|
||||
}
|
||||
return NO_ERROR;
|
||||
}
|
||||
@@ -1025,12 +1037,12 @@ CdmResponseType CdmSession::UpdateUsageEntryInformation() {
|
||||
}
|
||||
|
||||
CdmResponseType sts = NO_ERROR;
|
||||
M_TIME(
|
||||
sts = usage_table_header_->UpdateEntry(crypto_session_.get(),
|
||||
&usage_entry_),
|
||||
crypto_metrics_,
|
||||
crypto_session_update_usage_entry_,
|
||||
sts);
|
||||
// TODO(blueeyes): Add measurements to all UpdateEntry calls in a way that
|
||||
// allos us to isolate this particular use case within
|
||||
// UpdateUsageEntryInformation.
|
||||
M_TIME(sts = usage_table_header_->UpdateEntry(crypto_session_.get(),
|
||||
&usage_entry_),
|
||||
crypto_metrics_, usage_table_header_update_entry_, sts);
|
||||
|
||||
if (sts != NO_ERROR) return sts;
|
||||
|
||||
|
||||
@@ -227,8 +227,7 @@ void CryptoSession::Init() {
|
||||
sts = OEMCrypto_SetSandbox(
|
||||
reinterpret_cast<const uint8_t*>(sandbox_id.c_str()),
|
||||
sandbox_id.length());
|
||||
// TODO(blueeyes): it might be worth saving the sandbox id in a
|
||||
// metric.
|
||||
metrics_->oemcrypto_set_sandbox_.Record(sandbox_id);
|
||||
}
|
||||
M_TIME(sts = OEMCrypto_Initialize(), metrics_, oemcrypto_initialize_,
|
||||
sts);
|
||||
@@ -736,6 +735,7 @@ CdmResponseType CryptoSession::Open(SecurityLevel requested_security_level) {
|
||||
}
|
||||
}
|
||||
usage_table_header_ = *header;
|
||||
metrics_->usage_table_header_initial_size_.Record((*header)->size());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1499,11 +1499,7 @@ CdmResponseType CryptoSession::GenerateNonce(uint32_t* nonce) {
|
||||
|
||||
bool CryptoSession::SetDestinationBufferType() {
|
||||
if (Properties::oem_crypto_use_secure_buffers()) {
|
||||
if (GetSecurityLevel() == kSecurityLevelL1) {
|
||||
destination_buffer_type_ = OEMCrypto_BufferType_Secure;
|
||||
} else {
|
||||
destination_buffer_type_ = OEMCrypto_BufferType_Clear;
|
||||
}
|
||||
destination_buffer_type_ = OEMCrypto_BufferType_Secure;
|
||||
} else if (Properties::oem_crypto_use_fifo()) {
|
||||
destination_buffer_type_ = OEMCrypto_BufferType_Direct;
|
||||
} else if (Properties::oem_crypto_use_userspace_buffers()) {
|
||||
@@ -1812,6 +1808,14 @@ CdmResponseType CryptoSession::GetSrmVersion(uint16_t* srm_version) {
|
||||
status = OEMCrypto_GetCurrentSRMVersion(srm_version);
|
||||
});
|
||||
|
||||
// SRM is an optional feature. Whether it is implemented is up to the
|
||||
// discretion of OEMs
|
||||
if (status == OEMCrypto_ERROR_NOT_IMPLEMENTED) {
|
||||
LOGV("CryptoSession::GetSrmVersion: OEMCrypto_GetCurrentSRMVersion not "
|
||||
"implemented");
|
||||
return NOT_IMPLEMENTED_ERROR;
|
||||
}
|
||||
|
||||
return MapOEMCryptoResult(
|
||||
status, GET_SRM_VERSION_ERROR, "GetCurrentSRMVersion");
|
||||
}
|
||||
@@ -1863,6 +1867,7 @@ bool CryptoSession::GetResourceRatingTier(SecurityLevel security_level,
|
||||
}
|
||||
WithOecReadLock("GetResourceRatingTier", [&] {
|
||||
*tier = OEMCrypto_ResourceRatingTier(security_level);
|
||||
metrics_->oemcrypto_resource_rating_tier_.Record(*tier);
|
||||
});
|
||||
if (*tier < RESOURCE_RATING_TIER_LOW || *tier > RESOURCE_RATING_TIER_HIGH) {
|
||||
uint32_t api_version;
|
||||
@@ -1933,6 +1938,7 @@ CdmResponseType CryptoSession::SetDecryptHash(
|
||||
sts = OEMCrypto_SetDecryptHash(
|
||||
oec_session_id_, frame_number,
|
||||
reinterpret_cast<const uint8_t*>(hash.data()), hash.size());
|
||||
metrics_->oemcrypto_set_decrypt_hash_.Increment(sts);
|
||||
});
|
||||
|
||||
return MapOEMCryptoResult(sts, SET_DECRYPT_HASH_ERROR, "SetDecryptHash");
|
||||
@@ -1946,7 +1952,7 @@ CdmResponseType CryptoSession::GetDecryptHashError(std::string* error_string) {
|
||||
}
|
||||
error_string->clear();
|
||||
|
||||
uint32_t failed_frame_number;
|
||||
uint32_t failed_frame_number = 0;
|
||||
OEMCryptoResult sts;
|
||||
WithOecSessionLock("GetDecryptHashError", [&] {
|
||||
sts = OEMCrypto_GetHashErrorCode(oec_session_id_, &failed_frame_number);
|
||||
@@ -2274,6 +2280,7 @@ CdmResponseType CryptoSession::CreateUsageTableHeader(
|
||||
reinterpret_cast<uint8_t*>(
|
||||
const_cast<char*>(usage_table_header->data())),
|
||||
&usage_table_header_size);
|
||||
metrics_->oemcrypto_create_usage_table_header_.Increment(result);
|
||||
});
|
||||
|
||||
if (result == OEMCrypto_ERROR_SHORT_BUFFER) {
|
||||
@@ -2284,6 +2291,7 @@ CdmResponseType CryptoSession::CreateUsageTableHeader(
|
||||
reinterpret_cast<uint8_t*>(
|
||||
const_cast<char*>(usage_table_header->data())),
|
||||
&usage_table_header_size);
|
||||
metrics_->oemcrypto_create_usage_table_header_.Increment(result);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -2305,6 +2313,7 @@ CdmResponseType CryptoSession::LoadUsageTableHeader(
|
||||
requested_security_level_,
|
||||
reinterpret_cast<const uint8_t*>(usage_table_header.data()),
|
||||
usage_table_header.size());
|
||||
metrics_->oemcrypto_load_usage_table_header_.Increment(result);
|
||||
});
|
||||
|
||||
if (result != OEMCrypto_SUCCESS) {
|
||||
@@ -2347,6 +2356,7 @@ CdmResponseType CryptoSession::CreateUsageEntry(uint32_t* entry_number) {
|
||||
OEMCryptoResult result;
|
||||
WithOecWriteLock("CreateUsageEntry", [&] {
|
||||
result = OEMCrypto_CreateNewUsageEntry(oec_session_id_, entry_number);
|
||||
metrics_->oemcrypto_create_new_usage_entry_.Increment(result);
|
||||
});
|
||||
|
||||
if (result != OEMCrypto_SUCCESS) {
|
||||
@@ -2377,13 +2387,14 @@ CdmResponseType CryptoSession::LoadUsageEntry(
|
||||
oec_session_id_, entry_number,
|
||||
reinterpret_cast<const uint8_t*>(usage_entry.data()),
|
||||
usage_entry.size());
|
||||
metrics_->oemcrypto_load_usage_entry_.Increment(result);
|
||||
});
|
||||
|
||||
if (result != OEMCrypto_SUCCESS) {
|
||||
if (result == OEMCrypto_WARNING_GENERATION_SKEW) {
|
||||
LOGW("LoadUsageEntry: OEMCrypto_LoadUsageEntry warning: generation skew");
|
||||
} else {
|
||||
LOGE("LoadUsageTableHeader: OEMCrypto_LoadUsageEntry error: %d", result);
|
||||
LOGE("LoadUsageEntry: OEMCrypto_LoadUsageEntry error: %d", result);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2469,6 +2480,7 @@ CdmResponseType CryptoSession::ShrinkUsageTableHeader(
|
||||
result = OEMCrypto_ShrinkUsageTableHeader(
|
||||
requested_security_level_, new_entry_count, NULL,
|
||||
&usage_table_header_len);
|
||||
metrics_->oemcrypto_shrink_usage_table_header_.Increment(result);
|
||||
});
|
||||
|
||||
if (result == OEMCrypto_ERROR_SHORT_BUFFER) {
|
||||
@@ -2480,6 +2492,7 @@ CdmResponseType CryptoSession::ShrinkUsageTableHeader(
|
||||
reinterpret_cast<uint8_t*>(
|
||||
const_cast<char*>(usage_table_header->data())),
|
||||
&usage_table_header_len);
|
||||
metrics_->oemcrypto_shrink_usage_table_header_.Increment(result);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -2497,6 +2510,7 @@ CdmResponseType CryptoSession::MoveUsageEntry(uint32_t new_entry_number) {
|
||||
OEMCryptoResult result;
|
||||
WithOecWriteLock("MoveUsageEntry", [&] {
|
||||
result = OEMCrypto_MoveEntry(oec_session_id_, new_entry_number);
|
||||
metrics_->oemcrypto_move_entry_.Increment(result);
|
||||
});
|
||||
|
||||
return MapOEMCryptoResult(
|
||||
@@ -2545,6 +2559,7 @@ bool CryptoSession::CreateOldUsageEntry(
|
||||
reinterpret_cast<uint8_t*>(const_cast<char*>(client_mac_key.data())),
|
||||
reinterpret_cast<const uint8_t*>(provider_session_token.data()),
|
||||
provider_session_token.size());
|
||||
metrics_->oemcrypto_create_old_usage_entry_.Increment(result);
|
||||
});
|
||||
|
||||
if (result != OEMCrypto_SUCCESS) {
|
||||
@@ -2565,6 +2580,7 @@ CdmResponseType CryptoSession::CopyOldUsageEntry(
|
||||
oec_session_id_,
|
||||
reinterpret_cast<const uint8_t*>(provider_session_token.data()),
|
||||
provider_session_token.size());
|
||||
metrics_->oemcrypto_copy_old_usage_entry_.Increment(result);
|
||||
});
|
||||
|
||||
return MapOEMCryptoResult(
|
||||
|
||||
@@ -69,6 +69,7 @@ OEMCryptoResult EntitlementKeySession::SelectKey(const std::string& key_id,
|
||||
message.size(), 1, &entitled_key),
|
||||
metrics_, oemcrypto_load_entitled_keys_, result);
|
||||
if (result != OEMCrypto_SUCCESS) {
|
||||
LOGE("SelectKey: OEMCrypto_LoadEntitledContentKeys error=%d", result);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@@ -514,6 +514,9 @@ CdmResponseType CdmLicense::HandleKeyResponse(
|
||||
LOGE("CdmLicense::HandleKeyResponse: not initialized");
|
||||
return LICENSE_PARSER_NOT_INITIALIZED_2;
|
||||
}
|
||||
// Clear the latest service version when we receive a new response.
|
||||
latest_service_version_.Clear();
|
||||
|
||||
if (license_response.empty()) {
|
||||
LOGE("CdmLicense::HandleKeyResponse: empty license response");
|
||||
return EMPTY_LICENSE_RESPONSE_1;
|
||||
@@ -527,6 +530,8 @@ CdmResponseType CdmLicense::HandleKeyResponse(
|
||||
return INVALID_LICENSE_RESPONSE;
|
||||
}
|
||||
|
||||
latest_service_version_ = signed_response.service_version_info();
|
||||
|
||||
if (use_privacy_mode_ && Properties::allow_service_certificate_requests() &&
|
||||
signed_response.type() == SignedMessage::SERVICE_CERTIFICATE) {
|
||||
std::string signed_certificate;
|
||||
@@ -607,7 +612,7 @@ CdmResponseType CdmLicense::HandleKeyResponse(
|
||||
provider_client_token_ = license.provider_client_token();
|
||||
|
||||
if (license.has_srm_update()) {
|
||||
CdmResponseType status = crypto_session_->LoadSrm(license.srm_update());
|
||||
status = crypto_session_->LoadSrm(license.srm_update());
|
||||
switch (status) {
|
||||
case NO_ERROR:
|
||||
break;
|
||||
|
||||
@@ -390,6 +390,13 @@ message RemoteAttestation {
|
||||
optional bytes signature = 3;
|
||||
}
|
||||
|
||||
message VersionInfo {
|
||||
// License SDK version reported by the Widevine License SDK.
|
||||
optional string license_sdk_version = 1;
|
||||
// Version of the service hosting the license SDK.
|
||||
optional string license_service_version = 2;
|
||||
}
|
||||
|
||||
message SignedMessage {
|
||||
enum MessageType {
|
||||
LICENSE_REQUEST = 1;
|
||||
@@ -412,6 +419,9 @@ message SignedMessage {
|
||||
optional RemoteAttestation remote_attestation = 5;
|
||||
|
||||
repeated MetricData metric_data = 6;
|
||||
// Version information from the SDK and license service. This information is
|
||||
// provided in the license response.
|
||||
optional VersionInfo service_version_info = 7;
|
||||
}
|
||||
message GroupKeys {
|
||||
enum GroupLicenseVersion {
|
||||
|
||||
@@ -119,19 +119,19 @@ OEMCryptoResult OEMCrypto_CreateOldUsageEntry(SecurityLevel level,
|
||||
pst_length);
|
||||
}
|
||||
|
||||
uint32_t OEMCrypto_GetAnalogOutputFlags(SecurityLevel level) {
|
||||
uint32_t OEMCrypto_GetAnalogOutputFlags(SecurityLevel) {
|
||||
return ::OEMCrypto_GetAnalogOutputFlags();
|
||||
}
|
||||
|
||||
const char* OEMCrypto_BuildInformation(SecurityLevel level) {
|
||||
const char* OEMCrypto_BuildInformation(SecurityLevel) {
|
||||
return ::OEMCrypto_BuildInformation();
|
||||
}
|
||||
|
||||
uint32_t OEMCrypto_ResourceRatingTier(SecurityLevel level) {
|
||||
uint32_t OEMCrypto_ResourceRatingTier(SecurityLevel) {
|
||||
return ::OEMCrypto_ResourceRatingTier();
|
||||
}
|
||||
|
||||
uint32_t OEMCrypto_SupportsDecryptHash(SecurityLevel level) {
|
||||
uint32_t OEMCrypto_SupportsDecryptHash(SecurityLevel) {
|
||||
return ::OEMCrypto_SupportsDecryptHash();
|
||||
}
|
||||
|
||||
@@ -141,7 +141,7 @@ extern "C" OEMCryptoResult OEMCrypto_LoadKeys_Back_Compat(
|
||||
OEMCrypto_Substring enc_mac_keys_iv, OEMCrypto_Substring enc_mac_keys,
|
||||
size_t num_keys, const OEMCrypto_KeyObject* key_array,
|
||||
OEMCrypto_Substring pst, OEMCrypto_Substring srm_restriction_data,
|
||||
OEMCrypto_LicenseType license_type, OEMCryptoCipherMode* cipher_modes) {
|
||||
OEMCrypto_LicenseType license_type, OEMCryptoCipherMode*) {
|
||||
// TODO(b/72223802): make this backwards compatibile for versions < 14.
|
||||
return OEMCrypto_LoadKeys(session, message, message_length, signature,
|
||||
signature_length, enc_mac_keys_iv, enc_mac_keys,
|
||||
|
||||
@@ -231,7 +231,7 @@ void PolicyEngine::UpdateLicense(const License& license) {
|
||||
NotifyExpirationUpdate(current_time);
|
||||
}
|
||||
|
||||
void PolicyEngine::BeginDecryption() {
|
||||
bool PolicyEngine::BeginDecryption() {
|
||||
if (playback_start_time_ == 0) {
|
||||
switch (license_state_) {
|
||||
case kLicenseStateCanPlay:
|
||||
@@ -246,14 +246,17 @@ void PolicyEngine::BeginDecryption() {
|
||||
license_state_ = kLicenseStateNeedRenewal;
|
||||
}
|
||||
NotifyExpirationUpdate(playback_start_time_);
|
||||
break;
|
||||
return true;
|
||||
case kLicenseStateInitial:
|
||||
case kLicenseStatePending:
|
||||
case kLicenseStateExpired:
|
||||
default:
|
||||
break;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
void PolicyEngine::DecryptionEvent() { last_playback_time_ = GetCurrentTime(); }
|
||||
|
||||
@@ -500,7 +500,8 @@ CdmResponseType UsageTableHeader::StoreEntry(uint32_t usage_entry_number,
|
||||
CdmResponseType UsageTableHeader::Shrink(
|
||||
metrics::CryptoMetrics* metrics,
|
||||
uint32_t number_of_usage_entries_to_delete) {
|
||||
LOGI("UsageTableHeader::Shrink: %d", number_of_usage_entries_to_delete);
|
||||
LOGI("UsageTableHeader::Shrink: %d (of %d)",
|
||||
number_of_usage_entries_to_delete, usage_entry_info_.size());
|
||||
if (usage_entry_info_.empty()) {
|
||||
LOGE("UsageTableHeader::Shrink: usage entry info table unexpectedly empty");
|
||||
return NO_USAGE_ENTRIES;
|
||||
|
||||
@@ -405,10 +405,10 @@ TEST_F(WvCdmEngineTest, ParseDecryptHashStringTest) {
|
||||
const std::string test_frame_number_string =
|
||||
std::to_string(test_frame_number);
|
||||
const std::string test_invalid_hash = "an invalid hash";
|
||||
std::vector<uint8_t> binary_hash{ 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38 };
|
||||
std::vector<uint8_t> binary_hash{ 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0xFF };
|
||||
const std::string test_valid_decoded_hash(binary_hash.begin(),
|
||||
binary_hash.end());
|
||||
const std::string test_valid_hash = Base64Encode(binary_hash);
|
||||
const std::string test_valid_hash = b2a_hex(binary_hash);
|
||||
const std::string test_invalid_hash_string = "sample hash string";
|
||||
const std::string test_valid_hash_string = test_session_id + kComma +
|
||||
test_frame_number_string + kComma + test_valid_hash;
|
||||
|
||||
@@ -361,7 +361,7 @@ TEST_F(CdmSessionTest, UpdateUsageEntry) {
|
||||
std::string serialized_metrics;
|
||||
ASSERT_TRUE(metrics.SerializeToString(&serialized_metrics));
|
||||
EXPECT_GT(metrics.crypto_metrics()
|
||||
.crypto_session_update_usage_entry_time_us().size(), 0)
|
||||
.usage_table_header_update_entry_time_us().size(), 0)
|
||||
<< "Missing update usage entry metric. Metrics: "
|
||||
<< wvcdm::b2a_hex(serialized_metrics);
|
||||
}
|
||||
|
||||
@@ -819,6 +819,40 @@ TEST_F(PolicyEngineTest, PlaybackOk_RentalAndLicense0_WithPlayback) {
|
||||
EXPECT_FALSE(policy_engine_->CanDecryptContent(kSomeRandomKeyId));
|
||||
}
|
||||
|
||||
TEST_F(PolicyEngineTest,
|
||||
PlaybackOk_RentalAndLicense0_WithPlaybackBeforeLicense) {
|
||||
License_Policy* policy = license_.mutable_policy();
|
||||
policy->clear_license_duration_seconds();
|
||||
policy->clear_rental_duration_seconds();
|
||||
// Only |playback_duration_seconds| set.
|
||||
|
||||
policy_engine_->BeginDecryption();
|
||||
|
||||
EXPECT_CALL(*mock_clock_, GetCurrentTime())
|
||||
.WillOnce(Return(kLicenseStartTime + 1))
|
||||
.WillOnce(Return(kPlaybackStartTime))
|
||||
.WillOnce(Return(kPlaybackStartTime + kPlaybackDuration - 10))
|
||||
.WillOnce(Return(kPlaybackStartTime + kPlaybackDuration + 10));
|
||||
|
||||
ExpectSessionKeysChange(kKeyStatusExpired, false);
|
||||
ExpectSessionKeysChange(kKeyStatusUsable, true);
|
||||
EXPECT_CALL(mock_event_listener_, OnExpirationUpdate(_, 0));
|
||||
EXPECT_CALL(mock_event_listener_,
|
||||
OnExpirationUpdate(_, kPlaybackStartTime + kPlaybackDuration));
|
||||
|
||||
policy_engine_->SetLicense(license_);
|
||||
policy_engine_->BeginDecryption();
|
||||
policy_engine_->OnTimerEvent();
|
||||
|
||||
EXPECT_TRUE(policy_engine_->CanDecryptContent(kKeyId));
|
||||
EXPECT_FALSE(policy_engine_->CanDecryptContent(kSomeRandomKeyId));
|
||||
|
||||
policy_engine_->OnTimerEvent();
|
||||
|
||||
EXPECT_FALSE(policy_engine_->CanDecryptContent(kKeyId));
|
||||
EXPECT_FALSE(policy_engine_->CanDecryptContent(kSomeRandomKeyId));
|
||||
}
|
||||
|
||||
TEST_F(PolicyEngineTest, PlaybackOk_Durations0) {
|
||||
License_Policy* policy = license_.mutable_policy();
|
||||
policy->set_rental_duration_seconds(kDurationUnlimited);
|
||||
|
||||
Reference in New Issue
Block a user