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
This commit is contained in:
Robert Shih
2020-02-07 15:01:57 -08:00
parent 93fb84c8d5
commit 7bcf792dd8
5 changed files with 179 additions and 42 deletions

View File

@@ -26,11 +26,13 @@ cc_binary {
shared_libs: [
"libmedia",
"libmediametrics",
"libcutils",
"libutils",
"liblog",
"libbinder",
"libdl",
"libselinux",
"libstagefright_foundation",
],
static_libs: ["libdrmframeworkcommon"],

View File

@@ -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() :
}
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 @@ void DrmManager::removeClient(int uniqueId) {
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 @@ DrmConstraints* DrmManager::getConstraints(int uniqueId, const String8* path, co
constraints = rDrmEngine.getConstraints(uniqueId, path, action);
}
if (NULL != constraints) {
reportEngineMetrics(__func__, plugInId);
recordEngineMetrics(__func__, plugInId);
}
return constraints;
}
@@ -211,7 +293,7 @@ DrmMetadata* DrmManager::getMetadata(int uniqueId, const String8* path) {
meta = rDrmEngine.getMetadata(uniqueId, path);
}
if (NULL != meta) {
reportEngineMetrics(__func__, plugInId);
recordEngineMetrics(__func__, plugInId);
}
return meta;
}
@@ -222,7 +304,7 @@ bool DrmManager::canHandle(int uniqueId, const String8& path, const String8& mim
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 @@ DrmInfoStatus* DrmManager::processDrmInfo(int uniqueId, const DrmInfo* drmInfo)
infoStatus = rDrmEngine.processDrmInfo(uniqueId, drmInfo);
}
if (NULL != infoStatus) {
reportEngineMetrics(__func__, plugInId, mimeType);
recordEngineMetrics(__func__, plugInId, mimeType);
}
return infoStatus;
}
@@ -263,7 +345,7 @@ bool DrmManager::canHandle(int uniqueId, const String8& path) {
result = rDrmEngine.canHandle(uniqueId, path);
if (result) {
reportEngineMetrics(__func__, plugInPathList[i]);
recordEngineMetrics(__func__, plugInPathList[i]);
break;
}
}
@@ -280,7 +362,7 @@ DrmInfo* DrmManager::acquireDrmInfo(int uniqueId, const DrmInfoRequest* drmInfoR
info = rDrmEngine.acquireDrmInfo(uniqueId, drmInfoRequest);
}
if (NULL != info) {
reportEngineMetrics(__func__, plugInId, mimeType);
recordEngineMetrics(__func__, plugInId, mimeType);
}
return info;
}
@@ -296,7 +378,7 @@ status_t DrmManager::saveRights(int uniqueId, const DrmRights& drmRights,
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 @@ String8 DrmManager::getOriginalMimeType(int uniqueId, const String8& path, int f
mimeType = rDrmEngine.getOriginalMimeType(uniqueId, path, fd);
}
if (!mimeType.isEmpty()) {
reportEngineMetrics(__func__, plugInId, mimeType);
recordEngineMetrics(__func__, plugInId, mimeType);
}
return mimeType;
}
@@ -324,7 +406,7 @@ int DrmManager::getDrmObjectType(int uniqueId, const String8& path, const String
type = rDrmEngine.getDrmObjectType(uniqueId, path, mimeType);
}
if (DrmObjectType::UNKNOWN != type) {
reportEngineMetrics(__func__, plugInId, mimeType);
recordEngineMetrics(__func__, plugInId, mimeType);
}
return type;
}
@@ -338,7 +420,7 @@ int DrmManager::checkRightsStatus(int uniqueId, const String8& path, int action)
rightsStatus = rDrmEngine.checkRightsStatus(uniqueId, path, action);
}
if (RightsStatus::RIGHTS_INVALID != rightsStatus) {
reportEngineMetrics(__func__, plugInId);
recordEngineMetrics(__func__, plugInId);
}
return rightsStatus;
}
@@ -385,7 +467,7 @@ status_t DrmManager::removeRights(int uniqueId, const String8& path) {
result = rDrmEngine.removeRights(uniqueId, path);
}
if (DRM_NO_ERROR == result) {
reportEngineMetrics(__func__, plugInId);
recordEngineMetrics(__func__, plugInId);
}
return result;
}
@@ -399,7 +481,7 @@ status_t DrmManager::removeAllRights(int uniqueId) {
if (DRM_NO_ERROR != result) {
break;
}
reportEngineMetrics(__func__, plugInIdList[index]);
recordEngineMetrics(__func__, plugInIdList[index]);
}
return result;
}
@@ -416,7 +498,7 @@ int DrmManager::openConvertSession(int uniqueId, const String8& mimeType) {
++mConvertId;
convertId = mConvertId;
mConvertSessionMap.add(convertId, &rDrmEngine);
reportEngineMetrics(__func__, plugInId, mimeType);
recordEngineMetrics(__func__, plugInId, mimeType);
}
}
return convertId;
@@ -497,7 +579,7 @@ sp<DecryptHandle> DrmManager::openDecryptSession(
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 @@ sp<DecryptHandle> DrmManager::openDecryptSession(
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 @@ sp<DecryptHandle> DrmManager::openDecryptSession(
if (DRM_NO_ERROR == result) {
++mDecryptSessionId;
mDecryptSessionMap.add(mDecryptSessionId, &rDrmEngine);
reportEngineMetrics(__func__, plugInId, mimeType);
recordEngineMetrics(__func__, plugInId, mimeType);
break;
}
}

View File

@@ -17,13 +17,26 @@
#ifndef __DRM_MANAGER_H__
#define __DRM_MANAGER_H__
#include <drm/drm_framework_common.h>
#include <media/stagefright/foundation/AHandler.h>
#include <media/stagefright/foundation/ALooper.h>
#include <media/stagefright/foundation/AMessage.h>
#include <sys/types.h>
#include <utils/Errors.h>
#include <utils/threads.h>
#include <drm/drm_framework_common.h>
#include "IDrmEngine.h"
#include "PlugInManager.h"
#include "IDrmServiceListener.h"
#include <array>
#include <cstddef>
#include <map>
#include <set>
#include <string>
#include <utility>
#include <vector>
namespace android {
class IDrmManager;
@@ -40,6 +53,31 @@ class DrmInfoRequest;
class DrmSupportInfo;
class ActionDescription;
enum DrmManagerMethodId {
GET_CONSTRAINTS,
GET_METADATA,
CAN_HANDLE,
PROCESS_DRM_INFO,
ACQUIRE_DRM_INFO,
SAVE_RIGHTS,
GET_ORIGINAL_MIME_TYPE,
GET_DRM_OBJECT_TYPE,
CHECK_RIGHTS_STATUS,
REMOVE_RIGHTS,
REMOVE_ALL_RIGHTS,
OPEN_CONVERT_SESSION,
OPEN_DECRYPT_SESSION,
NUM_METHODS,
};
struct DrmManagerMetrics {
std::string mPluginId;
std::string mDescription;
std::set<std::string> mMimeTypes;
std::array<int64_t, DrmManagerMethodId::NUM_METHODS> mMethodCounts{};
uid_t mCallingUid;
};
/**
* This is implementation class for DRM Manager. This class delegates the
* functionality to corresponding DRM Engine.
@@ -47,7 +85,7 @@ class ActionDescription;
* The DrmManagerService class creates an instance of this class.
*
*/
class DrmManager : public IDrmEngine::OnInfoListener {
class DrmManager : public AHandler, public IDrmEngine::OnInfoListener {
public:
DrmManager();
virtual ~DrmManager();
@@ -134,6 +172,8 @@ public:
void onInfo(const DrmInfoEvent& event);
void initMetricsLooper();
private:
String8 getSupportedPlugInId(int uniqueId, const String8& path, const String8& mimeType);
@@ -143,16 +183,24 @@ private:
bool canHandle(int uniqueId, const String8& path);
void reportEngineMetrics(const char func[],
void onMessageReceived(const sp<AMessage> &msg);
int64_t getMetricsFlushPeriodUs();
void recordEngineMetrics(const char func[],
const String8& plugInId, const String8& mimeType = String8(""));
void flushEngineMetrics();
private:
enum {
kMaxNumUniqueIds = 0x1000,
kWhatFlushMetrics = 'metr',
};
bool mUniqueIdArray[kMaxNumUniqueIds];
static const String8 EMPTY_STRING;
static const std::map<const char*, size_t> kMethodIdMap;
int mDecryptSessionId;
int mConvertId;
@@ -160,11 +208,15 @@ private:
Mutex mListenerLock;
Mutex mDecryptLock;
Mutex mConvertLock;
Mutex mMetricsLock;
TPlugInManager<IDrmEngine> mPlugInManager;
KeyedVector< DrmSupportInfo, String8 > mSupportInfoToPlugInIdMap;
KeyedVector< int, IDrmEngine*> mConvertSessionMap;
KeyedVector< int, sp<IDrmServiceListener> > mServiceListeners;
KeyedVector< int, IDrmEngine*> mDecryptSessionMap;
std::map<std::pair<uid_t, std::string>, DrmManagerMetrics> mPluginMetrics;
sp<ALooper> mMetricsLooper;
};
};

View File

@@ -130,13 +130,14 @@ DrmManagerService::DrmManagerService() :
mDrmManager(NULL) {
ALOGV("created");
mDrmManager = new DrmManager();
mDrmManager->initMetricsLooper();
mDrmManager->loadPlugIns();
}
DrmManagerService::~DrmManagerService() {
ALOGV("Destroyed");
mDrmManager->unloadPlugIns();
delete mDrmManager; mDrmManager = NULL;
mDrmManager = NULL;
}
int DrmManagerService::addUniqueId(bool isNative) {

View File

@@ -142,7 +142,7 @@ public:
virtual status_t dump(int fd, const Vector<String16>& args);
private:
DrmManager* mDrmManager;
sp<DrmManager> mDrmManager;
};
};