Ref count WvCdmDecryptionModule in cdm_extended_duration_tests

[ Merge of http://go/wvgerrit/79884 ]

WvCdmDecryptionModule needs to be refcounted since it inherits
from RefBase. The test code instantiates it as a member variable.

Bug: 133188706
Test: WV unit/integration tests
Change-Id: I8ae3d92ae148677ea9a8290a6c0553c1a43e3454
This commit is contained in:
Rahul Frias
2019-05-27 17:19:20 -07:00
parent 96c36fa25e
commit 6004c2a945
2 changed files with 113 additions and 111 deletions

View File

@@ -249,7 +249,8 @@ class TestWvCdmClientPropertySet : public CdmClientPropertySet {
class WvCdmExtendedDurationTest : public WvCdmTestBase { class WvCdmExtendedDurationTest : public WvCdmTestBase {
public: public:
WvCdmExtendedDurationTest() {} WvCdmExtendedDurationTest()
: decryptor_(new wvcdm::WvContentDecryptionModule()) {}
~WvCdmExtendedDurationTest() {} ~WvCdmExtendedDurationTest() {}
protected: protected:
@@ -276,7 +277,7 @@ class WvCdmExtendedDurationTest : public WvCdmTestBase {
CdmAppParameterMap app_parameters; CdmAppParameterMap app_parameters;
CdmKeyRequest key_request; CdmKeyRequest key_request;
*response = decryptor_.GenerateKeyRequest( *response = decryptor_->GenerateKeyRequest(
session_id_, key_set_id_, "video/mp4", init_data, session_id_, key_set_id_, "video/mp4", init_data,
license_type, app_parameters, NULL, license_type, app_parameters, NULL,
kDefaultCdmIdentifier, &key_request); kDefaultCdmIdentifier, &key_request);
@@ -296,7 +297,7 @@ class WvCdmExtendedDurationTest : public WvCdmTestBase {
CdmKeyRequest key_request; CdmKeyRequest key_request;
EXPECT_EQ(KEY_MESSAGE, decryptor_.GenerateKeyRequest( EXPECT_EQ(KEY_MESSAGE, decryptor_->GenerateKeyRequest(
session_id_, key_set_id_, "video/mp4", init_data, session_id_, key_set_id_, "video/mp4", init_data,
license_type, app_parameters, NULL, license_type, app_parameters, NULL,
kDefaultCdmIdentifier, &key_request)); kDefaultCdmIdentifier, &key_request));
@@ -316,7 +317,7 @@ class WvCdmExtendedDurationTest : public WvCdmTestBase {
CdmAppParameterMap app_parameters; CdmAppParameterMap app_parameters;
CdmKeyRequest key_request; CdmKeyRequest key_request;
EXPECT_EQ(expected_response, decryptor_.GenerateKeyRequest( EXPECT_EQ(expected_response, decryptor_->GenerateKeyRequest(
session_id, key_set_id, "video/mp4", init_data, session_id, key_set_id, "video/mp4", init_data,
kLicenseTypeRelease, app_parameters, NULL, kLicenseTypeRelease, app_parameters, NULL,
kDefaultCdmIdentifier, &key_request)); kDefaultCdmIdentifier, &key_request));
@@ -422,7 +423,7 @@ class WvCdmExtendedDurationTest : public WvCdmTestBase {
CdmResponseType* status) { CdmResponseType* status) {
std::string resp = GetKeyRequestResponse(server_url, client_auth); std::string resp = GetKeyRequestResponse(server_url, client_auth);
CdmResponseType sts = CdmResponseType sts =
decryptor_.AddKey(session_id_, resp, &key_set_id_); decryptor_->AddKey(session_id_, resp, &key_set_id_);
if (status == NULL) { if (status == NULL) {
EXPECT_EQ(KEY_ADDED, sts); EXPECT_EQ(KEY_ADDED, sts);
@@ -433,17 +434,17 @@ class WvCdmExtendedDurationTest : public WvCdmTestBase {
void Unprovision() { void Unprovision() {
EXPECT_EQ(NO_ERROR, EXPECT_EQ(NO_ERROR,
decryptor_.Unprovision(kSecurityLevelL1, kDefaultCdmIdentifier)); decryptor_->Unprovision(kSecurityLevelL1, kDefaultCdmIdentifier));
EXPECT_EQ(NO_ERROR, EXPECT_EQ(NO_ERROR,
decryptor_.Unprovision(kSecurityLevelL3, kDefaultCdmIdentifier)); decryptor_->Unprovision(kSecurityLevelL3, kDefaultCdmIdentifier));
} }
void Provision() { void Provision() {
CdmResponseType status = decryptor_.OpenSession( CdmResponseType status = decryptor_->OpenSession(
config_.key_system(), NULL, kDefaultCdmIdentifier, NULL, &session_id_); config_.key_system(), NULL, kDefaultCdmIdentifier, NULL, &session_id_);
switch (status) { switch (status) {
case NO_ERROR: case NO_ERROR:
decryptor_.CloseSession(session_id_); decryptor_->CloseSession(session_id_);
return; return;
case NEED_PROVISIONING: case NEED_PROVISIONING:
break; break;
@@ -456,7 +457,7 @@ class WvCdmExtendedDurationTest : public WvCdmTestBase {
CdmCertificateType cert_type = kCertificateWidevine; CdmCertificateType cert_type = kCertificateWidevine;
std::string cert_authority, cert, wrapped_key; std::string cert_authority, cert, wrapped_key;
status = decryptor_.GetProvisioningRequest( status = decryptor_->GetProvisioningRequest(
cert_type, cert_authority, kDefaultCdmIdentifier, cert_type, cert_authority, kDefaultCdmIdentifier,
kEmptyServiceCertificate, &key_msg_, &provisioning_server_url); kEmptyServiceCertificate, &key_msg_, &provisioning_server_url);
EXPECT_EQ(NO_ERROR, status); EXPECT_EQ(NO_ERROR, status);
@@ -467,11 +468,11 @@ class WvCdmExtendedDurationTest : public WvCdmTestBase {
GetCertRequestResponse(config_.provisioning_server()); GetCertRequestResponse(config_.provisioning_server());
EXPECT_NE(0, static_cast<int>(response.size())); EXPECT_NE(0, static_cast<int>(response.size()));
EXPECT_EQ(NO_ERROR, EXPECT_EQ(NO_ERROR,
decryptor_.HandleProvisioningResponse(kDefaultCdmIdentifier, response, decryptor_->HandleProvisioningResponse(kDefaultCdmIdentifier, response,
&cert, &wrapped_key)); &cert, &wrapped_key));
EXPECT_EQ(0, static_cast<int>(cert.size())); EXPECT_EQ(0, static_cast<int>(cert.size()));
EXPECT_EQ(0, static_cast<int>(wrapped_key.size())); EXPECT_EQ(0, static_cast<int>(wrapped_key.size()));
decryptor_.CloseSession(session_id_); decryptor_->CloseSession(session_id_);
return; return;
} }
@@ -642,7 +643,7 @@ class WvCdmExtendedDurationTest : public WvCdmTestBase {
int64_t* license_duration_remaining, int64_t* license_duration_remaining,
int64_t* playback_duration_remaining) { int64_t* playback_duration_remaining) {
CdmQueryMap query_info; CdmQueryMap query_info;
EXPECT_EQ(NO_ERROR, decryptor_.QueryKeyStatus(session_id_, &query_info)); EXPECT_EQ(NO_ERROR, decryptor_->QueryKeyStatus(session_id_, &query_info));
EXPECT_THAT(query_info, Contains(Pair(QUERY_KEY_LICENSE_TYPE, EXPECT_THAT(query_info, Contains(Pair(QUERY_KEY_LICENSE_TYPE,
streaming ? QUERY_VALUE_STREAMING streaming ? QUERY_VALUE_STREAMING
@@ -670,7 +671,7 @@ class WvCdmExtendedDurationTest : public WvCdmTestBase {
uint32_t QueryStatus(SecurityLevel security_level, const std::string& key) { uint32_t QueryStatus(SecurityLevel security_level, const std::string& key) {
std::string str; std::string str;
EXPECT_EQ(wvcdm::NO_ERROR, EXPECT_EQ(wvcdm::NO_ERROR,
decryptor_.QueryStatus(security_level, key, &str)); decryptor_->QueryStatus(security_level, key, &str));
std::istringstream ss(str); std::istringstream ss(str);
uint32_t value; uint32_t value;
@@ -681,14 +682,14 @@ class WvCdmExtendedDurationTest : public WvCdmTestBase {
} }
std::string GetSecurityLevel(TestWvCdmClientPropertySet* property_set) { std::string GetSecurityLevel(TestWvCdmClientPropertySet* property_set) {
decryptor_.OpenSession(config_.key_system(), property_set, decryptor_->OpenSession(config_.key_system(), property_set,
kDefaultCdmIdentifier, NULL, &session_id_); kDefaultCdmIdentifier, NULL, &session_id_);
CdmQueryMap query_info; CdmQueryMap query_info;
EXPECT_EQ(NO_ERROR, EXPECT_EQ(NO_ERROR,
decryptor_.QuerySessionStatus(session_id_, &query_info)); decryptor_->QuerySessionStatus(session_id_, &query_info));
CdmQueryMap::iterator itr = query_info.find(QUERY_KEY_SECURITY_LEVEL); CdmQueryMap::iterator itr = query_info.find(QUERY_KEY_SECURITY_LEVEL);
EXPECT_TRUE(itr != query_info.end()); EXPECT_TRUE(itr != query_info.end());
decryptor_.CloseSession(session_id_); decryptor_->CloseSession(session_id_);
return itr->second; return itr->second;
} }
@@ -708,11 +709,10 @@ class WvCdmExtendedDurationTest : public WvCdmTestBase {
class CloseSessionThread : public android::Thread { class CloseSessionThread : public android::Thread {
public: public:
CloseSessionThread() : CloseSessionThread() :
Thread(false), Thread(false) {}
wv_content_decryption_module_(NULL) {}
~CloseSessionThread() {} ~CloseSessionThread() {}
bool Start(WvContentDecryptionModule* decryptor, bool Start(const android::sp<wvcdm::WvContentDecryptionModule>& decryptor,
const CdmSessionId& session_id, const CdmSessionId& session_id,
uint32_t time_in_msecs) { uint32_t time_in_msecs) {
wv_content_decryption_module_ = decryptor; wv_content_decryption_module_ = decryptor;
@@ -736,13 +736,13 @@ class WvCdmExtendedDurationTest : public WvCdmTestBase {
return false; return false;
} }
WvContentDecryptionModule* wv_content_decryption_module_; android::sp<wvcdm::WvContentDecryptionModule> wv_content_decryption_module_;
CdmSessionId sess_id_; CdmSessionId sess_id_;
struct timespec delay_; struct timespec delay_;
CORE_DISALLOW_COPY_AND_ASSIGN(CloseSessionThread); CORE_DISALLOW_COPY_AND_ASSIGN(CloseSessionThread);
}; };
WvContentDecryptionModule decryptor_; android::sp<wvcdm::WvContentDecryptionModule> decryptor_;
CdmKeyMessage key_msg_; CdmKeyMessage key_msg_;
CdmKeyResponse key_response_; CdmKeyResponse key_response_;
CdmSessionId session_id_; CdmSessionId session_id_;
@@ -752,8 +752,8 @@ class WvCdmExtendedDurationTest : public WvCdmTestBase {
TEST_F(WvCdmExtendedDurationTest, VerifyLicenseRequestTest) { TEST_F(WvCdmExtendedDurationTest, VerifyLicenseRequestTest) {
Provision(); Provision();
decryptor_.OpenSession(config_.key_system(), NULL, kDefaultCdmIdentifier, decryptor_->OpenSession(config_.key_system(), NULL, kDefaultCdmIdentifier,
NULL, &session_id_); NULL, &session_id_);
GenerateKeyRequest(binary_key_id(), kLicenseTypeStreaming); GenerateKeyRequest(binary_key_id(), kLicenseTypeStreaming);
EXPECT_TRUE(!key_msg_.empty()); EXPECT_TRUE(!key_msg_.empty());
@@ -816,13 +816,13 @@ TEST_F(WvCdmExtendedDurationTest, VerifyLicenseRequestTest) {
EXPECT_EQ(video_widevine::VERSION_2_1, license_request.protocol_version()); EXPECT_EQ(video_widevine::VERSION_2_1, license_request.protocol_version());
EXPECT_TRUE(license_request.has_key_control_nonce()); EXPECT_TRUE(license_request.has_key_control_nonce());
decryptor_.CloseSession(session_id_); decryptor_->CloseSession(session_id_);
} }
TEST_F(WvCdmExtendedDurationTest, VerifyLicenseRenewalTest) { TEST_F(WvCdmExtendedDurationTest, VerifyLicenseRenewalTest) {
Provision(); Provision();
decryptor_.OpenSession(config_.key_system(), NULL, kDefaultCdmIdentifier, decryptor_->OpenSession(config_.key_system(), NULL, kDefaultCdmIdentifier,
NULL, &session_id_); NULL, &session_id_);
GenerateKeyRequest(binary_key_id(), kLicenseTypeStreaming); GenerateKeyRequest(binary_key_id(), kLicenseTypeStreaming);
VerifyKeyRequestResponse(config_.license_server(), config_.client_auth(), VerifyKeyRequestResponse(config_.license_server(), config_.client_auth(),
false); false);
@@ -892,7 +892,7 @@ TEST_F(WvCdmExtendedDurationTest, VerifyLicenseRenewalTest) {
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()); EXPECT_TRUE(license_renewal.has_key_control_nonce());
decryptor_.CloseSession(session_id_); decryptor_->CloseSession(session_id_);
} }
TEST_F(WvCdmExtendedDurationTest, DecryptionCloseSessionConcurrencyTest) { TEST_F(WvCdmExtendedDurationTest, DecryptionCloseSessionConcurrencyTest) {
@@ -901,24 +901,24 @@ TEST_F(WvCdmExtendedDurationTest, DecryptionCloseSessionConcurrencyTest) {
// Leave session open to avoid CDM termination // Leave session open to avoid CDM termination
CdmSessionId session_id; CdmSessionId session_id;
decryptor_.OpenSession(config_.key_system(), NULL, kDefaultCdmIdentifier, decryptor_->OpenSession(config_.key_system(), NULL, kDefaultCdmIdentifier,
NULL, &session_id); NULL, &session_id);
// Retrieve offline license // Retrieve offline license
decryptor_.OpenSession(config_.key_system(), NULL, kDefaultCdmIdentifier, decryptor_->OpenSession(config_.key_system(), NULL, kDefaultCdmIdentifier,
NULL, &session_id_); NULL, &session_id_);
GenerateKeyRequest(kOfflineClip2PstInitData, kLicenseTypeOffline); GenerateKeyRequest(kOfflineClip2PstInitData, kLicenseTypeOffline);
VerifyKeyRequestResponse(config_.license_server(), config_.client_auth(), VerifyKeyRequestResponse(config_.license_server(), config_.client_auth(),
false); false);
EXPECT_FALSE(key_set_id_.empty()); EXPECT_FALSE(key_set_id_.empty());
decryptor_.CloseSession(session_id_); decryptor_->CloseSession(session_id_);
for (uint32_t j = 0; j < 500; ++j) { for (uint32_t j = 0; j < 500; ++j) {
decryptor_.OpenSession(config_.key_system(), NULL, kDefaultCdmIdentifier, decryptor_->OpenSession(config_.key_system(), NULL, kDefaultCdmIdentifier,
NULL, &session_id_); NULL, &session_id_);
EXPECT_EQ(KEY_ADDED, decryptor_.RestoreKey(session_id_, key_set_id_)); EXPECT_EQ(KEY_ADDED, decryptor_->RestoreKey(session_id_, key_set_id_));
CdmResponseType status = NO_ERROR; CdmResponseType status = NO_ERROR;
struct timespec decrypt_delay; struct timespec decrypt_delay;
@@ -926,7 +926,7 @@ TEST_F(WvCdmExtendedDurationTest, DecryptionCloseSessionConcurrencyTest) {
decrypt_delay.tv_nsec = 10000000ll; // 10 ms decrypt_delay.tv_nsec = 10000000ll; // 10 ms
CloseSessionThread* thread = new CloseSessionThread(); CloseSessionThread* thread = new CloseSessionThread();
thread->Start(&decryptor_, session_id_, 500 /* 500 ms */); thread->Start(decryptor_, session_id_, 500 /* 500 ms */);
thread = NULL; thread = NULL;
while (status == NO_ERROR) { while (status == NO_ERROR) {
@@ -946,8 +946,8 @@ TEST_F(WvCdmExtendedDurationTest, DecryptionCloseSessionConcurrencyTest) {
decryption_parameters.is_encrypted = (data + i)->is_encrypted; decryption_parameters.is_encrypted = (data + i)->is_encrypted;
decryption_parameters.is_secure = (data + i)->is_secure; decryption_parameters.is_secure = (data + i)->is_secure;
decryption_parameters.subsample_flags = (data + i)->subsample_flags; decryption_parameters.subsample_flags = (data + i)->subsample_flags;
status = decryptor_.Decrypt(session_id_, (data + i)->validate_key_id, status = decryptor_->Decrypt(session_id_, (data + i)->validate_key_id,
decryption_parameters); decryption_parameters);
switch (status) { switch (status) {
case SESSION_NOT_FOUND_FOR_DECRYPT: case SESSION_NOT_FOUND_FOR_DECRYPT:
@@ -964,7 +964,7 @@ TEST_F(WvCdmExtendedDurationTest, DecryptionCloseSessionConcurrencyTest) {
} }
} }
} }
decryptor_.CloseSession(session_id); decryptor_->CloseSession(session_id);
} }
// TODO(rfrias): Rewite this test when OEMCrypto v13 is the minimum version // TODO(rfrias): Rewite this test when OEMCrypto v13 is the minimum version
@@ -984,8 +984,8 @@ TEST_F(WvCdmExtendedDurationTest, DISABLED_UsageOverflowTest) {
DeviceFiles::GetUsageInfoFileName(""), &provider_session_tokens)); DeviceFiles::GetUsageInfoFileName(""), &provider_session_tokens));
for (size_t i = 0; i < kMaxUsageTableSize + 100; ++i) { for (size_t i = 0; i < kMaxUsageTableSize + 100; ++i) {
decryptor_.OpenSession(config_.key_system(), property_set, decryptor_->OpenSession(config_.key_system(), property_set,
kDefaultCdmIdentifier, NULL, &session_id_); kDefaultCdmIdentifier, NULL, &session_id_);
std::string key_id = a2bs_hex( std::string key_id = a2bs_hex(
"000000427073736800000000" // blob size and pssh "000000427073736800000000" // blob size and pssh
"EDEF8BA979D64ACEA3C827DCD51D21ED00000022" // Widevine system id "EDEF8BA979D64ACEA3C827DCD51D21ED00000022" // Widevine system id
@@ -995,13 +995,13 @@ TEST_F(WvCdmExtendedDurationTest, DISABLED_UsageOverflowTest) {
GenerateKeyRequest(key_id, kLicenseTypeStreaming); GenerateKeyRequest(key_id, kLicenseTypeStreaming);
VerifyKeyRequestResponse(config_.license_server(), config_.client_auth(), VerifyKeyRequestResponse(config_.license_server(), config_.client_auth(),
false); false);
decryptor_.CloseSession(session_id_); decryptor_->CloseSession(session_id_);
} }
CdmUsageInfo usage_info; CdmUsageInfo usage_info;
CdmUsageInfoReleaseMessage release_msg; CdmUsageInfoReleaseMessage release_msg;
CdmResponseType status = CdmResponseType status =
decryptor_.GetUsageInfo("", kDefaultCdmIdentifier, &usage_info); decryptor_->GetUsageInfo("", kDefaultCdmIdentifier, &usage_info);
EXPECT_EQ(usage_info.empty() ? NO_ERROR : KEY_MESSAGE, status); EXPECT_EQ(usage_info.empty() ? NO_ERROR : KEY_MESSAGE, status);
int error_count = 0; int error_count = 0;
while (usage_info.size() > 0) { while (usage_info.size() > 0) {
@@ -1009,12 +1009,12 @@ TEST_F(WvCdmExtendedDurationTest, DISABLED_UsageOverflowTest) {
release_msg = GetUsageInfoResponse(config_.license_server(), release_msg = GetUsageInfoResponse(config_.license_server(),
config_.client_auth(), usage_info[i]); config_.client_auth(), usage_info[i]);
EXPECT_EQ(NO_ERROR, EXPECT_EQ(NO_ERROR,
decryptor_.ReleaseUsageInfo(release_msg, kDefaultCdmIdentifier)) decryptor_->ReleaseUsageInfo(release_msg, kDefaultCdmIdentifier))
<< i << "/" << usage_info.size() << " (err " << (error_count++) << ")" << i << "/" << usage_info.size() << " (err " << (error_count++) << ")"
<< release_msg; << release_msg;
} }
ASSERT_LE(error_count, 100); // Give up after 100 failures. ASSERT_LE(error_count, 100); // Give up after 100 failures.
status = decryptor_.GetUsageInfo("", kDefaultCdmIdentifier, &usage_info); status = decryptor_->GetUsageInfo("", kDefaultCdmIdentifier, &usage_info);
switch (status) { switch (status) {
case KEY_MESSAGE: case KEY_MESSAGE:
EXPECT_FALSE(usage_info.empty()); EXPECT_FALSE(usage_info.empty());
@@ -1038,7 +1038,7 @@ TEST_F(WvCdmExtendedDurationTest, AutomatedOfflineSessionReleaseOnTimerEvent) {
// Leave session open to run the CDM timer // Leave session open to run the CDM timer
CdmSessionId streaming_session_id; CdmSessionId streaming_session_id;
decryptor_.OpenSession(config_.key_system(), NULL, kDefaultCdmIdentifier, decryptor_->OpenSession(config_.key_system(), NULL, kDefaultCdmIdentifier,
NULL, &streaming_session_id); NULL, &streaming_session_id);
// override default settings unless configured through the command line // override default settings unless configured through the command line
@@ -1049,21 +1049,21 @@ TEST_F(WvCdmExtendedDurationTest, AutomatedOfflineSessionReleaseOnTimerEvent) {
uint32_t initial_open_sessions = uint32_t initial_open_sessions =
QueryStatus(kLevelDefault, wvcdm::QUERY_KEY_NUMBER_OF_OPEN_SESSIONS); QueryStatus(kLevelDefault, wvcdm::QUERY_KEY_NUMBER_OF_OPEN_SESSIONS);
decryptor_.OpenSession(config_.key_system(), NULL, kDefaultCdmIdentifier, decryptor_->OpenSession(config_.key_system(), NULL, kDefaultCdmIdentifier,
NULL, &session_id_); NULL, &session_id_);
GenerateKeyRequest(kOfflineClip4, kLicenseTypeOffline); GenerateKeyRequest(kOfflineClip4, kLicenseTypeOffline);
VerifyKeyRequestResponse(kUatLicenseServer, client_auth, false); VerifyKeyRequestResponse(kUatLicenseServer, client_auth, false);
EXPECT_FALSE(key_set_id_.empty()); EXPECT_FALSE(key_set_id_.empty());
decryptor_.CloseSession(session_id_); decryptor_->CloseSession(session_id_);
CdmKeySetId key_set_id = key_set_id_; CdmKeySetId key_set_id = key_set_id_;
session_id_.clear(); session_id_.clear();
key_set_id_.clear(); key_set_id_.clear();
decryptor_.OpenSession(config_.key_system(), NULL, kDefaultCdmIdentifier, decryptor_->OpenSession(config_.key_system(), NULL, kDefaultCdmIdentifier,
NULL, &session_id_); NULL, &session_id_);
EXPECT_EQ(wvcdm::KEY_ADDED, decryptor_.RestoreKey(session_id_, key_set_id)); EXPECT_EQ(wvcdm::KEY_ADDED, decryptor_->RestoreKey(session_id_, key_set_id));
decryptor_.CloseSession(session_id_); decryptor_->CloseSession(session_id_);
session_id_.clear(); session_id_.clear();
GenerateKeyRelease(key_set_id); GenerateKeyRelease(key_set_id);
@@ -1084,7 +1084,7 @@ TEST_F(WvCdmExtendedDurationTest, AutomatedOfflineSessionReleaseOnTimerEvent) {
GenerateKeyRelease(key_set_id); GenerateKeyRelease(key_set_id);
key_set_id_ = key_set_id; key_set_id_ = key_set_id;
VerifyKeyRequestResponse(kUatLicenseServer, client_auth, false); VerifyKeyRequestResponse(kUatLicenseServer, client_auth, false);
decryptor_.CloseSession(streaming_session_id); decryptor_->CloseSession(streaming_session_id);
} }
// This test verifies that sessions allocated internally during key release // This test verifies that sessions allocated internally during key release
@@ -1102,33 +1102,33 @@ TEST_F(WvCdmExtendedDurationTest, AutomatedOfflineSessionReleaseOnOpenSession) {
uint32_t initial_open_sessions = uint32_t initial_open_sessions =
QueryStatus(kLevelDefault, wvcdm::QUERY_KEY_NUMBER_OF_OPEN_SESSIONS); QueryStatus(kLevelDefault, wvcdm::QUERY_KEY_NUMBER_OF_OPEN_SESSIONS);
decryptor_.OpenSession(config_.key_system(), NULL, kDefaultCdmIdentifier, decryptor_->OpenSession(config_.key_system(), NULL, kDefaultCdmIdentifier,
NULL, &session_id_); NULL, &session_id_);
GenerateKeyRequest(kOfflineClip4, kLicenseTypeOffline); GenerateKeyRequest(kOfflineClip4, kLicenseTypeOffline);
VerifyKeyRequestResponse(kUatLicenseServer, client_auth, false); VerifyKeyRequestResponse(kUatLicenseServer, client_auth, false);
EXPECT_FALSE(key_set_id_.empty()); EXPECT_FALSE(key_set_id_.empty());
decryptor_.CloseSession(session_id_); decryptor_->CloseSession(session_id_);
CdmKeySetId key_set_id = key_set_id_; CdmKeySetId key_set_id = key_set_id_;
session_id_.clear(); session_id_.clear();
key_set_id_.clear(); key_set_id_.clear();
decryptor_.OpenSession(config_.key_system(), NULL, kDefaultCdmIdentifier, decryptor_->OpenSession(config_.key_system(), NULL, kDefaultCdmIdentifier,
NULL, &session_id_); NULL, &session_id_);
EXPECT_EQ(wvcdm::KEY_ADDED, decryptor_.RestoreKey(session_id_, key_set_id)); EXPECT_EQ(wvcdm::KEY_ADDED, decryptor_->RestoreKey(session_id_, key_set_id));
decryptor_.CloseSession(session_id_); decryptor_->CloseSession(session_id_);
session_id_.clear(); session_id_.clear();
GenerateKeyRelease(key_set_id); GenerateKeyRelease(key_set_id);
decryptor_.OpenSession(config_.key_system(), NULL, kDefaultCdmIdentifier, decryptor_->OpenSession(config_.key_system(), NULL, kDefaultCdmIdentifier,
NULL, &session_id_); NULL, &session_id_);
EXPECT_GT( EXPECT_GT(
QueryStatus(kLevelDefault, wvcdm::QUERY_KEY_NUMBER_OF_OPEN_SESSIONS), QueryStatus(kLevelDefault, wvcdm::QUERY_KEY_NUMBER_OF_OPEN_SESSIONS),
initial_open_sessions); initial_open_sessions);
decryptor_.CloseSession(session_id_); decryptor_->CloseSession(session_id_);
EXPECT_GT( EXPECT_GT(
QueryStatus(kLevelDefault, wvcdm::QUERY_KEY_NUMBER_OF_OPEN_SESSIONS), QueryStatus(kLevelDefault, wvcdm::QUERY_KEY_NUMBER_OF_OPEN_SESSIONS),
@@ -1140,14 +1140,14 @@ TEST_F(WvCdmExtendedDurationTest, AutomatedOfflineSessionReleaseOnOpenSession) {
QueryStatus(kLevelDefault, wvcdm::QUERY_KEY_NUMBER_OF_OPEN_SESSIONS), QueryStatus(kLevelDefault, wvcdm::QUERY_KEY_NUMBER_OF_OPEN_SESSIONS),
initial_open_sessions); initial_open_sessions);
decryptor_.OpenSession(config_.key_system(), NULL, kDefaultCdmIdentifier, decryptor_->OpenSession(config_.key_system(), NULL, kDefaultCdmIdentifier,
NULL, &session_id_); NULL, &session_id_);
EXPECT_GT( EXPECT_GT(
QueryStatus(kLevelDefault, wvcdm::QUERY_KEY_NUMBER_OF_OPEN_SESSIONS), QueryStatus(kLevelDefault, wvcdm::QUERY_KEY_NUMBER_OF_OPEN_SESSIONS),
initial_open_sessions); initial_open_sessions);
decryptor_.CloseSession(session_id_); decryptor_->CloseSession(session_id_);
EXPECT_EQ( EXPECT_EQ(
QueryStatus(kLevelDefault, wvcdm::QUERY_KEY_NUMBER_OF_OPEN_SESSIONS), QueryStatus(kLevelDefault, wvcdm::QUERY_KEY_NUMBER_OF_OPEN_SESSIONS),
@@ -1184,13 +1184,13 @@ TEST_F(WvCdmExtendedDurationTest, DISABLED_AutomatedOfflineSessionReleaseTest) {
std::set<std::string> key_set_id_map; std::set<std::string> key_set_id_map;
for (uint32_t i = 0; i < num_key_set_ids; ++i) { for (uint32_t i = 0; i < num_key_set_ids; ++i) {
decryptor_.OpenSession(config_.key_system(), NULL, kDefaultCdmIdentifier, decryptor_->OpenSession(config_.key_system(), NULL, kDefaultCdmIdentifier,
NULL, &session_id_); NULL, &session_id_);
GenerateKeyRequest(kOfflineClip4, kLicenseTypeOffline); GenerateKeyRequest(kOfflineClip4, kLicenseTypeOffline);
VerifyKeyRequestResponse(kUatLicenseServer, client_auth, false); VerifyKeyRequestResponse(kUatLicenseServer, client_auth, false);
EXPECT_FALSE(key_set_id_.empty()); EXPECT_FALSE(key_set_id_.empty());
decryptor_.CloseSession(session_id_); decryptor_->CloseSession(session_id_);
key_set_id_map.insert(key_set_id_); key_set_id_map.insert(key_set_id_);
} }
@@ -1198,10 +1198,10 @@ TEST_F(WvCdmExtendedDurationTest, DISABLED_AutomatedOfflineSessionReleaseTest) {
for (iter = key_set_id_map.begin(); iter != key_set_id_map.end(); ++iter) { for (iter = key_set_id_map.begin(); iter != key_set_id_map.end(); ++iter) {
session_id_.clear(); session_id_.clear();
key_set_id_.clear(); key_set_id_.clear();
decryptor_.OpenSession(config_.key_system(), NULL, kDefaultCdmIdentifier, decryptor_->OpenSession(config_.key_system(), NULL, kDefaultCdmIdentifier,
NULL, &session_id_); NULL, &session_id_);
EXPECT_EQ(wvcdm::KEY_ADDED, decryptor_.RestoreKey(session_id_, *iter)); EXPECT_EQ(wvcdm::KEY_ADDED, decryptor_->RestoreKey(session_id_, *iter));
decryptor_.CloseSession(session_id_); decryptor_->CloseSession(session_id_);
} }
for (iter = key_set_id_map.begin(); iter != key_set_id_map.end(); ++iter) { for (iter = key_set_id_map.begin(); iter != key_set_id_map.end(); ++iter) {
@@ -1241,7 +1241,7 @@ TEST_P(WvCdmStreamingNoPstTest, UsageTest) {
Unprovision(); Unprovision();
Provision(); Provision();
decryptor_.OpenSession(config_.key_system(), NULL, kDefaultCdmIdentifier, decryptor_->OpenSession(config_.key_system(), NULL, kDefaultCdmIdentifier,
NULL, &session_id_); NULL, &session_id_);
GenerateKeyRequest(binary_key_id(), kLicenseTypeStreaming); GenerateKeyRequest(binary_key_id(), kLicenseTypeStreaming);
VerifyKeyRequestResponse(config_.license_server(), config_.client_auth(), VerifyKeyRequestResponse(config_.license_server(), config_.client_auth(),
@@ -1272,7 +1272,7 @@ TEST_P(WvCdmStreamingNoPstTest, UsageTest) {
decryption_parameters.is_secure = (data + i)->is_secure; decryption_parameters.is_secure = (data + i)->is_secure;
decryption_parameters.subsample_flags = (data + i)->subsample_flags; decryption_parameters.subsample_flags = (data + i)->subsample_flags;
EXPECT_EQ(NO_ERROR, EXPECT_EQ(NO_ERROR,
decryptor_.Decrypt(session_id_, (data + i)->validate_key_id, decryptor_->Decrypt(session_id_, (data + i)->validate_key_id,
decryption_parameters)); decryption_parameters));
EXPECT_EQ((data + i)->decrypt_data, decrypt_buffer); EXPECT_EQ((data + i)->decrypt_data, decrypt_buffer);
@@ -1304,7 +1304,7 @@ TEST_P(WvCdmStreamingNoPstTest, UsageTest) {
EXPECT_NEAR(initial_playback_duration_remaining - playback_duration_remaining, EXPECT_NEAR(initial_playback_duration_remaining - playback_duration_remaining,
expected_seconds_since_initial_playback, kClockTolerance); expected_seconds_since_initial_playback, kClockTolerance);
decryptor_.CloseSession(session_id_); decryptor_->CloseSession(session_id_);
} }
INSTANTIATE_TEST_CASE_P(Cdm, WvCdmStreamingNoPstTest, INSTANTIATE_TEST_CASE_P(Cdm, WvCdmStreamingNoPstTest,
@@ -1317,8 +1317,8 @@ TEST_P(WvCdmStreamingPstTest, UsageTest) {
Unprovision(); Unprovision();
Provision(); Provision();
decryptor_.OpenSession(config_.key_system(), NULL, kDefaultCdmIdentifier, decryptor_->OpenSession(config_.key_system(), NULL, kDefaultCdmIdentifier,
NULL, &session_id_); NULL, &session_id_);
GenerateKeyRequest(kStreamingClip8PstInitData, kLicenseTypeStreaming); GenerateKeyRequest(kStreamingClip8PstInitData, kLicenseTypeStreaming);
VerifyKeyRequestResponse(config_.license_server(), config_.client_auth(), VerifyKeyRequestResponse(config_.license_server(), config_.client_auth(),
false); false);
@@ -1348,8 +1348,8 @@ TEST_P(WvCdmStreamingPstTest, UsageTest) {
decryption_parameters.is_secure = (data + i)->is_secure; decryption_parameters.is_secure = (data + i)->is_secure;
decryption_parameters.subsample_flags = (data + i)->subsample_flags; decryption_parameters.subsample_flags = (data + i)->subsample_flags;
EXPECT_EQ(NO_ERROR, EXPECT_EQ(NO_ERROR,
decryptor_.Decrypt(session_id_, (data + i)->validate_key_id, decryptor_->Decrypt(session_id_, (data + i)->validate_key_id,
decryption_parameters)); decryption_parameters));
EXPECT_EQ((data + i)->decrypt_data, decrypt_buffer); EXPECT_EQ((data + i)->decrypt_data, decrypt_buffer);
} }
@@ -1371,7 +1371,7 @@ TEST_P(WvCdmStreamingPstTest, UsageTest) {
EXPECT_NEAR(initial_playback_duration_remaining - playback_duration_remaining, EXPECT_NEAR(initial_playback_duration_remaining - playback_duration_remaining,
expected_seconds_since_initial_playback, kClockTolerance); expected_seconds_since_initial_playback, kClockTolerance);
decryptor_.CloseSession(session_id_); decryptor_->CloseSession(session_id_);
} }
INSTANTIATE_TEST_CASE_P(Cdm, WvCdmStreamingPstTest, ::testing::Values(0, 1, 2)); INSTANTIATE_TEST_CASE_P(Cdm, WvCdmStreamingPstTest, ::testing::Values(0, 1, 2));
@@ -1384,7 +1384,7 @@ TEST_P(WvCdmStreamingUsageReportTest, UsageTest) {
Unprovision(); Unprovision();
Provision(); Provision();
decryptor_.OpenSession(config_.key_system(), NULL, kDefaultCdmIdentifier, decryptor_->OpenSession(config_.key_system(), NULL, kDefaultCdmIdentifier,
NULL, &session_id_); NULL, &session_id_);
GenerateKeyRequest(kStreamingClip8PstInitData, kLicenseTypeStreaming); GenerateKeyRequest(kStreamingClip8PstInitData, kLicenseTypeStreaming);
VerifyKeyRequestResponse(config_.license_server(), config_.client_auth(), VerifyKeyRequestResponse(config_.license_server(), config_.client_auth(),
@@ -1415,8 +1415,8 @@ TEST_P(WvCdmStreamingUsageReportTest, UsageTest) {
decryption_parameters.is_secure = (data + i)->is_secure; decryption_parameters.is_secure = (data + i)->is_secure;
decryption_parameters.subsample_flags = (data + i)->subsample_flags; decryption_parameters.subsample_flags = (data + i)->subsample_flags;
EXPECT_EQ(NO_ERROR, EXPECT_EQ(NO_ERROR,
decryptor_.Decrypt(session_id_, (data + i)->validate_key_id, decryptor_->Decrypt(session_id_, (data + i)->validate_key_id,
decryption_parameters)); decryption_parameters));
EXPECT_EQ((data + i)->decrypt_data, decrypt_buffer); EXPECT_EQ((data + i)->decrypt_data, decrypt_buffer);
} }
@@ -1438,13 +1438,13 @@ TEST_P(WvCdmStreamingUsageReportTest, UsageTest) {
EXPECT_NEAR(initial_playback_duration_remaining - playback_duration_remaining, EXPECT_NEAR(initial_playback_duration_remaining - playback_duration_remaining,
expected_seconds_since_initial_playback, kClockTolerance); expected_seconds_since_initial_playback, kClockTolerance);
decryptor_.CloseSession(session_id_); decryptor_->CloseSession(session_id_);
// Create usage report and validate // Create usage report and validate
CdmUsageInfo usage_info; CdmUsageInfo usage_info;
CdmUsageInfoReleaseMessage release_msg; CdmUsageInfoReleaseMessage release_msg;
CdmResponseType status = CdmResponseType status =
decryptor_.GetUsageInfo("", kDefaultCdmIdentifier, &usage_info); decryptor_->GetUsageInfo("", kDefaultCdmIdentifier, &usage_info);
EXPECT_EQ(usage_info.empty() ? NO_ERROR : KEY_MESSAGE, status); EXPECT_EQ(usage_info.empty() ? NO_ERROR : KEY_MESSAGE, status);
int error_count = 0; int error_count = 0;
while (usage_info.size() > 0) { while (usage_info.size() > 0) {
@@ -1457,12 +1457,12 @@ TEST_P(WvCdmStreamingUsageReportTest, UsageTest) {
release_msg = GetUsageInfoResponse(config_.license_server(), release_msg = GetUsageInfoResponse(config_.license_server(),
config_.client_auth(), usage_info[i]); config_.client_auth(), usage_info[i]);
EXPECT_EQ(NO_ERROR, EXPECT_EQ(NO_ERROR,
decryptor_.ReleaseUsageInfo(release_msg, kDefaultCdmIdentifier)) decryptor_->ReleaseUsageInfo(release_msg, kDefaultCdmIdentifier))
<< i << "/" << usage_info.size() << " (err " << (error_count++) << ")" << i << "/" << usage_info.size() << " (err " << (error_count++) << ")"
<< release_msg; << release_msg;
} }
ASSERT_LE(error_count, 100); // Give up after 100 failures. ASSERT_LE(error_count, 100); // Give up after 100 failures.
status = decryptor_.GetUsageInfo("", kDefaultCdmIdentifier, &usage_info); status = decryptor_->GetUsageInfo("", kDefaultCdmIdentifier, &usage_info);
switch (status) { switch (status) {
case KEY_MESSAGE: case KEY_MESSAGE:
EXPECT_FALSE(usage_info.empty()); EXPECT_FALSE(usage_info.empty());
@@ -1478,7 +1478,7 @@ TEST_P(WvCdmStreamingUsageReportTest, UsageTest) {
// Validate that update usage table entry is exercised. // Validate that update usage table entry is exercised.
drm_metrics::WvCdmMetrics metrics; drm_metrics::WvCdmMetrics metrics;
ASSERT_EQ(NO_ERROR, decryptor_.GetMetrics(kDefaultCdmIdentifier, &metrics)); ASSERT_EQ(NO_ERROR, decryptor_->GetMetrics(kDefaultCdmIdentifier, &metrics));
ValidateHasUpdateUsageEntry(metrics); ValidateHasUpdateUsageEntry(metrics);
} }
@@ -1493,8 +1493,8 @@ TEST_P(WvCdmOfflineUsageReportTest, UsageTest) {
Unprovision(); Unprovision();
Provision(); Provision();
decryptor_.OpenSession(config_.key_system(), NULL, kDefaultCdmIdentifier, decryptor_->OpenSession(config_.key_system(), NULL, kDefaultCdmIdentifier,
NULL, &session_id_); NULL, &session_id_);
GenerateKeyRequest(kOfflineClip2PstInitData, kLicenseTypeOffline); GenerateKeyRequest(kOfflineClip2PstInitData, kLicenseTypeOffline);
VerifyKeyRequestResponse(config_.license_server(), config_.client_auth(), VerifyKeyRequestResponse(config_.license_server(), config_.client_auth(),
false); false);
@@ -1509,7 +1509,7 @@ TEST_P(WvCdmOfflineUsageReportTest, UsageTest) {
QueryKeyStatus(false, true, &initial_license_duration_remaining, QueryKeyStatus(false, true, &initial_license_duration_remaining,
&initial_playback_duration_remaining); &initial_playback_duration_remaining);
decryptor_.CloseSession(session_id_); decryptor_->CloseSession(session_id_);
sleep(kMinute); sleep(kMinute);
int64_t expected_seconds_since_license_received = kMinute; int64_t expected_seconds_since_license_received = kMinute;
@@ -1518,9 +1518,9 @@ TEST_P(WvCdmOfflineUsageReportTest, UsageTest) {
for (size_t i = 0; i < GetParam(); ++i) { for (size_t i = 0; i < GetParam(); ++i) {
session_id_.clear(); session_id_.clear();
decryptor_.OpenSession(config_.key_system(), NULL, kDefaultCdmIdentifier, decryptor_->OpenSession(config_.key_system(), NULL, kDefaultCdmIdentifier,
NULL, &session_id_); NULL, &session_id_);
EXPECT_EQ(KEY_ADDED, decryptor_.RestoreKey(session_id_, key_set_id)); EXPECT_EQ(KEY_ADDED, decryptor_->RestoreKey(session_id_, key_set_id));
// Query and validate usage information // Query and validate usage information
int64_t license_duration_remaining = 0; int64_t license_duration_remaining = 0;
@@ -1546,14 +1546,14 @@ TEST_P(WvCdmOfflineUsageReportTest, UsageTest) {
decryption_parameters.is_secure = (data + i)->is_secure; decryption_parameters.is_secure = (data + i)->is_secure;
decryption_parameters.subsample_flags = (data + i)->subsample_flags; decryption_parameters.subsample_flags = (data + i)->subsample_flags;
EXPECT_EQ(NO_ERROR, EXPECT_EQ(NO_ERROR,
decryptor_.Decrypt(session_id_, (data + i)->validate_key_id, decryptor_->Decrypt(session_id_, (data + i)->validate_key_id,
decryption_parameters)); decryption_parameters));
EXPECT_EQ((data + i)->decrypt_data, decrypt_buffer); EXPECT_EQ((data + i)->decrypt_data, decrypt_buffer);
} }
sleep(10); sleep(10);
decryptor_.CloseSession(session_id_); decryptor_->CloseSession(session_id_);
sleep(kMinute - 10); sleep(kMinute - 10);
expected_seconds_since_license_received += kMinute; expected_seconds_since_license_received += kMinute;
@@ -1562,9 +1562,9 @@ TEST_P(WvCdmOfflineUsageReportTest, UsageTest) {
} }
session_id_.clear(); session_id_.clear();
decryptor_.OpenSession(config_.key_system(), NULL, kDefaultCdmIdentifier, decryptor_->OpenSession(config_.key_system(), NULL, kDefaultCdmIdentifier,
NULL, &session_id_); NULL, &session_id_);
EXPECT_EQ(KEY_ADDED, decryptor_.RestoreKey(session_id_, key_set_id)); EXPECT_EQ(KEY_ADDED, decryptor_->RestoreKey(session_id_, key_set_id));
// Query and validate usage information // Query and validate usage information
int64_t license_duration_remaining = 0; int64_t license_duration_remaining = 0;
@@ -1577,7 +1577,7 @@ TEST_P(WvCdmOfflineUsageReportTest, UsageTest) {
EXPECT_NEAR(initial_playback_duration_remaining - playback_duration_remaining, EXPECT_NEAR(initial_playback_duration_remaining - playback_duration_remaining,
expected_seconds_since_initial_playback, kClockTolerance); expected_seconds_since_initial_playback, kClockTolerance);
decryptor_.CloseSession(session_id_); decryptor_->CloseSession(session_id_);
session_id_.clear(); session_id_.clear();
key_set_id_.clear(); key_set_id_.clear();
@@ -1612,22 +1612,23 @@ TEST_F(WvCdmExtendedDurationTest, MaxUsageEntryOfflineRecoveryTest) {
// licenses will be deleted internally to make space and we will // licenses will be deleted internally to make space and we will
// not encounter an error. // not encounter an error.
for (size_t i = 0; i < 2000; ++i) { for (size_t i = 0; i < 2000; ++i) {
decryptor_.OpenSession(config_.key_system(), NULL, kDefaultCdmIdentifier, decryptor_->OpenSession(config_.key_system(), NULL, kDefaultCdmIdentifier,
NULL, &session_id_); NULL, &session_id_);
GenerateKeyRequest(kOfflineClip2PstInitData, kLicenseTypeOffline); GenerateKeyRequest(kOfflineClip2PstInitData, kLicenseTypeOffline);
VerifyKeyRequestResponse(config_.license_server(), client_auth, false); VerifyKeyRequestResponse(config_.license_server(), client_auth, false);
key_set_ids.push_back(key_set_id_); key_set_ids.push_back(key_set_id_);
decryptor_.CloseSession(session_id_); decryptor_->CloseSession(session_id_);
} }
uint32_t number_of_valid_offline_sessions = 0; uint32_t number_of_valid_offline_sessions = 0;
for (size_t i = 0; i < key_set_ids.size(); ++i) { for (size_t i = 0; i < key_set_ids.size(); ++i) {
session_id_.clear(); session_id_.clear();
decryptor_.OpenSession(config_.key_system(), NULL, kDefaultCdmIdentifier, decryptor_->OpenSession(config_.key_system(), NULL, kDefaultCdmIdentifier,
NULL, &session_id_); NULL, &session_id_);
CdmResponseType result = decryptor_.RestoreKey(session_id_, key_set_ids[i]); CdmResponseType result = decryptor_->RestoreKey(session_id_,
key_set_ids[i]);
if (result == KEY_ADDED) { if (result == KEY_ADDED) {
++number_of_valid_offline_sessions; ++number_of_valid_offline_sessions;
@@ -1643,19 +1644,19 @@ TEST_F(WvCdmExtendedDurationTest, MaxUsageEntryOfflineRecoveryTest) {
decryption_parameters.is_secure = data->is_secure; decryption_parameters.is_secure = data->is_secure;
decryption_parameters.subsample_flags = data->subsample_flags; decryption_parameters.subsample_flags = data->subsample_flags;
EXPECT_EQ(NO_ERROR, EXPECT_EQ(NO_ERROR,
decryptor_.Decrypt(session_id_, data->validate_key_id, decryptor_->Decrypt(session_id_, data->validate_key_id,
decryption_parameters)); decryption_parameters));
EXPECT_EQ(data->decrypt_data, decrypt_buffer); EXPECT_EQ(data->decrypt_data, decrypt_buffer);
decryptor_.CloseSession(session_id_); decryptor_->CloseSession(session_id_);
// Release the license // Release the license
GenerateKeyRelease(key_set_ids[i]); GenerateKeyRelease(key_set_ids[i]);
key_set_id_ = key_set_ids[i]; key_set_id_ = key_set_ids[i];
VerifyKeyRequestResponse(config_.license_server(), client_auth, false); VerifyKeyRequestResponse(config_.license_server(), client_auth, false);
} else { } else {
decryptor_.CloseSession(session_id_); decryptor_->CloseSession(session_id_);
} }
} }

View File

@@ -1623,8 +1623,9 @@ class TestWvCdmEventListener : public WvCdmEventListener {
class DecryptCallbackTester { class DecryptCallbackTester {
public: public:
DecryptCallbackTester(android::sp<wvcdm::WvContentDecryptionModule> decryptor, DecryptCallbackTester(
SubSampleInfo* sub_sample_info) const android::sp<wvcdm::WvContentDecryptionModule>& decryptor,
SubSampleInfo* sub_sample_info)
: decryptor_(decryptor), : decryptor_(decryptor),
sub_sample_info_(sub_sample_info) {} sub_sample_info_(sub_sample_info) {}