Create unique cdm engines per WVDrmPlugin instance

This change creates a unique id in the cdm identifier in order to force
a one-to-one mapping between WVDrmPlugin instances and CDM Engines. This
change simplifies some assumptions. This includes ensuring that the
metrics for a given MediaDrm instance map to a given CdmEngine instance.

This change contains the original change go/ag/3819203 and a fix to the
deadlock that was seen on Marlin and Taimen.

Bug: 73724453
Test: Updated unit tests. GTS test pass. Shaka Player, Netflix and Google Play test.
Change-Id: Ib208204a1b794df9f306fa11d13a8bb6cd6889f7
This commit is contained in:
Adam Stone
2018-03-29 12:28:57 -07:00
parent 1a25cbdad6
commit 5c71603e8c
11 changed files with 354 additions and 207 deletions

View File

@@ -26,7 +26,8 @@ Lock WvContentDecryptionModule::session_sharing_id_generation_lock_;
WvContentDecryptionModule::WvContentDecryptionModule() {}
WvContentDecryptionModule::~WvContentDecryptionModule() {
ForceDisablePolicyTimer();
CloseAllCdms();
DisablePolicyTimer();
}
bool WvContentDecryptionModule::IsSupported(const std::string& init_data_type) {
@@ -77,8 +78,6 @@ CdmResponseType WvContentDecryptionModule::CloseSession(
cdm_by_session_id_.erase(session_id);
}
DisablePolicyTimer();
return sts;
}
@@ -336,12 +335,21 @@ bool WvContentDecryptionModule::IsValidServiceCertificate(
return cert.has_certificate();
}
void WvContentDecryptionModule::GetSerializedMetrics(
std::string* serialized_metrics) {
CdmResponseType WvContentDecryptionModule::GetMetrics(
const CdmIdentifier& identifier, drm_metrics::WvCdmMetrics* metrics) {
if (!metrics) {
return PARAMETER_NULL;
}
AutoLock auto_lock(cdms_lock_);
CloseCdmsWithoutSessions();
metrics_group_.SerializeToString(serialized_metrics);
metrics_group_.Clear();
auto it = cdms_.find(identifier);
if (it == cdms_.end()) {
LOGE("WVContentDecryptionModule::GetMetrics. cdm_identifier not found");
// TODO(blueeyes): Add a better error.
return UNKNOWN_ERROR;
}
it->second.cdm_engine->GetMetrics()->Serialize(metrics);
return NO_ERROR;
}
WvContentDecryptionModule::CdmInfo::CdmInfo()
@@ -377,32 +385,45 @@ CdmEngine* WvContentDecryptionModule::GetCdmForSessionId(
return it->second;
}
// This method requires that the caller first acquire cdms_lock_.
void WvContentDecryptionModule::CloseCdmsWithoutSessions() {
for (auto it = cdms_.begin(); it != cdms_.end();) {
if (it->second.cdm_engine->SessionSize() != 0) {
++it;
} else {
// Retrieve the metrics from the engine and any completed
// sessions. Clear the metrics from any completed sessions.
metrics::EngineMetrics* engine_metrics =
it->second.cdm_engine->GetMetrics();
// engine_metrics should never be null.
if (engine_metrics != NULL) {
engine_metrics->Serialize(metrics_group_.add_metrics());
} else {
// Engine metrics should never be null.
LOGI(
"WvContentDecryptionModule::CloseCdmsWithoutSessions."
"engine_metrics was unexpectedly NULL.");
}
void WvContentDecryptionModule::CloseAllCdms() {
AutoLock auto_lock(cdms_lock_);
// The CDM is no longer used for this identifier, delete it.
it = cdms_.erase(it);
}
for (auto it = cdms_.begin(); it != cdms_.end();) {
it = cdms_.erase(it);
}
}
CdmResponseType WvContentDecryptionModule::CloseCdm(
const CdmIdentifier& cdm_identifier) {
// The policy timer ultimately calls OnTimerEvent (which wants to
// acquire cdms_lock_). Therefore, we cannot acquire cdms_lock_ and then the
// policy_timer_lock_ (via DisablePolicyTimer) at the same time.
// Acquire the cdms_lock_ first, in its own scope.
bool cdms_empty = false;
{
AutoLock auto_lock(cdms_lock_);
auto it = cdms_.find(cdm_identifier);
if (it == cdms_.end()) {
LOGE("WVContentDecryptionModule::Close. cdm_identifier not found.");
// TODO(blueeyes): Create a better error.
return UNKNOWN_ERROR;
}
// Remove any sessions that point to this engine.
for (auto session_it : cdm_by_session_id_) {
if (session_it.second == it->second.cdm_engine.get()) {
cdm_by_session_id_.erase(session_it.first);
}
}
cdms_.erase(it);
cdms_empty = cdms_.empty();
}
if (cdms_empty) {
DisablePolicyTimer();
}
return NO_ERROR;
}
void WvContentDecryptionModule::EnablePolicyTimer() {
AutoLock auto_lock(policy_timer_lock_);
if (!policy_timer_.IsRunning())
@@ -410,27 +431,6 @@ void WvContentDecryptionModule::EnablePolicyTimer() {
}
void WvContentDecryptionModule::DisablePolicyTimer() {
bool cdms_is_empty = false;
{
AutoLock auto_lock(cdms_lock_);
CloseCdmsWithoutSessions();
cdms_is_empty = cdms_.empty();
}
AutoLock auto_lock(policy_timer_lock_);
if (cdms_is_empty) {
if (policy_timer_.IsRunning()) {
policy_timer_.Stop();
}
}
}
void WvContentDecryptionModule::ForceDisablePolicyTimer() {
{
AutoLock auto_lock(cdms_lock_);
CloseCdmsWithoutSessions();
}
AutoLock auto_lock(policy_timer_lock_);
if (policy_timer_.IsRunning()) {
policy_timer_.Stop();