Added write protection for session to engine map. am: b6cdd12394 am: b7aa89024e
Original change: https://googleplex-android-review.googlesource.com/c/platform/vendor/widevine/+/15180882 Change-Id: I02aa84ef497a1ac8fb6ae4b04aec85133819ccd5
This commit is contained in:
@@ -215,6 +215,14 @@ class WvContentDecryptionModule : public android::RefBase, public TimerHandler {
|
||||
void DisableTimerAndWaitForExit();
|
||||
void OnTimerEvent();
|
||||
|
||||
// Fill the |metrics| parameter with the metrics data for the CdmEngine
|
||||
// associated with the given |identifier|. If the CdmEngine instance does
|
||||
// not exist, this will return an error.
|
||||
// This methods assumes that |metrics| is not null and that the |cdms_lock_|
|
||||
// has already been acquired.
|
||||
CdmResponseType GetMetricsInternal(const CdmIdentifier& identifier,
|
||||
drm_metrics::WvCdmMetrics* metrics);
|
||||
|
||||
static std::mutex session_sharing_id_generation_lock_;
|
||||
std::mutex timer_lock_;
|
||||
Timer timer_;
|
||||
@@ -222,14 +230,27 @@ class WvContentDecryptionModule : public android::RefBase, public TimerHandler {
|
||||
// instance variables
|
||||
// This manages the lifetime of the CDM instances.
|
||||
std::map<CdmIdentifier, CdmInfo> cdms_;
|
||||
std::mutex cdms_lock_;
|
||||
|
||||
// This contains weak pointers to the CDM instances contained in |cdms_|.
|
||||
std::map<std::string, CdmEngine*> cdm_by_session_id_;
|
||||
// Lock for accessing either |cdms_| or |cdm_by_session_id_|.
|
||||
// This lock should be acquired for any of the following:
|
||||
// 1) Getting a CDM instance from |cdms_| or |cdm_by_session_id_|
|
||||
// - Hold lock while searching, release lock once pointer is acquired
|
||||
// 2) Iterating over |cdms_| or |cdm_by_session_id_|
|
||||
// - Hold lock for the entire duration of iterating over CDMs
|
||||
// - DO NOT release the lock until all operations are complete
|
||||
// - This MUST be done regardless of whether |cdms_| or
|
||||
// |cdm_by_session_id_| is being modified
|
||||
// 3) Creating a new CDM instance with |cdms_|
|
||||
// - Hold lock when creating AND initializing the CDM
|
||||
// - Release once CDM is fully initialized
|
||||
// 4) Linking a session to a CDM with |cdm_by_session_id_|
|
||||
// - Hold lock when mapping a session ID to a CDM, release once set
|
||||
// 5) Unlinking a session from a CDM with |cdm_by_session_id_|
|
||||
// - Hold lock when erasing, release once erased.
|
||||
std::mutex cdms_lock_;
|
||||
|
||||
CORE_DISALLOW_COPY_AND_ASSIGN(WvContentDecryptionModule);
|
||||
};
|
||||
|
||||
} // namespace wvcdm
|
||||
|
||||
#endif // CDM_BASE_WV_CONTENT_DECRYPTION_MODULE_H_
|
||||
|
||||
@@ -71,6 +71,7 @@ CdmResponseType WvContentDecryptionModule::OpenSession(
|
||||
CdmResponseType sts = cdm_engine->OpenSession(key_system, property_set,
|
||||
event_listener, session_id);
|
||||
if (sts == NO_ERROR) {
|
||||
std::unique_lock<std::mutex> auto_lock(cdms_lock_);
|
||||
cdm_by_session_id_[*session_id] = cdm_engine;
|
||||
}
|
||||
return sts;
|
||||
@@ -82,12 +83,11 @@ CdmResponseType WvContentDecryptionModule::CloseSession(
|
||||
CdmEngine* cdm_engine = GetCdmForSessionId(session_id);
|
||||
// TODO(rfrias): Avoid reusing the error codes from CdmEngine.
|
||||
if (!cdm_engine) return SESSION_NOT_FOUND_1;
|
||||
std::unique_lock<std::mutex> auto_lock(cdms_lock_);
|
||||
CdmResponseType sts = cdm_engine->CloseSession(session_id);
|
||||
const CdmResponseType sts = cdm_engine->CloseSession(session_id);
|
||||
if (sts == NO_ERROR) {
|
||||
std::unique_lock<std::mutex> auto_lock(cdms_lock_);
|
||||
cdm_by_session_id_.erase(session_id);
|
||||
}
|
||||
|
||||
return sts;
|
||||
}
|
||||
|
||||
@@ -107,6 +107,7 @@ CdmResponseType WvContentDecryptionModule::GenerateKeyRequest(
|
||||
if (license_type == kLicenseTypeRelease) {
|
||||
sts = cdm_engine->OpenKeySetSession(key_set_id, property_set, nullptr);
|
||||
if (sts != NO_ERROR) return sts;
|
||||
std::unique_lock<std::mutex> auto_lock(cdms_lock_);
|
||||
cdm_by_session_id_[key_set_id] = cdm_engine;
|
||||
}
|
||||
|
||||
@@ -130,6 +131,7 @@ CdmResponseType WvContentDecryptionModule::GenerateKeyRequest(
|
||||
app_parameters, key_request);
|
||||
if (license_type == kLicenseTypeRelease && sts != KEY_MESSAGE) {
|
||||
cdm_engine->CloseKeySetSession(key_set_id);
|
||||
std::unique_lock<std::mutex> auto_lock(cdms_lock_);
|
||||
cdm_by_session_id_.erase(key_set_id);
|
||||
}
|
||||
return sts;
|
||||
@@ -152,6 +154,7 @@ CdmResponseType WvContentDecryptionModule::AddKey(
|
||||
// Empty session id indicates license type release.
|
||||
if (sts == KEY_ADDED && session_id.empty()) {
|
||||
cdm_engine->CloseKeySetSession(release_key_set_id);
|
||||
std::unique_lock<std::mutex> auto_lock(cdms_lock_);
|
||||
cdm_by_session_id_.erase(release_key_set_id);
|
||||
}
|
||||
return sts;
|
||||
@@ -297,11 +300,11 @@ CdmResponseType WvContentDecryptionModule::GetSecureStopIds(
|
||||
}
|
||||
|
||||
CdmEngine* cdm_engine = EnsureCdmForIdentifier(identifier);
|
||||
CdmResponseType sts =
|
||||
const CdmResponseType sts =
|
||||
cdm_engine->ListUsageIds(app_id, kSecurityLevelL1, nullptr, ssids);
|
||||
std::vector<CdmSecureStopId> secure_stop_ids;
|
||||
CdmResponseType sts_l3 = cdm_engine->ListUsageIds(app_id, kSecurityLevelL3,
|
||||
nullptr, &secure_stop_ids);
|
||||
const CdmResponseType sts_l3 = cdm_engine->ListUsageIds(
|
||||
app_id, kSecurityLevelL3, nullptr, &secure_stop_ids);
|
||||
ssids->insert(ssids->end(), secure_stop_ids.begin(), secure_stop_ids.end());
|
||||
return sts_l3 != NO_ERROR ? sts_l3 : sts;
|
||||
}
|
||||
@@ -383,17 +386,19 @@ CdmResponseType WvContentDecryptionModule::GetMetrics(
|
||||
if (!metrics || !full_list_returned) {
|
||||
return PARAMETER_NULL;
|
||||
}
|
||||
std::unique_lock<std::mutex> auto_lock(cdms_lock_);
|
||||
for (auto& key_value_pair : cdms_) {
|
||||
const CdmIdentifier& identifier = key_value_pair.first;
|
||||
drm_metrics::WvCdmMetrics metric;
|
||||
CdmResponseType status = GetMetrics(key_value_pair.first, &metric);
|
||||
const CdmResponseType status = GetMetricsInternal(identifier, &metric);
|
||||
if (status == NO_ERROR) {
|
||||
metrics->push_back(metric);
|
||||
} else {
|
||||
LOGD("GetMetrics call failed: cdm identifier=%u, error=%d",
|
||||
key_value_pair.first.unique_id, status);
|
||||
identifier.unique_id, status);
|
||||
}
|
||||
}
|
||||
// With no streaming activities, cdms_ size would be zero,
|
||||
// With no streaming activities, |cdms_| size would be zero,
|
||||
// treat it as a non full list in that case.
|
||||
*full_list_returned = !cdms_.empty() && metrics->size() == cdms_.size();
|
||||
|
||||
@@ -410,6 +415,12 @@ CdmResponseType WvContentDecryptionModule::GetMetrics(
|
||||
return PARAMETER_NULL;
|
||||
}
|
||||
std::unique_lock<std::mutex> auto_lock(cdms_lock_);
|
||||
return GetMetricsInternal(identifier, metrics);
|
||||
}
|
||||
|
||||
CdmResponseType WvContentDecryptionModule::GetMetricsInternal(
|
||||
const CdmIdentifier& identifier, drm_metrics::WvCdmMetrics* metrics) {
|
||||
// Note: Caller should lock before calling.
|
||||
auto it = cdms_.find(identifier);
|
||||
if (it == cdms_.end()) {
|
||||
LOGE("Cdm Identifier not found");
|
||||
@@ -454,6 +465,7 @@ CdmEngine* WvContentDecryptionModule::EnsureCdmForIdentifier(
|
||||
|
||||
CdmEngine* WvContentDecryptionModule::GetCdmForSessionId(
|
||||
const std::string& session_id) {
|
||||
std::unique_lock<std::mutex> auto_lock(cdms_lock_);
|
||||
// Use find to avoid creating empty entries when not found.
|
||||
auto it = cdm_by_session_id_.find(session_id);
|
||||
if (it == cdm_by_session_id_.end()) return nullptr;
|
||||
@@ -462,10 +474,8 @@ CdmEngine* WvContentDecryptionModule::GetCdmForSessionId(
|
||||
|
||||
void WvContentDecryptionModule::CloseAllCdms() {
|
||||
std::unique_lock<std::mutex> auto_lock(cdms_lock_);
|
||||
|
||||
for (auto it = cdms_.begin(); it != cdms_.end();) {
|
||||
it = cdms_.erase(it);
|
||||
}
|
||||
cdm_by_session_id_.clear();
|
||||
cdms_.clear();
|
||||
}
|
||||
|
||||
CdmResponseType WvContentDecryptionModule::CloseCdm(
|
||||
|
||||
Reference in New Issue
Block a user