Merge changes I30a3ede3,I6008ddba,I869c22a2 into pi-dev

* changes:
  Protect sessions from concurrent access.
  Address concurrency failures between calls to decrypt and periodic timer
  Revert of "Prevent race conditions between decrypt and close session"
This commit is contained in:
Rahul Frias
2018-05-15 23:21:04 +00:00
committed by Android (Google) Code Review
11 changed files with 48 additions and 31 deletions

View File

@@ -330,6 +330,17 @@ class CdmEngine {
// Protect release_key_sets_ from non-thread-safe operations. // Protect release_key_sets_ from non-thread-safe operations.
Lock release_key_sets_lock_; Lock release_key_sets_lock_;
// TODO(rfrias): Replace with two sets of locks, one to protect
// the CdmSessionMap and a per-session lock to control access to
// session usage/destruction.
// Locks the session map |session_map_| and session usage/destruction
// between session management calls (OpenSession, CloseSession, etc),
// periodic timer calls (OnTimerEvent), and calls to Decrypt.
// The layer above the CDM implementation is expected to handle thread
// synchronization to make sure other functions that access sessions do not
// occur simultaneously with OpenSession or CloseSession.
Lock session_map_lock_;
CORE_DISALLOW_COPY_AND_ASSIGN(CdmEngine); CORE_DISALLOW_COPY_AND_ASSIGN(CdmEngine);
}; };

View File

@@ -37,7 +37,7 @@ class CdmSession {
CdmSession(FileSystem* file_system, metrics::SessionMetrics* metrics); CdmSession(FileSystem* file_system, metrics::SessionMetrics* metrics);
virtual ~CdmSession(); virtual ~CdmSession();
void Close(); void Close() { closed_ = true; }
bool IsClosed() { return closed_; } bool IsClosed() { return closed_; }
// Initializes this instance of CdmSession with the given property set. // Initializes this instance of CdmSession with the given property set.
@@ -263,9 +263,6 @@ class CdmSession {
bool mock_license_parser_in_use_; bool mock_license_parser_in_use_;
bool mock_policy_engine_in_use_; bool mock_policy_engine_in_use_;
// Lock to avoid race conditions between Close() and Decrypt()
Lock close_lock_;
CORE_DISALLOW_COPY_AND_ASSIGN(CdmSession); CORE_DISALLOW_COPY_AND_ASSIGN(CdmSession);
}; };

View File

