implementing concurrent codec metrics
Following changes are made in this CL:
- extend IResourceManagerService interface to allow:
- notify create/start/stop of codecs
- implement concurrent codec metrics with different
buckets (such as different resolution, codec type)
for all the application/process and for the system.
- push the codec concurrency metrics to statsd
- move all metrics to a different class
- update codec reported metrics with codec id
Bug: 265488359
Test: atest cts/tests/media/misc/src/android/media/misc/cts/ResourceManagerTest.java
/data/nativetest64/ResourceManagerService_test/ResourceManagerService_test
/data/nativetest64/ResourceObserverService_test/ResourceObserverService_test
refactoring CL. Existing unit tests still pass.
Change-Id: Ibaa1fb9607e486f2eb79bf02d79c630e09d62b4a
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index 65485e0..f2b3dc5 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -20,6 +20,7 @@
#include <utils/Log.h>
#include <set>
+#include <random>
#include <stdlib.h>
#include <inttypes.h>
@@ -99,6 +100,7 @@
// These must be kept synchronized with the constants there.
static const char *kCodecLogSessionId = "android.media.mediacodec.log-session-id";
static const char *kCodecCodec = "android.media.mediacodec.codec"; /* e.g. OMX.google.aac.decoder */
+static const char *kCodecId = "android.media.mediacodec.id";
static const char *kCodecMime = "android.media.mediacodec.mime"; /* e.g. audio/mime */
static const char *kCodecMode = "android.media.mediacodec.mode"; /* audio, video */
static const char *kCodecModeVideo = "video"; /* values returned for kCodecMode */
@@ -218,7 +220,7 @@
sp<MediaCodec> codec = mMediaCodec.promote();
if (codec == NULL) {
// Codec is already gone, so remove the resources as well
- ::ndk::SpAIBinder binder(AServiceManager_getService("media.resource_manager"));
+ ::ndk::SpAIBinder binder(AServiceManager_waitForService("media.resource_manager"));
std::shared_ptr<IResourceManagerService> service =
IResourceManagerService::fromBinder(binder);
if (service == nullptr) {
@@ -290,6 +292,9 @@
void removeClient();
void markClientForPendingRemoval();
bool reclaimResource(const std::vector<MediaResourceParcel> &resources);
+ void notifyClientCreated();
+ void notifyClientStarted(ClientConfigParcel& clientConfig);
+ void notifyClientStopped(ClientConfigParcel& clientConfig);
inline void setCodecName(const char* name) {
mCodecName = name;
@@ -331,7 +336,7 @@
}
status_t MediaCodec::ResourceManagerServiceProxy::init() {
- ::ndk::SpAIBinder binder(AServiceManager_getService("media.resource_manager"));
+ ::ndk::SpAIBinder binder(AServiceManager_waitForService("media.resource_manager"));
mService = IResourceManagerService::fromBinder(binder);
if (mService == nullptr) {
ALOGE("Failed to get ResourceManagerService");
@@ -468,6 +473,32 @@
return status.isOk() && success;
}
+void MediaCodec::ResourceManagerServiceProxy::notifyClientCreated() {
+ ClientInfoParcel clientInfo{.pid = static_cast<int32_t>(mPid),
+ .uid = static_cast<int32_t>(mUid),
+ .id = getId(mClient),
+ .name = mCodecName};
+ mService->notifyClientCreated(clientInfo);
+}
+
+void MediaCodec::ResourceManagerServiceProxy::notifyClientStarted(
+ ClientConfigParcel& clientConfig) {
+ clientConfig.clientInfo.pid = static_cast<int32_t>(mPid);
+ clientConfig.clientInfo.uid = static_cast<int32_t>(mUid);
+ clientConfig.clientInfo.id = getId(mClient);
+ clientConfig.clientInfo.name = mCodecName;
+ mService->notifyClientStarted(clientConfig);
+}
+
+void MediaCodec::ResourceManagerServiceProxy::notifyClientStopped(
+ ClientConfigParcel& clientConfig) {
+ clientConfig.clientInfo.pid = static_cast<int32_t>(mPid);
+ clientConfig.clientInfo.uid = static_cast<int32_t>(mUid);
+ clientConfig.clientInfo.id = getId(mClient);
+ clientConfig.clientInfo.name = mCodecName;
+ mService->notifyClientStopped(clientConfig);
+}
+
////////////////////////////////////////////////////////////////////////////////
MediaCodec::BufferInfo::BufferInfo() : mOwnedByClient(false) {}
@@ -860,6 +891,23 @@
return new PersistentSurface(bufferProducer, bufferSource);
}
+// GenerateCodecId generates a 64bit Random ID for each codec that is created.
+// The Codec ID is generated as:
+// - A process-unique random high 32bits
+// - An atomic sequence low 32bits
+//
+static uint64_t GenerateCodecId() {
+ static std::atomic_uint64_t sId = [] {
+ std::random_device rd;
+ std::mt19937 gen(rd());
+ std::uniform_int_distribution<uint32_t> distrib(0, UINT32_MAX);
+ uint32_t randomID = distrib(gen);
+ uint64_t id = randomID;
+ return id << 32;
+ }();
+ return sId++;
+}
+
MediaCodec::MediaCodec(
const sp<ALooper> &looper, pid_t pid, uid_t uid,
std::function<sp<CodecBase>(const AString &, const char *)> getCodecBase,
@@ -902,6 +950,7 @@
mInputBufferCounter(0),
mGetCodecBase(getCodecBase),
mGetCodecInfo(getCodecInfo) {
+ mCodecId = GenerateCodecId();
mResourceManagerProxy = new ResourceManagerServiceProxy(pid, uid,
::ndk::SharedRefBase::make<ResourceManagerClient>(this, pid, uid));
if (!mGetCodecBase) {
@@ -1793,6 +1842,12 @@
break;
}
}
+
+ if (OK == err) {
+ // Notify the ResourceManager that, this codec has been created
+ // (initialized) successfully.
+ mResourceManagerProxy->notifyClientCreated();
+ }
return err;
}
@@ -1846,6 +1901,7 @@
format->findString("log-session-id", &mLogSessionId);
if (nextMetricsHandle != 0) {
+ mediametrics_setInt64(nextMetricsHandle, kCodecId, mCodecId);
int32_t profile = 0;
if (format->findInt32("profile", &profile)) {
mediametrics_setInt32(nextMetricsHandle, kCodecProfile, profile);
@@ -3340,6 +3396,17 @@
return DequeueOutputResult::kRepliedWithError;
}
+
+inline void MediaCodec::initClientConfigParcel(ClientConfigParcel& clientConfig) {
+ clientConfig.codecType = toMediaResourceSubType(mDomain);
+ clientConfig.isEncoder = mFlags & kFlagIsEncoder;
+ clientConfig.isHardware = !MediaCodecList::isSoftwareCodec(mComponentName);
+ clientConfig.width = mWidth;
+ clientConfig.height = mHeight;
+ clientConfig.timeStamp = systemTime(SYSTEM_TIME_MONOTONIC) / 1000LL;
+ clientConfig.id = mCodecId;
+}
+
void MediaCodec::onMessageReceived(const sp<AMessage> &msg) {
switch (msg->what()) {
case kWhatCodecNotify:
@@ -3586,14 +3653,8 @@
mediametrics_setInt32(mMetricsHandle, kCodecSecure, 0);
}
- MediaCodecInfo::Attributes attr = mCodecInfo
- ? mCodecInfo->getAttributes()
- : MediaCodecInfo::Attributes(0);
- if (mDomain == DOMAIN_VIDEO || !(attr & MediaCodecInfo::kFlagIsSoftwareOnly)) {
- // software audio codecs are currently ignored.
- mResourceManagerProxy->addResource(MediaResource::CodecResource(
+ mResourceManagerProxy->addResource(MediaResource::CodecResource(
mFlags & kFlagIsSecure, toMediaResourceSubType(mDomain)));
- }
postPendingRepliesAndDeferredMessages("kWhatComponentAllocated");
break;
@@ -3763,6 +3824,11 @@
mResourceManagerProxy->addResource(
MediaResource::GraphicMemoryResource(getGraphicBufferSize()));
}
+ // Notify the RM that the codec is in use (has been started).
+ ClientConfigParcel clientConfig;
+ initClientConfigParcel(clientConfig);
+ mResourceManagerProxy->notifyClientStarted(clientConfig);
+
setState(STARTED);
postPendingRepliesAndDeferredMessages("kWhatStartCompleted");
@@ -3993,6 +4059,11 @@
mState, stateString(mState).c_str());
break;
}
+ // Notify the RM that the codec has been stopped.
+ ClientConfigParcel clientConfig;
+ initClientConfigParcel(clientConfig);
+ mResourceManagerProxy->notifyClientStopped(clientConfig);
+
setState(INITIALIZED);
if (mReplyID) {
postPendingRepliesAndDeferredMessages("kWhatStopCompleted");
diff --git a/media/libstagefright/include/media/stagefright/MediaCodec.h b/media/libstagefright/include/media/stagefright/MediaCodec.h
index ad04b1f..df76faa 100644
--- a/media/libstagefright/include/media/stagefright/MediaCodec.h
+++ b/media/libstagefright/include/media/stagefright/MediaCodec.h
@@ -39,6 +39,7 @@
namespace android {
namespace media {
class MediaResourceParcel;
+class ClientConfigParcel;
} // media
} // android
} // aidl
@@ -71,6 +72,7 @@
using hardware::cas::native::V1_0::IDescrambler;
using aidl::android::media::MediaResourceParcel;
+using aidl::android::media::ClientConfigParcel;
struct MediaCodec : public AHandler {
enum Domain {
@@ -453,6 +455,8 @@
void updateTunnelPeek(const sp<AMessage> &msg);
void updatePlaybackDuration(const sp<AMessage> &msg);
+ inline void initClientConfigParcel(ClientConfigParcel& clientConfig);
+
sp<AMessage> mOutputFormat;
sp<AMessage> mInputFormat;
sp<AMessage> mCallback;
@@ -705,6 +709,8 @@
};
Histogram mLatencyHist;
+ // An unique ID for the codec - Used by the metrics.
+ uint64_t mCodecId = 0;
std::function<sp<CodecBase>(const AString &, const char *)> mGetCodecBase;
std::function<status_t(const AString &, sp<MediaCodecInfo> *)> mGetCodecInfo;
diff --git a/media/utils/ProcessInfo.cpp b/media/utils/ProcessInfo.cpp
index 13f16b1..6296351 100644
--- a/media/utils/ProcessInfo.cpp
+++ b/media/utils/ProcessInfo.cpp
@@ -30,10 +30,64 @@
static constexpr int32_t INVALID_ADJ = -10000;
static constexpr int32_t NATIVE_ADJ = -1000;
+/* Make sure this matches with ActivityManager::PROCESS_STATE_NONEXISTENT
+ * #include <binder/ActivityManager.h>
+ * using ActivityManager::PROCESS_STATE_NONEXISTENT;
+ */
+static constexpr int32_t PROCESS_STATE_NONEXISTENT = 20;
+
ProcessInfo::ProcessInfo() {}
+/*
+ * Checks whether the list of processes with given pids exist or not.
+ *
+ * Arguments:
+ * - pids (input): List of pids for which to check whether they are Existent or not.
+ * - existent (output): boolean vector corresponds to Existent state of each pids.
+ *
+ * On successful return:
+ * - existent[i] true corresponds to pids[i] still active and
+ * - existent[i] false corresponds to pids[i] already terminated (Nonexistent)
+ * On unsuccessful return, the output argument existent is invalid.
+ */
+bool ProcessInfo::checkProcessExistent(const std::vector<int32_t>& pids,
+ std::vector<bool>* existent) {
+ sp<IBinder> binder = defaultServiceManager()->waitForService(String16("processinfo"));
+ sp<IProcessInfoService> service = interface_cast<IProcessInfoService>(binder);
+
+ // Get the process state of the applications managed/tracked by the ActivityManagerService.
+ // Don't have to look into the native processes.
+ // If we really need the state of native process, then we can use ==> mOverrideMap
+ size_t count = pids.size();
+ std::vector<int32_t> states(count, PROCESS_STATE_NONEXISTENT);
+ status_t err = service->getProcessStatesFromPids(count,
+ const_cast<int32_t*>(pids.data()),
+ states.data());
+ if (err != OK) {
+ ALOGE("%s: IProcessInfoService::getProcessStatesFromPids failed with %d",
+ __func__, err);
+ return false;
+ }
+
+ existent->clear();
+ for (size_t index = 0; index < states.size(); index++) {
+ // If this process is not tracked by ActivityManagerService, look for overrides.
+ if (states[index] == PROCESS_STATE_NONEXISTENT) {
+ std::scoped_lock lock{mOverrideLock};
+ std::map<int, ProcessInfoOverride>::iterator it =
+ mOverrideMap.find(pids[index]);
+ if (it != mOverrideMap.end()) {
+ states[index] = it->second.procState;
+ }
+ }
+ existent->push_back(states[index] != PROCESS_STATE_NONEXISTENT);
+ }
+
+ return true;
+}
+
bool ProcessInfo::getPriority(int pid, int* priority) {
- sp<IBinder> binder = defaultServiceManager()->getService(String16("processinfo"));
+ sp<IBinder> binder = defaultServiceManager()->waitForService(String16("processinfo"));
sp<IProcessInfoService> service = interface_cast<IProcessInfoService>(binder);
size_t length = 1;
diff --git a/media/utils/include/mediautils/ProcessInfo.h b/media/utils/include/mediautils/ProcessInfo.h
index 9afa3df..c27c939 100644
--- a/media/utils/include/mediautils/ProcessInfo.h
+++ b/media/utils/include/mediautils/ProcessInfo.h
@@ -33,6 +33,8 @@
virtual bool isPidUidTrusted(int pid, int uid);
virtual bool overrideProcessInfo(int pid, int procState, int oomScore);
virtual void removeProcessInfoOverride(int pid);
+ bool checkProcessExistent(const std::vector<int32_t>& pids,
+ std::vector<bool>* existent) override;
protected:
virtual ~ProcessInfo();
diff --git a/media/utils/include/mediautils/ProcessInfoInterface.h b/media/utils/include/mediautils/ProcessInfoInterface.h
index b6529fc..e3384ba 100644
--- a/media/utils/include/mediautils/ProcessInfoInterface.h
+++ b/media/utils/include/mediautils/ProcessInfoInterface.h
@@ -17,16 +17,73 @@
#ifndef PROCESS_INFO_INTERFACE_H_
#define PROCESS_INFO_INTERFACE_H_
+#include <vector>
#include <utils/RefBase.h>
namespace android {
struct ProcessInfoInterface : public RefBase {
+ /*
+ * Gets the priority of the process (with given pid) as oom score.
+ *
+ * @param[in] pid pid of the process.
+ * @param[out] priority of the process.
+ *
+ * @return true for successful return and false otherwise.
+ */
virtual bool getPriority(int pid, int* priority) = 0;
+ /*
+ * Check whether the given pid is trusted or not.
+ *
+ * @param[in] pid pid of the process.
+ *
+ * @return true for trusted process and false otherwise.
+ */
virtual bool isPidTrusted(int pid) = 0;
+ /*
+ * Check whether the given pid and uid is trusted or not.
+ *
+ * @param[in] pid pid of the process.
+ * @param[in] uid uid of the process.
+ *
+ * @return true for trusted process and false otherwise.
+ */
virtual bool isPidUidTrusted(int pid, int uid) = 0;
+ /*
+ * Override process state and oom score of the pid.
+ *
+ * @param[in] pid pid of the process.
+ * @param[in] procState new state of the process to override with.
+ * @param[in] oomScore new oom score of the process to override with.
+ *
+ * @return true upon success and false otherwise.
+ */
virtual bool overrideProcessInfo(int pid, int procState, int oomScore) = 0;
+ /*
+ * Remove the override info of the given process.
+ *
+ * @param[in] pid pid of the process.
+ */
virtual void removeProcessInfoOverride(int pid) = 0;
+ /*
+ * Checks whether the list of processes with given pids exist or not.
+ *
+ * @param[in] pids List of pids for which to check whether they are Existent or not.
+ * @param[out] existent boolean vector corresponds to Existent state of each pids.
+ *
+ * @return true for successful return and false otherwise.
+ * On successful return:
+ * - existent[i] true corresponds to pids[i] still active and
+ * - existent[i] false corresponds to pids[i] already terminated (Nonexistent)
+ * On unsuccessful return, the output argument existent is invalid.
+ */
+ virtual bool checkProcessExistent(const std::vector<int32_t>& pids,
+ std::vector<bool>* existent) {
+ // A default implementation.
+ (void)pids;
+ (void)existent;
+ return false;
+ }
protected:
virtual ~ProcessInfoInterface() {}