Home | History | Annotate | Download | only in libmediadrm
      1 /*
      2  * Copyright (C) 2018 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 #define LOG_TAG "DrmMetrics"
     17 #include <iomanip>
     18 #include <utility>
     19 
     20 #include <android-base/macros.h>
     21 #include <media/stagefright/foundation/base64.h>
     22 #include <mediadrm/DrmMetrics.h>
     23 #include <sys/time.h>
     24 #include <utils/Log.h>
     25 #include <utils/Timers.h>
     26 
     27 #include "protos/metrics.pb.h"
     28 
     29 using ::android::String16;
     30 using ::android::String8;
     31 using ::android::drm_metrics::DrmFrameworkMetrics;
     32 using ::android::hardware::hidl_string;
     33 using ::android::hardware::hidl_vec;
     34 using ::android::hardware::drm::V1_0::EventType;
     35 using ::android::hardware::drm::V1_0::KeyStatusType;
     36 using ::android::hardware::drm::V1_1::DrmMetricGroup;
     37 using ::android::os::PersistableBundle;
     38 
     39 namespace {
     40 
     41 template <typename T> std::string GetAttributeName(T type);
     42 
     43 template <> std::string GetAttributeName<KeyStatusType>(KeyStatusType type) {
     44     static const char *type_names[] = {"USABLE", "EXPIRED",
     45                                        "OUTPUT_NOT_ALLOWED", "STATUS_PENDING",
     46                                        "INTERNAL_ERROR"};
     47     if (((size_t)type) > arraysize(type_names)) {
     48         return "UNKNOWN_TYPE";
     49     }
     50     return type_names[(size_t)type];
     51 }
     52 
     53 template <> std::string GetAttributeName<EventType>(EventType type) {
     54     static const char *type_names[] = {"PROVISION_REQUIRED", "KEY_NEEDED",
     55                                        "KEY_EXPIRED", "VENDOR_DEFINED",
     56                                        "SESSION_RECLAIMED"};
     57     if (((size_t)type) > arraysize(type_names)) {
     58         return "UNKNOWN_TYPE";
     59     }
     60     return type_names[(size_t)type];
     61 }
     62 
     63 template <typename T>
     64 void ExportCounterMetric(const android::CounterMetric<T> &counter,
     65                          PersistableBundle *metrics) {
     66     if (!metrics) {
     67         ALOGE("metrics was unexpectedly null.");
     68         return;
     69     }
     70     std::string success_count_name = counter.metric_name() + ".ok.count";
     71     std::string error_count_name = counter.metric_name() + ".error.count";
     72     std::vector<int64_t> status_values;
     73     counter.ExportValues(
     74         [&](const android::status_t status, const int64_t value) {
     75             if (status == android::OK) {
     76                 metrics->putLong(android::String16(success_count_name.c_str()),
     77                                  value);
     78             } else {
     79                 int64_t total_errors(0);
     80                 metrics->getLong(android::String16(error_count_name.c_str()),
     81                                  &total_errors);
     82                 metrics->putLong(android::String16(error_count_name.c_str()),
     83                                  total_errors + value);
     84                 status_values.push_back(status);
     85             }
     86         });
     87     if (!status_values.empty()) {
     88         std::string error_list_name = counter.metric_name() + ".error.list";
     89         metrics->putLongVector(android::String16(error_list_name.c_str()),
     90                                status_values);
     91     }
     92 }
     93 
     94 template <typename T>
     95 void ExportCounterMetricWithAttributeNames(
     96     const android::CounterMetric<T> &counter, PersistableBundle *metrics) {
     97     if (!metrics) {
     98         ALOGE("metrics was unexpectedly null.");
     99         return;
    100     }
    101     counter.ExportValues([&](const T &attribute, const int64_t value) {
    102         std::string name = counter.metric_name() + "." +
    103                            GetAttributeName(attribute) + ".count";
    104         metrics->putLong(android::String16(name.c_str()), value);
    105     });
    106 }
    107 
    108 template <typename T>
    109 void ExportEventMetric(const android::EventMetric<T> &event,
    110                        PersistableBundle *metrics) {
    111     if (!metrics) {
    112         ALOGE("metrics was unexpectedly null.");
    113         return;
    114     }
    115     std::string success_count_name = event.metric_name() + ".ok.count";
    116     std::string error_count_name = event.metric_name() + ".error.count";
    117     std::string timing_name = event.metric_name() + ".ok.average_time_micros";
    118     std::vector<int64_t> status_values;
    119     event.ExportValues([&](const android::status_t &status,
    120                            const android::EventStatistics &value) {
    121         if (status == android::OK) {
    122             metrics->putLong(android::String16(success_count_name.c_str()),
    123                              value.count);
    124             metrics->putLong(android::String16(timing_name.c_str()),
    125                              value.mean);
    126         } else {
    127             int64_t total_errors(0);
    128             metrics->getLong(android::String16(error_count_name.c_str()),
    129                              &total_errors);
    130             metrics->putLong(android::String16(error_count_name.c_str()),
    131                              total_errors + value.count);
    132             status_values.push_back(status);
    133         }
    134     });
    135     if (!status_values.empty()) {
    136         std::string error_list_name = event.metric_name() + ".error.list";
    137         metrics->putLongVector(android::String16(error_list_name.c_str()),
    138                                status_values);
    139     }
    140 }
    141 
    142 void ExportSessionLifespans(
    143     const std::map<std::string, std::pair<int64_t, int64_t>> &mSessionLifespans,
    144     PersistableBundle *metrics) {
    145     if (!metrics) {
    146         ALOGE("metrics was unexpectedly null.");
    147         return;
    148     }
    149 
    150     if (mSessionLifespans.empty()) {
    151         return;
    152     }
    153 
    154     PersistableBundle startTimesBundle;
    155     PersistableBundle endTimesBundle;
    156     for (auto it = mSessionLifespans.begin(); it != mSessionLifespans.end();
    157          it++) {
    158         String16 key(it->first.c_str(), it->first.size());
    159         startTimesBundle.putLong(key, it->second.first);
    160         endTimesBundle.putLong(key, it->second.second);
    161     }
    162     metrics->putPersistableBundle(
    163         android::String16("drm.mediadrm.session_start_times_ms"),
    164         startTimesBundle);
    165     metrics->putPersistableBundle(
    166         android::String16("drm.mediadrm.session_end_times_ms"), endTimesBundle);
    167 }
    168 
    169 std::string ToHexString(const android::Vector<uint8_t> &sessionId) {
    170     std::ostringstream out;
    171     out << std::hex << std::setfill('0');
    172     for (size_t i = 0; i < sessionId.size(); i++) {
    173         out << std::setw(2) << (int)(sessionId[i]);
    174     }
    175     return out.str();
    176 }
    177 
    178 template <typename CT>
    179 void SetValue(const String16 &name, DrmMetricGroup::ValueType type,
    180               const CT &value, PersistableBundle *bundle) {
    181     switch (type) {
    182     case DrmMetricGroup::ValueType::INT64_TYPE:
    183         bundle->putLong(name, value.int64Value);
    184         break;
    185     case DrmMetricGroup::ValueType::DOUBLE_TYPE:
    186         bundle->putDouble(name, value.doubleValue);
    187         break;
    188     case DrmMetricGroup::ValueType::STRING_TYPE:
    189         bundle->putString(name, String16(value.stringValue.c_str()));
    190         break;
    191     default:
    192         ALOGE("Unexpected value type: %hhu", type);
    193     }
    194 }
    195 
    196 inline String16 MakeIndexString(unsigned int index) {
    197   std::string str("[");
    198   str.append(std::to_string(index));
    199   str.append("]");
    200   return String16(str.c_str());
    201 }
    202 
    203 } // namespace
    204 
    205 namespace android {
    206 
    207 MediaDrmMetrics::MediaDrmMetrics()
    208     : mOpenSessionCounter("drm.mediadrm.open_session", "status"),
    209       mCloseSessionCounter("drm.mediadrm.close_session", "status"),
    210       mGetKeyRequestTimeUs("drm.mediadrm.get_key_request", "status"),
    211       mProvideKeyResponseTimeUs("drm.mediadrm.provide_key_response", "status"),
    212       mGetProvisionRequestCounter("drm.mediadrm.get_provision_request",
    213                                   "status"),
    214       mProvideProvisionResponseCounter(
    215           "drm.mediadrm.provide_provision_response", "status"),
    216       mKeyStatusChangeCounter("drm.mediadrm.key_status_change",
    217                               "key_status_type"),
    218       mEventCounter("drm.mediadrm.event", "event_type"),
    219       mGetDeviceUniqueIdCounter("drm.mediadrm.get_device_unique_id", "status") {
    220 }
    221 
    222 void MediaDrmMetrics::SetSessionStart(
    223     const android::Vector<uint8_t> &sessionId) {
    224     std::string sessionIdHex = ToHexString(sessionId);
    225     mSessionLifespans[sessionIdHex] =
    226         std::make_pair(GetCurrentTimeMs(), (int64_t)0);
    227 }
    228 
    229 void MediaDrmMetrics::SetSessionEnd(const android::Vector<uint8_t> &sessionId) {
    230     std::string sessionIdHex = ToHexString(sessionId);
    231     int64_t endTimeMs = GetCurrentTimeMs();
    232     if (mSessionLifespans.find(sessionIdHex) != mSessionLifespans.end()) {
    233         mSessionLifespans[sessionIdHex] =
    234             std::make_pair(mSessionLifespans[sessionIdHex].first, endTimeMs);
    235     } else {
    236         mSessionLifespans[sessionIdHex] = std::make_pair((int64_t)0, endTimeMs);
    237     }
    238 }
    239 
    240 void MediaDrmMetrics::Export(PersistableBundle *metrics) {
    241     if (!metrics) {
    242         ALOGE("metrics was unexpectedly null.");
    243         return;
    244     }
    245     ExportCounterMetric(mOpenSessionCounter, metrics);
    246     ExportCounterMetric(mCloseSessionCounter, metrics);
    247     ExportEventMetric(mGetKeyRequestTimeUs, metrics);
    248     ExportEventMetric(mProvideKeyResponseTimeUs, metrics);
    249     ExportCounterMetric(mGetProvisionRequestCounter, metrics);
    250     ExportCounterMetric(mProvideProvisionResponseCounter, metrics);
    251     ExportCounterMetricWithAttributeNames(mKeyStatusChangeCounter, metrics);
    252     ExportCounterMetricWithAttributeNames(mEventCounter, metrics);
    253     ExportCounterMetric(mGetDeviceUniqueIdCounter, metrics);
    254     ExportSessionLifespans(mSessionLifespans, metrics);
    255 }
    256 
    257 status_t MediaDrmMetrics::GetSerializedMetrics(std::string *serializedMetrics) {
    258 
    259     if (!serializedMetrics) {
    260         ALOGE("serializedMetrics was unexpectedly null.");
    261         return UNEXPECTED_NULL;
    262     }
    263 
    264     DrmFrameworkMetrics metrics;
    265 
    266     mOpenSessionCounter.ExportValues(
    267         [&](const android::status_t status, const int64_t value) {
    268             DrmFrameworkMetrics::Counter *counter =
    269                 metrics.add_open_session_counter();
    270             counter->set_count(value);
    271             counter->mutable_attributes()->set_error_code(status);
    272         });
    273 
    274     mCloseSessionCounter.ExportValues(
    275         [&](const android::status_t status, const int64_t value) {
    276             DrmFrameworkMetrics::Counter *counter =
    277                 metrics.add_close_session_counter();
    278             counter->set_count(value);
    279             counter->mutable_attributes()->set_error_code(status);
    280         });
    281 
    282     mGetProvisionRequestCounter.ExportValues(
    283         [&](const android::status_t status, const int64_t value) {
    284             DrmFrameworkMetrics::Counter *counter =
    285                 metrics.add_get_provisioning_request_counter();
    286             counter->set_count(value);
    287             counter->mutable_attributes()->set_error_code(status);
    288         });
    289 
    290     mProvideProvisionResponseCounter.ExportValues(
    291         [&](const android::status_t status, const int64_t value) {
    292             DrmFrameworkMetrics::Counter *counter =
    293                 metrics.add_provide_provisioning_response_counter();
    294             counter->set_count(value);
    295             counter->mutable_attributes()->set_error_code(status);
    296         });
    297 
    298     mKeyStatusChangeCounter.ExportValues(
    299         [&](const KeyStatusType key_status_type, const int64_t value) {
    300             DrmFrameworkMetrics::Counter *counter =
    301                 metrics.add_key_status_change_counter();
    302             counter->set_count(value);
    303             counter->mutable_attributes()->set_key_status_type(
    304                 (uint32_t)key_status_type);
    305         });
    306 
    307     mEventCounter.ExportValues(
    308         [&](const EventType event_type, const int64_t value) {
    309             DrmFrameworkMetrics::Counter *counter =
    310                 metrics.add_event_callback_counter();
    311             counter->set_count(value);
    312             counter->mutable_attributes()->set_event_type((uint32_t)event_type);
    313         });
    314 
    315     mGetDeviceUniqueIdCounter.ExportValues(
    316         [&](const status_t status, const int64_t value) {
    317             DrmFrameworkMetrics::Counter *counter =
    318                 metrics.add_get_device_unique_id_counter();
    319             counter->set_count(value);
    320             counter->mutable_attributes()->set_error_code(status);
    321         });
    322 
    323     mGetKeyRequestTimeUs.ExportValues(
    324         [&](const status_t status, const EventStatistics &stats) {
    325             DrmFrameworkMetrics::DistributionMetric *metric =
    326                 metrics.add_get_key_request_time_us();
    327             metric->set_min(stats.min);
    328             metric->set_max(stats.max);
    329             metric->set_mean(stats.mean);
    330             metric->set_operation_count(stats.count);
    331             metric->set_variance(stats.sum_squared_deviation / stats.count);
    332             metric->mutable_attributes()->set_error_code(status);
    333         });
    334 
    335     mProvideKeyResponseTimeUs.ExportValues(
    336         [&](const status_t status, const EventStatistics &stats) {
    337             DrmFrameworkMetrics::DistributionMetric *metric =
    338                 metrics.add_provide_key_response_time_us();
    339             metric->set_min(stats.min);
    340             metric->set_max(stats.max);
    341             metric->set_mean(stats.mean);
    342             metric->set_operation_count(stats.count);
    343             metric->set_variance(stats.sum_squared_deviation / stats.count);
    344             metric->mutable_attributes()->set_error_code(status);
    345         });
    346 
    347     for (const auto &sessionLifespan : mSessionLifespans) {
    348         auto *map = metrics.mutable_session_lifetimes();
    349 
    350         (*map)[sessionLifespan.first].set_start_time_ms(
    351             sessionLifespan.second.first);
    352         (*map)[sessionLifespan.first].set_end_time_ms(
    353             sessionLifespan.second.second);
    354     }
    355 
    356     if (!metrics.SerializeToString(serializedMetrics)) {
    357         ALOGE("Failed to serialize metrics.");
    358         return UNKNOWN_ERROR;
    359     }
    360 
    361     return OK;
    362 }
    363 
    364 int64_t MediaDrmMetrics::GetCurrentTimeMs() {
    365     struct timeval tv;
    366     gettimeofday(&tv, NULL);
    367     return ((int64_t)tv.tv_sec * 1000) + ((int64_t)tv.tv_usec / 1000);
    368 }
    369 
    370 status_t MediaDrmMetrics::HidlMetricsToBundle(
    371     const hidl_vec<DrmMetricGroup> &hidlMetricGroups,
    372     PersistableBundle *bundleMetricGroups) {
    373     if (bundleMetricGroups == nullptr) {
    374         return UNEXPECTED_NULL;
    375     }
    376     if (hidlMetricGroups.size() == 0) {
    377         return OK;
    378     }
    379 
    380     int groupIndex = 0;
    381     std::map<String16, int> indexMap;
    382     for (const auto &hidlMetricGroup : hidlMetricGroups) {
    383         PersistableBundle bundleMetricGroup;
    384         for (const auto &hidlMetric : hidlMetricGroup.metrics) {
    385             String16 metricName(hidlMetric.name.c_str());
    386             PersistableBundle bundleMetric;
    387             // Add metric component values.
    388             for (const auto &value : hidlMetric.values) {
    389                 SetValue(String16(value.componentName.c_str()), value.type,
    390                          value, &bundleMetric);
    391             }
    392             // Set metric attributes.
    393             PersistableBundle bundleMetricAttributes;
    394             for (const auto &attribute : hidlMetric.attributes) {
    395                 SetValue(String16(attribute.name.c_str()), attribute.type,
    396                          attribute, &bundleMetricAttributes);
    397             }
    398             // Add attributes to the bundle metric.
    399             bundleMetric.putPersistableBundle(String16("attributes"),
    400                                               bundleMetricAttributes);
    401             // Add one layer of indirection, allowing for repeated metric names.
    402             PersistableBundle repeatedMetrics;
    403             bundleMetricGroup.getPersistableBundle(metricName,
    404                                                    &repeatedMetrics);
    405             int index = indexMap[metricName];
    406             repeatedMetrics.putPersistableBundle(MakeIndexString(index),
    407                                                  bundleMetric);
    408             indexMap[metricName] = ++index;
    409 
    410             // Add the bundle metric to the group of metrics.
    411             bundleMetricGroup.putPersistableBundle(metricName,
    412                                                    repeatedMetrics);
    413         }
    414         // Add the bundle metric group to the collection of groups.
    415         bundleMetricGroups->putPersistableBundle(MakeIndexString(groupIndex++),
    416                                                  bundleMetricGroup);
    417     }
    418 
    419     return OK;
    420 }
    421 
    422 } // namespace android
    423