Fixes serialization of vendor metrics
Uses an updated proto model that's more efficient for serialization.
Test: Unit tests, google play and CTS tests.
Bug: 73724218
Change-Id: I936bc18216c0c67de580424b4c62344d94be6b38
diff --git a/drm/libmediadrm/Android.bp b/drm/libmediadrm/Android.bp
index 66e4400..4991e50 100644
--- a/drm/libmediadrm/Android.bp
+++ b/drm/libmediadrm/Android.bp
@@ -54,17 +54,18 @@
proto: {
export_proto_headers: true,
- type: "lite",
+ type: "lite",
},
shared_libs: [
"android.hardware.drm@1.0",
"android.hardware.drm@1.1",
"libbase",
"libbinder",
- "libhidlbase",
+ "libhidlbase",
"liblog",
"libmediametrics",
"libprotobuf-cpp-lite",
+ "libstagefright_foundation",
"libutils",
],
cflags: [
@@ -86,24 +87,25 @@
proto: {
export_proto_headers: true,
- type: "full",
+ type: "full",
},
shared_libs: [
"android.hardware.drm@1.0",
"android.hardware.drm@1.1",
"libbase",
"libbinder",
- "libhidlbase",
+ "libhidlbase",
"liblog",
"libmediametrics",
"libprotobuf-cpp-full",
+ "libstagefright_foundation",
"libutils",
],
cflags: [
// Suppress unused parameter and no error options. These cause problems
- // when using the map type in a proto definition.
- "-Wno-unused-parameter",
- "-Wno-error",
+ // when using the map type in a proto definition.
+ "-Wno-unused-parameter",
+ "-Wno-error",
],
}
diff --git a/drm/libmediadrm/DrmHal.cpp b/drm/libmediadrm/DrmHal.cpp
index 5d97188..4e8ad52 100644
--- a/drm/libmediadrm/DrmHal.cpp
+++ b/drm/libmediadrm/DrmHal.cpp
@@ -32,6 +32,7 @@
#include <media/drm/DrmAPI.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/AString.h>
+#include <media/stagefright/foundation/base64.h>
#include <media/stagefright/foundation/hexdump.h>
#include <media/stagefright/MediaErrors.h>
#include <mediadrm/DrmHal.h>
@@ -63,9 +64,27 @@
// This constant corresponds to the PROPERTY_DEVICE_UNIQUE_ID constant
// in the MediaDrm API.
constexpr char kPropertyDeviceUniqueId[] = "deviceUniqueId";
+constexpr char kEqualsSign[] = "=";
+template<typename T>
+std::string toBase64StringNoPad(const T* data, size_t size) {
+ if (size == 0) {
+ return "";
+ }
+ CHECK(sizeof(data[0] == 1));
+
+ android::AString outputString;
+ encodeBase64(data, size, &outputString);
+ // Remove trailing equals padding if it exists.
+ while (outputString.size() > 0 && outputString.endsWith(kEqualsSign)) {
+ outputString.erase(outputString.size() - 1, 1);
+ }
+
+ return std::string(outputString.c_str(), outputString.size());
}
+} // anonymous namespace
+
namespace android {
#define INIT_CHECK() {if (mInitCheck != OK) return mInitCheck;}
@@ -101,15 +120,6 @@
return hidl_string(string.string());
}
-std::string toHexString(const std::string& str) {
- std::ostringstream out;
- out << std::hex << std::setfill('0');
- for (size_t i = 0; i < str.size(); i++) {
- out << std::setw(2) << (int)(str[i]);
- }
- return out.str();
-}
-
static DrmPlugin::SecurityLevel toSecurityLevel(SecurityLevel level) {
switch(level) {
case SecurityLevel::SW_SECURE_CRYPTO:
@@ -340,6 +350,7 @@
sp<IDrmPlugin> DrmHal::makeDrmPlugin(const sp<IDrmFactory>& factory,
const uint8_t uuid[16], const String8& appPackageName) {
+ mAppPackageName = appPackageName;
mMetrics.SetAppPackageName(appPackageName);
sp<IDrmPlugin> plugin;
@@ -1353,9 +1364,10 @@
if (result != OK) {
ALOGE("Failed to serialize framework metrics: %d", result);
}
- serializedMetrics = toHexString(serializedMetrics);
- if (!serializedMetrics.empty()) {
- item.setCString("serialized_metrics", serializedMetrics.c_str());
+ std::string b64EncodedMetrics = toBase64StringNoPad(serializedMetrics.data(),
+ serializedMetrics.size());
+ if (!b64EncodedMetrics.empty()) {
+ item.setCString("serialized_metrics", b64EncodedMetrics.c_str());
}
if (!item.selfrecord()) {
ALOGE("Failed to self record framework metrics");
@@ -1364,14 +1376,16 @@
void DrmHal::reportPluginMetrics() const
{
- Vector<uint8_t> metrics;
+ Vector<uint8_t> metricsVector;
String8 vendor;
String8 description;
if (getPropertyStringInternal(String8("vendor"), vendor) == OK &&
getPropertyStringInternal(String8("description"), description) == OK &&
- getPropertyByteArrayInternal(String8("metrics"), metrics) == OK) {
- status_t res = android::reportDrmPluginMetrics(
- metrics, vendor, description);
+ getPropertyByteArrayInternal(String8("metrics"), metricsVector) == OK) {
+ std::string metricsString = toBase64StringNoPad(metricsVector.array(),
+ metricsVector.size());
+ status_t res = android::reportDrmPluginMetrics(metricsString, vendor,
+ description, mAppPackageName);
if (res != OK) {
ALOGE("Metrics were retrieved but could not be reported: %d", res);
}
diff --git a/drm/libmediadrm/PluginMetricsReporting.cpp b/drm/libmediadrm/PluginMetricsReporting.cpp
index 6c97f2b..5cb48bf 100644
--- a/drm/libmediadrm/PluginMetricsReporting.cpp
+++ b/drm/libmediadrm/PluginMetricsReporting.cpp
@@ -16,80 +16,35 @@
//#define LOG_NDEBUG 0
#define LOG_TAG "PluginMetricsReporting"
-#include <utils/Log.h>
-#include <inttypes.h>
#include <media/PluginMetricsReporting.h>
-#include <media/MediaAnalyticsItem.h>
+#include <inttypes.h>
-#include "protos/metrics.pb.h"
+#include <media/MediaAnalyticsItem.h>
+#include <utils/Log.h>
+
namespace android {
namespace {
-using android::drm_metrics::MetricsGroup;
-using android::drm_metrics::MetricsGroup_Metric;
-using android::drm_metrics::MetricsGroup_Metric_MetricValue;
+constexpr char kSerializedMetricsField[] = "serialized_metrics";
-const char* const kParentAttribute = "/parent/external";
-
-status_t reportMetricsGroup(const MetricsGroup& metricsGroup,
- const String8& batchName,
- const int64_t* parentId) {
- MediaAnalyticsItem analyticsItem(batchName.c_str());
+status_t reportVendorMetrics(const std::string& metrics,
+ const String8& name,
+ const String8& appPackageName) {
+ MediaAnalyticsItem analyticsItem(name.c_str());
analyticsItem.generateSessionID();
- int64_t sessionId = analyticsItem.getSessionID();
- if (parentId != NULL) {
- analyticsItem.setInt64(kParentAttribute, *parentId);
- }
- // Report the package name.
- if (metricsGroup.has_app_package_name()) {
- std::string app_package_name(metricsGroup.app_package_name().c_str(),
- metricsGroup.app_package_name().size());
- analyticsItem.setPkgName(app_package_name);
- }
-
- for (int i = 0; i < metricsGroup.metric_size(); ++i) {
- const MetricsGroup_Metric& metric = metricsGroup.metric(i);
- if (!metric.has_name()) {
- ALOGE("Metric with no name.");
- return BAD_VALUE;
- }
-
- if (!metric.has_value()) {
- ALOGE("Metric with no value.");
- return BAD_VALUE;
- }
-
- const MetricsGroup_Metric_MetricValue& value = metric.value();
- if (value.has_int_value()) {
- analyticsItem.setInt64(metric.name().c_str(),
- value.int_value());
- } else if (value.has_double_value()) {
- analyticsItem.setDouble(metric.name().c_str(),
- value.double_value());
- } else if (value.has_string_value()) {
- analyticsItem.setCString(metric.name().c_str(),
- value.string_value().c_str());
- } else {
- ALOGE("Metric Value with no actual value.");
- return BAD_VALUE;
- }
+ std::string app_package_name(appPackageName.c_str(), appPackageName.size());
+ analyticsItem.setPkgName(app_package_name);
+ if (metrics.size() > 0) {
+ analyticsItem.setCString(kSerializedMetricsField, metrics.c_str());
}
if (!analyticsItem.selfrecord()) {
- ALOGE("selfrecord() returned false. sessioId %" PRId64, sessionId);
- }
-
- for (int i = 0; i < metricsGroup.metric_sub_group_size(); ++i) {
- const MetricsGroup& subGroup = metricsGroup.metric_sub_group(i);
- status_t res = reportMetricsGroup(subGroup, batchName, &sessionId);
- if (res != OK) {
- return res;
- }
+ ALOGE("selfrecord() returned false. sessioId %" PRId64, analyticsItem.getSessionID());
}
return OK;
@@ -111,21 +66,16 @@
} // namespace
-status_t reportDrmPluginMetrics(const Vector<uint8_t>& serializedMetrics,
+status_t reportDrmPluginMetrics(const std::string& b64EncodedMetrics,
const String8& vendor,
- const String8& description) {
- MetricsGroup root_metrics_group;
- if (!root_metrics_group.ParseFromArray(serializedMetrics.array(),
- serializedMetrics.size())) {
- ALOGE("Failure to parse.");
- return BAD_VALUE;
- }
+ const String8& description,
+ const String8& appPackageName) {
String8 name = String8::format("drm.vendor.%s.%s",
sanitize(vendor).c_str(),
sanitize(description).c_str());
- return reportMetricsGroup(root_metrics_group, name, NULL);
+ return reportVendorMetrics(b64EncodedMetrics, name, appPackageName);
}
} // namespace android
diff --git a/drm/libmediadrm/protos/metrics.proto b/drm/libmediadrm/protos/metrics.proto
index aa26f5f..6160e6f 100644
--- a/drm/libmediadrm/protos/metrics.proto
+++ b/drm/libmediadrm/protos/metrics.proto
@@ -18,33 +18,6 @@
package android.drm_metrics;
-// The MetricsGroup is a collection of metric name/value pair instances
-// that can be serialized and provided to a caller.
-message MetricsGroup {
- message Metric {
- message MetricValue {
- // Exactly one of the following values must be set.
- optional int64 int_value = 1;
- optional double double_value = 2;
- optional string string_value = 3;
- }
-
- // The name of the metric. Must be valid UTF-8. Required.
- optional string name = 1;
-
- // The value of the metric. Required.
- optional MetricValue value = 2;
- }
-
- // The list of name/value pairs of metrics.
- repeated Metric metric = 1;
-
- // Allow multiple sub groups of metrics.
- repeated MetricsGroup metric_sub_group = 2;
-
- // Name of the application package associated with the metrics.
- optional string app_package_name = 3;
-}
// This message contains the specific metrics captured by DrmMetrics. It is
// used for serializing and logging metrics.
@@ -72,7 +45,7 @@
// The Counter message is used to store a count value with an associated
// Attribute.
message Counter {
- optional int64 count = 1;
+ optional uint64 count = 1;
// Represents the attributes associated with this counter instance.
optional Attributes attributes = 2;
}
@@ -80,11 +53,11 @@
// The DistributionMetric is meant to capture the moments of a normally
// distributed (or approximately normal) value.
message DistributionMetric {
- optional double min = 1;
- optional double max = 2;
- optional double mean = 3;
+ optional float min = 1;
+ optional float max = 2;
+ optional float mean = 3;
optional double variance = 4;
- optional double operation_count = 5;
+ optional uint64 operation_count = 5;
// Represents the attributes assocated with this distribution metric
// instance.
@@ -93,9 +66,9 @@
message SessionLifetime {
// Start time of the session in milliseconds since epoch.
- optional int64 start_time_ms = 1;
+ optional uint64 start_time_ms = 1;
// End time of the session in milliseconds since epoch.
- optional int64 end_time_ms = 2;
+ optional uint64 end_time_ms = 2;
}
// The count of open session operations. Each instance has a specific error
diff --git a/media/libmedia/include/media/DrmHal.h b/media/libmedia/include/media/DrmHal.h
index b0e1cc8..f267f76 100644
--- a/media/libmedia/include/media/DrmHal.h
+++ b/media/libmedia/include/media/DrmHal.h
@@ -182,6 +182,7 @@
const Vector<sp<IDrmFactory>> mFactories;
sp<IDrmPlugin> mPlugin;
sp<drm::V1_1::IDrmPlugin> mPluginV1_1;
+ String8 mAppPackageName;
// Mutable to allow modification within GetPropertyByteArray.
mutable MediaDrmMetrics mMetrics;
diff --git a/media/libmedia/include/media/PluginMetricsReporting.h b/media/libmedia/include/media/PluginMetricsReporting.h
index 4a5a363..e00bd43 100644
--- a/media/libmedia/include/media/PluginMetricsReporting.h
+++ b/media/libmedia/include/media/PluginMetricsReporting.h
@@ -20,13 +20,13 @@
#include <utils/Errors.h>
#include <utils/String8.h>
-#include <utils/Vector.h>
namespace android {
-status_t reportDrmPluginMetrics(const Vector<uint8_t>& serializedMetrics,
+status_t reportDrmPluginMetrics(const std::string& b64EncodedMetrics,
const String8& vendorName,
- const String8& description);
+ const String8& description,
+ const String8& appPackageName);
} // namespace android