am dffa3ca9: Merge "MediaDrm throws an exception when Secure Stops are requested" into lmp-mr1-dev
* commit 'dffa3ca991c64035e1852543a215f99935b58c7f': MediaDrm throws an exception when Secure Stops are requested
This commit is contained in:
@@ -100,6 +100,8 @@ class CdmSession {
|
||||
is_usage_update_needed_ = false;
|
||||
}
|
||||
|
||||
bool DeleteLicense();
|
||||
|
||||
private:
|
||||
// Internal constructor
|
||||
void Create(CdmLicense* license_parser, CryptoSession* crypto_session,
|
||||
@@ -112,7 +114,6 @@ class CdmSession {
|
||||
|
||||
CdmResponseType StoreLicense();
|
||||
bool StoreLicense(DeviceFiles::LicenseState state);
|
||||
bool DeleteLicense();
|
||||
|
||||
// instance variables
|
||||
bool initialized_;
|
||||
|
||||
@@ -108,7 +108,9 @@ class DeviceFiles {
|
||||
FRIEND_TEST(DeviceFilesUsageInfoTest, Store);
|
||||
FRIEND_TEST(WvCdmRequestLicenseTest, UnprovisionTest);
|
||||
FRIEND_TEST(WvCdmRequestLicenseTest, ForceL3Test);
|
||||
FRIEND_TEST(WvCdmRequestLicenseTest, UsageInfoRetryTest);
|
||||
FRIEND_TEST(WvCdmUsageInfoTest, UsageInfo);
|
||||
FRIEND_TEST(WvCdmExtendedDurationTest, UsageOverflowTest);
|
||||
#endif
|
||||
|
||||
scoped_ptr<File> file_;
|
||||
|
||||
@@ -36,8 +36,8 @@ class CdmLicense {
|
||||
const CdmSessionId& session_id,
|
||||
CdmKeyMessage* signed_request,
|
||||
std::string* server_url);
|
||||
virtual bool PrepareKeyUpdateRequest(bool is_renewal, CdmKeyMessage* signed_request,
|
||||
std::string* server_url);
|
||||
virtual CdmResponseType PrepareKeyUpdateRequest(
|
||||
bool is_renewal, CdmKeyMessage* signed_request, std::string* server_url);
|
||||
virtual CdmResponseType HandleKeyResponse(const CdmKeyResponse& license_response);
|
||||
virtual CdmResponseType HandleKeyUpdateResponse(
|
||||
bool is_renewal, const CdmKeyResponse& license_response);
|
||||
|
||||
@@ -654,16 +654,22 @@ CdmResponseType CdmEngine::GetUsageInfo(const std::string& app_id,
|
||||
CdmUsageInfo* usage_info) {
|
||||
// Return a random usage report from a random security level
|
||||
SecurityLevel security_level = ((rand() % 2) == 0) ? kLevelDefault : kLevel3;
|
||||
CdmResponseType status = GetUsageInfo(app_id, security_level, usage_info);
|
||||
CdmResponseType status = UNKNOWN_ERROR;
|
||||
do {
|
||||
status = GetUsageInfo(app_id, security_level, usage_info);
|
||||
|
||||
if (KEY_MESSAGE == status && !usage_info->empty())
|
||||
return status;
|
||||
} while (KEY_CANCELED == status);
|
||||
|
||||
|
||||
security_level = (kLevel3 == security_level) ? kLevelDefault : kLevel3;
|
||||
do {
|
||||
status = GetUsageInfo(app_id, security_level, usage_info);
|
||||
if (NEED_PROVISIONING == status)
|
||||
return NO_ERROR; // Valid scenario that one of the security
|
||||
// levels has not been provisioned
|
||||
} while (KEY_CANCELED == status);
|
||||
return status;
|
||||
}
|
||||
|
||||
@@ -716,13 +722,20 @@ CdmResponseType CdmEngine::GetUsageInfo(const std::string& app_id,
|
||||
|
||||
status = usage_session_->GenerateReleaseRequest(&(*usage_info)[0], &server_url);
|
||||
|
||||
if (KEY_MESSAGE != status) {
|
||||
switch (status) {
|
||||
case KEY_MESSAGE:
|
||||
break;
|
||||
case KEY_CANCELED: // usage information not present in
|
||||
usage_session_->DeleteLicense(); // OEMCrypto, delete and try again
|
||||
usage_info->clear();
|
||||
break;
|
||||
default:
|
||||
LOGE("CdmEngine::GetUsageInfo: generate release request error: %d",
|
||||
status);
|
||||
usage_info->clear();
|
||||
return status;
|
||||
break;
|
||||
}
|
||||
return KEY_MESSAGE;
|
||||
return status;
|
||||
}
|
||||
|
||||
CdmResponseType CdmEngine::ReleaseAllUsageInfo(const std::string& app_id) {
|
||||
|
||||
@@ -385,11 +385,11 @@ CdmResponseType CdmSession::Decrypt(const CdmDecryptionParameters& params) {
|
||||
// session keys.
|
||||
CdmResponseType CdmSession::GenerateRenewalRequest(CdmKeyMessage* key_request,
|
||||
std::string* server_url) {
|
||||
if (!license_parser_->PrepareKeyUpdateRequest(true, key_request,
|
||||
server_url)) {
|
||||
LOGE("CdmSession::GenerateRenewalRequest: ERROR on prepare");
|
||||
return KEY_ERROR;
|
||||
}
|
||||
CdmResponseType status =
|
||||
license_parser_->PrepareKeyUpdateRequest(true, key_request, server_url);
|
||||
|
||||
if (KEY_MESSAGE != status)
|
||||
return status;
|
||||
|
||||
if (is_offline_) {
|
||||
offline_key_renewal_request_ = *key_request;
|
||||
@@ -413,8 +413,11 @@ CdmResponseType CdmSession::RenewKey(const CdmKeyResponse& key_response) {
|
||||
CdmResponseType CdmSession::GenerateReleaseRequest(CdmKeyMessage* key_request,
|
||||
std::string* server_url) {
|
||||
is_release_ = true;
|
||||
if (!license_parser_->PrepareKeyUpdateRequest(false, key_request, server_url))
|
||||
return UNKNOWN_ERROR;
|
||||
CdmResponseType status =
|
||||
license_parser_->PrepareKeyUpdateRequest(false, key_request, server_url);
|
||||
|
||||
if (KEY_MESSAGE != status)
|
||||
return status;
|
||||
|
||||
if (is_offline_) { // Mark license as being released
|
||||
if (!StoreLicense(DeviceFiles::kLicenseStateReleasing))
|
||||
|
||||
@@ -716,13 +716,19 @@ CdmResponseType CryptoSession::DeactivateUsageInformation(
|
||||
OEMCryptoResult status =
|
||||
OEMCrypto_DeactivateUsageEntry(pst, provider_session_token.length());
|
||||
|
||||
if (OEMCrypto_SUCCESS != status) {
|
||||
switch(status) {
|
||||
case OEMCrypto_SUCCESS:
|
||||
return NO_ERROR;
|
||||
case OEMCrypto_ERROR_INVALID_CONTEXT:
|
||||
LOGE("CryptoSession::DeactivateUsageInformation: Deactivate Usage Entry "
|
||||
" invalid context error");
|
||||
return KEY_CANCELED;
|
||||
default:
|
||||
LOGE("CryptoSession::DeactivateUsageInformation: Deactivate Usage Entry "
|
||||
" error=%ld",
|
||||
status);
|
||||
return UNKNOWN_ERROR;
|
||||
}
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
CdmResponseType CryptoSession::GenerateUsageReport(
|
||||
|
||||
@@ -476,20 +476,21 @@ bool CdmLicense::PrepareKeyRequest(const InitializationData& init_data,
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CdmLicense::PrepareKeyUpdateRequest(bool is_renewal,
|
||||
CdmResponseType CdmLicense::PrepareKeyUpdateRequest(
|
||||
bool is_renewal,
|
||||
CdmKeyMessage* signed_request,
|
||||
std::string* server_url) {
|
||||
if (!initialized_) {
|
||||
LOGE("CdmLicense::PrepareKeyUpdateRequest: not initialized");
|
||||
return false;
|
||||
return UNKNOWN_ERROR;
|
||||
}
|
||||
if (!signed_request) {
|
||||
LOGE("CdmLicense::PrepareKeyUpdateRequest: No signed request provided");
|
||||
return false;
|
||||
return UNKNOWN_ERROR;
|
||||
}
|
||||
if (!server_url) {
|
||||
LOGE("CdmLicense::PrepareKeyUpdateRequest: No server url provided");
|
||||
return false;
|
||||
return UNKNOWN_ERROR;
|
||||
}
|
||||
|
||||
LicenseRequest license_request;
|
||||
@@ -513,7 +514,7 @@ bool CdmLicense::PrepareKeyUpdateRequest(bool is_renewal,
|
||||
CdmResponseType status =
|
||||
session_->DeactivateUsageInformation(provider_session_token_);
|
||||
if (NO_ERROR != status)
|
||||
return false;
|
||||
return status;
|
||||
}
|
||||
|
||||
std::string usage_report;
|
||||
@@ -526,7 +527,7 @@ bool CdmLicense::PrepareKeyUpdateRequest(bool is_renewal,
|
||||
if (NO_ERROR == status)
|
||||
current_license->set_session_usage_table_entry(usage_report);
|
||||
else
|
||||
return false;
|
||||
return KEY_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -545,7 +546,7 @@ bool CdmLicense::PrepareKeyUpdateRequest(bool is_renewal,
|
||||
// of the license response.
|
||||
uint32_t nonce;
|
||||
if (!session_->GenerateNonce(&nonce)) {
|
||||
return false;
|
||||
return KEY_ERROR;
|
||||
}
|
||||
license_request.set_key_control_nonce(nonce);
|
||||
LOGD("PrepareKeyUpdateRequest: nonce=%u", nonce);
|
||||
@@ -559,13 +560,13 @@ bool CdmLicense::PrepareKeyUpdateRequest(bool is_renewal,
|
||||
std::string license_request_signature;
|
||||
if (!session_->PrepareRenewalRequest(serialized_license_req,
|
||||
&license_request_signature))
|
||||
return false;
|
||||
return KEY_ERROR;
|
||||
|
||||
if (license_request_signature.empty()) {
|
||||
LOGE(
|
||||
"CdmLicense::PrepareKeyUpdateRequest: empty license request"
|
||||
" signature");
|
||||
return false;
|
||||
return KEY_ERROR;
|
||||
}
|
||||
|
||||
// Put serialize license request and signature together
|
||||
@@ -576,7 +577,7 @@ bool CdmLicense::PrepareKeyUpdateRequest(bool is_renewal,
|
||||
|
||||
signed_message.SerializeToString(signed_request);
|
||||
*server_url = server_url_;
|
||||
return true;
|
||||
return KEY_MESSAGE;
|
||||
}
|
||||
|
||||
CdmResponseType CdmLicense::HandleKeyResponse(
|
||||
|
||||
@@ -32,6 +32,8 @@ const uint32_t kMinute = 60;
|
||||
const uint32_t kClockTolerance = 5;
|
||||
const uint32_t kTwoMinutes = 120;
|
||||
|
||||
const uint32_t kMaxUsageTableSize = 50;
|
||||
|
||||
// Default license server, can be configured using --server command line option
|
||||
// Default key id (pssh), can be configured using --keyid command line option
|
||||
std::string g_client_auth;
|
||||
@@ -116,6 +118,29 @@ SubSampleInfo kEncryptedStreamingClip1SubSample = {
|
||||
"37326df26fa509343faa98dff667629f557873f1284903202e451227ef465a62"),
|
||||
wvcdm::a2b_hex("7362b5140c4ce0cd5f863858668d3f1a"), 0, 3};
|
||||
|
||||
SubSampleInfo kEncryptedStreamingClip5SubSample = {
|
||||
true, 1, true, true, false,
|
||||
wvcdm::a2bs_hex("3AE243D83B93B3311A1D777FF5FBE01A"),
|
||||
wvcdm::a2b_hex(
|
||||
"934997779aa1aeb45d6ba8845f13786575d0adf85a5e93674d9597f8d4286ed7"
|
||||
"dcce02f306e502bbd9f1cadf502f354038ca921276d158d911bdf3171d335b18"
|
||||
"0ae0f9abece16ff31ee263228354f724da2f3723b19caa38ea02bd6563b01208"
|
||||
"fb5bf57854ac0fe38d5883197ef90324b2721ff20fdcf9a53819515e6daa096e"
|
||||
"70f6f5c1d29a4a13dafd127e2e1f761ea0e28fd451607552ecbaef5da3c780bc"
|
||||
"aaf2667b4cc4f858f01d480cac9e32c3fbb5705e5d2adcceebefc2535c117208"
|
||||
"e65f604799fc3d7223e16908550f287a4bea687008cb0064cf14d3aeedb8c705"
|
||||
"09ebc5c2b8b5315f43c04d78d2f55f4b32c7d33e157114362106395cc0bb6d93"),
|
||||
wvcdm::a2b_hex(
|
||||
"2dd54eee1307753508e1f250d637044d6e8f5abf057dab73e9e95f83910e4efc"
|
||||
"191c9bac63950f13fd51833dd94a4d03f2b64fb5c721970c418fe53fa6f74ad5"
|
||||
"a6e16477a35c7aa6e28909b069cd25770ef80da20918fc30fe95fd5c87fd3522"
|
||||
"1649de17ca2c7b3dc31f936f0cbdf97c7b1c15de3a86b279dc4b4de64943914a"
|
||||
"99734556c4b7a1a0b022c1933cb0786068fc18d49fed2f2b49f3ac6d01c32d07"
|
||||
"92175ce2844eaf9064e6a3fcffade038d690cbed81659351163a22432f0d0545"
|
||||
"037e1c805d8e92a1272b4196ad0ce22f26bb80063137a8e454d3b97e2414283d"
|
||||
"ed0716cd8bceb80cf59166a217006bd147c51b04dfb183088ce3f51e9b9f759e"),
|
||||
wvcdm::a2b_hex("b358ab21ac90455bbf60490daad457e3"), 0, 3};
|
||||
|
||||
SubSampleInfo kEncryptedOfflineClip2SubSample = {
|
||||
true, 1, true, true, false,
|
||||
wvcdm::a2bs_hex("3260F39E12CCF653529990168A3583FF"),
|
||||
@@ -150,6 +175,7 @@ std::string kOfflineClip2PstInitData = wvcdm::a2bs_hex(
|
||||
"EDEF8BA979D64ACEA3C827DCD51D21ED00000020" // Widevine system id
|
||||
"08011a0d7769646576696e655f74657374220d6f" // pssh data
|
||||
"66666c696e655f636c697032");
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace wvcdm {
|
||||
@@ -167,6 +193,7 @@ class TestWvCdmClientPropertySet : public CdmClientPropertySet {
|
||||
session_sharing_id_(0) {}
|
||||
virtual ~TestWvCdmClientPropertySet() {}
|
||||
|
||||
virtual const std::string& app_id() const { return app_id_; }
|
||||
virtual const std::string& security_level() const { return security_level_; }
|
||||
virtual const std::string& service_certificate() const {
|
||||
return service_certificate_;
|
||||
@@ -177,6 +204,7 @@ class TestWvCdmClientPropertySet : public CdmClientPropertySet {
|
||||
}
|
||||
virtual uint32_t session_sharing_id() const { return session_sharing_id_; }
|
||||
|
||||
void set_app_id(const std::string& app_id) { app_id_ = app_id; }
|
||||
void set_security_level(const std::string& security_level) {
|
||||
if (!security_level.compare(QUERY_VALUE_SECURITY_LEVEL_L1) ||
|
||||
!security_level.compare(QUERY_VALUE_SECURITY_LEVEL_L3)) {
|
||||
@@ -195,6 +223,7 @@ class TestWvCdmClientPropertySet : public CdmClientPropertySet {
|
||||
void set_session_sharing_id(uint32_t id) { session_sharing_id_ = id; }
|
||||
|
||||
private:
|
||||
std::string app_id_;
|
||||
std::string security_level_;
|
||||
std::string service_certificate_;
|
||||
bool use_privacy_mode_;
|
||||
@@ -794,6 +823,53 @@ TEST_F(WvCdmExtendedDurationTest, VerifyLicenseRenewalTest) {
|
||||
decryptor_.CloseSession(session_id_);
|
||||
}
|
||||
|
||||
TEST_F(WvCdmExtendedDurationTest, UsageOverflowTest) {
|
||||
Provision();
|
||||
SubSampleInfo* data = &kEncryptedStreamingClip5SubSample;
|
||||
TestWvCdmClientPropertySet client_property_set;
|
||||
TestWvCdmClientPropertySet* property_set = NULL;
|
||||
|
||||
CdmSecurityLevel security_level = GetDefaultSecurityLevel();
|
||||
DeviceFiles handle;
|
||||
EXPECT_TRUE(handle.Init(security_level));
|
||||
File file;
|
||||
handle.SetTestFile(&file);
|
||||
EXPECT_TRUE(handle.DeleteAllUsageInfoForApp(""));
|
||||
|
||||
for (size_t i = 0; i < kMaxUsageTableSize + 100; ++i) {
|
||||
decryptor_.OpenSession(g_key_system, property_set, &session_id_);
|
||||
std::string key_id = a2bs_hex(
|
||||
"000000427073736800000000" // blob size and pssh
|
||||
"EDEF8BA979D64ACEA3C827DCD51D21ED00000022" // Widevine system id
|
||||
"08011a0d7769646576696e655f74657374220f73" // pssh data
|
||||
"747265616d696e675f636c697035");
|
||||
|
||||
GenerateKeyRequest(key_id, kLicenseTypeStreaming);
|
||||
VerifyKeyRequestResponse(g_license_server, g_client_auth, false);
|
||||
decryptor_.CloseSession(session_id_);
|
||||
}
|
||||
|
||||
uint32_t num_usage_info = 0;
|
||||
CdmUsageInfo usage_info;
|
||||
CdmUsageInfoReleaseMessage release_msg;
|
||||
CdmResponseType status = decryptor_.GetUsageInfo("", &usage_info);
|
||||
EXPECT_EQ(usage_info.empty() ? NO_ERROR : KEY_MESSAGE, status);
|
||||
while (usage_info.size() > 0) {
|
||||
for (size_t i = 0; i < usage_info.size(); ++i) {
|
||||
release_msg =
|
||||
GetUsageInfoResponse(g_license_server, g_client_auth, usage_info[i]);
|
||||
EXPECT_EQ(NO_ERROR, decryptor_.ReleaseUsageInfo(release_msg));
|
||||
}
|
||||
status = decryptor_.GetUsageInfo("", &usage_info);
|
||||
switch (status) {
|
||||
case KEY_MESSAGE: EXPECT_FALSE(usage_info.empty()); break;
|
||||
case NO_ERROR: EXPECT_TRUE(usage_info.empty()); break;
|
||||
default: FAIL() << "GetUsageInfo failed with error "
|
||||
<< static_cast<int>(status) ; break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class WvCdmStreamingNoPstTest : public WvCdmExtendedDurationTest,
|
||||
public ::testing::WithParamInterface<size_t> {};
|
||||
|
||||
|
||||
@@ -1200,6 +1200,68 @@ TEST_F(WvCdmRequestLicenseTest, RemoveKeys) {
|
||||
ASSERT_EQ(NO_ERROR, decryptor_.CloseSession(session_id_));
|
||||
}
|
||||
|
||||
TEST_F(WvCdmRequestLicenseTest, UsageInfoRetryTest) {
|
||||
Unprovision();
|
||||
Provision(kLevelDefault);
|
||||
|
||||
CdmSecurityLevel security_level = GetDefaultSecurityLevel();
|
||||
std::string app_id = "";
|
||||
DeviceFiles handle;
|
||||
EXPECT_TRUE(handle.Init(security_level));
|
||||
File file;
|
||||
handle.SetTestFile(&file);
|
||||
EXPECT_TRUE(handle.DeleteAllUsageInfoForApp(app_id));
|
||||
|
||||
SubSampleInfo* data = &usage_info_sub_samples_icp[0];
|
||||
decryptor_.OpenSession(g_key_system, NULL, &session_id_);
|
||||
std::string key_id = a2bs_hex(
|
||||
"000000427073736800000000" // blob size and pssh
|
||||
"EDEF8BA979D64ACEA3C827DCD51D21ED00000022" // Widevine system id
|
||||
"08011a0d7769646576696e655f74657374220f73" // pssh data
|
||||
"747265616d696e675f636c697033");
|
||||
|
||||
GenerateKeyRequest(key_id, kLicenseTypeStreaming, NULL);
|
||||
VerifyKeyRequestResponse(g_license_server, g_client_auth, false);
|
||||
|
||||
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[0]);
|
||||
decryption_parameters.is_encrypted = data->is_encrypted;
|
||||
decryption_parameters.is_secure = data->is_secure;
|
||||
EXPECT_EQ(NO_ERROR, decryptor_.Decrypt(session_id_, data->validate_key_id,
|
||||
decryption_parameters));
|
||||
|
||||
EXPECT_TRUE(std::equal(data->decrypt_data.begin(), data->decrypt_data.end(),
|
||||
decrypt_buffer.begin()));
|
||||
decryptor_.CloseSession(session_id_);
|
||||
|
||||
uint32_t num_usage_info = 0;
|
||||
CdmUsageInfo usage_info;
|
||||
CdmUsageInfoReleaseMessage release_msg;
|
||||
CdmResponseType status = decryptor_.GetUsageInfo(app_id, &usage_info);
|
||||
EXPECT_EQ(usage_info.empty() ? NO_ERROR : KEY_MESSAGE, status);
|
||||
|
||||
// Discard and retry to verify usage reports can be generated multiple times
|
||||
// before release.
|
||||
status = decryptor_.GetUsageInfo(app_id, &usage_info);
|
||||
EXPECT_EQ(usage_info.empty() ? NO_ERROR : KEY_MESSAGE, status);
|
||||
while (usage_info.size() > 0) {
|
||||
for (size_t i = 0; i < usage_info.size(); ++i) {
|
||||
release_msg =
|
||||
GetUsageInfoResponse(g_license_server, g_client_auth, usage_info[i]);
|
||||
EXPECT_EQ(NO_ERROR, decryptor_.ReleaseUsageInfo(release_msg));
|
||||
}
|
||||
status = decryptor_.GetUsageInfo(app_id, &usage_info);
|
||||
switch (status) {
|
||||
case KEY_MESSAGE: EXPECT_FALSE(usage_info.empty()); break;
|
||||
case NO_ERROR: EXPECT_TRUE(usage_info.empty()); break;
|
||||
default: FAIL() << "GetUsageInfo failed with error "
|
||||
<< static_cast<int>(status) ; break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class WvCdmUsageInfoTest
|
||||
: public WvCdmRequestLicenseTest,
|
||||
public ::testing::WithParamInterface<UsageInfoSubSampleInfo*> {};
|
||||
|
||||
Reference in New Issue
Block a user