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 DisableTimerAndWaitForExit();
|
||||||
void OnTimerEvent();
|
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_;
|
static std::mutex session_sharing_id_generation_lock_;
|
||||||
std::mutex timer_lock_;
|
std::mutex timer_lock_;
|
||||||
Timer timer_;
|
Timer timer_;
|
||||||
@@ -222,14 +230,27 @@ class WvContentDecryptionModule : public android::RefBase, public TimerHandler {
|
|||||||
// instance variables
|
// instance variables
|
||||||
// This manages the lifetime of the CDM instances.
|
// This manages the lifetime of the CDM instances.
|
||||||
std::map<CdmIdentifier, CdmInfo> cdms_;
|
std::map<CdmIdentifier, CdmInfo> cdms_;
|
||||||
std::mutex cdms_lock_;
|
|
||||||
|
|
||||||
// This contains weak pointers to the CDM instances contained in |cdms_|.
|
// This contains weak pointers to the CDM instances contained in |cdms_|.
|
||||||
std::map<std::string, CdmEngine*> cdm_by_session_id_;
|
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);
|
CORE_DISALLOW_COPY_AND_ASSIGN(WvContentDecryptionModule);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace wvcdm
|
} // namespace wvcdm
|
||||||
|
|
||||||
#endif // CDM_BASE_WV_CONTENT_DECRYPTION_MODULE_H_
|
#endif // CDM_BASE_WV_CONTENT_DECRYPTION_MODULE_H_
|
||||||
|
|||||||
@@ -71,6 +71,7 @@ CdmResponseType WvContentDecryptionModule::OpenSession(
|
|||||||
CdmResponseType sts = cdm_engine->OpenSession(key_system, property_set,
|
CdmResponseType sts = cdm_engine->OpenSession(key_system, property_set,
|
||||||
event_listener, session_id);
|
event_listener, session_id);
|
||||||
if (sts == NO_ERROR) {
|
if (sts == NO_ERROR) {
|
||||||
|
std::unique_lock<std::mutex> auto_lock(cdms_lock_);
|
||||||
cdm_by_session_id_[*session_id] = cdm_engine;
|
cdm_by_session_id_[*session_id] = cdm_engine;
|
||||||
}
|
}
|
||||||
return sts;
|
return sts;
|
||||||
@@ -82,12 +83,11 @@ CdmResponseType WvContentDecryptionModule::CloseSession(
|
|||||||
CdmEngine* cdm_engine = GetCdmForSessionId(session_id);
|
CdmEngine* cdm_engine = GetCdmForSessionId(session_id);
|
||||||
// TODO(rfrias): Avoid reusing the error codes from CdmEngine.
|
// TODO(rfrias): Avoid reusing the error codes from CdmEngine.
|
||||||
if (!cdm_engine) return SESSION_NOT_FOUND_1;
|
if (!cdm_engine) return SESSION_NOT_FOUND_1;
|
||||||
std::unique_lock<std::mutex> auto_lock(cdms_lock_);
|
const CdmResponseType sts = cdm_engine->CloseSession(session_id);
|
||||||
CdmResponseType sts = cdm_engine->CloseSession(session_id);
|
|
||||||
if (sts == NO_ERROR) {
|
if (sts == NO_ERROR) {
|
||||||
|
std::unique_lock<std::mutex> auto_lock(cdms_lock_);
|
||||||
cdm_by_session_id_.erase(session_id);
|
cdm_by_session_id_.erase(session_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
return sts;
|
return sts;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -107,6 +107,7 @@ CdmResponseType WvContentDecryptionModule::GenerateKeyRequest(
|
|||||||
if (license_type == kLicenseTypeRelease) {
|
if (license_type == kLicenseTypeRelease) {
|
||||||
sts = cdm_engine->OpenKeySetSession(key_set_id, property_set, nullptr);
|
sts = cdm_engine->OpenKeySetSession(key_set_id, property_set, nullptr);
|
||||||
if (sts != NO_ERROR) return sts;
|
if (sts != NO_ERROR) return sts;
|
||||||
|
std::unique_lock<std::mutex> auto_lock(cdms_lock_);
|
||||||
cdm_by_session_id_[key_set_id] = cdm_engine;
|
cdm_by_session_id_[key_set_id] = cdm_engine;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -130,6 +131,7 @@ CdmResponseType WvContentDecryptionModule::GenerateKeyRequest(
|
|||||||
app_parameters, key_request);
|
app_parameters, key_request);
|
||||||
if (license_type == kLicenseTypeRelease && sts != KEY_MESSAGE) {
|
if (license_type == kLicenseTypeRelease && sts != KEY_MESSAGE) {
|
||||||
cdm_engine->CloseKeySetSession(key_set_id);
|
cdm_engine->CloseKeySetSession(key_set_id);
|
||||||
|
std::unique_lock<std::mutex> auto_lock(cdms_lock_);
|
||||||
cdm_by_session_id_.erase(key_set_id);
|
cdm_by_session_id_.erase(key_set_id);
|
||||||
}
|
}
|
||||||
return sts;
|
return sts;
|
||||||
@@ -152,6 +154,7 @@ CdmResponseType WvContentDecryptionModule::AddKey(
|
|||||||
// Empty session id indicates license type release.
|
// Empty session id indicates license type release.
|
||||||
if (sts == KEY_ADDED && session_id.empty()) {
|
if (sts == KEY_ADDED && session_id.empty()) {
|
||||||
cdm_engine->CloseKeySetSession(release_key_set_id);
|
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);
|
cdm_by_session_id_.erase(release_key_set_id);
|
||||||
}
|
}
|
||||||
return sts;
|
return sts;
|
||||||
@@ -297,11 +300,11 @@ CdmResponseType WvContentDecryptionModule::GetSecureStopIds(
|
|||||||
}
|
}
|
||||||
|
|
||||||
CdmEngine* cdm_engine = EnsureCdmForIdentifier(identifier);
|
CdmEngine* cdm_engine = EnsureCdmForIdentifier(identifier);
|
||||||
CdmResponseType sts =
|
const CdmResponseType sts =
|
||||||
cdm_engine->ListUsageIds(app_id, kSecurityLevelL1, nullptr, ssids);
|
cdm_engine->ListUsageIds(app_id, kSecurityLevelL1, nullptr, ssids);
|
||||||
std::vector<CdmSecureStopId> secure_stop_ids;
|
std::vector<CdmSecureStopId> secure_stop_ids;
|
||||||
CdmResponseType sts_l3 = cdm_engine->ListUsageIds(app_id, kSecurityLevelL3,
|
const CdmResponseType sts_l3 = cdm_engine->ListUsageIds(
|
||||||
nullptr, &secure_stop_ids);
|
app_id, kSecurityLevelL3, nullptr, &secure_stop_ids);
|
||||||
ssids->insert(ssids->end(), secure_stop_ids.begin(), secure_stop_ids.end());
|
ssids->insert(ssids->end(), secure_stop_ids.begin(), secure_stop_ids.end());
|
||||||
return sts_l3 != NO_ERROR ? sts_l3 : sts;
|
return sts_l3 != NO_ERROR ? sts_l3 : sts;
|
||||||
}
|
}
|
||||||
@@ -383,17 +386,19 @@ CdmResponseType WvContentDecryptionModule::GetMetrics(
|
|||||||
if (!metrics || !full_list_returned) {
|
if (!metrics || !full_list_returned) {
|
||||||
return PARAMETER_NULL;
|
return PARAMETER_NULL;
|
||||||
}
|
}
|
||||||
|
std::unique_lock<std::mutex> auto_lock(cdms_lock_);
|
||||||
for (auto& key_value_pair : cdms_) {
|
for (auto& key_value_pair : cdms_) {
|
||||||
|
const CdmIdentifier& identifier = key_value_pair.first;
|
||||||
drm_metrics::WvCdmMetrics metric;
|
drm_metrics::WvCdmMetrics metric;
|
||||||
CdmResponseType status = GetMetrics(key_value_pair.first, &metric);
|
const CdmResponseType status = GetMetricsInternal(identifier, &metric);
|
||||||
if (status == NO_ERROR) {
|
if (status == NO_ERROR) {
|
||||||
metrics->push_back(metric);
|
metrics->push_back(metric);
|
||||||
} else {
|
} else {
|
||||||
LOGD("GetMetrics call failed: cdm identifier=%u, error=%d",
|
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.
|
// treat it as a non full list in that case.
|
||||||
*full_list_returned = !cdms_.empty() && metrics->size() == cdms_.size();
|
*full_list_returned = !cdms_.empty() && metrics->size() == cdms_.size();
|
||||||
|
|
||||||
@@ -410,6 +415,12 @@ CdmResponseType WvContentDecryptionModule::GetMetrics(
|
|||||||
return PARAMETER_NULL;
|
return PARAMETER_NULL;
|
||||||
}
|
}
|
||||||
std::unique_lock<std::mutex> auto_lock(cdms_lock_);
|
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);
|
auto it = cdms_.find(identifier);
|
||||||
if (it == cdms_.end()) {
|
if (it == cdms_.end()) {
|
||||||
LOGE("Cdm Identifier not found");
|
LOGE("Cdm Identifier not found");
|
||||||
@@ -454,6 +465,7 @@ CdmEngine* WvContentDecryptionModule::EnsureCdmForIdentifier(
|
|||||||
|
|
||||||
CdmEngine* WvContentDecryptionModule::GetCdmForSessionId(
|
CdmEngine* WvContentDecryptionModule::GetCdmForSessionId(
|
||||||
const std::string& session_id) {
|
const std::string& session_id) {
|
||||||
|
std::unique_lock<std::mutex> auto_lock(cdms_lock_);
|
||||||
// Use find to avoid creating empty entries when not found.
|
// Use find to avoid creating empty entries when not found.
|
||||||
auto it = cdm_by_session_id_.find(session_id);
|
auto it = cdm_by_session_id_.find(session_id);
|
||||||
if (it == cdm_by_session_id_.end()) return nullptr;
|
if (it == cdm_by_session_id_.end()) return nullptr;
|
||||||
@@ -462,10 +474,8 @@ CdmEngine* WvContentDecryptionModule::GetCdmForSessionId(
|
|||||||
|
|
||||||
void WvContentDecryptionModule::CloseAllCdms() {
|
void WvContentDecryptionModule::CloseAllCdms() {
|
||||||
std::unique_lock<std::mutex> auto_lock(cdms_lock_);
|
std::unique_lock<std::mutex> auto_lock(cdms_lock_);
|
||||||
|
cdm_by_session_id_.clear();
|
||||||
for (auto it = cdms_.begin(); it != cdms_.end();) {
|
cdms_.clear();
|
||||||
it = cdms_.erase(it);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CdmResponseType WvContentDecryptionModule::CloseCdm(
|
CdmResponseType WvContentDecryptionModule::CloseCdm(
|
||||||
|
|||||||
Reference in New Issue
Block a user