From 4b267e37f996b49d7437565b2351b2236c26f922 Mon Sep 17 00:00:00 2001 From: Alex Dale Date: Thu, 27 Apr 2023 15:31:39 -0700 Subject: [PATCH] Allow metrics history to outlive the Android CDM. [ Merge of http://go/wvgerrit/172910 ] The lifecycle of the Android CDM is controlled by Android's strong/ weak pointer functionality. Unfortunately, it does not provide an easily predictable point in the code where the CDM is to be deleted along with the saved metrics. In order to allow the CDM to keep a list of metrics that are persistent with the life of the service, a global thread safe queue is provided which is created when the first CDM is created, but will out live the CDM. The metrics will still be deleted when the DRM service is terminated. Bug: 270166158 Test: adb shell dumpsys android.hardware.drm.IDrmFactory/widevine -m Change-Id: Id98676d8b5278798b4de332cc272cd5b85024244 --- .../include/wv_content_decryption_module.h | 33 ++++++++++- .../cdm/src/wv_content_decryption_module.cpp | 56 ++++++++++++++++--- libwvdrmengine/src/WVCDMSingleton.cpp | 13 ++++- 3 files changed, 91 insertions(+), 11 deletions(-) diff --git a/libwvdrmengine/cdm/include/wv_content_decryption_module.h b/libwvdrmengine/cdm/include/wv_content_decryption_module.h index 909156ce..d6f6a5ab 100644 --- a/libwvdrmengine/cdm/include/wv_content_decryption_module.h +++ b/libwvdrmengine/cdm/include/wv_content_decryption_module.h @@ -52,9 +52,39 @@ class WvMetricsSnapshot { ::time_t timestamp_ = 0; }; +class WvMetricsSnapshotQueue + : public android::LightRefBase { + public: + WvMetricsSnapshotQueue(); + explicit WvMetricsSnapshotQueue(size_t capacity) : capacity_(capacity) {} + + size_t capacity() const { return capacity_; } + size_t size() const { return snapshots_.size(); } + + WvMetricsSnapshotQueue(const WvMetricsSnapshotQueue&) = delete; + WvMetricsSnapshotQueue(WvMetricsSnapshotQueue&&) = delete; + WvMetricsSnapshotQueue& operator=(const WvMetricsSnapshotQueue&) = delete; + WvMetricsSnapshotQueue& operator=(WvMetricsSnapshotQueue&&) = delete; + + void PushMetrics(WvMetricsSnapshot&& snapshot); + void PushMetrics(const WvMetricsSnapshot& snapshot); + + bool GetAll(std::vector* snapshots) const; + + void Clear(); + + private: + void ReFit(); + + const size_t capacity_; + mutable std::mutex mutex_; + std::deque snapshots_; +}; + class WvContentDecryptionModule : public android::RefBase, public TimerHandler { public: WvContentDecryptionModule(); + explicit WvContentDecryptionModule(WvMetricsSnapshotQueue* metrics_queue); virtual ~WvContentDecryptionModule(); // Static methods @@ -308,7 +338,8 @@ class WvContentDecryptionModule : public android::RefBase, public TimerHandler { // Contains a finite list of histories of different CDM engine instances. // When a CDM engine is closed, its metrics will be saved. - std::deque saved_metrics_snapshots_; + // Only used if not null. + WvMetricsSnapshotQueue* saved_metrics_snapshots_ = nullptr; CORE_DISALLOW_COPY_AND_ASSIGN(WvContentDecryptionModule); }; diff --git a/libwvdrmengine/cdm/src/wv_content_decryption_module.cpp b/libwvdrmengine/cdm/src/wv_content_decryption_module.cpp index 9b0d507d..9ce0108f 100644 --- a/libwvdrmengine/cdm/src/wv_content_decryption_module.cpp +++ b/libwvdrmengine/cdm/src/wv_content_decryption_module.cpp @@ -86,10 +86,48 @@ std::string WvMetricsSnapshot::GetFormattedTimestamp() const { return result; } +WvMetricsSnapshotQueue::WvMetricsSnapshotQueue() + : capacity_(kMaxSavedMetricsSnapshotCount) {} + +void WvMetricsSnapshotQueue::PushMetrics(WvMetricsSnapshot&& snapshot) { + std::unique_lock lock(mutex_); + snapshots_.push_front(std::move(snapshot)); + ReFit(); +} + +void WvMetricsSnapshotQueue::PushMetrics(const WvMetricsSnapshot& snapshot) { + std::unique_lock lock(mutex_); + snapshots_.push_front(snapshot); + ReFit(); +} + +bool WvMetricsSnapshotQueue::GetAll( + std::vector* snapshots) const { + if (snapshots == nullptr) return false; + std::unique_lock lock(mutex_); + snapshots->assign(snapshots_.begin(), snapshots_.end()); + return true; +} + +void WvMetricsSnapshotQueue::Clear() { + std::unique_lock lock(mutex_); + snapshots_.clear(); +} + +void WvMetricsSnapshotQueue::ReFit() { + if (capacity_ > 0 && snapshots_.size() > capacity_) { + snapshots_.resize(capacity_); + } +} + std::mutex WvContentDecryptionModule::session_sharing_id_generation_lock_; WvContentDecryptionModule::WvContentDecryptionModule() {} +WvContentDecryptionModule::WvContentDecryptionModule( + WvMetricsSnapshotQueue* metrics_queue) + : saved_metrics_snapshots_(metrics_queue) {} + WvContentDecryptionModule::~WvContentDecryptionModule() { CryptoSession::DisableDelayedTermination(); CloseAllCdms(); @@ -497,11 +535,16 @@ CdmResponseType WvContentDecryptionModule::GetAllSavedMetricsSnapshots( if (snapshots == nullptr) { return CdmResponseType(PARAMETER_NULL); } - std::unique_lock auto_lock(cdms_lock_); + if (saved_metrics_snapshots_ == nullptr) { + snapshots->clear(); + // Storing the metrics might not be available in some cases. + return CdmResponseType(NO_ERROR); + } // This has the potential to be an expensive operation. However, // this function is only used during debug reporting. - snapshots->assign(saved_metrics_snapshots_.cbegin(), - saved_metrics_snapshots_.cend()); + if (!saved_metrics_snapshots_->GetAll(snapshots)) { + return CdmResponseType(UNKNOWN_ERROR); + } return CdmResponseType(NO_ERROR); } @@ -521,12 +564,9 @@ CdmResponseType WvContentDecryptionModule::GetCurrentMetricsInternal( void WvContentDecryptionModule::SaveMetrics( const CdmIdentifier& identifier, drm_metrics::WvCdmMetrics&& metrics) { - // Caller should have acquired |cdms_lock_|. - saved_metrics_snapshots_.push_front( + if (saved_metrics_snapshots_ == nullptr) return; + saved_metrics_snapshots_->PushMetrics( WvMetricsSnapshot::MakeSnapshot(identifier, std::move(metrics))); - if (saved_metrics_snapshots_.size() > kMaxSavedMetricsSnapshotCount) { - saved_metrics_snapshots_.resize(kMaxSavedMetricsSnapshotCount); - } } WvContentDecryptionModule::CdmInfo::CdmInfo() diff --git a/libwvdrmengine/src/WVCDMSingleton.cpp b/libwvdrmengine/src/WVCDMSingleton.cpp index 6589613d..1d1fe23a 100644 --- a/libwvdrmengine/src/WVCDMSingleton.cpp +++ b/libwvdrmengine/src/WVCDMSingleton.cpp @@ -15,12 +15,16 @@ namespace wvdrm { -using wvcdm::WvContentDecryptionModule; using android::Mutex; using android::sp; using android::wp; +using wvcdm::WvContentDecryptionModule; +using wvcdm::WvMetricsSnapshotQueue; Mutex cdmLock; +// TODO(b/270166158): Make this a loadable/storable when provided +// a special debug property. +sp sMetricsQueue; // The strong pointers that keep this object alive live in the plugin objects. // If all the plugins are deleted, the CDM will be deleted, and subsequent // invocations of this code will construct a new CDM. @@ -29,11 +33,16 @@ wp sCdm; sp getCDM() { Mutex::Autolock lock(cdmLock); // This function is a critical section. + if (sMetricsQueue == nullptr) { + ALOGD("Instantiating CDM metrics queue"); + sMetricsQueue = new WvMetricsSnapshotQueue(); + } + sp cdm = sCdm.promote(); if (cdm == NULL) { ALOGD("Instantiating CDM."); - cdm = new WvContentDecryptionModule(); + cdm = new WvContentDecryptionModule(sMetricsQueue.get()); sCdm = cdm; }