1 /*
2 **
3 ** Copyright 2023, The Android Open Source Project
4 **
5 ** Licensed under the Apache License, Version 2.0 (the "License");
6 ** you may not use this file except in compliance with the License.
7 ** You may obtain a copy of the License at
8 **
9 **     http://www.apache.org/licenses/LICENSE-2.0
10 **
11 ** Unless required by applicable law or agreed to in writing, software
12 ** distributed under the License is distributed on an "AS IS" BASIS,
13 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 ** See the License for the specific language governing permissions and
15 ** limitations under the License.
16 */
17 
18 //#define LOG_NDEBUG 0
19 #define LOG_TAG "ResourceManagerMetrics"
20 #include <utils/Log.h>
21 #include <mediautils/ProcessInfo.h>
22 
23 #include <stats_media_metrics.h>
24 
25 #include "UidObserver.h"
26 #include "ResourceManagerMetrics.h"
27 
28 #include <cmath>
29 #include <sstream>
30 
31 namespace android {
32 
33 using stats::media_metrics::stats_write;
34 using stats::media_metrics::MEDIA_CODEC_STARTED;
35 using stats::media_metrics::MEDIA_CODEC_STOPPED;
36 // Disabling this for now.
37 #ifdef ENABLE_MEDIA_CODEC_CONCURRENT_USAGE_REPORTED
38 using stats::media_metrics::MEDIA_CODEC_CONCURRENT_USAGE_REPORTED;
39 #endif
40 using stats::media_metrics::MEDIA_CODEC_RECLAIM_REQUEST_COMPLETED;
41 using stats::media_metrics::MEDIA_CODEC_RECLAIM_REQUEST_COMPLETED__RECLAIM_STATUS__RECLAIM_SUCCESS;
42 using stats::media_metrics::\
43     MEDIA_CODEC_RECLAIM_REQUEST_COMPLETED__RECLAIM_STATUS__RECLAIM_FAILED_NO_CLIENTS;
44 using stats::media_metrics::\
45     MEDIA_CODEC_RECLAIM_REQUEST_COMPLETED__RECLAIM_STATUS__RECLAIM_FAILED_RECLAIM_RESOURCES;
46 using stats::media_metrics::MEDIA_CODEC_STARTED__CODEC_TYPE__CODEC_TYPE_UNSPECIFIED;
47 using stats::media_metrics::MEDIA_CODEC_STARTED__CODEC_TYPE__CODEC_TYPE_AUDIO;
48 using stats::media_metrics::MEDIA_CODEC_STARTED__CODEC_TYPE__CODEC_TYPE_VIDEO;
49 using stats::media_metrics::MEDIA_CODEC_STARTED__CODEC_TYPE__CODEC_TYPE_IMAGE;
50 
51 // Map MediaResourceSubType to stats::media_metrics::CodecType
getMetricsCodecType(MediaResourceSubType codecType)52 inline int32_t getMetricsCodecType(MediaResourceSubType codecType) {
53     switch (codecType) {
54         case MediaResourceSubType::kHwAudioCodec:
55         case MediaResourceSubType::kSwAudioCodec:
56             return MEDIA_CODEC_STARTED__CODEC_TYPE__CODEC_TYPE_AUDIO;
57         case MediaResourceSubType::kHwVideoCodec:
58         case MediaResourceSubType::kSwVideoCodec:
59             return MEDIA_CODEC_STARTED__CODEC_TYPE__CODEC_TYPE_VIDEO;
60         case MediaResourceSubType::kHwImageCodec:
61         case MediaResourceSubType::kSwImageCodec:
62             return MEDIA_CODEC_STARTED__CODEC_TYPE__CODEC_TYPE_IMAGE;
63         case MediaResourceSubType::kUnspecifiedSubType:
64             return MEDIA_CODEC_STARTED__CODEC_TYPE__CODEC_TYPE_UNSPECIFIED;
65     }
66     return MEDIA_CODEC_STARTED__CODEC_TYPE__CODEC_TYPE_UNSPECIFIED;
67 }
68 
getCodecType(MediaResourceSubType codecType)69 inline const char* getCodecType(MediaResourceSubType codecType) {
70     switch (codecType) {
71         case MediaResourceSubType::kHwAudioCodec:       return "Hw Audio";
72         case MediaResourceSubType::kSwAudioCodec:       return "Sw Audio";
73         case MediaResourceSubType::kHwVideoCodec:       return "Hw Video";
74         case MediaResourceSubType::kSwVideoCodec:       return "Sw Video";
75         case MediaResourceSubType::kHwImageCodec:       return "Hw Image";
76         case MediaResourceSubType::kSwImageCodec:       return "Sw Image";
77         case MediaResourceSubType::kUnspecifiedSubType:
78         default:
79                                                         return "Unspecified";
80     }
81     return "Unspecified";
82 }
83 
isHardwareCodec(MediaResourceSubType codecType)84 inline bool isHardwareCodec(MediaResourceSubType codecType) {
85     return (codecType == MediaResourceSubType::kHwAudioCodec ||
86             codecType == MediaResourceSubType::kHwVideoCodec ||
87             codecType == MediaResourceSubType::kHwImageCodec);
88 }
89 
getCodecBucket(bool isEncoder,MediaResourceSubType codecType)90 static CodecBucket getCodecBucket(bool isEncoder, MediaResourceSubType codecType) {
91     switch (codecType) {
92     case MediaResourceSubType::kHwAudioCodec:
93         return isEncoder? HwAudioEncoder : HwAudioDecoder;
94     case MediaResourceSubType::kSwAudioCodec:
95         return isEncoder? SwAudioEncoder : SwAudioDecoder;
96     case MediaResourceSubType::kHwVideoCodec:
97         return isEncoder? HwVideoEncoder : HwVideoDecoder;
98     case MediaResourceSubType::kSwVideoCodec:
99         return isEncoder? SwVideoEncoder : SwVideoDecoder;
100     case MediaResourceSubType::kHwImageCodec:
101         return isEncoder? HwImageEncoder : HwImageDecoder;
102     case MediaResourceSubType::kSwImageCodec:
103         return isEncoder? SwImageEncoder : SwImageDecoder;
104     case MediaResourceSubType::kUnspecifiedSubType:
105     default:
106         return CodecBucketUnspecified;
107     }
108 
109     return CodecBucketUnspecified;
110 }
111 
getLogMessage(const std::string & firstKey,const long & firstValue,const std::string & secondKey,const long & secondValue)112 static std::string getLogMessage(const std::string& firstKey, const long& firstValue,
113                                  const std::string& secondKey, const long& secondValue) {
114 
115     std::stringstream logMsg;
116     if (firstValue > 0) {
117         logMsg << firstKey << firstValue;
118     }
119     if (secondValue > 0) {
120         logMsg << secondKey << secondValue;
121     }
122     return logMsg.str();
123 }
124 
ResourceManagerMetrics(const sp<ProcessInfoInterface> & processInfo)125 ResourceManagerMetrics::ResourceManagerMetrics(const sp<ProcessInfoInterface>& processInfo) {
126     // Create a process termination watcher, with 5seconds of polling frequency.
127     mUidObserver = sp<UidObserver>::make(processInfo,
128         [this] (int32_t pid, uid_t uid) {
129             onProcessTerminated(pid, uid);
130         });
131     mUidObserver->start();
132 }
133 
~ResourceManagerMetrics()134 ResourceManagerMetrics::~ResourceManagerMetrics() {
135     mUidObserver->stop();
136 }
137 
addPid(int pid,uid_t uid)138 void ResourceManagerMetrics::addPid(int pid, uid_t uid) {
139     if (uid != 0) {
140         std::scoped_lock lock(mLock);
141         mUidObserver->add(pid, uid);
142     }
143 }
144 
notifyClientCreated(const ClientInfoParcel & clientInfo)145 void ResourceManagerMetrics::notifyClientCreated(const ClientInfoParcel& clientInfo) {
146     std::scoped_lock lock(mLock);
147     // Update the resource instance count.
148     std::map<std::string, int>::iterator found = mConcurrentResourceCountMap.find(clientInfo.name);
149     if (found == mConcurrentResourceCountMap.end()) {
150         mConcurrentResourceCountMap[clientInfo.name] = 1;
151     } else {
152         found->second++;
153     }
154 }
155 
notifyClientReleased(const ClientInfoParcel & clientInfo)156 void ResourceManagerMetrics::notifyClientReleased(const ClientInfoParcel& clientInfo) {
157     bool stopCalled = true;
158     ClientConfigParcel clientConfig;
159     {
160         std::scoped_lock lock(mLock);
161         ClientConfigMap::iterator found = mClientConfigMap.find(clientInfo.id);
162         if (found != mClientConfigMap.end()) {
163             // Release is called without Stop!
164             stopCalled = false;
165             clientConfig = found->second;
166             // Update the timestamp for stopping the codec.
167             clientConfig.timeStamp = systemTime(SYSTEM_TIME_MONOTONIC) / 1000LL;
168         }
169     }
170     if (!stopCalled) {
171         // call Stop to update the metrics.
172         notifyClientStopped(clientConfig);
173     }
174     {
175         std::scoped_lock lock(mLock);
176         // Update the resource instance count also.
177         std::map<std::string, int>::iterator found =
178             mConcurrentResourceCountMap.find(clientInfo.name);
179         if (found != mConcurrentResourceCountMap.end()) {
180             if (found->second > 0) {
181                 found->second--;
182             }
183         }
184     }
185 }
186 
notifyClientConfigChanged(const ClientConfigParcel & clientConfig)187 void ResourceManagerMetrics::notifyClientConfigChanged(const ClientConfigParcel& clientConfig) {
188     std::scoped_lock lock(mLock);
189     ClientConfigMap::iterator entry = mClientConfigMap.find(clientConfig.clientInfo.id);
190     if (entry != mClientConfigMap.end() &&
191         (clientConfig.codecType == MediaResourceSubType::kHwVideoCodec ||
192          clientConfig.codecType == MediaResourceSubType::kSwVideoCodec ||
193          clientConfig.codecType == MediaResourceSubType::kHwImageCodec ||
194          clientConfig.codecType == MediaResourceSubType::kSwImageCodec)) {
195         int pid = clientConfig.clientInfo.pid;
196         // Update the pixel count for this process
197         updatePixelCount(pid, clientConfig.width * (long)clientConfig.height,
198                          entry->second.width * (long)entry->second.height);
199         // Update the resolution in the record.
200         entry->second.width = clientConfig.width;
201         entry->second.height = clientConfig.height;
202     }
203 }
204 
notifyClientStarted(const ClientConfigParcel & clientConfig)205 void ResourceManagerMetrics::notifyClientStarted(const ClientConfigParcel& clientConfig) {
206     std::scoped_lock lock(mLock);
207     int pid = clientConfig.clientInfo.pid;
208     // We need to observer this process.
209     mUidObserver->add(pid, clientConfig.clientInfo.uid);
210 
211     // Update the client config for thic client.
212     mClientConfigMap[clientConfig.clientInfo.id] = clientConfig;
213 
214     // Update the concurrent codec count for this process.
215     CodecBucket codecBucket = getCodecBucket(clientConfig.isEncoder, clientConfig.codecType);
216     increaseConcurrentCodecs(pid, codecBucket);
217 
218     if (clientConfig.codecType == MediaResourceSubType::kHwVideoCodec ||
219         clientConfig.codecType == MediaResourceSubType::kSwVideoCodec ||
220         clientConfig.codecType == MediaResourceSubType::kHwImageCodec ||
221         clientConfig.codecType == MediaResourceSubType::kSwImageCodec) {
222         // Update the pixel count for this process
223         increasePixelCount(pid, clientConfig.width * (long)clientConfig.height);
224     }
225 
226     // System concurrent codec usage
227     int systemConcurrentCodecs = mConcurrentCodecsMap[codecBucket];
228     // Process/Application concurrent codec usage for this type of codec
229     const ConcurrentCodecs& concurrentCodecs = mProcessConcurrentCodecsMap[pid];
230     int appConcurrentCodecs = concurrentCodecs.mCurrent[codecBucket];
231     int hwVideoCodecs = concurrentCodecs.mHWVideoCodecs;
232     int swVideoCodecs = concurrentCodecs.mSWVideoCodecs;
233     int videoCodecs = concurrentCodecs.mVideoCodecs;
234     int audioCodecs = concurrentCodecs.mAudioCodecs;
235     int imageCodecs = concurrentCodecs.mImageCodecs;
236     // Process/Application's current pixel count.
237     long pixelCount = 0;
238     std::map<int32_t, PixelCount>::iterator it = mProcessPixelsMap.find(pid);
239     if (it != mProcessPixelsMap.end()) {
240         pixelCount = it->second.mCurrent;
241     }
242 
243     int result = stats_write(
244          MEDIA_CODEC_STARTED,
245          clientConfig.clientInfo.uid,
246          clientConfig.id,
247          clientConfig.clientInfo.name.c_str(),
248          getMetricsCodecType(clientConfig.codecType),
249          clientConfig.isEncoder,
250          isHardwareCodec(clientConfig.codecType),
251          clientConfig.width, clientConfig.height,
252          systemConcurrentCodecs,
253          appConcurrentCodecs,
254          pixelCount,
255          hwVideoCodecs,
256          swVideoCodecs,
257          videoCodecs,
258          audioCodecs,
259          imageCodecs);
260 
261     ALOGV("%s: Pushed MEDIA_CODEC_STARTED atom: "
262           "Process[pid(%d): uid(%d)] "
263           "Codec: [%s: %ju] is %s %s "
264           "Timestamp: %jd "
265           "Resolution: %d x %d "
266           "ConcurrentCodec[%d]={System: %d App: %d} "
267           "AppConcurrentCodecs{Video: %d(HW[%d] SW[%d]) Audio: %d Image: %d} "
268           "result: %d",
269           __func__,
270           pid, clientConfig.clientInfo.uid,
271           clientConfig.clientInfo.name.c_str(),
272           clientConfig.id,
273           getCodecType(clientConfig.codecType),
274           clientConfig.isEncoder? "encoder" : "decoder",
275           clientConfig.timeStamp,
276           clientConfig.width, clientConfig.height,
277           codecBucket, systemConcurrentCodecs, appConcurrentCodecs,
278           videoCodecs, hwVideoCodecs, swVideoCodecs, audioCodecs, imageCodecs,
279           result);
280 }
281 
notifyClientStopped(const ClientConfigParcel & clientConfig)282 void ResourceManagerMetrics::notifyClientStopped(const ClientConfigParcel& clientConfig) {
283     std::scoped_lock lock(mLock);
284     int pid = clientConfig.clientInfo.pid;
285     // Update the concurrent codec count for this process.
286     CodecBucket codecBucket = getCodecBucket(clientConfig.isEncoder, clientConfig.codecType);
287     decreaseConcurrentCodecs(pid, codecBucket);
288 
289     if (clientConfig.codecType == MediaResourceSubType::kHwVideoCodec ||
290         clientConfig.codecType == MediaResourceSubType::kSwVideoCodec ||
291         clientConfig.codecType == MediaResourceSubType::kHwImageCodec ||
292         clientConfig.codecType == MediaResourceSubType::kSwImageCodec) {
293         // Update the pixel count for this process
294         decreasePixelCount(pid, clientConfig.width * (long)clientConfig.height);
295     }
296 
297     // System concurrent codec usage
298     int systemConcurrentCodecs = mConcurrentCodecsMap[codecBucket];
299     // Process/Application concurrent codec usage for this type of codec
300     int appConcurrentCodecs = 0;
301     std::map<int32_t, ConcurrentCodecs>::iterator found = mProcessConcurrentCodecsMap.find(pid);
302     if (found != mProcessConcurrentCodecsMap.end()) {
303         appConcurrentCodecs = found->second.mCurrent[codecBucket];
304     }
305     // Process/Application's current pixel count.
306     long pixelCount = 0;
307     std::map<int32_t, PixelCount>::iterator it = mProcessPixelsMap.find(pid);
308     if (it != mProcessPixelsMap.end()) {
309         pixelCount = it->second.mCurrent;
310     }
311 
312     // calculate the usageTime as:
313     //  MediaCodecStopped.clientConfig.timeStamp -
314     //  MediaCodecStarted.clientConfig.timeStamp
315     int64_t usageTime = 0;
316     ClientConfigMap::iterator entry = mClientConfigMap.find(clientConfig.clientInfo.id);
317     if (entry != mClientConfigMap.end()) {
318         usageTime = clientConfig.timeStamp - entry->second.timeStamp;
319         // And we can erase this config now.
320         mClientConfigMap.erase(entry);
321     } else {
322         ALOGW("%s: Start Config is missing!", __func__);
323     }
324 
325      int result = stats_write(
326          MEDIA_CODEC_STOPPED,
327          clientConfig.clientInfo.uid,
328          clientConfig.id,
329          clientConfig.clientInfo.name.c_str(),
330          getMetricsCodecType(clientConfig.codecType),
331          clientConfig.isEncoder,
332          isHardwareCodec(clientConfig.codecType),
333          clientConfig.width, clientConfig.height,
334          systemConcurrentCodecs,
335          appConcurrentCodecs,
336          pixelCount,
337          usageTime);
338     ALOGV("%s: Pushed MEDIA_CODEC_STOPPED atom: "
339           "Process[pid(%d): uid(%d)] "
340           "Codec: [%s: %ju] is %s %s "
341           "Timestamp: %jd Usage time: %jd "
342           "Resolution: %d x %d "
343           "ConcurrentCodec[%d]={System: %d App: %d} "
344           "result: %d",
345           __func__,
346           pid, clientConfig.clientInfo.uid,
347           clientConfig.clientInfo.name.c_str(),
348           clientConfig.id,
349           getCodecType(clientConfig.codecType),
350           clientConfig.isEncoder? "encoder" : "decoder",
351           clientConfig.timeStamp, usageTime,
352           clientConfig.width, clientConfig.height,
353           codecBucket, systemConcurrentCodecs, appConcurrentCodecs,
354           result);
355 }
356 
onProcessTerminated(int32_t pid,uid_t uid)357 void ResourceManagerMetrics::onProcessTerminated(int32_t pid, uid_t uid) {
358     std::scoped_lock lock(mLock);
359     // post MediaCodecConcurrentUsageReported for this terminated pid.
360     pushConcurrentUsageReport(pid, uid);
361     // Remove all the metrics associated with this process.
362     std::map<int32_t, ConcurrentCodecs>::iterator it1 = mProcessConcurrentCodecsMap.find(pid);
363     if (it1 != mProcessConcurrentCodecsMap.end()) {
364         mProcessConcurrentCodecsMap.erase(it1);
365     }
366     std::map<int32_t, PixelCount>::iterator it2 = mProcessPixelsMap.find(pid);
367     if (it2 != mProcessPixelsMap.end()) {
368         mProcessPixelsMap.erase(it2);
369     }
370 }
371 
pushConcurrentUsageReport(int32_t pid,uid_t uid)372 void ResourceManagerMetrics::pushConcurrentUsageReport(int32_t pid, uid_t uid) {
373     // Process/Application peak concurrent codec usage
374     std::map<int32_t, ConcurrentCodecs>::iterator found = mProcessConcurrentCodecsMap.find(pid);
375     if (found == mProcessConcurrentCodecsMap.end()) {
376         ALOGI("%s: No MEDIA_CODEC_CONCURRENT_USAGE_REPORTED atom Entry for: "
377               "Application[pid(%d): uid(%d)]", __func__, pid, uid);
378         return;
379     }
380     const ConcurrentCodecsMap& codecsMap = found->second.mPeak;
381     int peakHwAudioEncoderCount = codecsMap[HwAudioEncoder];
382     int peakHwAudioDecoderCount = codecsMap[HwAudioDecoder];
383     int peakHwVideoEncoderCount = codecsMap[HwVideoEncoder];
384     int peakHwVideoDecoderCount = codecsMap[HwVideoDecoder];
385     int peakHwImageEncoderCount = codecsMap[HwImageEncoder];
386     int peakHwImageDecoderCount = codecsMap[HwImageDecoder];
387     int peakSwAudioEncoderCount = codecsMap[SwAudioEncoder];
388     int peakSwAudioDecoderCount = codecsMap[SwAudioDecoder];
389     int peakSwVideoEncoderCount = codecsMap[SwVideoEncoder];
390     int peakSwVideoDecoderCount = codecsMap[SwVideoDecoder];
391     int peakSwImageEncoderCount = codecsMap[SwImageEncoder];
392     int peakSwImageDecoderCount = codecsMap[SwImageDecoder];
393 
394     long peakPixels = 0;
395     std::map<int32_t, PixelCount>::iterator it = mProcessPixelsMap.find(pid);
396     if (it == mProcessPixelsMap.end()) {
397         ALOGI("%s: No Video Codec Entry for Application[pid(%d): uid(%d)]",
398               __func__, pid, uid);
399     } else {
400         peakPixels = it->second.mPeak;
401     }
402     std::string peakPixelsLog("Peak Pixels: " + std::to_string(peakPixels));
403 
404     std::stringstream peakCodecLog;
405     peakCodecLog << "Peak { ";
406     std::string logMsg;
407     logMsg = getLogMessage(" HW: ", peakHwAudioEncoderCount, " SW: ", peakSwAudioEncoderCount);
408     if (!logMsg.empty()) {
409         peakCodecLog << "AudioEnc[ " << logMsg << " ] ";
410     }
411     logMsg = getLogMessage(" HW: ", peakHwAudioDecoderCount, " SW: ", peakSwAudioDecoderCount);
412     if (!logMsg.empty()) {
413         peakCodecLog << "AudioDec[" << logMsg << " ] ";
414     }
415     logMsg = getLogMessage(" HW: ", peakHwVideoEncoderCount, " SW: ", peakSwVideoEncoderCount);
416     if (!logMsg.empty()) {
417         peakCodecLog << "VideoEnc[" << logMsg << " ] ";
418     }
419     logMsg = getLogMessage(" HW: ", peakHwVideoDecoderCount, " SW: ", peakSwVideoDecoderCount);
420     if (!logMsg.empty()) {
421         peakCodecLog << "VideoDec[" << logMsg << " ] ";
422     }
423     logMsg = getLogMessage(" HW: ", peakHwImageEncoderCount, " SW: ", peakSwImageEncoderCount);
424     if (!logMsg.empty()) {
425         peakCodecLog << "ImageEnc[" << logMsg << " ] ";
426     }
427     logMsg = getLogMessage(" HW: ", peakHwImageDecoderCount, " SW: ", peakSwImageDecoderCount);
428     if (!logMsg.empty()) {
429         peakCodecLog << "ImageDec[" << logMsg << " ] ";
430     }
431     peakCodecLog << "}";
432 
433 #ifdef ENABLE_MEDIA_CODEC_CONCURRENT_USAGE_REPORTED
434     int result = stats_write(
435         MEDIA_CODEC_CONCURRENT_USAGE_REPORTED,
436         uid,
437         peakHwVideoDecoderCount,
438         peakHwVideoEncoderCount,
439         peakSwVideoDecoderCount,
440         peakSwVideoEncoderCount,
441         peakHwAudioDecoderCount,
442         peakHwAudioEncoderCount,
443         peakSwAudioDecoderCount,
444         peakSwAudioEncoderCount,
445         peakHwImageDecoderCount,
446         peakHwImageEncoderCount,
447         peakSwImageDecoderCount,
448         peakSwImageEncoderCount,
449         peakPixels);
450     ALOGI("%s: Pushed MEDIA_CODEC_CONCURRENT_USAGE_REPORTED atom: "
451           "Process[pid(%d): uid(%d)] %s %s result: %d",
452           __func__, pid, uid, peakCodecLog.str().c_str(), peakPixelsLog.c_str(), result);
453 #else
454     ALOGI("%s: Concurrent Codec Usage Report for the Process[pid(%d): uid(%d)] is %s %s",
455           __func__, pid, uid, peakCodecLog.str().c_str(), peakPixelsLog.c_str());
456 #endif
457 }
458 
pushReclaimStats(int32_t callingPid,int32_t requesterUid,int requesterPriority,const std::string & clientName,int32_t noOfConcurrentCodecs,int32_t reclaimStatus,int32_t noOfCodecsReclaimed=0,int32_t targetIndex=-1,int32_t targetClientPid=-1,int32_t targetClientUid=-1,int32_t targetPriority=-1)459 inline void pushReclaimStats(int32_t callingPid,
460                              int32_t requesterUid,
461                              int requesterPriority,
462                              const std::string& clientName,
463                              int32_t noOfConcurrentCodecs,
464                              int32_t reclaimStatus,
465                              int32_t noOfCodecsReclaimed = 0,
466                              int32_t targetIndex = -1,
467                              int32_t targetClientPid = -1,
468                              int32_t targetClientUid = -1,
469                              int32_t targetPriority = -1) {
470     // Post the pushed atom
471     int result = stats_write(
472         MEDIA_CODEC_RECLAIM_REQUEST_COMPLETED,
473         requesterUid,
474         requesterPriority,
475         clientName.c_str(),
476         noOfConcurrentCodecs,
477         reclaimStatus,
478         noOfCodecsReclaimed,
479         targetIndex,
480         targetClientUid,
481         targetPriority);
482     ALOGI("%s: Pushed MEDIA_CODEC_RECLAIM_REQUEST_COMPLETED atom: "
483           "Requester[pid(%d): uid(%d): priority(%d)] "
484           "Codec: [%s] "
485           "No of concurrent codecs: %d "
486           "Reclaim Status: %d "
487           "No of codecs reclaimed: %d "
488           "Target[%d][pid(%d): uid(%d): priority(%d)] result: %d",
489           __func__, callingPid, requesterUid, requesterPriority,
490               clientName.c_str(), noOfConcurrentCodecs,
491           reclaimStatus, noOfCodecsReclaimed,
492           targetIndex, targetClientPid, targetClientUid, targetPriority, result);
493 }
494 
pushReclaimAtom(const ClientInfoParcel & clientInfo,const std::vector<int> & priorities,const std::vector<ClientInfo> & targetClients,bool reclaimed)495 void ResourceManagerMetrics::pushReclaimAtom(const ClientInfoParcel& clientInfo,
496                                              const std::vector<int>& priorities,
497                                              const std::vector<ClientInfo>& targetClients,
498                                              bool reclaimed) {
499     // Construct the metrics for codec reclaim as a pushed atom.
500     // 1. Information about the requester.
501     //  - UID and the priority (oom score)
502     int32_t callingPid = clientInfo.pid;
503     int32_t requesterUid = clientInfo.uid;
504     std::string clientName = clientInfo.name;
505     int requesterPriority = priorities[0];
506 
507     //  2. Information about the codec.
508     //  - Name of the codec requested
509     //  - Number of concurrent codecs running.
510     int32_t noOfConcurrentCodecs = 0;
511     std::map<std::string, int>::iterator found = mConcurrentResourceCountMap.find(clientName);
512     if (found != mConcurrentResourceCountMap.end()) {
513         noOfConcurrentCodecs = found->second;
514     }
515 
516     // 3. Information about the Reclaim:
517     // - Status of reclaim request
518     // - How many codecs are reclaimed
519     // - For each codecs reclaimed, information of the process that it belonged to:
520     //    - UID and the Priority (oom score)
521     int32_t reclaimStatus = MEDIA_CODEC_RECLAIM_REQUEST_COMPLETED__RECLAIM_STATUS__RECLAIM_SUCCESS;
522     if (!reclaimed) {
523       if (targetClients.size() == 0) {
524         // No clients to reclaim from
525         reclaimStatus =
526             MEDIA_CODEC_RECLAIM_REQUEST_COMPLETED__RECLAIM_STATUS__RECLAIM_FAILED_NO_CLIENTS;
527       } else {
528         // Couldn't reclaim resources from the clients
529         reclaimStatus =
530             MEDIA_CODEC_RECLAIM_REQUEST_COMPLETED__RECLAIM_STATUS__RECLAIM_FAILED_RECLAIM_RESOURCES;
531       }
532     }
533 
534     if (targetClients.empty()) {
535         // Push the reclaim atom to stats.
536         pushReclaimStats(callingPid,
537                          requesterUid,
538                          requesterPriority,
539                          clientName,
540                          noOfConcurrentCodecs,
541                          reclaimStatus);
542         return;
543     }
544 
545     int32_t noOfCodecsReclaimed = targetClients.size();
546     int32_t targetIndex = 1;
547     for (const ClientInfo& targetClient : targetClients) {
548         int targetPriority = priorities[targetIndex];
549         // Push the reclaim atom to stats.
550         pushReclaimStats(callingPid,
551                          requesterUid,
552                          requesterPriority,
553                          clientName,
554                          noOfConcurrentCodecs,
555                          reclaimStatus,
556                          noOfCodecsReclaimed,
557                          targetIndex,
558                          targetClient.mPid,
559                          targetClient.mUid,
560                          targetPriority);
561         targetIndex++;
562     }
563 }
564 
increaseConcurrentCodecs(int32_t pid,CodecBucket codecBucket)565 void ResourceManagerMetrics::increaseConcurrentCodecs(int32_t pid,
566                                                       CodecBucket codecBucket) {
567     // Increase the codec usage across the system.
568     mConcurrentCodecsMap[codecBucket]++;
569 
570     // Now update the codec usage for this (pid) process.
571     std::map<int32_t, ConcurrentCodecs>::iterator found = mProcessConcurrentCodecsMap.find(pid);
572     if (found == mProcessConcurrentCodecsMap.end()) {
573         ConcurrentCodecs codecs;
574         codecs.mCurrent[codecBucket] = 1;
575         codecs.mPeak[codecBucket] = 1;
576         auto added = mProcessConcurrentCodecsMap.emplace(pid, codecs);
577         found = added.first;
578     } else {
579         found->second.mCurrent[codecBucket]++;
580         // Check if it's the peak count for this slot.
581         if (found->second.mPeak[codecBucket] < found->second.mCurrent[codecBucket]) {
582             found->second.mPeak[codecBucket] = found->second.mCurrent[codecBucket];
583         }
584     }
585 
586     switch (codecBucket) {
587         case HwVideoEncoder:
588         case HwVideoDecoder:
589         case SwVideoEncoder:
590         case SwVideoDecoder:
591             if (codecBucket == HwVideoEncoder || codecBucket == HwVideoDecoder) {
592                 found->second.mHWVideoCodecs++;
593             } else {
594                 found->second.mSWVideoCodecs++;
595             }
596             found->second.mVideoCodecs++;
597             break;
598         case HwAudioEncoder:
599         case HwAudioDecoder:
600         case SwAudioEncoder:
601         case SwAudioDecoder:
602             found->second.mAudioCodecs++;
603             break;
604         case HwImageEncoder:
605         case HwImageDecoder:
606         case SwImageEncoder:
607         case SwImageDecoder:
608             found->second.mImageCodecs++;
609             break;
610         default:
611             break;
612     }
613 }
614 
decreaseConcurrentCodecs(int32_t pid,CodecBucket codecBucket)615 void ResourceManagerMetrics::decreaseConcurrentCodecs(int32_t pid,
616                                                       CodecBucket codecBucket) {
617     // Decrease the codec usage across the system.
618     if (mConcurrentCodecsMap[codecBucket] > 0) {
619         mConcurrentCodecsMap[codecBucket]--;
620     }
621 
622     // Now update the codec usage for this (pid) process.
623     std::map<int32_t, ConcurrentCodecs>::iterator found = mProcessConcurrentCodecsMap.find(pid);
624     if (found != mProcessConcurrentCodecsMap.end()) {
625         if (found->second.mCurrent[codecBucket] > 0) {
626             found->second.mCurrent[codecBucket]--;
627         }
628 
629         switch (codecBucket) {
630             case HwVideoEncoder:
631             case HwVideoDecoder:
632             case SwVideoEncoder:
633             case SwVideoDecoder:
634                 if (codecBucket == HwVideoEncoder || codecBucket == HwVideoDecoder) {
635                     found->second.mHWVideoCodecs--;
636                 } else {
637                     found->second.mSWVideoCodecs--;
638                 }
639                 found->second.mVideoCodecs--;
640                 break;
641             case HwAudioEncoder:
642             case HwAudioDecoder:
643             case SwAudioEncoder:
644             case SwAudioDecoder:
645                 found->second.mAudioCodecs--;
646                 break;
647             case HwImageEncoder:
648             case HwImageDecoder:
649             case SwImageEncoder:
650             case SwImageDecoder:
651                 found->second.mImageCodecs--;
652                 break;
653             default:
654                 break;
655         }
656     }
657 }
658 
increasePixelCount(int32_t pid,long pixels)659 void ResourceManagerMetrics::increasePixelCount(int32_t pid, long pixels) {
660     // Now update the current pixel usage for this (pid) process.
661     std::map<int32_t, PixelCount>::iterator found = mProcessPixelsMap.find(pid);
662     if (found == mProcessPixelsMap.end()) {
663         PixelCount pixelCount {pixels, pixels};
664         mProcessPixelsMap.emplace(pid, pixelCount);
665     } else {
666         if (__builtin_add_overflow(found->second.mCurrent, pixels, &found->second.mCurrent)) {
667             ALOGI("Pixel Count overflow");
668             return;
669         }
670         // Check if it's the peak count for this slot.
671         if (found->second.mPeak < found->second.mCurrent) {
672             found->second.mPeak = found->second.mCurrent;
673         }
674     }
675 }
676 
updatePixelCount(int32_t pid,long newPixels,long lastPixels)677 void ResourceManagerMetrics::updatePixelCount(int32_t pid, long newPixels, long lastPixels) {
678     // Since there is change in resolution, decrease it by last pixels and
679     // increase it by new pixels.
680     decreasePixelCount(pid, lastPixels);
681     increasePixelCount(pid, newPixels);
682 }
683 
decreasePixelCount(int32_t pid,long pixels)684 void ResourceManagerMetrics::decreasePixelCount(int32_t pid, long pixels) {
685     // Now update the current pixel usage for this (pid) process.
686     std::map<int32_t, PixelCount>::iterator found = mProcessPixelsMap.find(pid);
687     if (found != mProcessPixelsMap.end()) {
688         if (found->second.mCurrent < pixels) {
689             found->second.mCurrent = 0;
690         } else {
691             if (__builtin_sub_overflow(found->second.mCurrent, pixels, &found->second.mCurrent)) {
692                 ALOGI("Pixel Count overflow");
693                 return;
694             }
695         }
696     }
697 }
698 
getPeakConcurrentPixelCount(int pid) const699 long ResourceManagerMetrics::getPeakConcurrentPixelCount(int pid) const {
700     std::map<int32_t, PixelCount>::const_iterator found = mProcessPixelsMap.find(pid);
701     if (found != mProcessPixelsMap.end()) {
702         return found->second.mPeak;
703     }
704 
705     return 0;
706 }
707 
getCurrentConcurrentPixelCount(int pid) const708 long ResourceManagerMetrics::getCurrentConcurrentPixelCount(int pid) const {
709     std::map<int32_t, PixelCount>::const_iterator found = mProcessPixelsMap.find(pid);
710     if (found != mProcessPixelsMap.end()) {
711         return found->second.mCurrent;
712     }
713 
714     return 0;
715 }
716 
getConcurrentInstanceCount(const std::map<std::string,int> & resourceMap)717 static std::string getConcurrentInstanceCount(const std::map<std::string, int>& resourceMap) {
718     if (resourceMap.empty()) {
719         return "";
720     }
721     std::stringstream concurrentInstanceInfo;
722     for (const auto& [name, count] : resourceMap) {
723         if (count > 0) {
724             concurrentInstanceInfo << "      Name: " << name << " Instances: " << count << "\n";
725         }
726     }
727 
728     std::string info = concurrentInstanceInfo.str();
729     if (info.empty()) {
730         return "";
731     }
732     return "    Current Concurrent Codec Instances:\n" + info;
733 }
734 
getAppsPixelCount(const std::map<int32_t,PixelCount> & pixelMap)735 static std::string getAppsPixelCount(const std::map<int32_t, PixelCount>& pixelMap) {
736     if (pixelMap.empty()) {
737         return "";
738     }
739     std::stringstream pixelInfo;
740     for (const auto& [pid, pixelCount] : pixelMap) {
741         std::string logMsg = getLogMessage(" Current Pixels: ", pixelCount.mCurrent,
742                                            " Peak Pixels: ", pixelCount.mPeak);
743         if (!logMsg.empty()) {
744             pixelInfo  << "      PID[" << pid << "]: {" << logMsg << " }\n";
745         }
746     }
747 
748     return "    Applications Pixel Usage:\n" + pixelInfo.str();
749 }
750 
getCodecUsageMetrics(const ConcurrentCodecsMap & codecsMap)751 static std::string getCodecUsageMetrics(const ConcurrentCodecsMap& codecsMap) {
752     int peakHwAudioEncoderCount = codecsMap[HwAudioEncoder];
753     int peakHwAudioDecoderCount = codecsMap[HwAudioDecoder];
754     int peakHwVideoEncoderCount = codecsMap[HwVideoEncoder];
755     int peakHwVideoDecoderCount = codecsMap[HwVideoDecoder];
756     int peakHwImageEncoderCount = codecsMap[HwImageEncoder];
757     int peakHwImageDecoderCount = codecsMap[HwImageDecoder];
758     int peakSwAudioEncoderCount = codecsMap[SwAudioEncoder];
759     int peakSwAudioDecoderCount = codecsMap[SwAudioDecoder];
760     int peakSwVideoEncoderCount = codecsMap[SwVideoEncoder];
761     int peakSwVideoDecoderCount = codecsMap[SwVideoDecoder];
762     int peakSwImageEncoderCount = codecsMap[SwImageEncoder];
763     int peakSwImageDecoderCount = codecsMap[SwImageDecoder];
764     std::stringstream usageMetrics;
765     std::string logMsg;
766     logMsg = getLogMessage(" HW: ", peakHwAudioEncoderCount, " SW: ", peakSwAudioEncoderCount);
767     if (!logMsg.empty()) {
768         usageMetrics << "AudioEnc[" << logMsg << " ] ";
769     }
770     logMsg = getLogMessage(" HW: ", peakHwAudioDecoderCount, " SW: ", peakSwAudioDecoderCount);
771     if (!logMsg.empty()) {
772         usageMetrics << "AudioDec[" << logMsg << " ] ";
773     }
774     logMsg = getLogMessage(" HW: ", peakHwVideoEncoderCount, " SW: ", peakSwVideoEncoderCount);
775     if (!logMsg.empty()) {
776         usageMetrics << "VideoEnc[" << logMsg << " ] ";
777     }
778     logMsg = getLogMessage(" HW: ", peakHwVideoDecoderCount, " SW: ", peakSwVideoDecoderCount);
779     if (!logMsg.empty()) {
780         usageMetrics << "VideoDec[" << logMsg << " ] ";
781     }
782     logMsg = getLogMessage(" HW: ", peakHwImageEncoderCount, " SW: ", peakSwImageEncoderCount);
783     if (!logMsg.empty()) {
784         usageMetrics << "ImageEnc[" << logMsg << " ] ";
785     }
786     logMsg = getLogMessage(" HW: ", peakHwImageDecoderCount, " SW: ", peakSwImageDecoderCount);
787     if (!logMsg.empty()) {
788         usageMetrics << "ImageDec[" << logMsg << " ] ";
789     }
790 
791     return usageMetrics.str();
792 }
793 
getAppsCodecUsageMetrics(const std::map<int32_t,ConcurrentCodecs> & processCodecsMap)794 static std::string getAppsCodecUsageMetrics(
795         const std::map<int32_t, ConcurrentCodecs>& processCodecsMap) {
796     if (processCodecsMap.empty()) {
797         return "";
798     }
799     std::stringstream codecUsage;
800     std::string info;
801     for (const auto& [pid, codecMap] : processCodecsMap) {
802         codecUsage << "      PID[" << pid << "]: ";
803         info = getCodecUsageMetrics(codecMap.mCurrent);
804         if (!info.empty()) {
805             codecUsage << "Current Codec Usage: { " << info << "} ";
806         }
807         info = getCodecUsageMetrics(codecMap.mPeak);
808         if (!info.empty()) {
809             codecUsage << "Peak Codec Usage: { " << info << "}";
810         }
811         codecUsage << "\n";
812     }
813 
814     return "    Applications Codec Usage:\n" + codecUsage.str();
815 }
816 
817 
dump() const818 std::string ResourceManagerMetrics::dump() const {
819     std::string metricsLog("  Metrics logs:\n");
820     metricsLog += getConcurrentInstanceCount(mConcurrentResourceCountMap);
821     metricsLog += getAppsPixelCount(mProcessPixelsMap);
822     metricsLog += getAppsCodecUsageMetrics(mProcessConcurrentCodecsMap);
823 
824     return std::move(metricsLog);
825 }
826 
827 } // namespace android
828