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.
Merged-In: Ibaa1fb9607e486f2eb79bf02d79c630e09d62b4a
Change-Id: Ibaa1fb9607e486f2eb79bf02d79c630e09d62b4a
diff --git a/services/mediaresourcemanager/ResourceManagerMetrics.cpp b/services/mediaresourcemanager/ResourceManagerMetrics.cpp
new file mode 100644
index 0000000..b60e734
--- /dev/null
+++ b/services/mediaresourcemanager/ResourceManagerMetrics.cpp
@@ -0,0 +1,561 @@
+/*
+**
+** Copyright 2023, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "ResourceManagerMetrics"
+#include <utils/Log.h>
+#include <mediautils/ProcessInfo.h>
+
+#include <stats_media_metrics.h>
+
+#include "UidObserver.h"
+#include "ResourceManagerMetrics.h"
+
+#include <cmath>
+#include <sstream>
+
+namespace android {
+
+using stats::media_metrics::stats_write;
+using stats::media_metrics::MEDIA_CODEC_STARTED;
+using stats::media_metrics::MEDIA_CODEC_STOPPED;
+// Disabling this for now.
+#ifdef ENABLE_MEDIA_CODEC_CONCURRENT_USAGE_REPORTED
+using stats::media_metrics::MEDIA_CODEC_CONCURRENT_USAGE_REPORTED;
+#endif
+using stats::media_metrics::MEDIA_CODEC_RECLAIM_REQUEST_COMPLETED;
+using stats::media_metrics::MEDIA_CODEC_RECLAIM_REQUEST_COMPLETED__RECLAIM_STATUS__RECLAIM_SUCCESS;
+using stats::media_metrics::\
+ MEDIA_CODEC_RECLAIM_REQUEST_COMPLETED__RECLAIM_STATUS__RECLAIM_FAILED_NO_CLIENTS;
+using stats::media_metrics::\
+ MEDIA_CODEC_RECLAIM_REQUEST_COMPLETED__RECLAIM_STATUS__RECLAIM_FAILED_RECLAIM_RESOURCES;
+
+inline const char* getCodecType(MediaResourceSubType codecType) {
+ switch (codecType) {
+ case MediaResourceSubType::kAudioCodec: return "Audio";
+ case MediaResourceSubType::kVideoCodec: return "Video";
+ case MediaResourceSubType::kImageCodec: return "Image";
+ case MediaResourceSubType::kUnspecifiedSubType:
+ default:
+ return "Unspecified";
+ }
+ return "Unspecified";
+}
+
+static CodecBucket getCodecBucket(bool isHardware,
+ bool isEncoder,
+ MediaResourceSubType codecType) {
+ if (isHardware) {
+ switch (codecType) {
+ case MediaResourceSubType::kAudioCodec:
+ if (isEncoder) return HwAudioEncoder;
+ return HwAudioDecoder;
+ case MediaResourceSubType::kVideoCodec:
+ if (isEncoder) return HwVideoEncoder;
+ return HwVideoDecoder;
+ case MediaResourceSubType::kImageCodec:
+ if (isEncoder) return HwImageEncoder;
+ return HwImageDecoder;
+ case MediaResourceSubType::kUnspecifiedSubType:
+ default:
+ return CodecBucketUnspecified;
+ }
+ } else {
+ switch (codecType) {
+ case MediaResourceSubType::kAudioCodec:
+ if (isEncoder) return SwAudioEncoder;
+ return SwAudioDecoder;
+ case MediaResourceSubType::kVideoCodec:
+ if (isEncoder) return SwVideoEncoder;
+ return SwVideoDecoder;
+ case MediaResourceSubType::kImageCodec:
+ if (isEncoder) return SwImageEncoder;
+ return SwImageDecoder;
+ case MediaResourceSubType::kUnspecifiedSubType:
+ default:
+ return CodecBucketUnspecified;
+ }
+ }
+
+ return CodecBucketUnspecified;
+}
+
+static bool getLogMessage(int hwCount, int swCount, std::stringstream& logMsg) {
+ bool update = false;
+ logMsg.clear();
+
+ if (hwCount > 0) {
+ logMsg << " HW: " << hwCount;
+ update = true;
+ }
+ if (swCount > 0) {
+ logMsg << " SW: " << swCount;
+ update = true;
+ }
+
+ if (update) {
+ logMsg << " ] ";
+ }
+ return update;
+}
+
+ResourceManagerMetrics::ResourceManagerMetrics(const sp<ProcessInfoInterface>& processInfo) {
+ // Create a process termination watcher, with 5seconds of polling frequency.
+ mUidObserver = sp<UidObserver>::make(processInfo,
+ [this] (int32_t pid, uid_t uid) {
+ onProcessTerminated(pid, uid);
+ });
+ mUidObserver->start();
+}
+
+ResourceManagerMetrics::~ResourceManagerMetrics() {
+ mUidObserver->stop();
+}
+
+void ResourceManagerMetrics::addPid(int pid, uid_t uid) {
+ if (uid != 0) {
+ std::scoped_lock lock(mLock);
+ mUidObserver->add(pid, uid);
+ }
+}
+
+void ResourceManagerMetrics::notifyClientCreated(const ClientInfoParcel& clientInfo) {
+ std::scoped_lock lock(mLock);
+ // Update the resource instance count.
+ std::map<std::string, int>::iterator found = mConcurrentResourceCountMap.find(clientInfo.name);
+ if (found == mConcurrentResourceCountMap.end()) {
+ mConcurrentResourceCountMap[clientInfo.name] = 1;
+ } else {
+ found->second++;
+ }
+}
+
+void ResourceManagerMetrics::notifyClientReleased(const ClientInfoParcel& clientInfo) {
+ bool stopCalled = true;
+ ClientConfigMap::iterator found;
+ {
+ std::scoped_lock lock(mLock);
+ found = mClientConfigMap.find(clientInfo.id);
+ if (found != mClientConfigMap.end()) {
+ // Release is called without Stop!
+ stopCalled = false;
+ }
+ }
+ if (!stopCalled) {
+ // call Stop to update the metrics.
+ notifyClientStopped(found->second);
+ }
+ {
+ std::scoped_lock lock(mLock);
+ // Update the resource instance count also.
+ std::map<std::string, int>::iterator found =
+ mConcurrentResourceCountMap.find(clientInfo.name);
+ if (found != mConcurrentResourceCountMap.end()) {
+ if (found->second > 0) {
+ found->second--;
+ }
+ }
+ }
+}
+
+void ResourceManagerMetrics::notifyClientStarted(const ClientConfigParcel& clientConfig) {
+ std::scoped_lock lock(mLock);
+ int pid = clientConfig.clientInfo.pid;
+ // We need to observer this process.
+ mUidObserver->add(pid, clientConfig.clientInfo.uid);
+
+ // Update the client config for thic client.
+ mClientConfigMap[clientConfig.clientInfo.id] = clientConfig;
+
+ // Update the concurrent codec count for this process.
+ CodecBucket codecBucket = getCodecBucket(clientConfig.isHardware,
+ clientConfig.isEncoder,
+ clientConfig.codecType);
+ increaseConcurrentCodecs(pid, codecBucket);
+
+ if (clientConfig.codecType == MediaResourceSubType::kVideoCodec ||
+ clientConfig.codecType == MediaResourceSubType::kImageCodec) {
+ // Update the pixel count for this process
+ increasePixelCount(pid, clientConfig.width * (long)clientConfig.height);
+ }
+
+ // System concurrent codec usage
+ int systemConcurrentCodecCount = mConcurrentCodecsMap[codecBucket];
+ // Process/Application concurrent codec usage for this type of codec
+ int appConcurrentCodecCount = mProcessConcurrentCodecsMap[pid].mCurrent[codecBucket];
+ // Process/Application's current pixel count.
+ long pixelCount = 0;
+ std::map<int32_t, PixelCount>::iterator it = mProcessPixelsMap.find(pid);
+ if (it != mProcessPixelsMap.end()) {
+ pixelCount = it->second.mCurrent;
+ }
+
+ int result = stats_write(
+ MEDIA_CODEC_STARTED,
+ clientConfig.clientInfo.uid,
+ clientConfig.id,
+ clientConfig.clientInfo.name.c_str(),
+ static_cast<int32_t>(clientConfig.codecType),
+ clientConfig.isEncoder,
+ clientConfig.isHardware,
+ clientConfig.width, clientConfig.height,
+ systemConcurrentCodecCount,
+ appConcurrentCodecCount,
+ pixelCount);
+
+ ALOGV("%s: Pushed MEDIA_CODEC_STARTED atom: "
+ "Process[pid(%d): uid(%d)] "
+ "Codec: [%s: %ju] is %s %s %s "
+ "Timestamp: %jd "
+ "Resolution: %d x %d "
+ "ConcurrentCodec[%d]={System: %d App: %d} "
+ "result: %d",
+ __func__,
+ pid, clientConfig.clientInfo.uid,
+ clientConfig.clientInfo.name.c_str(),
+ clientConfig.id,
+ clientConfig.isHardware? "hardware" : "software",
+ getCodecType(clientConfig.codecType),
+ clientConfig.isEncoder? "encoder" : "decoder",
+ clientConfig.timeStamp,
+ clientConfig.width, clientConfig.height,
+ codecBucket, systemConcurrentCodecCount, appConcurrentCodecCount,
+ result);
+}
+
+void ResourceManagerMetrics::notifyClientStopped(const ClientConfigParcel& clientConfig) {
+ std::scoped_lock lock(mLock);
+ int pid = clientConfig.clientInfo.pid;
+ // Update the concurrent codec count for this process.
+ CodecBucket codecBucket = getCodecBucket(clientConfig.isHardware,
+ clientConfig.isEncoder,
+ clientConfig.codecType);
+ decreaseConcurrentCodecs(pid, codecBucket);
+
+ if (clientConfig.codecType == MediaResourceSubType::kVideoCodec ||
+ clientConfig.codecType == MediaResourceSubType::kImageCodec) {
+ // Update the pixel count for this process
+ decreasePixelCount(pid, clientConfig.width * (long)clientConfig.height);
+ }
+
+ // System concurrent codec usage
+ int systemConcurrentCodecCount = mConcurrentCodecsMap[codecBucket];
+ // Process/Application concurrent codec usage for this type of codec
+ int appConcurrentCodecCount = 0;
+ std::map<int32_t, ConcurrentCodecs>::iterator found = mProcessConcurrentCodecsMap.find(pid);
+ if (found != mProcessConcurrentCodecsMap.end()) {
+ appConcurrentCodecCount = found->second.mCurrent[codecBucket];
+ }
+ // Process/Application's current pixel count.
+ long pixelCount = 0;
+ std::map<int32_t, PixelCount>::iterator it = mProcessPixelsMap.find(pid);
+ if (it != mProcessPixelsMap.end()) {
+ pixelCount = it->second.mCurrent;
+ }
+
+ // calculate the usageTime as:
+ // MediaCodecStopped.clientConfig.timeStamp -
+ // MediaCodecStarted.clientConfig.timeStamp
+ int64_t usageTime = 0;
+ ClientConfigMap::iterator entry = mClientConfigMap.find(clientConfig.clientInfo.id);
+ if (entry != mClientConfigMap.end()) {
+ usageTime = clientConfig.timeStamp - entry->second.timeStamp;
+ // And we can erase this config now.
+ mClientConfigMap.erase(entry);
+ } else {
+ ALOGW("%s: Start Config is missing!", __func__);
+ }
+
+ int result = stats_write(
+ MEDIA_CODEC_STOPPED,
+ clientConfig.clientInfo.uid,
+ clientConfig.id,
+ clientConfig.clientInfo.name.c_str(),
+ static_cast<int32_t>(clientConfig.codecType),
+ clientConfig.isEncoder,
+ clientConfig.isHardware,
+ clientConfig.width, clientConfig.height,
+ systemConcurrentCodecCount,
+ appConcurrentCodecCount,
+ pixelCount,
+ usageTime);
+ ALOGV("%s: Pushed MEDIA_CODEC_STOPPED atom: "
+ "Process[pid(%d): uid(%d)] "
+ "Codec: [%s: %ju] is %s %s %s "
+ "Timestamp: %jd Usage time: %jd "
+ "Resolution: %d x %d "
+ "ConcurrentCodec[%d]={System: %d App: %d} "
+ "result: %d",
+ __func__,
+ pid, clientConfig.clientInfo.uid,
+ clientConfig.clientInfo.name.c_str(),
+ clientConfig.id,
+ clientConfig.isHardware? "hardware" : "software",
+ getCodecType(clientConfig.codecType),
+ clientConfig.isEncoder? "encoder" : "decoder",
+ clientConfig.timeStamp, usageTime,
+ clientConfig.width, clientConfig.height,
+ codecBucket, systemConcurrentCodecCount, appConcurrentCodecCount,
+ result);
+}
+
+void ResourceManagerMetrics::onProcessTerminated(int32_t pid, uid_t uid) {
+ std::scoped_lock lock(mLock);
+ // post MediaCodecConcurrentUsageReported for this terminated pid.
+ pushConcurrentUsageReport(pid, uid);
+}
+
+void ResourceManagerMetrics::pushConcurrentUsageReport(int32_t pid, uid_t uid) {
+ // Process/Application peak concurrent codec usage
+ std::map<int32_t, ConcurrentCodecs>::iterator found = mProcessConcurrentCodecsMap.find(pid);
+ if (found == mProcessConcurrentCodecsMap.end()) {
+ ALOGI("%s: No MEDIA_CODEC_CONCURRENT_USAGE_REPORTED atom Entry for: "
+ "Application[pid(%d): uid(%d)]", __func__, pid, uid);
+ return;
+ }
+ const ConcurrentCodecsMap& codecsMap = found->second.mPeak;
+ int peakHwAudioEncoderCount = codecsMap[HwAudioEncoder];
+ int peakHwAudioDecoderCount = codecsMap[HwAudioDecoder];
+ int peakHwVideoEncoderCount = codecsMap[HwVideoEncoder];
+ int peakHwVideoDecoderCount = codecsMap[HwVideoDecoder];
+ int peakHwImageEncoderCount = codecsMap[HwImageEncoder];
+ int peakHwImageDecoderCount = codecsMap[HwImageDecoder];
+ int peakSwAudioEncoderCount = codecsMap[SwAudioEncoder];
+ int peakSwAudioDecoderCount = codecsMap[SwAudioDecoder];
+ int peakSwVideoEncoderCount = codecsMap[SwVideoEncoder];
+ int peakSwVideoDecoderCount = codecsMap[SwVideoDecoder];
+ int peakSwImageEncoderCount = codecsMap[SwImageEncoder];
+ int peakSwImageDecoderCount = codecsMap[SwImageDecoder];
+
+ long peakPixels = 0;
+ std::map<int32_t, PixelCount>::iterator it = mProcessPixelsMap.find(pid);
+ if (it == mProcessPixelsMap.end()) {
+ ALOGI("%s: No Video Codec Entry for Application[pid(%d): uid(%d)]",
+ __func__, pid, uid);
+ } else {
+ peakPixels = it->second.mPeak;
+ }
+ std::string peakPixelsLog("Peak Pixels: " + std::to_string(peakPixels));
+
+ std::stringstream peakCodecLog;
+ peakCodecLog << "Peak { ";
+ std::stringstream logMsg;
+ if (getLogMessage(peakHwAudioEncoderCount, peakSwAudioEncoderCount, logMsg)) {
+ peakCodecLog << "AudioEnc[" << logMsg.str();
+ }
+ if (getLogMessage(peakHwAudioDecoderCount, peakSwAudioDecoderCount, logMsg)) {
+ peakCodecLog << "AudioDec[" << logMsg.str();
+ }
+ if (getLogMessage(peakHwVideoEncoderCount, peakSwVideoEncoderCount, logMsg)) {
+ peakCodecLog << "VideoEnc[" << logMsg.str();
+ }
+ if (getLogMessage(peakHwVideoDecoderCount, peakSwVideoDecoderCount, logMsg)) {
+ peakCodecLog << "VideoDec[" << logMsg.str();
+ }
+ if (getLogMessage(peakHwImageEncoderCount, peakSwImageEncoderCount, logMsg)) {
+ peakCodecLog << "ImageEnc[" << logMsg.str();
+ }
+ if (getLogMessage(peakHwImageDecoderCount, peakSwImageDecoderCount, logMsg)) {
+ peakCodecLog << "ImageDec[" << logMsg.str();
+ }
+ peakCodecLog << "}";
+
+#ifdef ENABLE_MEDIA_CODEC_CONCURRENT_USAGE_REPORTED
+ int result = stats_write(
+ MEDIA_CODEC_CONCURRENT_USAGE_REPORTED,
+ uid,
+ peakHwVideoDecoderCount,
+ peakHwVideoEncoderCount,
+ peakSwVideoDecoderCount,
+ peakSwVideoEncoderCount,
+ peakHwAudioDecoderCount,
+ peakHwAudioEncoderCount,
+ peakSwAudioDecoderCount,
+ peakSwAudioEncoderCount,
+ peakHwImageDecoderCount,
+ peakHwImageEncoderCount,
+ peakSwImageDecoderCount,
+ peakSwImageEncoderCount,
+ peakPixels);
+ ALOGI("%s: Pushed MEDIA_CODEC_CONCURRENT_USAGE_REPORTED atom: "
+ "Process[pid(%d): uid(%d)] %s %s result: %d",
+ __func__, pid, uid, peakCodecLog.str().c_str(), peakPixelsLog.c_str(), result);
+#else
+ ALOGI("%s: Concurrent Codec Usage Report for the Process[pid(%d): uid(%d)] is %s %s",
+ __func__, pid, uid, peakCodecLog.str().c_str(), peakPixelsLog.c_str());
+#endif
+}
+
+void ResourceManagerMetrics::pushReclaimAtom(const ClientInfoParcel& clientInfo,
+ const std::vector<int>& priorities,
+ const Vector<std::shared_ptr<IResourceManagerClient>>& clients,
+ const PidUidVector& idList, bool reclaimed) {
+ // Construct the metrics for codec reclaim as a pushed atom.
+ // 1. Information about the requester.
+ // - UID and the priority (oom score)
+ int32_t callingPid = clientInfo.pid;
+ int32_t requesterUid = clientInfo.uid;
+ std::string clientName = clientInfo.name;
+ int requesterPriority = priorities[0];
+
+ // 2. Information about the codec.
+ // - Name of the codec requested
+ // - Number of concurrent codecs running.
+ int32_t noOfConcurrentCodecs = 0;
+ std::map<std::string, int>::iterator found = mConcurrentResourceCountMap.find(clientName);
+ if (found != mConcurrentResourceCountMap.end()) {
+ noOfConcurrentCodecs = found->second;
+ }
+
+ // 3. Information about the Reclaim:
+ // - Status of reclaim request
+ // - How many codecs are reclaimed
+ // - For each codecs reclaimed, information of the process that it belonged to:
+ // - UID and the Priority (oom score)
+ int32_t reclaimStatus = MEDIA_CODEC_RECLAIM_REQUEST_COMPLETED__RECLAIM_STATUS__RECLAIM_SUCCESS;
+ if (!reclaimed) {
+ if (clients.size() == 0) {
+ // No clients to reclaim from
+ reclaimStatus =
+ MEDIA_CODEC_RECLAIM_REQUEST_COMPLETED__RECLAIM_STATUS__RECLAIM_FAILED_NO_CLIENTS;
+ } else {
+ // Couldn't reclaim resources from the clients
+ reclaimStatus =
+ MEDIA_CODEC_RECLAIM_REQUEST_COMPLETED__RECLAIM_STATUS__RECLAIM_FAILED_RECLAIM_RESOURCES;
+ }
+ }
+ int32_t noOfCodecsReclaimed = clients.size();
+ int32_t targetIndex = 1;
+ for (PidUidVector::const_reference id : idList) {
+ int32_t targetUid = id.second;
+ int targetPriority = priorities[targetIndex];
+ // Post the pushed atom
+ int result = stats_write(
+ MEDIA_CODEC_RECLAIM_REQUEST_COMPLETED,
+ requesterUid,
+ requesterPriority,
+ clientName.c_str(),
+ noOfConcurrentCodecs,
+ reclaimStatus,
+ noOfCodecsReclaimed,
+ targetIndex,
+ targetUid,
+ targetPriority);
+ ALOGI("%s: Pushed MEDIA_CODEC_RECLAIM_REQUEST_COMPLETED atom: "
+ "Requester[pid(%d): uid(%d): priority(%d)] "
+ "Codec: [%s] "
+ "No of concurrent codecs: %d "
+ "Reclaim Status: %d "
+ "No of codecs reclaimed: %d "
+ "Target[%d][pid(%d): uid(%d): priority(%d)] result: %d",
+ __func__, callingPid, requesterUid, requesterPriority,
+ clientName.c_str(), noOfConcurrentCodecs,
+ reclaimStatus, noOfCodecsReclaimed,
+ targetIndex, id.first, targetUid, targetPriority, result);
+ targetIndex++;
+ }
+}
+
+void ResourceManagerMetrics::increaseConcurrentCodecs(int32_t pid,
+ CodecBucket codecBucket) {
+ // Increase the codec usage across the system.
+ mConcurrentCodecsMap[codecBucket]++;
+
+ // Now update the codec usage for this (pid) process.
+ std::map<int32_t, ConcurrentCodecs>::iterator found = mProcessConcurrentCodecsMap.find(pid);
+ if (found == mProcessConcurrentCodecsMap.end()) {
+ ConcurrentCodecs codecs;
+ codecs.mCurrent[codecBucket] = 1;
+ codecs.mPeak[codecBucket] = 1;
+ mProcessConcurrentCodecsMap.emplace(pid, codecs);
+ } else {
+ found->second.mCurrent[codecBucket]++;
+ // Check if it's the peak count for this slot.
+ if (found->second.mPeak[codecBucket] < found->second.mCurrent[codecBucket]) {
+ found->second.mPeak[codecBucket] = found->second.mCurrent[codecBucket];
+ }
+ }
+}
+
+void ResourceManagerMetrics::decreaseConcurrentCodecs(int32_t pid,
+ CodecBucket codecBucket) {
+ // Decrease the codec usage across the system.
+ if (mConcurrentCodecsMap[codecBucket] > 0) {
+ mConcurrentCodecsMap[codecBucket]--;
+ }
+
+ // Now update the codec usage for this (pid) process.
+ std::map<int32_t, ConcurrentCodecs>::iterator found = mProcessConcurrentCodecsMap.find(pid);
+ if (found != mProcessConcurrentCodecsMap.end()) {
+ if (found->second.mCurrent[codecBucket] > 0) {
+ found->second.mCurrent[codecBucket]--;
+ }
+ }
+}
+
+void ResourceManagerMetrics::increasePixelCount(int32_t pid, long pixels) {
+ // Now update the current pixel usage for this (pid) process.
+ std::map<int32_t, PixelCount>::iterator found = mProcessPixelsMap.find(pid);
+ if (found == mProcessPixelsMap.end()) {
+ PixelCount pixelCount {pixels, pixels};
+ mProcessPixelsMap.emplace(pid, pixelCount);
+ } else {
+ if (__builtin_add_overflow(found->second.mCurrent, pixels, &found->second.mCurrent)) {
+ ALOGI("Pixel Count overflow");
+ return;
+ }
+ // Check if it's the peak count for this slot.
+ if (found->second.mPeak < found->second.mCurrent) {
+ found->second.mPeak = found->second.mCurrent;
+ }
+ }
+}
+
+void ResourceManagerMetrics::decreasePixelCount(int32_t pid, long pixels) {
+ // Now update the current pixel usage for this (pid) process.
+ std::map<int32_t, PixelCount>::iterator found = mProcessPixelsMap.find(pid);
+ if (found != mProcessPixelsMap.end()) {
+ if (found->second.mCurrent < pixels) {
+ found->second.mCurrent = 0;
+ } else {
+ if (__builtin_sub_overflow(found->second.mCurrent, pixels, &found->second.mCurrent)) {
+ ALOGI("Pixel Count overflow");
+ return;
+ }
+ }
+ }
+}
+
+long ResourceManagerMetrics::getPeakConcurrentPixelCount(int pid) const {
+ std::map<int32_t, PixelCount>::const_iterator found = mProcessPixelsMap.find(pid);
+ if (found != mProcessPixelsMap.end()) {
+ return found->second.mPeak;
+ }
+
+ return 0;
+}
+
+long ResourceManagerMetrics::getCurrentConcurrentPixelCount(int pid) const {
+ std::map<int32_t, PixelCount>::const_iterator found = mProcessPixelsMap.find(pid);
+ if (found != mProcessPixelsMap.end()) {
+ return found->second.mCurrent;
+ }
+
+ return 0;
+}
+
+} // namespace android