Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 32494f54 authored by Adam Stone's avatar Adam Stone
Browse files

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
parent 56ecf3e3
Loading
Loading
Loading
Loading
+9 −7
Original line number Diff line number Diff line
@@ -65,6 +65,7 @@ cc_library_shared {
        "liblog",
        "libmediametrics",
        "libprotobuf-cpp-lite",
        "libstagefright_foundation",
        "libutils",
    ],
    cflags: [
@@ -97,6 +98,7 @@ cc_library_shared {
        "liblog",
        "libmediametrics",
        "libprotobuf-cpp-full",
        "libstagefright_foundation",
        "libutils",
    ],
    cflags: [
+30 −16
Original line number Diff line number Diff line
@@ -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,8 +64,26 @@ namespace {
// 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 {

@@ -101,15 +120,6 @@ static hidl_string toHidlString(const String8& string) {
    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 @@ Vector<sp<IDrmFactory>> DrmHal::makeDrmFactories() {

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 @@ void DrmHal::reportFrameworkMetrics() const
    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::reportFrameworkMetrics() const

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);
        }
+17 −67
Original line number Diff line number Diff line
@@ -16,80 +16,35 @@

//#define LOG_NDEBUG 0
#define LOG_TAG "PluginMetricsReporting"
#include <utils/Log.h>
#include <inttypes.h>

#include <media/PluginMetricsReporting.h>

#include <inttypes.h>

#include <media/MediaAnalyticsItem.h>
#include <utils/Log.h>

#include "protos/metrics.pb.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());
    std::string app_package_name(appPackageName.c_str(), appPackageName.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;
        }
    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 @@ String8 sanitize(const String8& input) {

}  // 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
+7 −34
Original line number Diff line number Diff line
@@ -18,33 +18,6 @@ syntax = "proto2";

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 @@ message DrmFrameworkMetrics {
  // 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 @@ message DrmFrameworkMetrics {
  // 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 DrmFrameworkMetrics {

  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
+1 −0
Original line number Diff line number Diff line
@@ -182,6 +182,7 @@ private:
    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;
Loading