DrmManager: locally aggregate API metrics
Aggregate DrmManager API invocation counts per plugin over at least
fixed period of time before sending metrics to mediametrics service.
The default period is 1 day; the period is configurable through the
property drmmanager.metrics.period.
Bug: 134789967
Test: dumpsys media.metrics
Change-Id: I2cf28f1dfaa485ca319360705b872eed995b3d7f
diff --git a/drm/drmserver/DrmManager.cpp b/drm/drmserver/DrmManager.cpp
index 38dc052..9a32cc5 100644
--- a/drm/drmserver/DrmManager.cpp
+++ b/drm/drmserver/DrmManager.cpp
@@ -16,9 +16,10 @@
//#define LOG_NDEBUG 0
#define LOG_TAG "DrmManager(Native)"
-#include "utils/Log.h"
+#include <cutils/properties.h>
#include <utils/String8.h>
+#include <utils/Log.h>
#include <binder/IPCThreadState.h>
#include <drm/DrmInfo.h>
@@ -37,12 +38,30 @@
#include "DrmManager.h"
#include "ReadWriteUtils.h"
+#include <algorithm>
+
#define DECRYPT_FILE_ERROR (-1)
using namespace android;
const String8 DrmManager::EMPTY_STRING("");
+const std::map<const char*, size_t> DrmManager::kMethodIdMap {
+ {"getConstraints" , DrmManagerMethodId::GET_CONSTRAINTS },
+ {"getMetadata" , DrmManagerMethodId::GET_METADATA },
+ {"canHandle" , DrmManagerMethodId::CAN_HANDLE },
+ {"processDrmInfo" , DrmManagerMethodId::PROCESS_DRM_INFO },
+ {"acquireDrmInfo" , DrmManagerMethodId::ACQUIRE_DRM_INFO },
+ {"saveRights" , DrmManagerMethodId::SAVE_RIGHTS },
+ {"getOriginalMimeType", DrmManagerMethodId::GET_ORIGINAL_MIME_TYPE},
+ {"getDrmObjectType" , DrmManagerMethodId::GET_DRM_OBJECT_TYPE },
+ {"checkRightsStatus" , DrmManagerMethodId::CHECK_RIGHTS_STATUS },
+ {"removeRights" , DrmManagerMethodId::REMOVE_RIGHTS },
+ {"removeAllRights" , DrmManagerMethodId::REMOVE_ALL_RIGHTS },
+ {"openConvertSession" , DrmManagerMethodId::OPEN_CONVERT_SESSION },
+ {"openDecryptSession" , DrmManagerMethodId::OPEN_DECRYPT_SESSION }
+};
+
DrmManager::DrmManager() :
mDecryptSessionId(0),
mConvertId(0) {
@@ -51,42 +70,106 @@
}
DrmManager::~DrmManager() {
-
+ if (mMetricsLooper != NULL) {
+ mMetricsLooper->stop();
+ }
+ flushEngineMetrics();
}
-void DrmManager::reportEngineMetrics(
- const char func[], const String8& plugInId, const String8& mimeType) {
- IDrmEngine& engine = mPlugInManager.getPlugIn(plugInId);
+void DrmManager::initMetricsLooper() {
+ if (mMetricsLooper != NULL) {
+ return;
+ }
+ mMetricsLooper = new ALooper;
+ mMetricsLooper->setName("DrmManagerMetricsLooper");
+ mMetricsLooper->start();
+ mMetricsLooper->registerHandler(this);
- std::unique_ptr<mediametrics::Item> item(mediametrics::Item::create("drmmanager"));
- item->setUid(IPCThreadState::self()->getCallingUid());
- item->setCString("function_name", func);
- item->setCString("plugin_id", plugInId.getPathLeaf().getBasePath().c_str());
+ sp<AMessage> msg = new AMessage(kWhatFlushMetrics, this);
+ msg->post(getMetricsFlushPeriodUs());
+}
+void DrmManager::onMessageReceived(const sp<AMessage> &msg) {
+ switch (msg->what()) {
+ case kWhatFlushMetrics:
+ {
+ flushEngineMetrics();
+ msg->post(getMetricsFlushPeriodUs());
+ break;
+ }
+ default:
+ {
+ ALOGW("Unrecognized message type: %zd", msg->what());
+ }
+ }
+}
+
+int64_t DrmManager::getMetricsFlushPeriodUs() {
+ return 1000 * 1000 * std::max(1ll, property_get_int64("drmmanager.metrics.period", 86400));
+}
+
+void DrmManager::recordEngineMetrics(
+ const char func[], const String8& plugInId8, const String8& mimeType) {
+ IDrmEngine& engine = mPlugInManager.getPlugIn(plugInId8);
std::unique_ptr<DrmSupportInfo> info(engine.getSupportInfo(0));
- if (NULL != info) {
- item->setCString("description", info->getDescription().c_str());
+
+ uid_t callingUid = IPCThreadState::self()->getCallingUid();
+ std::string plugInId(plugInId8.getPathLeaf().getBasePath().c_str());
+ ALOGV("%d calling %s %s", callingUid, plugInId.c_str(), func);
+
+ Mutex::Autolock _l(mMetricsLock);
+ auto& metrics = mPluginMetrics[std::make_pair(callingUid, plugInId)];
+ if (metrics.mPluginId.empty()) {
+ metrics.mPluginId = plugInId;
+ metrics.mCallingUid = callingUid;
+ if (NULL != info) {
+ metrics.mDescription = info->getDescription().c_str();
+ }
}
if (!mimeType.isEmpty()) {
- item->setCString("mime_types", mimeType.c_str());
+ metrics.mMimeTypes.insert(mimeType.c_str());
} else if (NULL != info) {
DrmSupportInfo::MimeTypeIterator mimeIter = info->getMimeTypeIterator();
- String8 mimes;
while (mimeIter.hasNext()) {
- mimes += mimeIter.next();
- if (mimeIter.hasNext()) {
- mimes += ",";
- }
+ metrics.mMimeTypes.insert(mimeIter.next().c_str());
}
- item->setCString("mime_types", mimes.c_str());
}
- if (!item->selfrecord()) {
- ALOGE("Failed to record metrics");
+ size_t methodId = kMethodIdMap.at(func);
+ if (methodId < metrics.mMethodCounts.size()) {
+ metrics.mMethodCounts[methodId]++;
}
}
+void DrmManager::flushEngineMetrics() {
+ using namespace std::string_literals;
+ Mutex::Autolock _l(mMetricsLock);
+ for (auto kv : mPluginMetrics) {
+ DrmManagerMetrics& metrics = kv.second;
+ std::unique_ptr<mediametrics::Item> item(mediametrics::Item::create("drmmanager"));
+ item->setUid(metrics.mCallingUid);
+ item->setCString("plugin_id", metrics.mPluginId.c_str());
+ item->setCString("description", metrics.mDescription.c_str());
+
+ std::vector<std::string> mimeTypes(metrics.mMimeTypes.begin(), metrics.mMimeTypes.end());
+ std::string mimeTypesStr(mimeTypes.empty() ? "" : mimeTypes[0]);
+ for (size_t i = 1; i < mimeTypes.size() ; i++) {
+ mimeTypesStr.append(",").append(mimeTypes[i]);
+ }
+ item->setCString("mime_types", mimeTypesStr.c_str());
+
+ for (size_t i = 0; i < metrics.mMethodCounts.size() ; i++) {
+ item->setInt64(("method"s + std::to_string(i)).c_str(), metrics.mMethodCounts[i]);
+ }
+
+ if (!item->selfrecord()) {
+ ALOGE("Failed to record metrics");
+ }
+ }
+ mPluginMetrics.clear();
+}
+
int DrmManager::addUniqueId(bool isNative) {
Mutex::Autolock _l(mLock);
@@ -184,7 +267,6 @@
for (size_t index = 0; index < plugInIdList.size(); index++) {
IDrmEngine& rDrmEngine = mPlugInManager.getPlugIn(plugInIdList.itemAt(index));
rDrmEngine.terminate(uniqueId);
- reportEngineMetrics(__func__, plugInIdList[index]);
}
}
@@ -197,7 +279,7 @@
constraints = rDrmEngine.getConstraints(uniqueId, path, action);
}
if (NULL != constraints) {
- reportEngineMetrics(__func__, plugInId);
+ recordEngineMetrics(__func__, plugInId);
}
return constraints;
}
@@ -211,7 +293,7 @@
meta = rDrmEngine.getMetadata(uniqueId, path);
}
if (NULL != meta) {
- reportEngineMetrics(__func__, plugInId);
+ recordEngineMetrics(__func__, plugInId);
}
return meta;
}
@@ -222,7 +304,7 @@
bool result = (EMPTY_STRING != plugInId) ? true : false;
if (result) {
- reportEngineMetrics(__func__, plugInId, mimeType);
+ recordEngineMetrics(__func__, plugInId, mimeType);
}
if (0 < path.length()) {
@@ -249,7 +331,7 @@
infoStatus = rDrmEngine.processDrmInfo(uniqueId, drmInfo);
}
if (NULL != infoStatus) {
- reportEngineMetrics(__func__, plugInId, mimeType);
+ recordEngineMetrics(__func__, plugInId, mimeType);
}
return infoStatus;
}
@@ -263,7 +345,7 @@
result = rDrmEngine.canHandle(uniqueId, path);
if (result) {
- reportEngineMetrics(__func__, plugInPathList[i]);
+ recordEngineMetrics(__func__, plugInPathList[i]);
break;
}
}
@@ -280,7 +362,7 @@
info = rDrmEngine.acquireDrmInfo(uniqueId, drmInfoRequest);
}
if (NULL != info) {
- reportEngineMetrics(__func__, plugInId, mimeType);
+ recordEngineMetrics(__func__, plugInId, mimeType);
}
return info;
}
@@ -296,7 +378,7 @@
result = rDrmEngine.saveRights(uniqueId, drmRights, rightsPath, contentPath);
}
if (DRM_NO_ERROR == result) {
- reportEngineMetrics(__func__, plugInId, mimeType);
+ recordEngineMetrics(__func__, plugInId, mimeType);
}
return result;
}
@@ -310,7 +392,7 @@
mimeType = rDrmEngine.getOriginalMimeType(uniqueId, path, fd);
}
if (!mimeType.isEmpty()) {
- reportEngineMetrics(__func__, plugInId, mimeType);
+ recordEngineMetrics(__func__, plugInId, mimeType);
}
return mimeType;
}
@@ -324,7 +406,7 @@
type = rDrmEngine.getDrmObjectType(uniqueId, path, mimeType);
}
if (DrmObjectType::UNKNOWN != type) {
- reportEngineMetrics(__func__, plugInId, mimeType);
+ recordEngineMetrics(__func__, plugInId, mimeType);
}
return type;
}
@@ -338,7 +420,7 @@
rightsStatus = rDrmEngine.checkRightsStatus(uniqueId, path, action);
}
if (RightsStatus::RIGHTS_INVALID != rightsStatus) {
- reportEngineMetrics(__func__, plugInId);
+ recordEngineMetrics(__func__, plugInId);
}
return rightsStatus;
}
@@ -385,7 +467,7 @@
result = rDrmEngine.removeRights(uniqueId, path);
}
if (DRM_NO_ERROR == result) {
- reportEngineMetrics(__func__, plugInId);
+ recordEngineMetrics(__func__, plugInId);
}
return result;
}
@@ -399,7 +481,7 @@
if (DRM_NO_ERROR != result) {
break;
}
- reportEngineMetrics(__func__, plugInIdList[index]);
+ recordEngineMetrics(__func__, plugInIdList[index]);
}
return result;
}
@@ -416,7 +498,7 @@
++mConvertId;
convertId = mConvertId;
mConvertSessionMap.add(convertId, &rDrmEngine);
- reportEngineMetrics(__func__, plugInId, mimeType);
+ recordEngineMetrics(__func__, plugInId, mimeType);
}
}
return convertId;
@@ -497,7 +579,7 @@
if (DRM_NO_ERROR == result) {
++mDecryptSessionId;
mDecryptSessionMap.add(mDecryptSessionId, &rDrmEngine);
- reportEngineMetrics(__func__, plugInId, String8(mime));
+ recordEngineMetrics(__func__, plugInId, String8(mime));
break;
}
}
@@ -526,7 +608,7 @@
if (DRM_NO_ERROR == result) {
++mDecryptSessionId;
mDecryptSessionMap.add(mDecryptSessionId, &rDrmEngine);
- reportEngineMetrics(__func__, plugInId, String8(mime));
+ recordEngineMetrics(__func__, plugInId, String8(mime));
break;
}
}
@@ -556,7 +638,7 @@
if (DRM_NO_ERROR == result) {
++mDecryptSessionId;
mDecryptSessionMap.add(mDecryptSessionId, &rDrmEngine);
- reportEngineMetrics(__func__, plugInId, mimeType);
+ recordEngineMetrics(__func__, plugInId, mimeType);
break;
}
}