Merge "Android CDM: Restored secure stop tests." into udc-dev

This commit is contained in:
Alex Dale
2023-03-30 06:11:58 +00:00
committed by Android (Google) Code Review
11 changed files with 1842 additions and 343 deletions

View File

@@ -214,17 +214,17 @@ class CdmEngine {
// Return the list of IDs associated with usage records for the // Return the list of IDs associated with usage records for the
// current (origin-specific) file system. At least one parameter // current (origin-specific) file system. At least one parameter
// |ksids| or |provider_session_tokens| needs to be supplied. // |ksids| or |psts| needs to be supplied.
virtual CdmResponseType ListUsageIds( virtual CdmResponseType ListUsageIds(const std::string& app_id,
const std::string& app_id, CdmSecurityLevel security_level, CdmSecurityLevel security_level,
std::vector<std::string>* ksids, std::vector<CdmKeySetId>* ksids,
std::vector<std::string>* provider_session_tokens); std::vector<CdmSecureStopId>* psts);
// Delete the usage record for the given key_set_id. This removes the // Delete the usage record for the given key_set_id. This removes the
// usage record in the file system and the OEMCrypto usage record. // usage record in the file system and the OEMCrypto usage record.
virtual CdmResponseType DeleteUsageRecord(const std::string& app_id, virtual CdmResponseType DeleteUsageRecord(const std::string& app_id,
CdmSecurityLevel security_level, CdmSecurityLevel security_level,
const std::string& key_set_id); const CdmKeySetId& key_set_id);
// Get offline license status: active, release or unknown // Get offline license status: active, release or unknown
virtual CdmResponseType GetOfflineLicenseState( virtual CdmResponseType GetOfflineLicenseState(
@@ -245,7 +245,7 @@ class CdmEngine {
// in the event of an error. // in the event of an error.
virtual CdmResponseType GetUsageInfo(const std::string& app_id, virtual CdmResponseType GetUsageInfo(const std::string& app_id,
int* error_detail, int* error_detail,
CdmUsageInfo* usage_info); CdmUsageReport* usage_report);
// Retrieve usage info whose PST is specified by |ssid| // Retrieve usage info whose PST is specified by |ssid|
// If |error_detail| is not null, an additional error code may be provided // If |error_detail| is not null, an additional error code may be provided
@@ -253,7 +253,7 @@ class CdmEngine {
virtual CdmResponseType GetUsageInfo(const std::string& app_id, virtual CdmResponseType GetUsageInfo(const std::string& app_id,
const CdmSecureStopId& ssid, const CdmSecureStopId& ssid,
int* error_detail, int* error_detail,
CdmUsageInfo* usage_info); CdmUsageReport* usage_report);
// Retrieve usage info for a given security level and whose // Retrieve usage info for a given security level and whose
// PST is specified by |ssid|. // PST is specified by |ssid|.
@@ -263,7 +263,7 @@ class CdmEngine {
const CdmSecureStopId& ssid, const CdmSecureStopId& ssid,
RequestedSecurityLevel security_level, RequestedSecurityLevel security_level,
int* error_detail, int* error_detail,
CdmUsageInfo* usage_info); CdmUsageReport* usage_report);
// Remove all usage records for the current origin. // Remove all usage records for the current origin.
virtual CdmResponseType RemoveAllUsageInfo(const std::string& app_id, virtual CdmResponseType RemoveAllUsageInfo(const std::string& app_id,
@@ -276,8 +276,7 @@ class CdmEngine {
virtual CdmResponseType RemoveUsageInfo( virtual CdmResponseType RemoveUsageInfo(
const std::string& app_id, const CdmSecureStopId& secure_stop_id); const std::string& app_id, const CdmSecureStopId& secure_stop_id);
virtual CdmResponseType ReleaseUsageInfo( virtual CdmResponseType ReleaseUsageInfo(const CdmKeyResponse& message);
const CdmUsageInfoReleaseMessage& message);
virtual CdmResponseType LoadUsageSession(const CdmKeySetId& key_set_id, virtual CdmResponseType LoadUsageSession(const CdmKeySetId& key_set_id,
CdmKeyMessage* release_message); CdmKeyMessage* release_message);
@@ -412,7 +411,7 @@ class CdmEngine {
bool ValidateKeySystem(const CdmKeySystem& key_system); bool ValidateKeySystem(const CdmKeySystem& key_system);
CdmResponseType GetUsageInfo(const std::string& app_id, CdmResponseType GetUsageInfo(const std::string& app_id,
RequestedSecurityLevel requested_security_level, RequestedSecurityLevel requested_security_level,
int* error_detail, CdmUsageInfo* usage_info); int* error_detail, CdmUsageReport* usage_report);
void OnKeyReleaseEvent(const CdmKeySetId& key_set_id); void OnKeyReleaseEvent(const CdmKeySetId& key_set_id);

View File

@@ -184,10 +184,10 @@ class CdmEngineMetricsImpl : public T {
} }
CdmResponseType GetUsageInfo(const std::string& app_id, int* error_detail, CdmResponseType GetUsageInfo(const std::string& app_id, int* error_detail,
CdmUsageInfo* usage_info) override { CdmUsageReport* usage_report) override {
CdmResponseType sts; CdmResponseType sts;
int error_detail_alt; int error_detail_alt;
M_TIME(sts = T::GetUsageInfo(app_id, &error_detail_alt, usage_info), M_TIME(sts = T::GetUsageInfo(app_id, &error_detail_alt, usage_report),
metrics_, cdm_engine_get_usage_info_, sts, error_detail_alt); metrics_, cdm_engine_get_usage_info_, sts, error_detail_alt);
if (error_detail != nullptr) { if (error_detail != nullptr) {
*error_detail = error_detail_alt; *error_detail = error_detail_alt;
@@ -197,10 +197,10 @@ class CdmEngineMetricsImpl : public T {
CdmResponseType GetUsageInfo(const std::string& app_id, CdmResponseType GetUsageInfo(const std::string& app_id,
const CdmSecureStopId& ssid, int* error_detail, const CdmSecureStopId& ssid, int* error_detail,
CdmUsageInfo* usage_info) override { CdmUsageReport* usage_report) override {
CdmResponseType sts; CdmResponseType sts;
int error_detail_alt; int error_detail_alt;
M_TIME(sts = T::GetUsageInfo(app_id, ssid, &error_detail_alt, usage_info), M_TIME(sts = T::GetUsageInfo(app_id, ssid, &error_detail_alt, usage_report),
metrics_, cdm_engine_get_usage_info_, sts, error_detail_alt); metrics_, cdm_engine_get_usage_info_, sts, error_detail_alt);
if (error_detail != nullptr) { if (error_detail != nullptr) {
*error_detail = error_detail_alt; *error_detail = error_detail_alt;
@@ -209,14 +209,14 @@ class CdmEngineMetricsImpl : public T {
} }
CdmResponseType RemoveAllUsageInfo(const std::string& app_id) override { CdmResponseType RemoveAllUsageInfo(const std::string& app_id) override {
CdmResponseType sts = T::RemoveAllUsageInfo(app_id); const CdmResponseType sts = T::RemoveAllUsageInfo(app_id);
metrics_->cdm_engine_remove_all_usage_info_.Increment(sts); metrics_->cdm_engine_remove_all_usage_info_.Increment(sts);
return sts; return sts;
} }
CdmResponseType RemoveAllUsageInfo(const std::string& app_id, CdmResponseType RemoveAllUsageInfo(const std::string& app_id,
CdmSecurityLevel security_level) override { CdmSecurityLevel security_level) override {
CdmResponseType sts = T::RemoveAllUsageInfo(app_id, security_level); const CdmResponseType sts = T::RemoveAllUsageInfo(app_id, security_level);
metrics_->cdm_engine_remove_all_usage_info_.Increment(sts); metrics_->cdm_engine_remove_all_usage_info_.Increment(sts);
return sts; return sts;
} }
@@ -224,24 +224,23 @@ class CdmEngineMetricsImpl : public T {
CdmResponseType RemoveUsageInfo( CdmResponseType RemoveUsageInfo(
const std::string& app_id, const std::string& app_id,
const CdmSecureStopId& secure_stop_id) override { const CdmSecureStopId& secure_stop_id) override {
CdmResponseType sts = T::RemoveUsageInfo(app_id, secure_stop_id); const CdmResponseType sts = T::RemoveUsageInfo(app_id, secure_stop_id);
metrics_->cdm_engine_remove_usage_info_.Increment(sts); metrics_->cdm_engine_remove_usage_info_.Increment(sts);
return sts; return sts;
} }
CdmResponseType ReleaseUsageInfo( CdmResponseType ReleaseUsageInfo(const CdmKeyResponse& message) override {
const CdmUsageInfoReleaseMessage& message) override { const CdmResponseType sts = T::ReleaseUsageInfo(message);
CdmResponseType sts = T::ReleaseUsageInfo(message);
metrics_->cdm_engine_release_usage_info_.Increment(sts); metrics_->cdm_engine_release_usage_info_.Increment(sts);
return sts; return sts;
} }
CdmResponseType ListUsageIds( CdmResponseType ListUsageIds(const std::string& app_id,
const std::string& app_id, CdmSecurityLevel security_level, CdmSecurityLevel security_level,
std::vector<std::string>* ksids, std::vector<CdmKeySetId>* ksids,
std::vector<std::string>* provider_session_tokens) override { std::vector<CdmSecureStopId>* ssids) override {
CdmResponseType sts = const CdmResponseType sts =
T::ListUsageIds(app_id, security_level, ksids, provider_session_tokens); T::ListUsageIds(app_id, security_level, ksids, ssids);
metrics_->cdm_engine_get_secure_stop_ids_.Increment(sts); metrics_->cdm_engine_get_secure_stop_ids_.Increment(sts);
return sts; return sts;
} }

View File

@@ -21,7 +21,6 @@ using CdmInitData = std::string;
using CdmKeyMessage = std::string; using CdmKeyMessage = std::string;
using CdmKeyResponse = std::string; using CdmKeyResponse = std::string;
using KeyId = std::string; using KeyId = std::string;
using CdmSecureStopId = std::string;
using CdmSessionId = std::string; using CdmSessionId = std::string;
using CdmKeySetId = std::string; using CdmKeySetId = std::string;
using RequestId = std::string; using RequestId = std::string;
@@ -39,6 +38,11 @@ using UsageTableHeader = std::string;
using UsageEntry = std::string; using UsageEntry = std::string;
using UsageEntryIndex = uint32_t; using UsageEntryIndex = uint32_t;
// Secure stop related data types.
using CdmSecureStopId = std::string;
using CdmUsageReport = std::string;
using CdmUsageReportList = std::vector<std::string>;
enum CdmKeyRequestType : uint32_t { enum CdmKeyRequestType : uint32_t {
kKeyRequestTypeUnknown, kKeyRequestTypeUnknown,
kKeyRequestTypeInitial, kKeyRequestTypeInitial,

View File

@@ -1302,12 +1302,12 @@ CdmResponseType CdmEngine::ListStoredLicenses(
return CdmResponseType(NO_ERROR); return CdmResponseType(NO_ERROR);
} }
CdmResponseType CdmEngine::ListUsageIds( CdmResponseType CdmEngine::ListUsageIds(const std::string& app_id,
const std::string& app_id, CdmSecurityLevel security_level, CdmSecurityLevel security_level,
std::vector<std::string>* ksids, std::vector<CdmKeySetId>* ksids,
std::vector<std::string>* provider_session_tokens) { std::vector<CdmSecureStopId>* psts) {
if (!ksids && !provider_session_tokens) { if (!ksids && !psts) {
LOGE("Outputs |ksids| and |provider_session_tokens| are null"); LOGE("Outputs |ksids| and |psts| are null");
return CdmResponseType(INVALID_PARAMETERS_ENG_23); return CdmResponseType(INVALID_PARAMETERS_ENG_23);
} }
if (security_level == kSecurityLevelL1 && OkpIsInFallbackMode()) { if (security_level == kSecurityLevelL1 && OkpIsInFallbackMode()) {
@@ -1319,7 +1319,7 @@ CdmResponseType CdmEngine::ListUsageIds(
LOGE("Unable to initialize device files"); LOGE("Unable to initialize device files");
return CdmResponseType(LIST_USAGE_ERROR_1); return CdmResponseType(LIST_USAGE_ERROR_1);
} }
if (!handle.ListUsageIds(app_id, ksids, provider_session_tokens)) { if (!handle.ListUsageIds(app_id, ksids, psts)) {
LOGE("Failed: app_id = %s, security_level = %s", IdToString(app_id), LOGE("Failed: app_id = %s, security_level = %s", IdToString(app_id),
CdmSecurityLevelToString(security_level)); CdmSecurityLevelToString(security_level));
return CdmResponseType(LIST_USAGE_ERROR_2); return CdmResponseType(LIST_USAGE_ERROR_2);
@@ -1329,7 +1329,7 @@ CdmResponseType CdmEngine::ListUsageIds(
CdmResponseType CdmEngine::DeleteUsageRecord(const std::string& app_id, CdmResponseType CdmEngine::DeleteUsageRecord(const std::string& app_id,
CdmSecurityLevel security_level, CdmSecurityLevel security_level,
const std::string& key_set_id) { const CdmKeySetId& key_set_id) {
LOGI("app_id = %s, key_set_id = %s", IdToString(app_id), LOGI("app_id = %s, key_set_id = %s", IdToString(app_id),
IdToString(key_set_id)); IdToString(key_set_id));
if (security_level == kSecurityLevelL1 && OkpIsInFallbackMode()) { if (security_level == kSecurityLevelL1 && OkpIsInFallbackMode()) {
@@ -1465,18 +1465,18 @@ CdmResponseType CdmEngine::StoreAtscLicense(
CdmResponseType CdmEngine::GetUsageInfo(const std::string& app_id, CdmResponseType CdmEngine::GetUsageInfo(const std::string& app_id,
const CdmSecureStopId& ssid, const CdmSecureStopId& ssid,
int* error_detail, int* error_detail,
CdmUsageInfo* usage_info) { CdmUsageReport* usage_report) {
// Try to find usage info at the default security level. If the // Try to find usage info at the default security level. If the
// security level is unprovisioned or we are unable to find it, // security level is unprovisioned or we are unable to find it,
// try L3. // try L3.
CdmResponseType status = CdmResponseType status =
GetUsageInfo(app_id, ssid, kLevelDefault, error_detail, usage_info); GetUsageInfo(app_id, ssid, kLevelDefault, error_detail, usage_report);
switch (status.code()) { switch (status.code()) {
case NEED_PROVISIONING: case NEED_PROVISIONING:
case GET_USAGE_INFO_ERROR_1: case GET_USAGE_INFO_ERROR_1:
case GET_USAGE_INFO_ERROR_2: case GET_USAGE_INFO_ERROR_2:
case USAGE_INFO_NOT_FOUND: case USAGE_INFO_NOT_FOUND:
status = GetUsageInfo(app_id, ssid, kLevel3, error_detail, usage_info); status = GetUsageInfo(app_id, ssid, kLevel3, error_detail, usage_report);
return status; return status;
default: default:
return status; return status;
@@ -1487,15 +1487,17 @@ CdmResponseType CdmEngine::GetUsageInfo(const std::string& app_id,
const CdmSecureStopId& ssid, const CdmSecureStopId& ssid,
RequestedSecurityLevel security_level, RequestedSecurityLevel security_level,
int* error_detail, int* error_detail,
CdmUsageInfo* usage_info) { CdmUsageReport* usage_report) {
LOGI("app_id = %s, ssid = %s", IdToString(app_id), IdToString(ssid)); LOGI("app_id = %s, ssid = %s", IdToString(app_id), IdToString(ssid));
if (!usage_property_set_) { if (!usage_property_set_) {
usage_property_set_.reset(new UsagePropertySet()); usage_property_set_.reset(new UsagePropertySet());
} }
if (usage_info == nullptr) { if (usage_report == nullptr) {
LOGE("Output |usage_info| is null"); LOGE("Output |usage_report| is null");
return CdmResponseType(PARAMETER_NULL); return CdmResponseType(PARAMETER_NULL);
} }
usage_report->clear();
usage_property_set_->set_security_level(security_level); usage_property_set_->set_security_level(security_level);
usage_property_set_->set_app_id(app_id); usage_property_set_->set_app_id(app_id);
usage_session_.reset(new CdmSession(file_system_, metrics_->AddSession())); usage_session_.reset(new CdmSession(file_system_, metrics_->AddSession()));
@@ -1536,32 +1538,28 @@ CdmResponseType CdmEngine::GetUsageInfo(const std::string& app_id,
if (KEY_ADDED != status) { if (KEY_ADDED != status) {
LOGE("RestoreUsageSession failed: status = %d", static_cast<int>(status)); LOGE("RestoreUsageSession failed: status = %d", static_cast<int>(status));
usage_info->clear();
return status; return status;
} }
CdmKeyRequest request; CdmKeyRequest request;
status = usage_session_->GenerateReleaseRequest(&request); status = usage_session_->GenerateReleaseRequest(&request);
usage_info->clear();
usage_info->push_back(request.message);
if (KEY_MESSAGE != status) { if (KEY_MESSAGE != status) {
LOGE("GenerateReleaseRequest failed: status = %d", LOGE("GenerateReleaseRequest failed: status = %d",
static_cast<int>(status)); static_cast<int>(status));
usage_info->clear();
return status; return status;
} }
*usage_report = std::move(request.message);
return CdmResponseType(KEY_MESSAGE); return CdmResponseType(KEY_MESSAGE);
} }
CdmResponseType CdmEngine::GetUsageInfo(const std::string& app_id, CdmResponseType CdmEngine::GetUsageInfo(const std::string& app_id,
int* error_detail, int* error_detail,
CdmUsageInfo* usage_info) { CdmUsageReport* usage_report) {
LOGI("app_id = %s", IdToString(app_id)); LOGI("app_id = %s", IdToString(app_id));
if (usage_info == nullptr) { if (usage_report == nullptr) {
LOGE("Output |usage_info| is null"); LOGE("Output |usage_report| is null");
return CdmResponseType(PARAMETER_NULL); return CdmResponseType(PARAMETER_NULL);
} }
// Return a random usage report from a random security level // Return a random usage report from a random security level
@@ -1569,15 +1567,15 @@ CdmResponseType CdmEngine::GetUsageInfo(const std::string& app_id,
wvutil::CdmRandom::RandomBool() ? kLevelDefault : kLevel3; wvutil::CdmRandom::RandomBool() ? kLevelDefault : kLevel3;
CdmResponseType status(UNKNOWN_ERROR); CdmResponseType status(UNKNOWN_ERROR);
do { do {
status = GetUsageInfo(app_id, security_level, error_detail, usage_info); status = GetUsageInfo(app_id, security_level, error_detail, usage_report);
if (KEY_MESSAGE == status && !usage_info->empty()) { if (KEY_MESSAGE == status && !usage_report->empty()) {
return status; return status;
} }
} while (KEY_CANCELED == status); } while (KEY_CANCELED == status);
security_level = (kLevel3 == security_level) ? kLevelDefault : kLevel3; security_level = (kLevel3 == security_level) ? kLevelDefault : kLevel3;
do { do {
status = GetUsageInfo(app_id, security_level, error_detail, usage_info); status = GetUsageInfo(app_id, security_level, error_detail, usage_report);
if (NEED_PROVISIONING == status) if (NEED_PROVISIONING == status)
return CdmResponseType( return CdmResponseType(
NO_ERROR); // Valid scenario that one of the security NO_ERROR); // Valid scenario that one of the security
@@ -1588,13 +1586,14 @@ CdmResponseType CdmEngine::GetUsageInfo(const std::string& app_id,
CdmResponseType CdmEngine::GetUsageInfo( CdmResponseType CdmEngine::GetUsageInfo(
const std::string& app_id, RequestedSecurityLevel requested_security_level, const std::string& app_id, RequestedSecurityLevel requested_security_level,
int* error_detail, CdmUsageInfo* usage_info) { int* error_detail, CdmUsageReport* usage_report) {
LOGI("app_id = %s, security_level = %s", IdToString(app_id), LOGI("app_id = %s, security_level = %s", IdToString(app_id),
RequestedSecurityLevelToString(requested_security_level)); RequestedSecurityLevelToString(requested_security_level));
if (usage_info == nullptr) { if (usage_report == nullptr) {
LOGE("Output |usage_info| is null"); LOGE("Output |usage_report| is null");
return CdmResponseType(PARAMETER_NULL); return CdmResponseType(PARAMETER_NULL);
} }
usage_report->clear();
if (requested_security_level == kLevelDefault && OkpIsInFallbackMode()) { if (requested_security_level == kLevelDefault && OkpIsInFallbackMode()) {
LOGD("OKP fallback to L3"); LOGD("OKP fallback to L3");
requested_security_level = kLevel3; requested_security_level = kLevel3;
@@ -1627,7 +1626,6 @@ CdmResponseType CdmEngine::GetUsageInfo(
} }
if (usage_data.empty()) { if (usage_data.empty()) {
usage_info->clear();
return CdmResponseType(NO_ERROR); return CdmResponseType(NO_ERROR);
} }
@@ -1637,27 +1635,22 @@ CdmResponseType CdmEngine::GetUsageInfo(
// TODO(b/141704872): Make multiple attempts. // TODO(b/141704872): Make multiple attempts.
LOGE("RestoreUsageSession failed: index = %zu, status = %d", index, LOGE("RestoreUsageSession failed: index = %zu, status = %d", index,
static_cast<int>(status)); static_cast<int>(status));
usage_info->clear();
return status; return status;
} }
CdmKeyRequest request; CdmKeyRequest request;
status = usage_session_->GenerateReleaseRequest(&request); status = usage_session_->GenerateReleaseRequest(&request);
usage_info->clear();
usage_info->push_back(request.message);
switch (status.code()) { switch (status.code()) {
case KEY_MESSAGE: case KEY_MESSAGE:
*usage_report = std::move(request.message);
break; break;
case KEY_CANCELED: // usage information not present in case KEY_CANCELED: // usage information not present in
usage_session_->DeleteLicenseFile(); // OEMCrypto, delete and try again usage_session_->DeleteLicenseFile(); // OEMCrypto, delete and try again
usage_info->clear();
break; break;
default: default:
LOGE("GenerateReleaseRequest failed: status = %d", LOGE("GenerateReleaseRequest failed: status = %d",
static_cast<int>(status)); static_cast<int>(status));
usage_info->clear();
break; break;
} }
return status; return status;
@@ -1782,8 +1775,7 @@ CdmResponseType CdmEngine::RemoveUsageInfo(
return CdmResponseType(REMOVE_USAGE_INFO_ERROR_3); return CdmResponseType(REMOVE_USAGE_INFO_ERROR_3);
} }
CdmResponseType CdmEngine::ReleaseUsageInfo( CdmResponseType CdmEngine::ReleaseUsageInfo(const CdmKeyResponse& message) {
const CdmUsageInfoReleaseMessage& message) {
LOGI("message_size = %zu", message.size()); LOGI("message_size = %zu", message.size());
if (!usage_session_) { if (!usage_session_) {
LOGE("Usage session not initialized"); LOGE("Usage session not initialized");

View File

@@ -95,8 +95,8 @@ class MockCdmEngineImpl : public CdmEngine {
(override)); (override));
MOCK_METHOD(CdmResponseType, Unprovision, (CdmSecurityLevel), (override)); MOCK_METHOD(CdmResponseType, Unprovision, (CdmSecurityLevel), (override));
MOCK_METHOD(CdmResponseType, ListUsageIds, MOCK_METHOD(CdmResponseType, ListUsageIds,
(const std::string&, CdmSecurityLevel, std::vector<std::string>*, (const std::string&, CdmSecurityLevel, std::vector<CdmKeySetId>*,
std::vector<std::string>*), std::vector<CdmSecureStopId>*),
(override)); (override));
MOCK_METHOD(CdmResponseType, RemoveAllUsageInfo, (const std::string&), MOCK_METHOD(CdmResponseType, RemoveAllUsageInfo, (const std::string&),
(override)); (override));
@@ -104,8 +104,8 @@ class MockCdmEngineImpl : public CdmEngine {
(const std::string&, CdmSecurityLevel), (override)); (const std::string&, CdmSecurityLevel), (override));
MOCK_METHOD(CdmResponseType, RemoveUsageInfo, MOCK_METHOD(CdmResponseType, RemoveUsageInfo,
(const std::string&, const CdmSecureStopId&), (override)); (const std::string&, const CdmSecureStopId&), (override));
MOCK_METHOD(CdmResponseType, ReleaseUsageInfo, MOCK_METHOD(CdmResponseType, ReleaseUsageInfo, (const CdmKeyResponse&),
(const CdmUsageInfoReleaseMessage&), (override)); (override));
MOCK_METHOD(CdmResponseType, DecryptV16, MOCK_METHOD(CdmResponseType, DecryptV16,
(const CdmSessionId&, const CdmDecryptionParametersV16&), (const CdmSessionId&, const CdmDecryptionParametersV16&),
(override)); (override));
@@ -464,17 +464,17 @@ TEST_F(WvCdmEngineMetricsImplTest, ReleaseUsageInfo) {
} }
TEST_F(WvCdmEngineMetricsImplTest, ListUsageIds) { TEST_F(WvCdmEngineMetricsImplTest, ListUsageIds) {
std::vector<std::string> ksids; std::vector<CdmKeySetId> ksids;
std::vector<std::string> provider_session_tokens; std::vector<CdmSecureStopId> ssids;
EXPECT_CALL(*test_cdm_metrics_engine_, EXPECT_CALL(*test_cdm_metrics_engine_,
ListUsageIds(Eq("fake app id"), Eq(kSecurityLevelL2), Eq(&ksids), ListUsageIds(Eq("fake app id"), Eq(kSecurityLevelL2), Eq(&ksids),
Eq(&provider_session_tokens))) Eq(&ssids)))
.WillOnce(Return(CdmResponseType(UNKNOWN_ERROR))); .WillOnce(Return(CdmResponseType(UNKNOWN_ERROR)));
ASSERT_EQ(wvcdm::UNKNOWN_ERROR, test_cdm_metrics_engine_->ListUsageIds( ASSERT_EQ(wvcdm::UNKNOWN_ERROR,
"fake app id", kSecurityLevelL2, &ksids, test_cdm_metrics_engine_->ListUsageIds(
&provider_session_tokens)); "fake app id", kSecurityLevelL2, &ksids, &ssids));
drm_metrics::WvCdmMetrics metrics_proto; drm_metrics::WvCdmMetrics metrics_proto;
test_cdm_metrics_engine_->GetMetricsSnapshot(&metrics_proto); test_cdm_metrics_engine_->GetMetricsSnapshot(&metrics_proto);

View File

@@ -105,19 +105,18 @@ class WvContentDecryptionModule : public android::RefBase, public TimerHandler {
// Secure stop related methods // Secure stop related methods
virtual CdmResponseType GetUsageInfo(const std::string& app_id, virtual CdmResponseType GetUsageInfo(const std::string& app_id,
const CdmIdentifier& identifier, const CdmIdentifier& identifier,
CdmUsageInfo* usage_info); CdmUsageReportList* usage_reports);
virtual CdmResponseType GetUsageInfo(const std::string& app_id, virtual CdmResponseType GetUsageInfo(const std::string& app_id,
const CdmSecureStopId& ssid, const CdmSecureStopId& ssid,
const CdmIdentifier& identifier, const CdmIdentifier& identifier,
CdmUsageInfo* usage_info); CdmUsageReport* usage_report);
virtual CdmResponseType RemoveAllUsageInfo(const std::string& app_id, virtual CdmResponseType RemoveAllUsageInfo(const std::string& app_id,
const CdmIdentifier& identifier); const CdmIdentifier& identifier);
virtual CdmResponseType RemoveUsageInfo( virtual CdmResponseType RemoveUsageInfo(
const std::string& app_id, const CdmIdentifier& identifier, const std::string& app_id, const CdmIdentifier& identifier,
const CdmSecureStopId& secure_stop_id); const CdmSecureStopId& secure_stop_id);
virtual CdmResponseType ReleaseUsageInfo( virtual CdmResponseType ReleaseUsageInfo(const CdmKeyResponse& message,
const CdmUsageInfoReleaseMessage& message, const CdmIdentifier& identifier);
const CdmIdentifier& identifier);
virtual CdmResponseType GetSecureStopIds(const std::string& app_id, virtual CdmResponseType GetSecureStopIds(const std::string& app_id,
const CdmIdentifier& identifier, const CdmIdentifier& identifier,

View File

@@ -261,18 +261,28 @@ bool WvContentDecryptionModule::IsProvisioned(CdmSecurityLevel security_level,
CdmResponseType WvContentDecryptionModule::GetUsageInfo( CdmResponseType WvContentDecryptionModule::GetUsageInfo(
const std::string& app_id, const CdmIdentifier& identifier, const std::string& app_id, const CdmIdentifier& identifier,
CdmUsageInfo* usage_info) { CdmUsageReportList* usage_reports) {
if (usage_reports == nullptr) return CdmResponseType(PARAMETER_NULL);
CdmEngine* cdm_engine = EnsureCdmForIdentifier(identifier); CdmEngine* cdm_engine = EnsureCdmForIdentifier(identifier);
int error_detail = NO_ERROR; int error_detail = NO_ERROR;
return cdm_engine->GetUsageInfo(app_id, &error_detail, usage_info); CdmUsageReport usage_report;
// Doesn't actually retrieve all reports, just a single random one.
const CdmResponseType status =
cdm_engine->GetUsageInfo(app_id, &error_detail, &usage_report);
usage_reports->clear();
// Possible that no report is available, still a successful call.
if ((status == NO_ERROR || status == KEY_MESSAGE) && !usage_report.empty()) {
usage_reports->push_back(std::move(usage_report));
}
return status;
} }
CdmResponseType WvContentDecryptionModule::GetUsageInfo( CdmResponseType WvContentDecryptionModule::GetUsageInfo(
const std::string& app_id, const CdmSecureStopId& ssid, const std::string& app_id, const CdmSecureStopId& ssid,
const CdmIdentifier& identifier, CdmUsageInfo* usage_info) { const CdmIdentifier& identifier, CdmUsageReport* usage_report) {
CdmEngine* cdm_engine = EnsureCdmForIdentifier(identifier); CdmEngine* cdm_engine = EnsureCdmForIdentifier(identifier);
int error_detail = NO_ERROR; int error_detail = NO_ERROR;
return cdm_engine->GetUsageInfo(app_id, ssid, &error_detail, usage_info); return cdm_engine->GetUsageInfo(app_id, ssid, &error_detail, usage_report);
} }
CdmResponseType WvContentDecryptionModule::RemoveAllUsageInfo( CdmResponseType WvContentDecryptionModule::RemoveAllUsageInfo(
@@ -289,8 +299,7 @@ CdmResponseType WvContentDecryptionModule::RemoveUsageInfo(
} }
CdmResponseType WvContentDecryptionModule::ReleaseUsageInfo( CdmResponseType WvContentDecryptionModule::ReleaseUsageInfo(
const CdmUsageInfoReleaseMessage& message, const CdmKeyResponse& message, const CdmIdentifier& identifier) {
const CdmIdentifier& identifier) {
CdmEngine* cdm_engine = EnsureCdmForIdentifier(identifier); CdmEngine* cdm_engine = EnsureCdmForIdentifier(identifier);
return cdm_engine->ReleaseUsageInfo(message); return cdm_engine->ReleaseUsageInfo(message);
} }
@@ -306,10 +315,10 @@ CdmResponseType WvContentDecryptionModule::GetSecureStopIds(
CdmEngine* cdm_engine = EnsureCdmForIdentifier(identifier); CdmEngine* cdm_engine = EnsureCdmForIdentifier(identifier);
const CdmResponseType sts = const CdmResponseType sts =
cdm_engine->ListUsageIds(app_id, kSecurityLevelL1, nullptr, ssids); cdm_engine->ListUsageIds(app_id, kSecurityLevelL1, nullptr, ssids);
std::vector<CdmSecureStopId> secure_stop_ids; std::vector<CdmSecureStopId> ssids_l3;
const CdmResponseType sts_l3 = cdm_engine->ListUsageIds( const CdmResponseType sts_l3 =
app_id, kSecurityLevelL3, nullptr, &secure_stop_ids); cdm_engine->ListUsageIds(app_id, kSecurityLevelL3, nullptr, &ssids_l3);
ssids->insert(ssids->end(), secure_stop_ids.begin(), secure_stop_ids.end()); ssids->insert(ssids->end(), ssids_l3.begin(), ssids_l3.end());
return sts_l3 != NO_ERROR ? sts_l3 : sts; return sts_l3 != NO_ERROR ? sts_l3 : sts;
} }

View File

@@ -50,7 +50,7 @@ const int kHttpOk = 200;
const uint32_t kMinute = 60; const uint32_t kMinute = 60;
const uint32_t kClockTolerance = 10; const uint32_t kClockTolerance = 10;
const uint32_t kMaxUsageTableSize = 50; const uint32_t kMaxUsageTableSize = 300;
const std::string kEmptyServiceCertificate; const std::string kEmptyServiceCertificate;
constexpr int64_t kUnlimitedDurationValue = LLONG_MAX; constexpr int64_t kUnlimitedDurationValue = LLONG_MAX;
@@ -71,7 +71,7 @@ struct SubSampleInfo {
}; };
// clang-format off // clang-format off
SubSampleInfo kEncryptedStreamingNoPstSubSample = { const SubSampleInfo kEncryptedStreamingNoPstSubSample = {
// key SD, encrypted, 256b // key SD, encrypted, 256b
true, 1, true, true, false, true, 1, true, true, false,
wvutil::a2bs_hex("371EA35E1A985D75D198A7F41020DC23"), wvutil::a2bs_hex("371EA35E1A985D75D198A7F41020DC23"),
@@ -95,7 +95,7 @@ SubSampleInfo kEncryptedStreamingNoPstSubSample = {
"08a899cd760ff0899a1170c2f224b9c52997a0785b7fe170805fd3e8b1127659"), "08a899cd760ff0899a1170c2f224b9c52997a0785b7fe170805fd3e8b1127659"),
wvutil::a2b_hex("f6f4b1e600a5b67813ed2bded913ba9f"), 0, 3}; wvutil::a2b_hex("f6f4b1e600a5b67813ed2bded913ba9f"), 0, 3};
SubSampleInfo kEncryptedStreamingClip8SubSample = { const SubSampleInfo kEncryptedStreamingClip8SubSample = {
true, 1, true, true, false, true, 1, true, true, false,
wvutil::a2bs_hex("E82DDD1D07CBB31CDD31EBAAE0894609"), wvutil::a2bs_hex("E82DDD1D07CBB31CDD31EBAAE0894609"),
wvutil::a2b_hex( wvutil::a2b_hex(
@@ -118,7 +118,7 @@ SubSampleInfo kEncryptedStreamingClip8SubSample = {
"37326df26fa509343faa98dff667629f557873f1284903202e451227ef465a62"), "37326df26fa509343faa98dff667629f557873f1284903202e451227ef465a62"),
wvutil::a2b_hex("7362b5140c4ce0cd5f863858668d3f1a"), 0, 3}; wvutil::a2b_hex("7362b5140c4ce0cd5f863858668d3f1a"), 0, 3};
SubSampleInfo kEncryptedStreamingClip5SubSample = { const SubSampleInfo kEncryptedStreamingClip5SubSample = {
true, 1, true, true, false, true, 1, true, true, false,
wvutil::a2bs_hex("3AE243D83B93B3311A1D777FF5FBE01A"), wvutil::a2bs_hex("3AE243D83B93B3311A1D777FF5FBE01A"),
wvutil::a2b_hex( wvutil::a2b_hex(
@@ -141,7 +141,7 @@ SubSampleInfo kEncryptedStreamingClip5SubSample = {
"ed0716cd8bceb80cf59166a217006bd147c51b04dfb183088ce3f51e9b9f759e"), "ed0716cd8bceb80cf59166a217006bd147c51b04dfb183088ce3f51e9b9f759e"),
wvutil::a2b_hex("b358ab21ac90455bbf60490daad457e3"), 0, 3}; wvutil::a2b_hex("b358ab21ac90455bbf60490daad457e3"), 0, 3};
SubSampleInfo kEncryptedOfflineClip2SubSample = { const SubSampleInfo kEncryptedOfflineClip2SubSample = {
true, 1, true, true, false, true, 1, true, true, false,
wvutil::a2bs_hex("3260F39E12CCF653529990168A3583FF"), wvutil::a2bs_hex("3260F39E12CCF653529990168A3583FF"),
wvutil::a2b_hex( wvutil::a2b_hex(
@@ -164,13 +164,13 @@ SubSampleInfo kEncryptedOfflineClip2SubSample = {
"944B5080B998BB0FE6E566AAFAE2328B37FD189F1920A964434ECF18E11AC81E"), "944B5080B998BB0FE6E566AAFAE2328B37FD189F1920A964434ECF18E11AC81E"),
wvutil::a2b_hex("7362b5140c4ce0cd5f863858668d3f1a"), 0, 3}; wvutil::a2b_hex("7362b5140c4ce0cd5f863858668d3f1a"), 0, 3};
std::string kStreamingClip8PstInitData = wvutil::a2bs_hex( const std::string kStreamingClip8PstInitData = wvutil::a2bs_hex(
"000000427073736800000000" // blob size and pssh "000000427073736800000000" // blob size and pssh
"EDEF8BA979D64ACEA3C827DCD51D21ED00000022" // Widevine system id "EDEF8BA979D64ACEA3C827DCD51D21ED00000022" // Widevine system id
"08011a0d7769646576696e655f74657374220f73" // pssh data "08011a0d7769646576696e655f74657374220f73" // pssh data
"747265616d696e675f636c697038"); "747265616d696e675f636c697038");
std::string kOfflineClip2PstInitData = wvutil::a2bs_hex( const std::string kOfflineClip2PstInitData = wvutil::a2bs_hex(
"000000407073736800000000" // blob size and pssh "000000407073736800000000" // blob size and pssh
"EDEF8BA979D64ACEA3C827DCD51D21ED00000020" // Widevine system id "EDEF8BA979D64ACEA3C827DCD51D21ED00000020" // Widevine system id
"08011a0d7769646576696e655f74657374220d6f" // pssh data "08011a0d7769646576696e655f74657374220d6f" // pssh data
@@ -399,30 +399,30 @@ class WvCdmExtendedDurationTest : public WvCdmTestBase {
// Post a request and extract the signed provisioning message from // Post a request and extract the signed provisioning message from
// the HTTP response. // the HTTP response.
std::string GetUsageInfoResponse(const std::string& server_url, std::string GetSecureStopResponse(const std::string& server_url,
const std::string& client_auth, const std::string& client_auth,
const std::string& usage_info_request) { const std::string& secure_stop_request) {
// Use secure connection and chunk transfer coding. // Use secure connection and chunk transfer coding.
UrlRequest url_request(server_url + client_auth); UrlRequest url_request(server_url + client_auth);
EXPECT_TRUE(url_request.is_connected()) << "Fail to connect to " EXPECT_TRUE(url_request.is_connected())
<< server_url << client_auth; << "Fail to connect to " << server_url << client_auth;
url_request.PostRequest(usage_info_request); url_request.PostRequest(secure_stop_request);
std::string message; std::string message;
EXPECT_TRUE(url_request.GetResponse(&message)); EXPECT_TRUE(url_request.GetResponse(&message));
int http_status_code = url_request.GetStatusCode(message); const int http_status_code = url_request.GetStatusCode(message);
if (kHttpOk != http_status_code) { if (kHttpOk != http_status_code) {
LogResponseError(message, http_status_code); LogResponseError(message, http_status_code);
} }
EXPECT_EQ(kHttpOk, http_status_code); EXPECT_EQ(kHttpOk, http_status_code);
std::string usage_info; std::string secure_stop_response;
if (kHttpOk == http_status_code) { if (kHttpOk == http_status_code) {
LicenseRequest license; LicenseRequest license;
license.GetDrmMessage(message, usage_info); license.GetDrmMessage(message, secure_stop_response);
LOGV("HTTP response body: (%zu bytes)", usage_info.size()); LOGV("HTTP response body: (%zu bytes)", secure_stop_response.size());
} }
return usage_info; return secure_stop_response;
} }
void VerifyKeyRequestResponse(const std::string& server_url, void VerifyKeyRequestResponse(const std::string& server_url,
@@ -554,7 +554,6 @@ class WvCdmExtendedDurationTest : public WvCdmTestBase {
license_renewal.type()); license_renewal.type());
EXPECT_LT(0, license_renewal.request_time()); EXPECT_LT(0, license_renewal.request_time());
EXPECT_EQ(video_widevine::VERSION_2_1, license_renewal.protocol_version()); EXPECT_EQ(video_widevine::VERSION_2_1, license_renewal.protocol_version());
EXPECT_TRUE(license_renewal.has_key_control_nonce());
} }
void ValidateReleaseRequest(std::string& usage_msg, bool license_used, void ValidateReleaseRequest(std::string& usage_msg, bool license_used,
@@ -635,7 +634,6 @@ class WvCdmExtendedDurationTest : public WvCdmTestBase {
license_renewal.type()); license_renewal.type());
EXPECT_LT(0, license_renewal.request_time()); EXPECT_LT(0, license_renewal.request_time());
EXPECT_EQ(video_widevine::VERSION_2_1, license_renewal.protocol_version()); EXPECT_EQ(video_widevine::VERSION_2_1, license_renewal.protocol_version());
EXPECT_TRUE(license_renewal.has_key_control_nonce());
} }
void ValidateHasUpdateUsageEntry( void ValidateHasUpdateUsageEntry(
@@ -909,7 +907,6 @@ TEST_F(WvCdmExtendedDurationTest, VerifyLicenseRenewalTest) {
license_renewal.type()); license_renewal.type());
EXPECT_LT(0, license_renewal.request_time()); EXPECT_LT(0, license_renewal.request_time());
EXPECT_EQ(video_widevine::VERSION_2_1, license_renewal.protocol_version()); EXPECT_EQ(video_widevine::VERSION_2_1, license_renewal.protocol_version());
EXPECT_TRUE(license_renewal.has_key_control_nonce());
decryptor_->CloseSession(session_id_); decryptor_->CloseSession(session_id_);
} }
@@ -955,7 +952,7 @@ TEST_F(WvCdmExtendedDurationTest, DecryptionCloseSessionConcurrencyTest) {
(delay_remaining.tv_sec > 0 || delay_remaining.tv_nsec > 0)) { (delay_remaining.tv_sec > 0 || delay_remaining.tv_nsec > 0)) {
result = nanosleep(&delay_remaining, &delay_remaining); result = nanosleep(&delay_remaining, &delay_remaining);
} }
SubSampleInfo* data = &kEncryptedOfflineClip2SubSample; const SubSampleInfo* data = &kEncryptedOfflineClip2SubSample;
for (size_t i = 0; i < data->num_of_subsamples; i++) { for (size_t i = 0; i < data->num_of_subsamples; i++) {
std::vector<uint8_t> decrypt_buffer((data + i)->encrypt_data.size()); std::vector<uint8_t> decrypt_buffer((data + i)->encrypt_data.size());
CdmDecryptionParameters decryption_parameters( CdmDecryptionParameters decryption_parameters(
@@ -986,6 +983,67 @@ TEST_F(WvCdmExtendedDurationTest, DecryptionCloseSessionConcurrencyTest) {
decryptor_->CloseSession(session_id); decryptor_->CloseSession(session_id);
} }
TEST_F(WvCdmExtendedDurationTest, DISABLED_UsageOverflowTest) {
Provision();
TestWvCdmClientPropertySet client_property_set;
TestWvCdmClientPropertySet* property_set = nullptr;
CdmSecurityLevel security_level = GetDefaultSecurityLevel();
FileSystem file_system;
DeviceFiles handle(&file_system);
EXPECT_TRUE(handle.Init(security_level));
std::vector<std::string> provider_session_tokens;
EXPECT_TRUE(handle.DeleteAllUsageInfoForApp(
DeviceFiles::GetUsageInfoFileName(""), &provider_session_tokens));
const std::string key_id = wvutil::a2bs_hex(
"000000427073736800000000" // blob size and pssh
"EDEF8BA979D64ACEA3C827DCD51D21ED00000022" // Widevine system id
"08011a0d7769646576696e655f74657374220f73" // pssh data
"747265616d696e675f636c697035");
for (size_t i = 0; i < kMaxUsageTableSize + 100; ++i) {
decryptor_->OpenSession(config_.key_system(), property_set,
kDefaultCdmIdentifier, nullptr, &session_id_);
GenerateKeyRequest(key_id, kLicenseTypeStreaming);
VerifyKeyRequestResponse(config_.license_server(), config_.client_auth(),
false);
decryptor_->CloseSession(session_id_);
}
CdmUsageReportList usage_reports;
CdmResponseType status =
decryptor_->GetUsageInfo("", kDefaultCdmIdentifier, &usage_reports);
EXPECT_EQ(usage_reports.empty() ? NO_ERROR : KEY_MESSAGE, status);
int error_count = 0;
while (!usage_reports.empty()) {
// Release each of the listed secure stops.
for (size_t i = 0; i < usage_reports.size(); ++i) {
const CdmUsageReport& usage_report = usage_reports[i];
const CdmKeyMessage release_msg = GetSecureStopResponse(
config_.license_server(), config_.client_auth(), usage_report);
EXPECT_EQ(NO_ERROR,
decryptor_->ReleaseUsageInfo(release_msg, kDefaultCdmIdentifier))
<< i << "/" << usage_reports.size() << " (err " << (error_count++) << ")"
<< release_msg;
}
ASSERT_LE(error_count, 100); // Give up after 100 failures.
// Get an updated list. The CDM might not list all entries at once.
status = decryptor_->GetUsageInfo("", kDefaultCdmIdentifier, &usage_reports);
switch (status.code()) {
case KEY_MESSAGE:
EXPECT_FALSE(usage_reports.empty());
break;
case NO_ERROR:
EXPECT_TRUE(usage_reports.empty());
break;
default:
FAIL() << "GetUsageInfo failed with error " << static_cast<int>(status);
break;
}
}
}
// This test verifies that sessions allocated internally during key release // This test verifies that sessions allocated internally during key release
// message generation are deallocated after their time to live period expires // message generation are deallocated after their time to live period expires
// by timer events (if other sessions are open). // by timer events (if other sessions are open).
@@ -1218,7 +1276,7 @@ TEST_P(WvCdmStreamingNoPstTest, UsageTest) {
for (size_t i = 0; i < GetParam(); ++i) { for (size_t i = 0; i < GetParam(); ++i) {
// Decrypt data // Decrypt data
SubSampleInfo* data = &kEncryptedStreamingNoPstSubSample; const SubSampleInfo* data = &kEncryptedStreamingNoPstSubSample;
for (size_t i = 0; i < data->num_of_subsamples; i++) { for (size_t i = 0; i < data->num_of_subsamples; i++) {
std::vector<uint8_t> decrypt_buffer((data + i)->encrypt_data.size()); std::vector<uint8_t> decrypt_buffer((data + i)->encrypt_data.size());
CdmDecryptionParameters decryption_parameters( CdmDecryptionParameters decryption_parameters(
@@ -1282,6 +1340,218 @@ TEST_P(WvCdmStreamingNoPstTest, UsageTest) {
INSTANTIATE_TEST_CASE_P(Cdm, WvCdmStreamingNoPstTest, INSTANTIATE_TEST_CASE_P(Cdm, WvCdmStreamingNoPstTest,
::testing::Values(0, 1, 2)); ::testing::Values(0, 1, 2));
class WvCdmStreamingPstTest : public WvCdmExtendedDurationTest,
public ::testing::WithParamInterface<size_t> {};
// TODO(b275651559): Re-enable test once the issue with "license remaining
// duration" is addressed.
TEST_P(WvCdmStreamingPstTest, DISABLED_UsageTest) {
Unprovision();
Provision();
decryptor_->OpenSession(config_.key_system(), nullptr, kDefaultCdmIdentifier,
nullptr, &session_id_);
GenerateKeyRequest(kStreamingClip8PstInitData, kLicenseTypeStreaming);
VerifyKeyRequestResponse(config_.license_server(), config_.client_auth(),
false);
ValidateResponse(video_widevine::STREAMING, true);
int64_t initial_license_duration_remaining = 0;
int64_t initial_playback_duration_remaining = 0;
QueryKeyStatus(true, false, &initial_license_duration_remaining,
&initial_playback_duration_remaining);
sleep(kMinute);
int64_t expected_seconds_since_license_received = kMinute;
int64_t expected_seconds_since_initial_playback = 0;
int64_t expected_seconds_since_last_playback = 0;
const size_t minutes = GetParam();
for (size_t m = 0; m < minutes; ++m) {
// Decrypt data
const SubSampleInfo& data = kEncryptedStreamingClip8SubSample;
std::vector<uint8_t> decrypt_buffer(data.encrypt_data.size());
CdmDecryptionParameters decryption_parameters(
&data.key_id, &data.encrypt_data.front(),
data.encrypt_data.size(), &data.iv,
data.block_offset, decrypt_buffer.data());
decryption_parameters.is_encrypted = data.is_encrypted;
decryption_parameters.is_secure = data.is_secure;
decryption_parameters.subsample_flags = data.subsample_flags;
EXPECT_EQ(NO_ERROR,
decryptor_->Decrypt(session_id_, data.validate_key_id,
decryption_parameters));
EXPECT_EQ(data.decrypt_data, decrypt_buffer);
sleep(kMinute);
expected_seconds_since_license_received += kMinute;
expected_seconds_since_initial_playback += kMinute;
expected_seconds_since_last_playback = kMinute;
}
// Query and validate usage information
int64_t license_duration_remaining = 0;
int64_t playback_duration_remaining = 0;
QueryKeyStatus(true, false, &license_duration_remaining,
&playback_duration_remaining);
if (initial_license_duration_remaining == kUnlimitedDurationValue) {
EXPECT_EQ(license_duration_remaining, kUnlimitedDurationValue);
} else {
EXPECT_NEAR(initial_license_duration_remaining - license_duration_remaining,
expected_seconds_since_license_received, kClockTolerance)
<< "initial_license_duration_remaining = "
<< initial_license_duration_remaining
<< ", license_duration_remaining = " << license_duration_remaining;
}
if (initial_playback_duration_remaining == kUnlimitedDurationValue) {
EXPECT_EQ(playback_duration_remaining, kUnlimitedDurationValue);
} else {
EXPECT_NEAR(initial_playback_duration_remaining - playback_duration_remaining,
expected_seconds_since_initial_playback, kClockTolerance)
<< "initial_playback_duration_remaining = "
<< initial_playback_duration_remaining
<< ", playback_duration_remaining = " << playback_duration_remaining;
}
decryptor_->CloseSession(session_id_);
}
INSTANTIATE_TEST_CASE_P(Cdm, WvCdmStreamingPstTest, ::testing::Values(0, 1, 2));
class WvCdmStreamingUsageReportTest
: public WvCdmExtendedDurationTest,
public ::testing::WithParamInterface<size_t> {};
// TODO(b275651559): Re-enable test once the issue with "license remaining
// duration" is addressed.
TEST_P(WvCdmStreamingUsageReportTest, DISABLED_UsageTest) {
Unprovision();
Provision();
decryptor_->OpenSession(config_.key_system(), nullptr, kDefaultCdmIdentifier,
nullptr, &session_id_);
GenerateKeyRequest(kStreamingClip8PstInitData, kLicenseTypeStreaming);
VerifyKeyRequestResponse(config_.license_server(), config_.client_auth(),
false);
ValidateResponse(video_widevine::STREAMING, true);
int64_t initial_license_duration_remaining = 0;
int64_t initial_playback_duration_remaining = 0;
QueryKeyStatus(true, false, &initial_license_duration_remaining,
&initial_playback_duration_remaining);
sleep(kMinute);
int64_t expected_seconds_since_license_received = kMinute;
int64_t expected_seconds_since_initial_playback = 0;
int64_t expected_seconds_since_last_playback = 0;
const size_t minutes = GetParam();
for (size_t m = 0; m < minutes; ++m) {
// Decrypt data
const SubSampleInfo& data = kEncryptedStreamingClip8SubSample;
std::vector<uint8_t> decrypt_buffer(data.encrypt_data.size());
CdmDecryptionParameters decryption_parameters(
&data.key_id, &data.encrypt_data.front(),
data.encrypt_data.size(), &data.iv,
data.block_offset, decrypt_buffer.data());
decryption_parameters.is_encrypted = data.is_encrypted;
decryption_parameters.is_secure = data.is_secure;
decryption_parameters.subsample_flags = data.subsample_flags;
EXPECT_EQ(NO_ERROR,
decryptor_->Decrypt(session_id_, data.validate_key_id,
decryption_parameters));
EXPECT_EQ(data.decrypt_data, decrypt_buffer);
sleep(kMinute);
expected_seconds_since_license_received += kMinute;
expected_seconds_since_initial_playback += kMinute;
expected_seconds_since_last_playback = kMinute;
}
// Query and validate usage information
int64_t license_duration_remaining = 0;
int64_t playback_duration_remaining = 0;
QueryKeyStatus(true, false, &license_duration_remaining,
&playback_duration_remaining);
// For unlimited "rental durations", the "license duration" will
// effectively be unlimited. Remaining license duration in this
// case is represented by |kUnlimitedDurationValue| and will not
// change over time.
if (initial_license_duration_remaining == kUnlimitedDurationValue) {
EXPECT_EQ(license_duration_remaining, kUnlimitedDurationValue);
} else {
EXPECT_NEAR(initial_license_duration_remaining - license_duration_remaining,
expected_seconds_since_license_received, kClockTolerance)
<< "initial_license_duration_remaining = "
<< initial_license_duration_remaining
<< ", license_duration_remaining = " << license_duration_remaining;
}
if (initial_playback_duration_remaining == kUnlimitedDurationValue) {
EXPECT_EQ(playback_duration_remaining, kUnlimitedDurationValue);
} else {
EXPECT_NEAR(initial_playback_duration_remaining - playback_duration_remaining,
expected_seconds_since_initial_playback, kClockTolerance)
<< "initial_playback_duration_remaining = "
<< initial_playback_duration_remaining
<< ", playback_duration_remaining = " << playback_duration_remaining;
}
decryptor_->CloseSession(session_id_);
// Create usage report and validate
CdmUsageReportList usage_reports;
CdmResponseType status =
decryptor_->GetUsageInfo("", kDefaultCdmIdentifier, &usage_reports);
EXPECT_EQ(usage_reports.empty() ? NO_ERROR : KEY_MESSAGE, status);
int error_count = 0;
while (!usage_reports.empty()) {
for (size_t i = 0; i < usage_reports.size(); ++i) {
ValidateReleaseRequest(usage_reports[i],
expected_seconds_since_initial_playback != 0,
expected_seconds_since_license_received,
expected_seconds_since_initial_playback,
expected_seconds_since_last_playback);
const CdmKeyResponse release_msg = GetSecureStopResponse(config_.license_server(),
config_.client_auth(), usage_reports[i]);
EXPECT_EQ(NO_ERROR,
decryptor_->ReleaseUsageInfo(release_msg, kDefaultCdmIdentifier))
<< i << "/" << usage_reports.size() << " (err " << (error_count++) << ")"
<< release_msg;
}
ASSERT_LE(error_count, 100); // Give up after 100 failures.
status = decryptor_->GetUsageInfo("", kDefaultCdmIdentifier, &usage_reports);
switch (status.code()) {
case KEY_MESSAGE:
EXPECT_FALSE(usage_reports.empty());
break;
case NO_ERROR:
EXPECT_TRUE(usage_reports.empty());
break;
default:
FAIL() << "GetUsageInfo failed with error " << static_cast<int>(status);
break;
}
}
// Validate that update usage table entry is exercised.
drm_metrics::WvCdmMetrics metrics;
ASSERT_EQ(NO_ERROR, decryptor_->GetMetrics(kDefaultCdmIdentifier, &metrics));
ValidateHasUpdateUsageEntry(metrics);
}
INSTANTIATE_TEST_CASE_P(Cdm, WvCdmStreamingUsageReportTest,
::testing::Values(0, 1, 2));
class WvCdmOfflineUsageReportTest class WvCdmOfflineUsageReportTest
: public WvCdmExtendedDurationTest, : public WvCdmExtendedDurationTest,
public ::testing::WithParamInterface<size_t> {}; public ::testing::WithParamInterface<size_t> {};
@@ -1350,7 +1620,7 @@ TEST_P(WvCdmOfflineUsageReportTest, UsageTest) {
} }
// Decrypt data // Decrypt data
SubSampleInfo* data = &kEncryptedOfflineClip2SubSample; const SubSampleInfo* data = &kEncryptedOfflineClip2SubSample;
for (size_t i = 0; i < data->num_of_subsamples; i++) { for (size_t i = 0; i < data->num_of_subsamples; i++) {
std::vector<uint8_t> decrypt_buffer((data + i)->encrypt_data.size()); std::vector<uint8_t> decrypt_buffer((data + i)->encrypt_data.size());
CdmDecryptionParameters decryption_parameters( CdmDecryptionParameters decryption_parameters(
@@ -1464,7 +1734,7 @@ TEST_F(WvCdmExtendedDurationTest, MaxUsageEntryOfflineRecoveryTest) {
++number_of_valid_offline_sessions; ++number_of_valid_offline_sessions;
// Decrypt data // Decrypt data
SubSampleInfo* data = &kEncryptedOfflineClip2SubSample; const SubSampleInfo* data = &kEncryptedOfflineClip2SubSample;
std::vector<uint8_t> decrypt_buffer(data->encrypt_data.size()); std::vector<uint8_t> decrypt_buffer(data->encrypt_data.size());
CdmDecryptionParameters decryption_parameters( CdmDecryptionParameters decryption_parameters(
&data->key_id, &data->encrypt_data.front(), &data->key_id, &data->encrypt_data.front(),

File diff suppressed because it is too large Load Diff

View File

@@ -84,8 +84,8 @@ using wvcdm::CdmProvisioningResponse;
using wvcdm::CdmQueryMap; using wvcdm::CdmQueryMap;
using wvcdm::CdmSecureStopId; using wvcdm::CdmSecureStopId;
using wvcdm::CdmSecurityLevel; using wvcdm::CdmSecurityLevel;
using wvcdm::CdmUsageInfo; using wvcdm::CdmUsageReport;
using wvcdm::CdmUsageInfoReleaseMessage; using wvcdm::CdmUsageReportList;
using wvcdm::kDefaultCdmIdentifier; using wvcdm::kDefaultCdmIdentifier;
using wvcdm::KeyId; using wvcdm::KeyId;
using wvcdm::RequestedSecurityLevel; using wvcdm::RequestedSecurityLevel;
@@ -672,73 +672,55 @@ Status WVDrmPlugin::unprovisionDevice() {
::ndk::ScopedAStatus WVDrmPlugin::getSecureStop( ::ndk::ScopedAStatus WVDrmPlugin::getSecureStop(
const ::aidl::android::hardware::drm::SecureStopId& in_secureStopId, const ::aidl::android::hardware::drm::SecureStopId& in_secureStopId,
::aidl::android::hardware::drm::SecureStop* _aidl_return) { ::aidl::android::hardware::drm::SecureStop* _aidl_return) {
if (!in_secureStopId.secureStopId.size()) { *_aidl_return = SecureStop();
*_aidl_return = SecureStop(); if (in_secureStopId.secureStopId.empty()) {
return toNdkScopedAStatus(Status::BAD_VALUE); return toNdkScopedAStatus(Status::BAD_VALUE);
} }
vector<uint8_t> cdmStopVec;
SecureStop secureStop;
CdmIdentifier identifier; CdmIdentifier identifier;
auto status = mCdmIdentifierBuilder.getCdmIdentifier(&identifier); auto status = mCdmIdentifierBuilder.getCdmIdentifier(&identifier);
if (status != Status::OK) { if (status != Status::OK) {
*_aidl_return = SecureStop();
return toNdkScopedAStatus(status); return toNdkScopedAStatus(status);
} }
CdmUsageInfo cdmUsageInfo; const CdmSecureStopId cdmSsId(in_secureStopId.secureStopId.begin(),
CdmSecureStopId cdmSsId(in_secureStopId.secureStopId.begin(), in_secureStopId.secureStopId.end());
in_secureStopId.secureStopId.end()); CdmUsageReport cdmUsageReport;
CdmResponseType res = mCDM->GetUsageInfo(mPropertySet.app_id(), cdmSsId, CdmResponseType res = mCDM->GetUsageInfo(mPropertySet.app_id(), cdmSsId,
identifier, &cdmUsageInfo); identifier, &cdmUsageReport);
SecureStop secureStop;
if (isCdmResponseTypeSuccess(res)) { if (isCdmResponseTypeSuccess(res)) {
for (CdmUsageInfo::const_iterator iter = cdmUsageInfo.begin(); secureStop.opaqueData = StrToVector(cdmUsageReport);
iter != cdmUsageInfo.end(); ++iter) { *_aidl_return = std::move(secureStop);
const std::string& cdmStop = *iter;
cdmStopVec = StrToVector(cdmStop);
}
secureStop.opaqueData = cdmStopVec;
} }
*_aidl_return = secureStop;
return toNdkScopedAStatus(mapCdmResponseType(res)); return toNdkScopedAStatus(mapCdmResponseType(res));
} }
::ndk::ScopedAStatus WVDrmPlugin::getSecureStops( ::ndk::ScopedAStatus WVDrmPlugin::getSecureStops(
vector<::aidl::android::hardware::drm::SecureStop>* _aidl_return) { vector<::aidl::android::hardware::drm::SecureStop>* _aidl_return) {
std::list<vector<uint8_t>> secureStops; _aidl_return->clear();
vector<SecureStop> secureStopsVec;
CdmIdentifier identifier; CdmIdentifier identifier;
auto status = mCdmIdentifierBuilder.getCdmIdentifier(&identifier); auto status = mCdmIdentifierBuilder.getCdmIdentifier(&identifier);
if (status != Status::OK) { if (status != Status::OK) {
*_aidl_return = secureStopsVec;
return toNdkScopedAStatus(status); return toNdkScopedAStatus(status);
} }
CdmUsageInfo cdmUsageInfo; CdmUsageReportList cdmUsageReports;
CdmResponseType res = const CdmResponseType res =
mCDM->GetUsageInfo(mPropertySet.app_id(), identifier, &cdmUsageInfo); mCDM->GetUsageInfo(mPropertySet.app_id(), identifier, &cdmUsageReports);
vector<SecureStop> secureStops;
if (isCdmResponseTypeSuccess(res)) { if (isCdmResponseTypeSuccess(res)) {
secureStops.clear(); for (const CdmUsageReport& cdmUsageReport : cdmUsageReports) {
for (CdmUsageInfo::const_iterator iter = cdmUsageInfo.begin(); SecureStop secureStop;
iter != cdmUsageInfo.end(); ++iter) { secureStop.opaqueData = StrToVector(cdmUsageReport);
const std::string& cdmStop = *iter; secureStops.push_back(std::move(secureStop));
secureStops.push_back(StrToVector(cdmStop));
} }
} }
*_aidl_return = std::move(secureStops);
std::list<vector<uint8_t>>::iterator iter = secureStops.begin();
while (iter != secureStops.end()) {
SecureStop secureStop;
secureStop.opaqueData = *iter++;
secureStopsVec.push_back(secureStop);
}
*_aidl_return = secureStopsVec;
return toNdkScopedAStatus(mapCdmResponseType(res)); return toNdkScopedAStatus(mapCdmResponseType(res));
} }
@@ -763,8 +745,8 @@ Status WVDrmPlugin::unprovisionDevice() {
return toNdkScopedAStatus(status); return toNdkScopedAStatus(status);
} }
CdmUsageInfoReleaseMessage cdmMessage(in_secureStopId.secureStopId.begin(), const CdmKeyResponse cdmMessage(in_secureStopId.secureStopId.begin(),
in_secureStopId.secureStopId.end()); in_secureStopId.secureStopId.end());
CdmResponseType res = mCDM->ReleaseUsageInfo(cdmMessage, identifier); CdmResponseType res = mCDM->ReleaseUsageInfo(cdmMessage, identifier);
return toNdkScopedAStatus(mapCdmResponseType(res)); return toNdkScopedAStatus(mapCdmResponseType(res));
} }
@@ -832,9 +814,10 @@ Status WVDrmPlugin::unprovisionDevice() {
return toNdkScopedAStatus(status); return toNdkScopedAStatus(status);
} }
const vector<uint8_t> data = in_ssRelease.opaqueData; const vector<uint8_t>& data = in_ssRelease.opaqueData;
CdmUsageInfoReleaseMessage cdmMessage(data.begin(), data.end()); const CdmKeyResponse cdmMessage(data.begin(), data.end());
CdmResponseType res = mCDM->ReleaseUsageInfo(cdmMessage, identifier); // Only releases a single secure stop.
const CdmResponseType res = mCDM->ReleaseUsageInfo(cdmMessage, identifier);
return toNdkScopedAStatus(mapCdmResponseType(res)); return toNdkScopedAStatus(mapCdmResponseType(res));
} }
@@ -850,10 +833,10 @@ Status WVDrmPlugin::unprovisionDevice() {
return toNdkScopedAStatus(status); return toNdkScopedAStatus(status);
} }
CdmSecureStopId id(in_secureStopId.secureStopId.begin(), const CdmSecureStopId ssid(in_secureStopId.secureStopId.begin(),
in_secureStopId.secureStopId.end()); in_secureStopId.secureStopId.end());
CdmResponseType res = const CdmResponseType res =
mCDM->RemoveUsageInfo(mPropertySet.app_id(), identifier, id); mCDM->RemoveUsageInfo(mPropertySet.app_id(), identifier, ssid);
return toNdkScopedAStatus(mapCdmResponseType(res)); return toNdkScopedAStatus(mapCdmResponseType(res));
} }
@@ -864,7 +847,7 @@ Status WVDrmPlugin::unprovisionDevice() {
return toNdkScopedAStatus(status); return toNdkScopedAStatus(status);
} }
CdmResponseType res = const CdmResponseType res =
mCDM->RemoveAllUsageInfo(mPropertySet.app_id(), identifier); mCDM->RemoveAllUsageInfo(mPropertySet.app_id(), identifier);
return toNdkScopedAStatus(mapCdmResponseType(res)); return toNdkScopedAStatus(mapCdmResponseType(res));
} }

View File

@@ -5,8 +5,6 @@
// //
// #define LOG_NDEBUG 0 // #define LOG_NDEBUG 0
#define LOG_TAG "WVDrmPluginHalTest" #define LOG_TAG "WVDrmPluginHalTest"
#include "WVDrmPlugin.h"
#include <stdio.h> #include <stdio.h>
#include <utils/Log.h> #include <utils/Log.h>
@@ -15,16 +13,18 @@
#include <string> #include <string>
#include <vector> #include <vector>
#include "WVDrmPlugin.h"
#include "WVErrors.h" #include "WVErrors.h"
#include "cdm_client_property_set.h" #include "cdm_client_property_set.h"
#include "cdm_random.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "media/stagefright/MediaErrors.h" #include "media/stagefright/MediaErrors.h"
#include "media/stagefright/foundation/ABase.h" #include "media/stagefright/foundation/ABase.h"
#include "string_conversions.h" #include "string_conversions.h"
#include "wv_cdm_constants.h" #include "wv_cdm_constants.h"
#include "wv_cdm_types.h" #include "wv_cdm_types.h"
#include "wv_content_decryption_module.h" #include "wv_content_decryption_module.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
namespace { namespace {
typedef std::vector<::aidl::android::hardware::drm::KeyValue> KeyedVector; typedef std::vector<::aidl::android::hardware::drm::KeyValue> KeyedVector;
@@ -47,6 +47,8 @@ using ::aidl::android::hardware::drm::KeyValue;
using ::aidl::android::hardware::drm::OfflineLicenseState; using ::aidl::android::hardware::drm::OfflineLicenseState;
using ::aidl::android::hardware::drm::ProvideProvisionResponseResult; using ::aidl::android::hardware::drm::ProvideProvisionResponseResult;
using ::aidl::android::hardware::drm::ProvisionRequest; using ::aidl::android::hardware::drm::ProvisionRequest;
using ::aidl::android::hardware::drm::SecureStop;
using ::aidl::android::hardware::drm::SecureStopId;
using ::aidl::android::hardware::drm::SecurityLevel; using ::aidl::android::hardware::drm::SecurityLevel;
using ::aidl::android::hardware::drm::Status; using ::aidl::android::hardware::drm::Status;
@@ -54,6 +56,7 @@ using ::testing::_;
using ::testing::AllOf; using ::testing::AllOf;
using ::testing::Args; using ::testing::Args;
using ::testing::AtLeast; using ::testing::AtLeast;
using ::testing::Contains;
using ::testing::DefaultValue; using ::testing::DefaultValue;
using ::testing::DoAll; using ::testing::DoAll;
using ::testing::ElementsAreArray; using ::testing::ElementsAreArray;
@@ -89,7 +92,10 @@ using wvcdm::CdmOfflineLicenseState;
using wvcdm::CdmProvisioningRequest; using wvcdm::CdmProvisioningRequest;
using wvcdm::CdmProvisioningResponse; using wvcdm::CdmProvisioningResponse;
using wvcdm::CdmQueryMap; using wvcdm::CdmQueryMap;
using wvcdm::CdmSecureStopId;
using wvcdm::CdmSecurityLevel; using wvcdm::CdmSecurityLevel;
using wvcdm::CdmUsageReport;
using wvcdm::CdmUsageReportList;
using wvcdm::EMPTY_ORIGIN; using wvcdm::EMPTY_ORIGIN;
using wvcdm::kCertificateWidevine; using wvcdm::kCertificateWidevine;
using wvcdm::KEY_ID_SIZE; using wvcdm::KEY_ID_SIZE;
@@ -133,6 +139,7 @@ using wvcdm::QUERY_VALUE_SECURITY_LEVEL_L3;
using wvcdm::SESSION_ID_PREFIX; using wvcdm::SESSION_ID_PREFIX;
using wvcdm::WvCdmEventListener; using wvcdm::WvCdmEventListener;
using wvutil::Base64Encode; using wvutil::Base64Encode;
using wvutil::CdmRandom;
namespace { namespace {
const std::string kEmptyString; const std::string kEmptyString;
@@ -157,93 +164,107 @@ const char kSerializedMetricsHex[] =
"0"; "0";
#define N_ELEM(a) (sizeof(a) / sizeof(a[0])) #define N_ELEM(a) (sizeof(a) / sizeof(a[0]))
} // anonymous namespace
class MockCDM : public WvContentDecryptionModule { class MockCDM : public WvContentDecryptionModule {
public: public:
MOCK_METHOD(CdmResponseType, OpenSession, virtual ~MockCDM() {}
(const CdmKeySystem &, CdmClientPropertySet *,
const CdmIdentifier &, WvCdmEventListener *, CdmSessionId *),
(override));
MOCK_METHOD(CdmResponseType, CloseSession, (const CdmSessionId &), MOCK_METHOD(CdmResponseType, OpenSession,
(override)); (const CdmKeySystem &, CdmClientPropertySet *,
const CdmIdentifier &, WvCdmEventListener *, CdmSessionId *),
(override));
MOCK_METHOD(CdmResponseType, GenerateKeyRequest, MOCK_METHOD(CdmResponseType, CloseSession, (const CdmSessionId &), (override));
(const CdmSessionId &, const CdmKeySetId &, const std::string &,
const CdmInitData &, const CdmLicenseType, CdmAppParameterMap &,
CdmClientPropertySet *, const CdmIdentifier &, CdmKeyRequest *),
(override));
MOCK_METHOD(CdmResponseType, AddKey, MOCK_METHOD(CdmResponseType, GenerateKeyRequest,
(const CdmSessionId &, const CdmKeyResponse &, CdmKeySetId *), (const CdmSessionId &, const CdmKeySetId &, const std::string &,
(override)); const CdmInitData &, const CdmLicenseType, CdmAppParameterMap &,
CdmClientPropertySet *, const CdmIdentifier &, CdmKeyRequest *),
(override));
MOCK_METHOD(CdmResponseType, RemoveKeys, (const CdmSessionId &), (override)); MOCK_METHOD(CdmResponseType, AddKey,
(const CdmSessionId &, const CdmKeyResponse &, CdmKeySetId *),
(override));
MOCK_METHOD(CdmResponseType, RestoreKey, MOCK_METHOD(CdmResponseType, RemoveKeys, (const CdmSessionId &), (override));
(const CdmSessionId &, const CdmKeySetId &), (override));
MOCK_METHOD(CdmResponseType, QueryStatus, MOCK_METHOD(CdmResponseType, RestoreKey,
(wvcdm::RequestedSecurityLevel, const std::string &, (const CdmSessionId &, const CdmKeySetId &), (override));
std::string *),
(override));
MOCK_METHOD(CdmResponseType, QuerySessionStatus, MOCK_METHOD(CdmResponseType, QueryStatus,
(const CdmSessionId &, CdmQueryMap *), (override)); (wvcdm::RequestedSecurityLevel, const std::string &,
std::string *),
(override));
MOCK_METHOD(CdmResponseType, QueryKeyStatus, MOCK_METHOD(CdmResponseType, QuerySessionStatus,
(const CdmSessionId &, CdmQueryMap *), (override)); (const CdmSessionId &, CdmQueryMap *), (override));
MOCK_METHOD(CdmResponseType, QueryOemCryptoSessionId, MOCK_METHOD(CdmResponseType, QueryKeyStatus,
(const CdmSessionId &, CdmQueryMap *), (override)); (const CdmSessionId &, CdmQueryMap *), (override));
MOCK_METHOD(CdmResponseType, GetProvisioningRequest, MOCK_METHOD(CdmResponseType, QueryOemCryptoSessionId,
(CdmCertificateType, const std::string &, const CdmIdentifier &, (const CdmSessionId &, CdmQueryMap *), (override));
const std::string &, wvcdm::RequestedSecurityLevel,
CdmProvisioningRequest *, std::string *),
(override));
MOCK_METHOD(CdmResponseType, HandleProvisioningResponse, MOCK_METHOD(CdmResponseType, GetProvisioningRequest,
(const CdmIdentifier &, const CdmProvisioningResponse &, (CdmCertificateType, const std::string &, const CdmIdentifier &,
wvcdm::RequestedSecurityLevel, std::string *, std::string *), const std::string &, wvcdm::RequestedSecurityLevel,
(override)); CdmProvisioningRequest *, std::string *),
(override));
MOCK_METHOD(CdmResponseType, Unprovision, MOCK_METHOD(CdmResponseType, HandleProvisioningResponse,
(CdmSecurityLevel, const CdmIdentifier &), (override)); (const CdmIdentifier &, const CdmProvisioningResponse &,
wvcdm::RequestedSecurityLevel, std::string *, std::string *),
(override));
MOCK_METHOD(bool, IsProvisioned, MOCK_METHOD(CdmResponseType, Unprovision,
(CdmSecurityLevel, const std::string &, const std::string &, (CdmSecurityLevel, const CdmIdentifier &), (override));
bool),
(override));
MOCK_METHOD(bool, IsValidServiceCertificate, (const std::string &), MOCK_METHOD(bool, IsProvisioned,
(override)); (CdmSecurityLevel, const std::string &, const std::string &, bool),
(override));
MOCK_METHOD(CdmResponseType, GetMetrics, MOCK_METHOD(CdmResponseType, GetUsageInfo,
(const CdmIdentifier &, drm_metrics::WvCdmMetrics *), (override)); (const std::string &, const CdmIdentifier &, CdmUsageReportList *),
(override));
MOCK_METHOD(CdmResponseType, GetDecryptHashError, MOCK_METHOD(CdmResponseType, GetUsageInfo,
(const CdmSessionId &, std::string *), (override)); (const std::string &, const CdmSecureStopId &,
const CdmIdentifier &, CdmUsageReport *),
(override));
MOCK_METHOD(CdmResponseType, ListStoredLicenses, MOCK_METHOD(CdmResponseType, RemoveAllUsageInfo,
(CdmSecurityLevel, const CdmIdentifier &, (const std::string &, const CdmIdentifier &), (override));
std::vector<std::string> *),
(override));
MOCK_METHOD(CdmResponseType, GetOfflineLicenseState, MOCK_METHOD(CdmResponseType, ReleaseUsageInfo,
(const std::string &, CdmSecurityLevel, const CdmIdentifier &, (const CdmKeyResponse &, const CdmIdentifier &), (override));
CdmOfflineLicenseState *),
(override));
MOCK_METHOD(CdmResponseType, RemoveOfflineLicense, MOCK_METHOD(bool, IsValidServiceCertificate, (const std::string &),
(const std::string &, CdmSecurityLevel, const CdmIdentifier &), (override));
(override));
MOCK_METHOD(CdmResponseType, StoreAtscLicense, MOCK_METHOD(CdmResponseType, GetMetrics,
(const CdmIdentifier &, wvcdm::RequestedSecurityLevel, (const CdmIdentifier &, drm_metrics::WvCdmMetrics *), (override));
const std::string &, const std::string &),
(override)); MOCK_METHOD(CdmResponseType, GetDecryptHashError,
(const CdmSessionId &, std::string *), (override));
MOCK_METHOD(CdmResponseType, ListStoredLicenses,
(CdmSecurityLevel, const CdmIdentifier &,
std::vector<std::string> *),
(override));
MOCK_METHOD(CdmResponseType, GetOfflineLicenseState,
(const std::string &, CdmSecurityLevel, const CdmIdentifier &,
CdmOfflineLicenseState *),
(override));
MOCK_METHOD(CdmResponseType, RemoveOfflineLicense,
(const std::string &, CdmSecurityLevel, const CdmIdentifier &),
(override));
MOCK_METHOD(CdmResponseType, StoreAtscLicense,
(const CdmIdentifier &, wvcdm::RequestedSecurityLevel,
const std::string &, const std::string &),
(override));
}; };
class MockCrypto : public WVGenericCryptoInterface { class MockCrypto : public WVGenericCryptoInterface {
@@ -280,6 +301,8 @@ public:
(override)); (override));
}; };
} // anonymous namespace
template <uint8_t DIGIT> template <uint8_t DIGIT>
CdmResponseType setSessionIdOnMap(testing::Unused, CdmQueryMap *map) { CdmResponseType setSessionIdOnMap(testing::Unused, CdmQueryMap *map) {
static const char oecId[] = {DIGIT + '0', '\0'}; static const char oecId[] = {DIGIT + '0', '\0'};
@@ -968,6 +991,62 @@ TEST_F(WVDrmPluginHalTest, RejectsAtscUnprovisionDeviceRequests) {
ASSERT_EQ(Status::ERROR_DRM_CANNOT_HANDLE, status); ASSERT_EQ(Status::ERROR_DRM_CANNOT_HANDLE, status);
} }
TEST_F(WVDrmPluginHalTest, GetsSecureStops) {
static constexpr uint32_t kStopSize = 53;
static constexpr uint32_t kStopCount = 7;
CdmUsageReportList fakeSecureStops;
for (uint32_t i = 0; i < kStopCount; ++i) {
fakeSecureStops.push_back(CdmRandom::RandomData(kStopSize));
}
const std::string app_id = "my_app_id";
EXPECT_CALL(*mCdm, GetUsageInfo(app_id, _, _))
.WillOnce(DoAll(SetArgPointee<2>(fakeSecureStops),
testing::Return(CdmResponseType(wvcdm::NO_ERROR))));
auto ret = mPlugin->setPropertyString("appId", app_id);
EXPECT_TRUE(ret.isOk());
std::vector<SecureStop> secureStops;
ret = mPlugin->getSecureStops(&secureStops);
EXPECT_TRUE(ret.isOk());
CdmUsageReportList stops;
for (const auto &stop : secureStops) {
stops.emplace_back(stop.opaqueData.begin(), stop.opaqueData.end());
}
EXPECT_EQ(kStopCount, stops.size());
for (const CdmUsageReport &expectedSecureStop : fakeSecureStops) {
EXPECT_THAT(stops, Contains(expectedSecureStop));
}
}
TEST_F(WVDrmPluginHalTest, ReleasesAllSecureStops) {
const std::string app_id = "";
EXPECT_CALL(*mCdm, RemoveAllUsageInfo(app_id, _)).Times(1);
auto ret = mPlugin->setPropertyString("appId", app_id);
EXPECT_TRUE(ret.isOk());
ret = mPlugin->releaseAllSecureStops();
EXPECT_TRUE(ret.isOk());
}
TEST_F(WVDrmPluginHalTest, ReleasesSecureStop) {
static constexpr uint32_t kMessageSize = 128;
const CdmKeyResponse releaseMessage = CdmRandom::RandomData(kMessageSize);
EXPECT_CALL(*mCdm, ReleaseUsageInfo(releaseMessage, _)).Times(1);
SecureStopId stopId;
stopId.secureStopId.assign(releaseMessage.begin(), releaseMessage.end());
auto ret = mPlugin->releaseSecureStop(stopId);
EXPECT_TRUE(ret.isOk());
}
TEST_F(WVDrmPluginHalTest, ReturnsExpectedPropertyValues) { TEST_F(WVDrmPluginHalTest, ReturnsExpectedPropertyValues) {
CdmQueryMap l1Map; CdmQueryMap l1Map;
l1Map[QUERY_KEY_SECURITY_LEVEL] = QUERY_VALUE_SECURITY_LEVEL_L1; l1Map[QUERY_KEY_SECURITY_LEVEL] = QUERY_VALUE_SECURITY_LEVEL_L1;