@@ -10,7 +10,6 @@
#include <string> #include <string>
#include "cdm_session.h" #include "cdm_session.h"
#include "lock.h"
#include "shared_ptr.h" #include "shared_ptr.h"
#include "wv_cdm_types.h" #include "wv_cdm_types.h"
@@ -18,11 +17,18 @@ namespace wvcdm {
typedef std::list<shared_ptr<CdmSession> > CdmSessionList; typedef std::list<shared_ptr<CdmSession> > CdmSessionList;
// TODO(rfrias): Concurrency protection for this class has moved to CdmEngine.
// Add it back when locks to control access to session usage and destruction
// are introduced.
class CdmSessionMap { class CdmSessionMap {
public: public:
CdmSessionMap() {} CdmSessionMap() {}
virtual ~CdmSessionMap(); virtual ~CdmSessionMap();
// Use |Terminate| rather than relying on the destructor to release
// resources, as it can be protected by locks.
void Terminate();
void Add(const std::string& id, CdmSession* session); void Add(const std::string& id, CdmSession* session);
bool CloseSession(const std::string& id); bool CloseSession(const std::string& id);
@@ -43,7 +49,6 @@ class CdmSessionMap {
bool FindSessionNoLock(const CdmSessionId& session_id, bool FindSessionNoLock(const CdmSessionId& session_id,
shared_ptr<CdmSession>* session); shared_ptr<CdmSession>* session);
Lock lock_;
CdmIdToSessionMap sessions_; CdmIdToSessionMap sessions_;
CORE_DISALLOW_COPY_AND_ASSIGN(CdmSessionMap); CORE_DISALLOW_COPY_AND_ASSIGN(CdmSessionMap);

View File

@@ -12,9 +12,17 @@
#include <stddef.h> #include <stddef.h>
#include <memory> #include <memory>
#include "lock.h"
#include "wv_cdm_types.h" #include "wv_cdm_types.h"
namespace wvcdm {
extern Lock shared_ptr_ref_count_lock_;
} // namespace wvcdm
namespace { namespace {
bool Barrier_AtomicIncrement(volatile uint32_t* ptr, uint32_t value) { bool Barrier_AtomicIncrement(volatile uint32_t* ptr, uint32_t value) {
*ptr += value; *ptr += value;
return *ptr; return *ptr;
@@ -25,10 +33,12 @@ bool NoBarrier_AtomicIncrement(volatile uint32_t* ptr, uint32_t value) {
} }
inline bool RefCountDec(volatile uint32_t *ptr) { inline bool RefCountDec(volatile uint32_t *ptr) {
wvcdm::AutoLock auto_lock(wvcdm::shared_ptr_ref_count_lock_);
return Barrier_AtomicIncrement(ptr, -1) != 0; return Barrier_AtomicIncrement(ptr, -1) != 0;
} }
inline void RefCountInc(volatile uint32_t *ptr) { inline void RefCountInc(volatile uint32_t *ptr) {
wvcdm::AutoLock auto_lock(wvcdm::shared_ptr_ref_count_lock_);
NoBarrier_AtomicIncrement(ptr, 1); NoBarrier_AtomicIncrement(ptr, 1);
} }

View File

@@ -333,7 +333,6 @@ enum CdmResponseType {
GET_PROVISIONING_METHOD_ERROR = 289, GET_PROVISIONING_METHOD_ERROR = 289,
SESSION_NOT_FOUND_17 = 290, SESSION_NOT_FOUND_17 = 290,
SESSION_NOT_FOUND_18 = 291, SESSION_NOT_FOUND_18 = 291,
SESSION_CLOSED_1 = 292,
}; };
enum CdmKeyStatus { enum CdmKeyStatus {

View File

@@ -30,6 +30,8 @@ const size_t kUsageReportsPerRequest = 1;
namespace wvcdm { namespace wvcdm {
Lock shared_ptr_ref_count_lock_;
class UsagePropertySet : public CdmClientPropertySet { class UsagePropertySet : public CdmClientPropertySet {
public: public:
UsagePropertySet() {} UsagePropertySet() {}
@@ -83,7 +85,10 @@ CdmEngine::CdmEngine(FileSystem* file_system, const std::string& spoid)
} }
} }
CdmEngine::~CdmEngine() {} CdmEngine::~CdmEngine() {
AutoLock lock(session_map_lock_);
session_map_.Terminate();
}
CdmResponseType CdmEngine::OpenSession( CdmResponseType CdmEngine::OpenSession(
const CdmKeySystem& key_system, CdmClientPropertySet* property_set, const CdmKeySystem& key_system, CdmClientPropertySet* property_set,
@@ -141,6 +146,7 @@ CdmResponseType CdmEngine::OpenSession(
CdmSessionId id = new_session->session_id(); CdmSessionId id = new_session->session_id();
LOGI("CdmEngine::OpenSession: %s", id.c_str()); LOGI("CdmEngine::OpenSession: %s", id.c_str());
AutoLock lock(session_map_lock_);
session_map_.Add(id, new_session.release()); session_map_.Add(id, new_session.release());
if (session_id) *session_id = id; if (session_id) *session_id = id;
return NO_ERROR; return NO_ERROR;
@@ -182,6 +188,7 @@ CdmResponseType CdmEngine::OpenKeySetSession(
CdmResponseType CdmEngine::CloseSession(const CdmSessionId& session_id) { CdmResponseType CdmEngine::CloseSession(const CdmSessionId& session_id) {
LOGI("CdmEngine::CloseSession: %s", session_id.c_str()); LOGI("CdmEngine::CloseSession: %s", session_id.c_str());
AutoLock lock(session_map_lock_);
if (!session_map_.CloseSession(session_id)) { if (!session_map_.CloseSession(session_id)) {
LOGE("CdmEngine::CloseSession: session not found = %s", session_id.c_str()); LOGE("CdmEngine::CloseSession: session not found = %s", session_id.c_str());
return SESSION_NOT_FOUND_1; return SESSION_NOT_FOUND_1;
@@ -215,6 +222,7 @@ CdmResponseType CdmEngine::CloseKeySetSession(const CdmKeySetId& key_set_id) {
} }
bool CdmEngine::IsOpenSession(const CdmSessionId& session_id) { bool CdmEngine::IsOpenSession(const CdmSessionId& session_id) {
AutoLock lock(session_map_lock_);
return session_map_.Exists(session_id); return session_map_.Exists(session_id);
} }
@@ -1470,6 +1478,7 @@ CdmResponseType CdmEngine::Decrypt(const CdmSessionId& session_id,
// else we must be level 1 direct and we don't need to return a buffer. // else we must be level 1 direct and we don't need to return a buffer.
} }
AutoLock lock(session_map_lock_);
shared_ptr<CdmSession> session; shared_ptr<CdmSession> session;
if (session_id.empty()) { if (session_id.empty()) {
CdmSessionList sessions; CdmSessionList sessions;
@@ -1590,6 +1599,7 @@ bool CdmEngine::FindSessionForKey(const KeyId& key_id,
uint32_t session_sharing_id = Properties::GetSessionSharingId(*session_id); uint32_t session_sharing_id = Properties::GetSessionSharingId(*session_id);
AutoLock lock(session_map_lock_);
CdmSessionList sessions; CdmSessionList sessions;
session_map_.GetSessionList(sessions); session_map_.GetSessionList(sessions);
@@ -1635,9 +1645,6 @@ void CdmEngine::OnTimerEvent() {
Clock clock; Clock clock;
uint64_t current_time = clock.GetCurrentTime(); uint64_t current_time = clock.GetCurrentTime();
CdmSessionList sessions;
session_map_.GetSessionList(sessions);
bool usage_update_period_expired = false; bool usage_update_period_expired = false;
if (current_time - last_usage_information_update_time_ > if (current_time - last_usage_information_update_time_ >
kUpdateUsageInformationPeriod) { kUpdateUsageInformationPeriod) {
@@ -1648,6 +1655,10 @@ void CdmEngine::OnTimerEvent() {
bool is_initial_usage_update = false; bool is_initial_usage_update = false;
bool is_usage_update_needed = false; bool is_usage_update_needed = false;
AutoLock lock(session_map_lock_);
CdmSessionList sessions;
session_map_.GetSessionList(sessions);
while (!sessions.empty()) { while (!sessions.empty()) {
is_initial_usage_update = is_initial_usage_update =
is_initial_usage_update || sessions.front()->is_initial_usage_update(); is_initial_usage_update || sessions.front()->is_initial_usage_update();

View File

@@ -72,11 +72,6 @@ CdmSession::~CdmSession() {
} }
} }
void CdmSession::Close() {
AutoLock lock(close_lock_);
closed_ = true;
}
CdmResponseType CdmSession::Init( CdmResponseType CdmSession::Init(
CdmClientPropertySet* cdm_client_property_set) { CdmClientPropertySet* cdm_client_property_set) {
return Init(cdm_client_property_set, NULL, NULL); return Init(cdm_client_property_set, NULL, NULL);
@@ -581,11 +576,6 @@ CdmResponseType CdmSession::Decrypt(const CdmDecryptionParameters& params) {
return NOT_INITIALIZED_ERROR; return NOT_INITIALIZED_ERROR;
} }
AutoLock lock(close_lock_);
if (IsClosed()) {
return SESSION_CLOSED_1;
}
// Playback may not begin until either the start time passes or the license // Playback may not begin until either the start time passes or the license
// is updated, so we treat this Decrypt call as invalid. // is updated, so we treat this Decrypt call as invalid.
if (params.is_encrypted) { if (params.is_encrypted) {

View File

@@ -12,7 +12,10 @@
namespace wvcdm { namespace wvcdm {
CdmSessionMap::~CdmSessionMap() { CdmSessionMap::~CdmSessionMap() {
AutoLock lock(lock_); Terminate();
}
void CdmSessionMap::Terminate() {
for (CdmIdToSessionMap::iterator i = sessions_.begin(); for (CdmIdToSessionMap::iterator i = sessions_.begin();
i != sessions_.end(); ++i) { i != sessions_.end(); ++i) {
i->second->Close(); i->second->Close();
@@ -22,12 +25,10 @@ CdmSessionMap::~CdmSessionMap() {
} }
void CdmSessionMap::Add(const std::string& id, CdmSession* session) { void CdmSessionMap::Add(const std::string& id, CdmSession* session) {
AutoLock lock(lock_);
sessions_[id].reset(session); sessions_[id].reset(session);
} }
bool CdmSessionMap::CloseSession(const std::string& id) { bool CdmSessionMap::CloseSession(const std::string& id) {
AutoLock lock(lock_);
shared_ptr<CdmSession> session; shared_ptr<CdmSession> session;
if (!FindSessionNoLock(id, &session)) { if (!FindSessionNoLock(id, &session)) {
return false; return false;
@@ -38,13 +39,11 @@ bool CdmSessionMap::CloseSession(const std::string& id) {
} }
bool CdmSessionMap::Exists(const std::string& id) { bool CdmSessionMap::Exists(const std::string& id) {
AutoLock lock(lock_);
return sessions_.find(id) != sessions_.end(); return sessions_.find(id) != sessions_.end();
} }
bool CdmSessionMap::FindSession(const CdmSessionId& id, bool CdmSessionMap::FindSession(const CdmSessionId& id,
shared_ptr<CdmSession>* session) { shared_ptr<CdmSession>* session) {
AutoLock lock(lock_);
return FindSessionNoLock(id, session); return FindSessionNoLock(id, session);
} }
@@ -61,7 +60,6 @@ bool CdmSessionMap::FindSessionNoLock(const CdmSessionId& session_id,
void CdmSessionMap::GetSessionList(CdmSessionList& sessions) { void CdmSessionMap::GetSessionList(CdmSessionList& sessions) {
sessions.clear(); sessions.clear();
AutoLock lock(lock_);
for (CdmIdToSessionMap::iterator iter = sessions_.begin(); for (CdmIdToSessionMap::iterator iter = sessions_.begin();
iter != sessions_.end(); ++iter) { iter != sessions_.end(); ++iter) {
if (!(iter->second)->IsClosed()) { if (!(iter->second)->IsClosed()) {

View File

@@ -599,8 +599,6 @@ void PrintTo(const enum CdmResponseType& value, ::std::ostream* os) {
break; break;
case SESSION_NOT_FOUND_18: *os << "SESSION_NOT_FOUND_18"; case SESSION_NOT_FOUND_18: *os << "SESSION_NOT_FOUND_18";
break; break;
case SESSION_CLOSED_1: *os << "SESSION_CLOSED_1";
break;
default: default:
*os << "Unknown CdmResponseType"; *os << "Unknown CdmResponseType";
break; break;

View File

@@ -230,7 +230,6 @@ static android::status_t mapCdmResponseType(wvcdm::CdmResponseType res) {
case wvcdm::SESSION_NOT_FOUND_10: case wvcdm::SESSION_NOT_FOUND_10:
case wvcdm::SESSION_NOT_FOUND_17: case wvcdm::SESSION_NOT_FOUND_17:
case wvcdm::SESSION_NOT_FOUND_18: case wvcdm::SESSION_NOT_FOUND_18:
case wvcdm::SESSION_CLOSED_1:
return android::ERROR_DRM_SESSION_NOT_OPENED; return android::ERROR_DRM_SESSION_NOT_OPENED;
case wvcdm::SESSION_KEYS_NOT_FOUND: case wvcdm::SESSION_KEYS_NOT_FOUND:
return kSessionKeysNotFound; return kSessionKeysNotFound;

View File

@@ -58,7 +58,6 @@ static Status mapCdmResponseType(wvcdm::CdmResponseType res) {
case wvcdm::SESSION_NOT_FOUND_10: case wvcdm::SESSION_NOT_FOUND_10:
case wvcdm::SESSION_NOT_FOUND_17: case wvcdm::SESSION_NOT_FOUND_17:
case wvcdm::SESSION_NOT_FOUND_18: case wvcdm::SESSION_NOT_FOUND_18:
case wvcdm::SESSION_CLOSED_1:
return Status::ERROR_DRM_SESSION_NOT_OPENED; return Status::ERROR_DRM_SESSION_NOT_OPENED;
case wvcdm::DECRYPT_ERROR: case wvcdm::DECRYPT_ERROR: