Fix deadlock when pending key release sessions are deallocated

[ Merge from http://go/wvgerrit/27261/ ]

Sessions created to release keys are periodically cleaned up if the
key release operation does not complete within a specific
amount of time. If other sessions are open, they will be released
through the timer thread. This would result in deadlock as a mutex
was taken twice.

Test: Verified by cdm_extended_duration_test
(AutomatedOfflineSessionReleaseOnOpenSession and
AutomatedOfflineSessionReleaseOnTimerEvent tests)

b/37546078

Change-Id: I7d45f939bdce77e5db461a401364da4f42c1c034
This commit is contained in:
Rahul Frias
2017-05-11 20:12:33 -07:00
parent ee283ec61c
commit 02fe2ef693
2 changed files with 164 additions and 26 deletions

View File

@@ -1443,35 +1443,37 @@ void CdmEngine::OnTimerEvent() {
bool is_initial_usage_update = false;
bool is_usage_update_needed = false;
AutoLock lock(session_list_lock_);
for (CdmSessionMap::iterator iter = sessions_.begin();
iter != sessions_.end(); ++iter) {
is_initial_usage_update =
is_initial_usage_update || iter->second->is_initial_usage_update();
is_usage_update_needed =
is_usage_update_needed || iter->second->is_usage_update_needed();
iter->second->OnTimerEvent(usage_update_period_expired);
}
if (is_usage_update_needed &&
(usage_update_period_expired || is_initial_usage_update)) {
bool has_usage_been_updated = false;
{
AutoLock lock(session_list_lock_);
for (CdmSessionMap::iterator iter = sessions_.begin();
iter != sessions_.end(); ++iter) {
iter->second->reset_usage_flags();
if (iter->second->get_usage_support_type() == kUsageEntrySupport)
iter->second->UpdateUsageEntryInformation();
is_initial_usage_update =
is_initial_usage_update || iter->second->is_initial_usage_update();
is_usage_update_needed =
is_usage_update_needed || iter->second->is_usage_update_needed();
if (!has_usage_been_updated) {
// usage is updated for all sessions so this needs to be
// called only once per update usage information period
if (iter->second->get_usage_support_type() == kUsageTableSupport) {
CdmResponseType status = iter->second->UpdateUsageTableInformation();
if (NO_ERROR != status) {
LOGW("Update usage information failed: %d", status);
} else {
has_usage_been_updated = true;
iter->second->OnTimerEvent(usage_update_period_expired);
}
if (is_usage_update_needed &&
(usage_update_period_expired || is_initial_usage_update)) {
bool has_usage_been_updated = false;
for (CdmSessionMap::iterator iter = sessions_.begin();
iter != sessions_.end(); ++iter) {
iter->second->reset_usage_flags();
if (iter->second->get_usage_support_type() == kUsageEntrySupport)
iter->second->UpdateUsageEntryInformation();
if (!has_usage_been_updated) {
// usage is updated for all sessions so this needs to be
// called only once per update usage information period
if (iter->second->get_usage_support_type() == kUsageTableSupport) {
CdmResponseType status = iter->second->UpdateUsageTableInformation();
if (NO_ERROR != status) {
LOGW("Update usage information failed: %d", status);
} else {
has_usage_been_updated = true;
}
}
}
}