diff --git a/libwvdrmengine/cdm/include/wv_content_decryption_module.h b/libwvdrmengine/cdm/include/wv_content_decryption_module.h index 70a5543e..909156ce 100644 --- a/libwvdrmengine/cdm/include/wv_content_decryption_module.h +++ b/libwvdrmengine/cdm/include/wv_content_decryption_module.h @@ -5,12 +5,14 @@ #ifndef CDM_BASE_WV_CONTENT_DECRYPTION_MODULE_H_ #define CDM_BASE_WV_CONTENT_DECRYPTION_MODULE_H_ -#include +#include #include #include #include +#include + #include "cdm_identifier.h" #include "disallow_copy_and_assign.h" #include "file_store.h" @@ -24,6 +26,32 @@ class CdmClientPropertySet; class CdmEngine; class WvCdmEventListener; +class WvMetricsSnapshot { + public: + WvMetricsSnapshot(const CdmIdentifier& identifier, + drm_metrics::WvCdmMetrics&& metrics, ::time_t ts); + + // Acts as a constructor, but uses the current time. + static WvMetricsSnapshot MakeSnapshot(const CdmIdentifier& identifier, + drm_metrics::WvCdmMetrics&& metrics); + + WvMetricsSnapshot() = default; + WvMetricsSnapshot(const WvMetricsSnapshot&) = default; + WvMetricsSnapshot(WvMetricsSnapshot&&) = default; + WvMetricsSnapshot& operator=(const WvMetricsSnapshot&) = default; + WvMetricsSnapshot& operator=(WvMetricsSnapshot&&) = default; + + const CdmIdentifier& cdm_id() const { return cdm_id_; } + const drm_metrics::WvCdmMetrics& metrics() const { return metrics_; } + ::time_t timestamp() const { return timestamp_; } + std::string GetFormattedTimestamp() const; + + private: + CdmIdentifier cdm_id_; + drm_metrics::WvCdmMetrics metrics_; + ::time_t timestamp_ = 0; +}; + class WvContentDecryptionModule : public android::RefBase, public TimerHandler { public: WvContentDecryptionModule(); @@ -142,18 +170,30 @@ class WvContentDecryptionModule : public android::RefBase, public TimerHandler { // Validate a passed-in service certificate virtual bool IsValidServiceCertificate(const std::string& certificate); - // Fill the metrics parameter with the metrics data for the CdmEngine - // associated with the given CdmIdentifier. If the CdmEngine instance does - // not exist, this will return an error. - virtual CdmResponseType GetMetrics(const CdmIdentifier& identifier, - drm_metrics::WvCdmMetrics* metrics); + // Fill the |metrics| parameter with the engine metrics data for the + // CdmEngine associated with the given CdmIdentifier. + // If the CdmEngine instance does not exist, this will return an error. + virtual CdmResponseType GetCurrentMetrics(const CdmIdentifier& identifier, + drm_metrics::WvCdmMetrics* metrics); - // Fill the metrics parameter with the metrics data for all the CdmEngine - // associated with the given CdmIdentifiers. If there are no CdmEngine - // instances, this will return an error. - virtual CdmResponseType GetMetrics( - std::vector* metrics, - bool* full_list_returned); + // Fill the |snapshots| parameter wrapped engine metrics for all CdmEngine + // instances that currently enabled (actively decrypting or performing + // other engine-level operations). + // Current metrics snapshots contain the engine identifier, metrics data + // and time (roughly current time). + // |full_list_returned| will indicate whether all existing enginers were + // able to report their metrics successfully. + virtual CdmResponseType GetAllCurrentMetricsSnapshots( + std::vector* snapshots, bool* full_list_returned); + + // Fill the |snapshots| parameter wrapped engine metrics for several of + // the most recently closed CdmEngine instances. + // Saved metrics snapshots contain the engine identifier, metrics data + // and time of closing. + // The same engine identifier may appear multiple times in the list ( + // depending on how the app utilizes the MediaDrm plugin). + virtual CdmResponseType GetAllSavedMetricsSnapshots( + std::vector* snapshots); // Closes the CdmEngine and sessions associated with the given CdmIdentifier. virtual CdmResponseType CloseCdm(const CdmIdentifier& identifier); @@ -234,8 +274,10 @@ class WvContentDecryptionModule : public android::RefBase, public TimerHandler { // 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); + CdmResponseType GetCurrentMetricsInternal(const CdmIdentifier& identifier, + drm_metrics::WvCdmMetrics* metrics); + void SaveMetrics(const CdmIdentifier& identifier, + drm_metrics::WvCdmMetrics&& metrics); static std::mutex session_sharing_id_generation_lock_; std::mutex timer_lock_; @@ -264,6 +306,10 @@ class WvContentDecryptionModule : public android::RefBase, public TimerHandler { // - Hold lock when erasing, release once erased. std::mutex cdms_lock_; + // 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_; + CORE_DISALLOW_COPY_AND_ASSIGN(WvContentDecryptionModule); }; } // namespace wvcdm diff --git a/libwvdrmengine/cdm/src/wv_content_decryption_module.cpp b/libwvdrmengine/cdm/src/wv_content_decryption_module.cpp index c4895761..9b0d507d 100644 --- a/libwvdrmengine/cdm/src/wv_content_decryption_module.cpp +++ b/libwvdrmengine/cdm/src/wv_content_decryption_module.cpp @@ -20,14 +20,71 @@ #include "wv_cdm_event_listener.h" #include "wv_metrics.pb.h" +namespace wvcdm { + using wvutil::FileSystem; using wvutil::LoggingUidSetter; namespace { const int kCdmTimerDurationSeconds = 1; + +// In the interest of limiting memory usage, only a limited number of +// the most recent metrics snapshots whould be stored. +constexpr size_t kMaxSavedMetricsSnapshotCount = 50; + +// Value returned by time() if the operation fails. +constexpr time_t kTimeError = static_cast(-1); + +// Removes certain field from the provided CdmIdentifier as to make +// it better usable for tracking the same engine across different +// calls into the DRM plugin service. +CdmIdentifier ScrubIdentifierForMetrics(const CdmIdentifier& identifier) { + return CdmIdentifier{identifier.spoid, identifier.origin, + identifier.app_package_name, identifier.unique_id, + /* user_id */ wvutil::UNKNOWN_UID}; +} } // namespace -namespace wvcdm { +WvMetricsSnapshot::WvMetricsSnapshot(const CdmIdentifier& identifier, + drm_metrics::WvCdmMetrics&& metrics, + time_t ts) + : cdm_id_(ScrubIdentifierForMetrics(identifier)), + metrics_(std::move(metrics)), + timestamp_(ts) {} + +WvMetricsSnapshot WvMetricsSnapshot::MakeSnapshot( + const CdmIdentifier& identifier, drm_metrics::WvCdmMetrics&& metrics) { + const time_t now = time(nullptr); + if (now == kTimeError) { + LOGW("Failed to get current time"); + return WvMetricsSnapshot(identifier, std::move(metrics), 0); + } + return WvMetricsSnapshot(identifier, std::move(metrics), now); +} + +std::string WvMetricsSnapshot::GetFormattedTimestamp() const { + if (timestamp_ == 0) return ""; + struct tm time_info = {}; + if (localtime_r(×tamp_, &time_info) == nullptr) { + LOGE("Failed to convert to local time"); + return ""; + } + char timestamp_buffer[64]; // asctime_r() requires at least 29 bytes. + memset(timestamp_buffer, 0, sizeof(timestamp_buffer)); + if (asctime_r(&time_info, timestamp_buffer) == nullptr) { + LOGE("Failed to format localtime to ASC time"); + return ""; + } + std::string result(timestamp_buffer); + // The Linux manual illustrates asctime_r() as returning a value + // with a new line character at the end. However, it does not + // specify this in the description. This is to account for different + // behavior on different systems. + if (!result.empty() && result.back() == '\n') { + result.pop_back(); + } + return result; +} std::mutex WvContentDecryptionModule::session_sharing_id_generation_lock_; @@ -394,45 +451,61 @@ bool WvContentDecryptionModule::IsValidServiceCertificate( return cert.has_certificate(); } -CdmResponseType WvContentDecryptionModule::GetMetrics( - std::vector* metrics, bool* full_list_returned) { - if (!metrics || !full_list_returned) { - return CdmResponseType(PARAMETER_NULL); - } - std::unique_lock auto_lock(cdms_lock_); - for (auto& key_value_pair : cdms_) { - const CdmIdentifier& identifier = key_value_pair.first; - drm_metrics::WvCdmMetrics 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", - identifier.unique_id, status.ToInt()); - } - } - // 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(); - - // We only return error if no metrics is returned when cdms_ is not empty. - // - metrics && cdms_ sizes can both be zero, returns NO_ERROR - // - metrics size <= cdms_, returns NO_ERROR - // - metrics is empty, but cdms_ is not, returns UNKNOWN_ERROR - return (metrics->empty() && !cdms_.empty()) ? CdmResponseType(UNKNOWN_ERROR) - : CdmResponseType(NO_ERROR); -} - -CdmResponseType WvContentDecryptionModule::GetMetrics( +CdmResponseType WvContentDecryptionModule::GetCurrentMetrics( const CdmIdentifier& identifier, drm_metrics::WvCdmMetrics* metrics) { if (!metrics) { return CdmResponseType(PARAMETER_NULL); } std::unique_lock auto_lock(cdms_lock_); - return GetMetricsInternal(identifier, metrics); + return GetCurrentMetricsInternal(identifier, metrics); } -CdmResponseType WvContentDecryptionModule::GetMetricsInternal( +CdmResponseType WvContentDecryptionModule::GetAllCurrentMetricsSnapshots( + std::vector* snapshots, bool* full_list_returned) { + if (!snapshots || !full_list_returned) { + return CdmResponseType(PARAMETER_NULL); + } + snapshots->clear(); + std::unique_lock auto_lock(cdms_lock_); + for (const auto& cdm_info : cdms_) { + const CdmIdentifier& identifier = cdm_info.first; + drm_metrics::WvCdmMetrics metric; + const CdmResponseType status = + GetCurrentMetricsInternal(identifier, &metric); + if (status == NO_ERROR) { + snapshots->push_back( + WvMetricsSnapshot::MakeSnapshot(identifier, std::move(metric))); + } else { + LOGD("Failed to get metrics: cdm_identifier = %u, error = %s", + identifier.unique_id, status.ToString().c_str()); + } + } + // With no streaming activities, |cdms_| size would be zero, + // treat it as a non full list in that case. + *full_list_returned = !cdms_.empty() && snapshots->size() == cdms_.size(); + + // We only return error if no metrics is returned when cdms_ is not empty. + // - metrics && cdms_ sizes can both be zero, returns NO_ERROR + // - metrics size <= cdms_, returns NO_ERROR + // - metrics is empty, but cdms_ is not, returns UNKNOWN_ERROR + return (snapshots->empty() && !cdms_.empty()) ? CdmResponseType(UNKNOWN_ERROR) + : CdmResponseType(NO_ERROR); +} + +CdmResponseType WvContentDecryptionModule::GetAllSavedMetricsSnapshots( + std::vector* snapshots) { + if (snapshots == nullptr) { + return CdmResponseType(PARAMETER_NULL); + } + std::unique_lock auto_lock(cdms_lock_); + // 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()); + return CdmResponseType(NO_ERROR); +} + +CdmResponseType WvContentDecryptionModule::GetCurrentMetricsInternal( const CdmIdentifier& identifier, drm_metrics::WvCdmMetrics* metrics) { // Note: Caller should lock before calling. auto it = cdms_.find(identifier); @@ -446,6 +519,16 @@ CdmResponseType WvContentDecryptionModule::GetMetricsInternal( : CdmResponseType(UNKNOWN_ERROR); } +void WvContentDecryptionModule::SaveMetrics( + const CdmIdentifier& identifier, drm_metrics::WvCdmMetrics&& metrics) { + // Caller should have acquired |cdms_lock_|. + saved_metrics_snapshots_.push_front( + WvMetricsSnapshot::MakeSnapshot(identifier, std::move(metrics))); + if (saved_metrics_snapshots_.size() > kMaxSavedMetricsSnapshotCount) { + saved_metrics_snapshots_.resize(kMaxSavedMetricsSnapshotCount); + } +} + WvContentDecryptionModule::CdmInfo::CdmInfo() : cdm_engine(CdmEngineFactory::CreateCdmEngine(&file_system)) {} @@ -489,6 +572,17 @@ CdmEngine* WvContentDecryptionModule::GetCdmForSessionId( void WvContentDecryptionModule::CloseAllCdms() { std::unique_lock auto_lock(cdms_lock_); + for (const auto& cdm_info : cdms_) { + const CdmIdentifier& identifier = cdm_info.first; + drm_metrics::WvCdmMetrics metrics; + const CdmResponseType status = + GetCurrentMetricsInternal(identifier, &metrics); + if (status == NO_ERROR) { + SaveMetrics(identifier, std::move(metrics)); + } else { + LOGD("CloseAllCdms failed to save metrics"); + } + } cdm_by_session_id_.clear(); cdms_.clear(); } @@ -496,22 +590,32 @@ void WvContentDecryptionModule::CloseAllCdms() { CdmResponseType WvContentDecryptionModule::CloseCdm( const CdmIdentifier& cdm_identifier) { std::unique_lock auto_lock(cdms_lock_); - auto it = cdms_.find(cdm_identifier); - if (it == cdms_.end()) { + auto cdm_it = cdms_.find(cdm_identifier); + if (cdm_it == cdms_.end()) { LOGE("Cdm Identifier not found"); // TODO(blueeyes): Create a better error. return CdmResponseType(UNKNOWN_ERROR); } + CdmEngine* cdm_engine = cdm_it->second.cdm_engine.get(); + // Save metrics snapshot. + drm_metrics::WvCdmMetrics metrics; + const bool success = cdm_engine->GetMetricsSnapshot(&metrics); + if (success) { + SaveMetrics(cdm_identifier, std::move(metrics)); + } else { + LOGW("Failed to get metrics snapshot: unique_id = %" PRIu32, + cdm_identifier.unique_id); + } // Remove any sessions that point to this engine. for (auto session_it = cdm_by_session_id_.begin(); session_it != cdm_by_session_id_.end();) { - if (session_it->second == it->second.cdm_engine.get()) { + if (session_it->second == cdm_engine) { session_it = cdm_by_session_id_.erase(session_it); } else { ++session_it; } } - cdms_.erase(it); + cdms_.erase(cdm_it); return CdmResponseType(NO_ERROR); } diff --git a/libwvdrmengine/cdm/test/cdm_extended_duration_test.cpp b/libwvdrmengine/cdm/test/cdm_extended_duration_test.cpp index 259de488..8207015c 100644 --- a/libwvdrmengine/cdm/test/cdm_extended_duration_test.cpp +++ b/libwvdrmengine/cdm/test/cdm_extended_duration_test.cpp @@ -1545,7 +1545,8 @@ TEST_P(WvCdmStreamingUsageReportTest, DISABLED_UsageTest) { // Validate that update usage table entry is exercised. drm_metrics::WvCdmMetrics metrics; - ASSERT_EQ(NO_ERROR, decryptor_->GetMetrics(kDefaultCdmIdentifier, &metrics)); + ASSERT_EQ(NO_ERROR, decryptor_->GetCurrentMetrics( + kDefaultCdmIdentifier, &metrics)); ValidateHasUpdateUsageEntry(metrics); } diff --git a/libwvdrmengine/cdm/test/wv_cdm_metrics_test.cpp b/libwvdrmengine/cdm/test/wv_cdm_metrics_test.cpp index 2fda2fe8..2c21bc64 100644 --- a/libwvdrmengine/cdm/test/wv_cdm_metrics_test.cpp +++ b/libwvdrmengine/cdm/test/wv_cdm_metrics_test.cpp @@ -45,7 +45,7 @@ class WvContentDecryptionModuleMetricsTest : public WvCdmTestBase { TEST_F(WvContentDecryptionModuleMetricsTest, IdentifierNotFound) { drm_metrics::WvCdmMetrics metrics; ASSERT_EQ(wvcdm::UNKNOWN_ERROR, - decryptor_.GetMetrics(kDefaultCdmIdentifier, &metrics)); + decryptor_.GetCurrentMetrics(kDefaultCdmIdentifier, &metrics)); } TEST_F(WvContentDecryptionModuleMetricsTest, EngineOnlyMetrics) { @@ -62,7 +62,7 @@ TEST_F(WvContentDecryptionModuleMetricsTest, EngineOnlyMetrics) { drm_metrics::WvCdmMetrics metrics; ASSERT_EQ(wvcdm::NO_ERROR, - decryptor_.GetMetrics(kDefaultCdmIdentifier, &metrics)); + decryptor_.GetCurrentMetrics(kDefaultCdmIdentifier, &metrics)); // 100 is an arbitrary high value that shouldn't ever occur. EXPECT_THAT(metrics.engine_metrics() @@ -110,7 +110,7 @@ TEST_F(WvContentDecryptionModuleMetricsTest, EngineAndSessionMetrics) { drm_metrics::WvCdmMetrics metrics; ASSERT_EQ(wvcdm::NO_ERROR, - decryptor_.GetMetrics(kDefaultCdmIdentifier, &metrics)); + decryptor_.GetCurrentMetrics(kDefaultCdmIdentifier, &metrics)); std::string serialized_metrics; ASSERT_TRUE(metrics.SerializeToString(&serialized_metrics)); @@ -162,7 +162,8 @@ TEST_F(WvContentDecryptionModuleMetricsTest, for (int i = 0; i < cdm_engine_count; i++) { drm_metrics::WvCdmMetrics metrics; metrics.Clear(); - ASSERT_EQ(wvcdm::NO_ERROR, decryptor_.GetMetrics(identifiers[i], &metrics)); + ASSERT_EQ(wvcdm::NO_ERROR, + decryptor_.GetCurrentMetrics(identifiers[i], &metrics)); std::string serialized_metrics; ASSERT_TRUE(metrics.SerializeToString(&serialized_metrics)); diff --git a/libwvdrmengine/mediadrm/src/WVDrmPlugin.cpp b/libwvdrmengine/mediadrm/src/WVDrmPlugin.cpp index ba8df0d6..d7e73717 100644 --- a/libwvdrmengine/mediadrm/src/WVDrmPlugin.cpp +++ b/libwvdrmengine/mediadrm/src/WVDrmPlugin.cpp @@ -19,6 +19,7 @@ #include #include #include +#include #include "Utils.h" #include "android-base/macros.h" @@ -754,24 +755,23 @@ Status WVDrmPlugin::unprovisionDevice() { ::ndk::ScopedAStatus WVDrmPlugin::getMetrics( vector<::aidl::android::hardware::drm::DrmMetricGroup>* _aidl_return) { + _aidl_return->clear(); CdmIdentifier identifier; auto status = mCdmIdentifierBuilder.getCdmIdentifier(&identifier); if (status != Status::OK) { - *_aidl_return = vector(); return toNdkScopedAStatus(status); } drm_metrics::WvCdmMetrics proto_metrics; - CdmResponseType result = mCDM->GetMetrics(identifier, &proto_metrics); + const CdmResponseType result = mCDM->GetCurrentMetrics(identifier, &proto_metrics); if (result != wvcdm::NO_ERROR) { - *_aidl_return = vector(); return toNdkScopedAStatus(mapCdmResponseType(result)); } vector wvMetrics; ::wvcdm::WvMetricsAdapter adapter; ::wvcdm::WvMetricsAdapter::ToWvMetrics(proto_metrics, &wvMetrics); - *_aidl_return = wvMetrics; + *_aidl_return = std::move(wvMetrics); return toNdkScopedAStatus(Status::OK); } @@ -1196,7 +1196,8 @@ Status WVDrmPlugin::unprovisionDevice() { if (status != Status::OK) { ALOGE("Unexpected error retrieving cdm identifier: %d", status.get()); } else { - status = mapCdmResponseType(mCDM->GetMetrics(identifier, &metrics)); + status = + mapCdmResponseType(mCDM->GetCurrentMetrics(identifier, &metrics)); } } if (status == Status::OK) { diff --git a/libwvdrmengine/mediadrm/test/WVDrmPlugin_hal_test.cpp b/libwvdrmengine/mediadrm/test/WVDrmPlugin_hal_test.cpp index a4d3b7f0..e1fb9163 100644 --- a/libwvdrmengine/mediadrm/test/WVDrmPlugin_hal_test.cpp +++ b/libwvdrmengine/mediadrm/test/WVDrmPlugin_hal_test.cpp @@ -241,7 +241,7 @@ class MockCDM : public WvContentDecryptionModule { MOCK_METHOD(bool, IsValidServiceCertificate, (const std::string &), (override)); - MOCK_METHOD(CdmResponseType, GetMetrics, + MOCK_METHOD(CdmResponseType, GetCurrentMetrics, (const CdmIdentifier &, drm_metrics::WvCdmMetrics *), (override)); MOCK_METHOD(CdmResponseType, GetDecryptHashError, @@ -1175,7 +1175,7 @@ TEST_F(WVDrmPluginHalTest, ReturnsExpectedPropertyValues) { .WillOnce(DoAll(SetArgPointee<2>(wvcdm::QUERY_VALUE_NOT_SUPPORTED), testing::Return(CdmResponseType(wvcdm::NO_ERROR)))); - EXPECT_CALL(*mCdm, GetMetrics(_, _)) + EXPECT_CALL(*mCdm, GetCurrentMetrics(_, _)) .WillOnce(DoAll(SetArgPointee<1>(expected_metrics), testing::Return(CdmResponseType(wvcdm::NO_ERROR)))); diff --git a/libwvdrmengine/src/WVDrmFactory.cpp b/libwvdrmengine/src/WVDrmFactory.cpp index 998f08b0..76c5c067 100644 --- a/libwvdrmengine/src/WVDrmFactory.cpp +++ b/libwvdrmengine/src/WVDrmFactory.cpp @@ -9,8 +9,10 @@ #include "WVDrmFactory.h" -#include #include +#include +#include +#include #include #include @@ -23,6 +25,7 @@ #include "WVUUID.h" #include "android-base/properties.h" #include "cutils/properties.h" +#include "string_conversions.h" #include "wv_cdm_constants.h" #include "wv_content_decryption_module.h" #include "wv_metrics.h" @@ -59,21 +62,44 @@ void FormatIndent(int fd, size_t indent) { if (real_indent < indent) FormatIndent(fd, indent - real_indent); } +void FormatWvCdmIdentifier(int fd, size_t parent_indent, + const wvcdm::CdmIdentifier& identifier) { + const size_t indent = parent_indent + 2; + // Spoid. + FormatIndent(fd, indent); + dprintf(fd, "spoid: \"%s\"\n", wvutil::b2a_hex(identifier.spoid).c_str()); + // Origin. + FormatIndent(fd, indent); + dprintf(fd, "origin: \"%s\"\n", wvutil::b2a_hex(identifier.origin).c_str()); + // App package name. + FormatIndent(fd, indent); + dprintf(fd, "app_package_name: \"%s\"\n", + identifier.app_package_name.c_str()); + // Unique ID. + FormatIndent(fd, indent); + dprintf(fd, "unique_id: %" PRIu32 "\n", identifier.unique_id); +} + void FormatWvMetricsSnapshotItem(int fd, size_t parent_indent, - drm_metrics::WvCdmMetrics& metrics, + const wvcdm::WvMetricsSnapshot& snapshot, size_t item_index) { const size_t indent = parent_indent + 2; - // TODO(b/239462891): Provide identifier and timestamp for metrics. - - // Serialized proto size. + // CDM identifier. FormatIndent(fd, parent_indent); // First parameter uses indent + list tick. - dprintf(fd, "- serialized_proto_bytes: %zu # [%zu]\n", - metrics.ByteSizeLong(), item_index); - + dprintf(fd, "- identifier: # [%zu]\n", item_index); + FormatWvCdmIdentifier(fd, indent, snapshot.cdm_id()); + // Timestamp. + FormatIndent(fd, indent); + dprintf(fd, "timestamp: \"%s\"\n", snapshot.GetFormattedTimestamp().c_str()); + // Serialized proto size. + FormatIndent(fd, indent); + dprintf(fd, "serialized_proto_bytes: %zu\n", + snapshot.metrics().ByteSizeLong()); + // Engine metrics. FormatIndent(fd, indent); dprintf(fd, "cdm_metrics:\n"); std::stringstream ss; - wv_metrics::FormatWvCdmMetrics(metrics, indent, ss); + wv_metrics::FormatWvCdmMetrics(snapshot.metrics(), indent, ss); PrintStream(fd, ss); } } // namespace @@ -213,15 +239,15 @@ void WVDrmFactory::printCdmMetrics(int fd) { android::sp cdm(getCDM()); - vector metrics; - bool full_list_returned = true; + std::vector snapshots; + bool full_list_returned = false; wvcdm::CdmResponseType result = - cdm->GetMetrics(&metrics, &full_list_returned); + cdm->GetAllCurrentMetricsSnapshots(&snapshots, &full_list_returned); if (result != wvcdm::NO_ERROR) { dprintf(fd, " live_metrics:\n"); dprintf(fd, " error_message: \"%s\"\n", result.ToString().c_str()); dprintf(fd, " error_code: %d\n", static_cast(result.code())); - } else if (metrics.empty()) { + } else if (snapshots.empty()) { // YAML does not support empty property values. const char kNoMetricsMessage[] = "Metrics not available, please retry while streaming a video."; @@ -229,15 +255,15 @@ void WVDrmFactory::printCdmMetrics(int fd) { } else { dprintf(fd, " live_metrics: "); if (full_list_returned) { - dprintf(fd, "# count = %zu\n", metrics.size()); + dprintf(fd, "# count = %zu\n", snapshots.size()); } else { const char kPartialListMessage[] = "Some metrics are missing due to an internal error, " "check logs for details."; - dprintf(fd, "# count = %zu, %s\n", metrics.size(), kPartialListMessage); + dprintf(fd, "# count = %zu, %s\n", snapshots.size(), kPartialListMessage); } - for (size_t i = 0; i < metrics.size(); i++) { - FormatWvMetricsSnapshotItem(fd, 2, metrics[i], i); + for (size_t i = 0; i < snapshots.size(); i++) { + FormatWvMetricsSnapshotItem(fd, 2, snapshots[i], i); } } // TODO(b/270166158): Print metrics history.