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() {}
diff --git a/services/mediametrics/statsd_codec.cpp b/services/mediametrics/statsd_codec.cpp
index c5957e9..cb5e783 100644
--- a/services/mediametrics/statsd_codec.cpp
+++ b/services/mediametrics/statsd_codec.cpp
@@ -444,6 +444,12 @@
     }
     AStatsEvent_writeInt32(event, hdrFormat);
 
+    int64_t codecId = 0;
+    if (item->getInt64("android.media.mediacodec.id", &codecId)) {
+        metrics_proto.set_codec_id(codecId);
+    }
+    AStatsEvent_writeInt64(event, codecId);
+
     int err = AStatsEvent_write(event);
     if (err < 0) {
       ALOGE("Failed to write codec metrics to statsd (%d)", err);
diff --git a/services/mediaresourcemanager/Android.bp b/services/mediaresourcemanager/Android.bp
index 2b8245e..a2bd5e1 100644
--- a/services/mediaresourcemanager/Android.bp
+++ b/services/mediaresourcemanager/Android.bp
@@ -17,6 +17,7 @@
         "aidl/android/media/MediaResourceParcel.aidl",
         "aidl/android/media/MediaResourcePolicyParcel.aidl",
         "aidl/android/media/ClientInfoParcel.aidl",
+        "aidl/android/media/ClientConfigParcel.aidl",
     ],
     path: "aidl",
 }
@@ -73,9 +74,11 @@
     name: "libresourcemanagerservice",
 
     srcs: [
+        "ResourceManagerMetrics.cpp",
         "ResourceManagerService.cpp",
         "ResourceObserverService.cpp",
         "ServiceLog.cpp",
+        "UidObserver.cpp",
 
         // TODO: convert to AIDL?
         "IMediaResourceMonitor.cpp",
@@ -92,6 +95,7 @@
         "libstatspull",
         "libstatssocket",
         "libprotobuf-cpp-lite",
+        "libactivitymanager_aidl",
     ],
 
     static_libs: [
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
diff --git a/services/mediaresourcemanager/ResourceManagerMetrics.h b/services/mediaresourcemanager/ResourceManagerMetrics.h
new file mode 100644
index 0000000..b7810e5
--- /dev/null
+++ b/services/mediaresourcemanager/ResourceManagerMetrics.h
@@ -0,0 +1,179 @@
+/*
+**
+** 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.
+*/
+
+#ifndef ANDROID_MEDIA_RESOURCEMANAGERMETRICS_H_
+#define ANDROID_MEDIA_RESOURCEMANAGERMETRICS_H_
+
+#include "ResourceManagerService.h"
+
+namespace android {
+
+using ::aidl::android::media::ClientInfoParcel;
+using ::aidl::android::media::ClientConfigParcel;
+using ::aidl::android::media::IResourceManagerClient;
+
+struct ProcessInfoInterface;
+
+class UidObserver;
+
+//
+// Enumeration for Codec bucket based on:
+//   - Encoder or Decoder
+//   - hardware implementation or not
+//   - Audio/Video/Image codec
+//
+enum CodecBucket {
+    CodecBucketUnspecified = 0,
+    HwAudioEncoder = 1,
+    HwAudioDecoder = 2,
+    HwVideoEncoder = 3,
+    HwVideoDecoder = 4,
+    HwImageEncoder = 5,
+    HwImageDecoder = 6,
+    SwAudioEncoder = 7,
+    SwAudioDecoder = 8,
+    SwVideoEncoder = 9,
+    SwVideoDecoder = 10,
+    SwImageEncoder = 11,
+    SwImageDecoder = 12,
+    CodecBucketMaxSize = 13,
+};
+
+// Map of client id and client configuration, when it was started last.
+typedef std::map<int64_t, ClientConfigParcel> ClientConfigMap;
+
+// Map of pid and the uid.
+typedef std::map<int32_t, uid_t> PidUidMap;
+
+// Map of concurrent codes by Codec type bucket.
+struct ConcurrentCodecsMap {
+    int& operator[](CodecBucket index) {
+        return mCodec[index];
+    }
+
+    const int& operator[](CodecBucket index) const {
+        return mCodec[index];
+    }
+
+private:
+    int mCodec[CodecBucketMaxSize] = {0};
+};
+
+// Current and Peak ConcurrentCodecMap for a process.
+struct ConcurrentCodecs {
+    ConcurrentCodecsMap mCurrent;
+    ConcurrentCodecsMap mPeak;
+};
+
+// Current and Peak pixel count for a process.
+struct PixelCount {
+    long mCurrent = 0;
+    long mPeak = 0;
+};
+
+//
+// ResourceManagerMetrics class that maintaines concurrent codec count based:
+//
+//  1. # of concurrent active codecs (initialized, but aren't released yet) of given
+//     implementation (by codec name) across the system.
+//
+//  2. # of concurrent codec usage (started, but not stopped yet), which is
+//  measured using codec type bucket (CodecBucket) for:
+//   - each process/application.
+//   - across the system.
+//  Also the peak count of the same for each process/application is maintained.
+//
+//  3. # of Peak Concurrent Pixels for each process/application.
+//  This should help with understanding the (video) memory usage per
+//  application.
+//
+//
+class ResourceManagerMetrics {
+public:
+    ResourceManagerMetrics(const sp<ProcessInfoInterface>& processInfo);
+    ~ResourceManagerMetrics();
+
+    // To be called when a client is created.
+    void notifyClientCreated(const ClientInfoParcel& clientInfo);
+
+    // To be called when a client is released.
+    void notifyClientReleased(const ClientInfoParcel& clientInfo);
+
+    // To be called when a client is started.
+    void notifyClientStarted(const ClientConfigParcel& clientConfig);
+
+    // To be called when a client is stopped.
+    void notifyClientStopped(const ClientConfigParcel& clientConfig);
+
+    // To be called when after a reclaim event.
+    void pushReclaimAtom(const ClientInfoParcel& clientInfo,
+                         const std::vector<int>& priorities,
+                         const Vector<std::shared_ptr<IResourceManagerClient>>& clients,
+                         const PidUidVector& idList, bool reclaimed);
+
+    // Add this pid/uid set to monitor for the process termination state.
+    void addPid(int pid, uid_t uid = 0);
+
+    // Get the peak concurrent pixel count (associated with the video codecs) for the process.
+    long getPeakConcurrentPixelCount(int pid) const;
+    // Get the current concurrent pixel count (associated with the video codecs) for the process.
+    long getCurrentConcurrentPixelCount(int pid) const;
+
+private:
+    ResourceManagerMetrics(const ResourceManagerMetrics&) = delete;
+    ResourceManagerMetrics(ResourceManagerMetrics&&) = delete;
+    ResourceManagerMetrics& operator=(const ResourceManagerMetrics&) = delete;
+    ResourceManagerMetrics& operator=(ResourceManagerMetrics&&) = delete;
+
+    // To increase/decrease the concurrent codec usage for a given CodecBucket.
+    void increaseConcurrentCodecs(int32_t pid, CodecBucket codecBucket);
+    void decreaseConcurrentCodecs(int32_t pid, CodecBucket codecBucket);
+
+    // To increase/decrease the concurrent pixels usage for a process.
+    void increasePixelCount(int32_t pid, long pixels);
+    void decreasePixelCount(int32_t pid, long pixels);
+
+    // Issued when the process/application with given pid/uid is terminated.
+    void onProcessTerminated(int32_t pid, uid_t uid);
+
+    // To push conccuret codec usage of a process/application.
+    void pushConcurrentUsageReport(int32_t pid, uid_t uid);
+
+private:
+    std::mutex mLock;
+
+    // Map of client id and the configuration.
+    ClientConfigMap mClientConfigMap;
+
+    // Concurrent and Peak Pixel count for each process/application.
+    std::map<int32_t, PixelCount> mProcessPixelsMap;
+
+    // Map of resources (name) and number of concurrent instances
+    std::map<std::string, int> mConcurrentResourceCountMap;
+
+    // Map of concurrent codes by CodecBucket across the system.
+    ConcurrentCodecsMap mConcurrentCodecsMap;
+    // Map of concurrent and peak codes by CodecBucket for each process/application.
+    std::map<int32_t, ConcurrentCodecs> mProcessConcurrentCodecsMap;
+
+    // Uid Observer to monitor the application termination.
+    sp<UidObserver> mUidObserver;
+};
+
+} // namespace android
+
+#endif  // ANDROID_MEDIA_RESOURCEMANAGERMETRICS_H_
diff --git a/services/mediaresourcemanager/ResourceManagerService.cpp b/services/mediaresourcemanager/ResourceManagerService.cpp
index ce910b1..abf447a 100644
--- a/services/mediaresourcemanager/ResourceManagerService.cpp
+++ b/services/mediaresourcemanager/ResourceManagerService.cpp
@@ -35,23 +35,15 @@
 #include <sys/stat.h>
 #include <sys/time.h>
 #include <unistd.h>
-#include <stats_media_metrics.h>
 
 #include "IMediaResourceMonitor.h"
+#include "ResourceManagerMetrics.h"
 #include "ResourceManagerService.h"
 #include "ResourceObserverService.h"
 #include "ServiceLog.h"
 
 namespace android {
 
-using stats::media_metrics::stats_write;
-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;
-
 //static
 std::mutex ResourceManagerService::sCookieLock;
 //static
@@ -61,8 +53,8 @@
 
 class DeathNotifier : public RefBase {
 public:
-    DeathNotifier(const std::shared_ptr<ResourceManagerService> &service, int pid,
-            int64_t clientId);
+    DeathNotifier(const std::shared_ptr<ResourceManagerService> &service,
+                  const ClientInfoParcel& clientInfo);
 
     virtual ~DeathNotifier() {}
 
@@ -72,13 +64,12 @@
 
 protected:
     std::weak_ptr<ResourceManagerService> mService;
-    int mPid;
-    int64_t mClientId;
+    const ClientInfoParcel mClientInfo;
 };
 
 DeathNotifier::DeathNotifier(const std::shared_ptr<ResourceManagerService> &service,
-        int pid, int64_t clientId)
-    : mService(service), mPid(pid), mClientId(clientId) {}
+                             const ClientInfoParcel& clientInfo)
+    : mService(service), mClientInfo(clientInfo) {}
 
 //static
 void DeathNotifier::BinderDiedCallback(void* cookie) {
@@ -105,16 +96,16 @@
         return;
     }
 
-    service->overridePid(mPid, -1);
+    service->overridePid(mClientInfo.pid, -1);
     // thiz is freed in the call below, so it must be last call referring thiz
-    ClientInfoParcel clientInfo{.pid = mPid, .id = mClientId};
-    service->removeResource(clientInfo, false /*checkValid*/);
+    service->removeResource(mClientInfo, false /*checkValid*/);
 }
 
 class OverrideProcessInfoDeathNotifier : public DeathNotifier {
 public:
     OverrideProcessInfoDeathNotifier(const std::shared_ptr<ResourceManagerService> &service,
-            int pid) : DeathNotifier(service, pid, 0) {}
+                                     const ClientInfoParcel& clientInfo)
+            : DeathNotifier(service, clientInfo) {}
 
     virtual ~OverrideProcessInfoDeathNotifier() {}
 
@@ -129,7 +120,7 @@
         return;
     }
 
-    service->removeProcessInfoOverride(mPid);
+    service->removeProcessInfoOverride(mClientInfo.pid);
 }
 
 template <typename T>
@@ -202,7 +193,11 @@
         ResourceInfo info;
         info.uid = uid;
         info.clientId = clientId;
-        info.name = name;
+        if (name.empty()) {
+            info.name = "<unknown client>";
+        } else {
+            info.name = name;
+        }
         info.client = client;
         info.cookie = 0;
         info.pendingRemoval = false;
@@ -292,10 +287,7 @@
             snprintf(buffer, SIZE, "        Id: %lld\n", (long long)infos[j].clientId);
             result.append(buffer);
 
-            std::string clientName = "<unknown client>";
-            if (infos[j].client != nullptr) {
-                clientName = infos[j].name;
-            }
+            std::string clientName = infos[j].name;
             snprintf(buffer, SIZE, "        Name: %s\n", clientName.c_str());
             result.append(buffer);
 
@@ -357,6 +349,8 @@
       mCpuBoostCount(0),
       mDeathRecipient(AIBinder_DeathRecipient_new(DeathNotifier::BinderDiedCallback)) {
     mSystemCB->noteResetVideo();
+    // Create ResourceManagerMetrics that handles all the metrics.
+    mResourceManagerMetrics = std::make_unique<ResourceManagerMetrics>(mProcessInfo);
 }
 
 //static
@@ -510,49 +504,16 @@
     }
     if (info.cookie == 0 && client != nullptr) {
         info.cookie = addCookieAndLink_l(client,
-                new DeathNotifier(ref<ResourceManagerService>(), pid, clientId));
+                new DeathNotifier(ref<ResourceManagerService>(), clientInfo));
     }
     if (mObserverService != nullptr && !resourceAdded.empty()) {
         mObserverService->onResourceAdded(uid, pid, resourceAdded);
     }
     notifyResourceGranted(pid, resources);
 
-    // Increase the instance count of the resource associated with this client.
-    increaseResourceInstanceCount(clientId, name);
-
     return Status::ok();
 }
 
-void ResourceManagerService::increaseResourceInstanceCount(int64_t clientId,
-                                                           const std::string& name) {
-    // Check whether this client has been looked into already.
-    if (mClientIdSet.find(clientId) == mClientIdSet.end()) {
-        mClientIdSet.insert(clientId);
-        // Update the resource instance count.
-        auto found = mConcurrentResourceCountMap.find(name);
-        if (found == mConcurrentResourceCountMap.end()) {
-            mConcurrentResourceCountMap[name] = 1;
-        } else {
-            found->second++;
-        }
-    }
-}
-
-void ResourceManagerService::decreaseResourceInstanceCount(int64_t clientId,
-                                                           const std::string& name) {
-    // Since this client has been removed, remove it from mClientIdSet
-    mClientIdSet.erase(clientId);
-    // Update the resource instance count also.
-    auto found = mConcurrentResourceCountMap.find(name);
-    if (found != mConcurrentResourceCountMap.end()) {
-        if (found->second == 1) {
-            mConcurrentResourceCountMap.erase(found);
-        } else {
-            found->second--;
-        }
-    }
-}
-
 Status ResourceManagerService::removeResource(const ClientInfoParcel& clientInfo,
         const std::vector<MediaResourceParcel>& resources) {
     int32_t pid = clientInfo.pid;
@@ -657,9 +618,8 @@
         onLastRemoved(it->second, info);
     }
 
-    // Since this client has been removed, decrease the corresponding
-    // resources instance count.
-    decreaseResourceInstanceCount(clientId, info.name);
+    // Since this client has been removed, update the metrics collector.
+    mResourceManagerMetrics->notifyClientReleased(clientInfo);
 
     removeCookieAndUnlink_l(info.client, info.cookie);
 
@@ -791,73 +751,19 @@
 void ResourceManagerService::pushReclaimAtom(const ClientInfoParcel& clientInfo,
                         const Vector<std::shared_ptr<IResourceManagerClient>>& clients,
                         const PidUidVector& idVector, 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 = -1;
     getPriority_l(callingPid, &requesterPriority);
+    std::vector<int> priorities;
+    priorities.push_back(requesterPriority);
 
-    //  2. Information about the codec.
-    //  - Name of the codec requested
-    //  - Number of concurrent codecs running.
-    int32_t noOfConcurrentCodecs = 0;
-    auto 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 (const auto& id : idVector) {
-        int32_t targetUid = id.second;
+    for (PidUidVector::const_reference id : idVector) {
         int targetPriority = -1;
         getPriority_l(id.first, &targetPriority);
-        // 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)] "
-              "Atom Size: %d",
-              __func__, callingPid, requesterUid, requesterPriority,
-              clientName.c_str(), noOfConcurrentCodecs,
-              reclaimStatus, noOfCodecsReclaimed,
-              targetIndex, id.first, targetUid, targetPriority, result);
-        targetIndex++;
+        priorities.push_back(targetPriority);
     }
+    mResourceManagerMetrics->pushReclaimAtom(clientInfo, priorities, clients,
+                                             idVector, reclaimed);
 }
 
 bool ResourceManagerService::reclaimUnconditionallyFrom(
@@ -933,6 +839,7 @@
         mOverridePidMap.erase(originalPid);
         if (newPid != -1) {
             mOverridePidMap.emplace(originalPid, newPid);
+            mResourceManagerMetrics->addPid(newPid);
         }
     }
 
@@ -966,8 +873,12 @@
         return Status::fromServiceSpecificError(BAD_VALUE);
     }
 
+    ClientInfoParcel clientInfo{.pid = static_cast<int32_t>(pid),
+                                .uid = 0,
+                                .id = 0,
+                                .name = "<unknown client>"};
     uintptr_t cookie = addCookieAndLink_l(client,
-            new OverrideProcessInfoDeathNotifier(ref<ResourceManagerService>(), pid));
+            new OverrideProcessInfoDeathNotifier(ref<ResourceManagerService>(), clientInfo));
 
     mProcessInfoOverrideMap.emplace(pid, ProcessInfoOverride{cookie, client});
 
@@ -1282,4 +1193,27 @@
     return true;
 }
 
+Status ResourceManagerService::notifyClientCreated(const ClientInfoParcel& clientInfo) {
+    mResourceManagerMetrics->notifyClientCreated(clientInfo);
+    return Status::ok();
+}
+
+Status ResourceManagerService::notifyClientStarted(const ClientConfigParcel& clientConfig) {
+    mResourceManagerMetrics->notifyClientStarted(clientConfig);
+    return Status::ok();
+}
+
+Status ResourceManagerService::notifyClientStopped(const ClientConfigParcel& clientConfig) {
+    mResourceManagerMetrics->notifyClientStopped(clientConfig);
+    return Status::ok();
+}
+
+long ResourceManagerService::getPeakConcurrentPixelCount(int pid) const {
+    return mResourceManagerMetrics->getPeakConcurrentPixelCount(pid);
+}
+
+long ResourceManagerService::getCurrentConcurrentPixelCount(int pid) const {
+    return mResourceManagerMetrics->getCurrentConcurrentPixelCount(pid);
+}
+
 } // namespace android
diff --git a/services/mediaresourcemanager/ResourceManagerService.h b/services/mediaresourcemanager/ResourceManagerService.h
index 0016a19..b9756ae 100644
--- a/services/mediaresourcemanager/ResourceManagerService.h
+++ b/services/mediaresourcemanager/ResourceManagerService.h
@@ -39,6 +39,7 @@
 class ResourceObserverService;
 class ServiceLog;
 struct ProcessInfoInterface;
+class ResourceManagerMetrics;
 
 using Status = ::ndk::ScopedAStatus;
 using ::aidl::android::media::IResourceManagerClient;
@@ -46,6 +47,7 @@
 using ::aidl::android::media::MediaResourceParcel;
 using ::aidl::android::media::MediaResourcePolicyParcel;
 using ::aidl::android::media::ClientInfoParcel;
+using ::aidl::android::media::ClientConfigParcel;
 
 typedef std::map<std::tuple<
         MediaResource::Type, MediaResource::SubType, std::vector<uint8_t>>,
@@ -61,6 +63,7 @@
     bool pendingRemoval{false};
 };
 
+// vector of <PID, UID>
 typedef std::vector<std::pair<int32_t, uid_t>> PidUidVector;
 
 // TODO: convert these to std::map
@@ -118,6 +121,12 @@
 
     Status removeResource(const ClientInfoParcel& clientInfo, bool checkValid);
 
+    Status notifyClientCreated(const ClientInfoParcel& clientInfo) override;
+
+    Status notifyClientStarted(const ClientConfigParcel& clientConfig) override;
+
+    Status notifyClientStopped(const ClientConfigParcel& clientConfig) override;
+
 private:
     friend class ResourceManagerServiceTest;
     friend class DeathNotifier;
@@ -182,15 +191,15 @@
     void removeCookieAndUnlink_l(const std::shared_ptr<IResourceManagerClient>& client,
                                  uintptr_t cookie);
 
-    // To increase/decrease the number of instances of a given resource
-    // associated with a client.
-    void increaseResourceInstanceCount(int64_t clientId, const std::string& name);
-    void decreaseResourceInstanceCount(int64_t clientId, const std::string& name);
-
     void pushReclaimAtom(const ClientInfoParcel& clientInfo,
                          const Vector<std::shared_ptr<IResourceManagerClient>>& clients,
                          const PidUidVector& idList, bool reclaimed);
 
+    // Get the peak concurrent pixel count (associated with the video codecs) for the process.
+    long getPeakConcurrentPixelCount(int pid) const;
+    // Get the current concurrent pixel count (associated with the video codecs) for the process.
+    long getCurrentConcurrentPixelCount(int pid) const;
+
     mutable Mutex mLock;
     sp<ProcessInfoInterface> mProcessInfo;
     sp<SystemCallbackInterface> mSystemCB;
@@ -211,11 +220,7 @@
     static std::map<uintptr_t, sp<DeathNotifier> > sCookieToDeathNotifierMap
             GUARDED_BY(sCookieLock);
     std::shared_ptr<ResourceObserverService> mObserverService;
-
-    // List of active clients
-    std::set<int64_t> mClientIdSet;
-    // Map of resources (name) and number of concurrent instances
-    std::map<std::string, int> mConcurrentResourceCountMap;
+    std::unique_ptr<ResourceManagerMetrics> mResourceManagerMetrics;
 };
 
 // ----------------------------------------------------------------------------
diff --git a/services/mediaresourcemanager/UidObserver.cpp b/services/mediaresourcemanager/UidObserver.cpp
new file mode 100644
index 0000000..f321ebc
--- /dev/null
+++ b/services/mediaresourcemanager/UidObserver.cpp
@@ -0,0 +1,182 @@
+/*
+**
+** 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 <android/binder_process.h>
+#include <mediautils/ProcessInfo.h>
+#include "UidObserver.h"
+
+namespace {
+const char* kActivityServiceName = "activity";
+}; // namespace anonymous
+
+namespace android {
+
+UidObserver::UidObserver(const sp<ProcessInfoInterface>& processInfo,
+                         OnProcessTerminated onProcessTerminated) :
+     mRegistered(false),
+     mOnProcessTerminated(std::move(onProcessTerminated)),
+     mProcessInfo(processInfo) {
+}
+
+UidObserver::~UidObserver() {
+    stop();
+}
+
+void UidObserver::start() {
+    // Use check service to see if the activity service is available
+    // If not available then register for notifications, instead of blocking
+    // till the service is ready
+    sp<IServiceManager> sm = defaultServiceManager();
+    sp<IBinder> binder = sm->checkService(String16(kActivityServiceName));
+    if (!binder) {
+        sm->registerForNotifications(String16(kActivityServiceName), this);
+    } else {
+        registerWithActivityManager();
+    }
+}
+
+void UidObserver::stop() {
+    std::scoped_lock lock{mLock};
+
+    if (mRegistered) {
+        // Unregistered with ActivityManager
+        mAm.unregisterUidObserver(this);
+        mAm.unlinkToDeath(this);
+        mRegistered = false;
+    }
+}
+
+void UidObserver::add(int pid, uid_t uid) {
+    bool needToRegister = false;
+    {
+        std::scoped_lock lock(mLock);
+        std::map<uid_t, std::set<int32_t>>::iterator found = mUids.find(uid);
+        if (found != mUids.end()) {
+            found->second.insert(pid);
+        } else {
+            std::set<int32_t> pids{pid};
+            mUids.emplace(uid, std::move(pids));
+        }
+        needToRegister = !mRegistered;
+    }
+    if (needToRegister) {
+        start();
+    }
+}
+
+void UidObserver::registerWithActivityManager() {
+    std::scoped_lock lock{mLock};
+
+    if (mRegistered) {
+        return;
+    }
+    status_t res = mAm.linkToDeath(this);
+    // Register for UID gone.
+    mAm.registerUidObserver(this, ActivityManager::UID_OBSERVER_GONE,
+                            ActivityManager::PROCESS_STATE_UNKNOWN,
+                            String16("mediaserver"));
+    if (res == OK) {
+        mRegistered = true;
+        ALOGV("UidObserver: Registered with ActivityManager");
+    }
+}
+
+void UidObserver::onServiceRegistration(const String16& name, const sp<IBinder>&) {
+    if (name != String16(kActivityServiceName)) {
+        return;
+    }
+
+    registerWithActivityManager();
+}
+
+void UidObserver::getTerminatedProcesses(const std::vector<int32_t>& pids,
+                                         std::vector<int32_t>& terminatedPids) {
+    std::vector<bool> existent;
+    terminatedPids.clear();
+    if (mProcessInfo->checkProcessExistent(pids, &existent)) {
+        for (size_t index = 0; index < existent.size(); index++) {
+            if (!existent[index]) {
+                // This process has been terminated already.
+                terminatedPids.push_back(pids[index]);
+            }
+        }
+    }
+}
+
+// This callback will be issued for every UID that is gone/terminated.
+// Since one UID could have multiple PIDs, this callback can be issued
+// multiple times with that same UID for each activity/pid.
+// So, we need to check which one among the PIDs (that share the same UID)
+// is gone.
+void UidObserver::onUidGone(uid_t uid, bool /*disabled*/) {
+    std::vector<int32_t> terminatedPids;
+    {
+        std::scoped_lock lock{mLock};
+        std::map<uid_t, std::set<int32_t>>::iterator found = mUids.find(uid);
+        if (found != mUids.end()) {
+            if (found->second.size() == 1) {
+                terminatedPids.push_back(*(found->second.begin()));
+                // Only one PID. So we can remove this UID entry.
+                mUids.erase(found);
+            } else {
+                // There are multiple PIDs with the same UID.
+                // Get the list of all terminated PIDs (with the same UID)
+                std::vector<int32_t> pids;
+                std::copy(found->second.begin(), found->second.end(), std::back_inserter(pids));
+                getTerminatedProcesses(pids, terminatedPids);
+                for (int32_t pid : terminatedPids) {
+                    // Remove all the terminated PIDs
+                    found->second.erase(pid);
+                }
+                // If all PIDs under this UID have terminated, remove this UID entry.
+                if (found->second.size() == 0) {
+                    mUids.erase(uid);
+                }
+            }
+        }
+    }
+
+    for (int32_t pid : terminatedPids) {
+        mOnProcessTerminated(pid, uid);
+    }
+}
+
+void UidObserver::onUidActive(uid_t /*uid*/) {
+}
+
+void UidObserver::onUidIdle(uid_t /*uid*/, bool /*disabled*/) {
+}
+
+void UidObserver::onUidStateChanged(uid_t /*uid*/,
+                                    int32_t /*procState*/,
+                                    int64_t /*procStateSeq*/,
+                                    int32_t /*capability*/) {
+}
+
+void UidObserver::onUidProcAdjChanged(uid_t /*uid*/) {
+}
+
+void UidObserver::binderDied(const wp<IBinder>& /*who*/) {
+    std::scoped_lock lock{mLock};
+    ALOGE("UidObserver: ActivityManager has died");
+    mRegistered = false;
+}
+
+}  // namespace android
diff --git a/services/mediaresourcemanager/UidObserver.h b/services/mediaresourcemanager/UidObserver.h
new file mode 100644
index 0000000..ed76839
--- /dev/null
+++ b/services/mediaresourcemanager/UidObserver.h
@@ -0,0 +1,116 @@
+/*
+**
+** 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.
+*/
+
+#ifndef ANDROID_MEDIA_UIDOBSERVER_H_
+#define ANDROID_MEDIA_UIDOBSERVER_H_
+
+#include <map>
+#include <set>
+#include <mutex>
+#include <functional>
+#include <binder/ActivityManager.h>
+#include <binder/IUidObserver.h>
+#include <binder/BinderService.h>
+
+namespace android {
+
+using OnProcessTerminated = std::function<void(int32_t pid, uid_t)>;
+
+struct ProcessInfoInterface;
+
+//
+// UidObserver class
+//
+// This class implements a callback mechanism to notify the termination of the
+// process/applications that are registered with this class.
+//
+// It uses ActivityManager get notification on when an UID is not existent
+// anymore.
+// Since one UID could have multiple PIDs, it uses ActivityManager
+// (through ProcessInfoInterface) to query for the process/application
+// state for the pids.
+//
+class UidObserver :
+        public BnUidObserver,
+        public virtual IBinder::DeathRecipient,
+        public virtual IServiceManager::LocalRegistrationCallback {
+public:
+    explicit UidObserver(const sp<ProcessInfoInterface>& processInfo,
+                         OnProcessTerminated onProcessTerminated);
+    virtual ~UidObserver();
+
+    // Start registration (with Application Manager)
+    void start();
+    // Stop registration (with Application Manager)
+    void stop();
+
+    // Add this pid/uid to set of Uid to be observed.
+    void add(int pid, uid_t uid);
+
+private:
+    UidObserver() = delete;
+    UidObserver(const UidObserver&) = delete;
+    UidObserver(UidObserver&&) = delete;
+    UidObserver& operator=(const UidObserver&) = delete;
+    UidObserver& operator=(UidObserver&&) = delete;
+
+    // IUidObserver implementation.
+    void onUidGone(uid_t uid, bool disabled) override;
+    void onUidActive(uid_t uid) override;
+    void onUidIdle(uid_t uid, bool disabled) override;
+    void onUidStateChanged(uid_t uid, int32_t procState, int64_t procStateSeq,
+            int32_t capability) override;
+    void onUidProcAdjChanged(uid_t uid) override;
+
+    // IServiceManager::LocalRegistrationCallback implementation.
+    void onServiceRegistration(const String16& name,
+                    const sp<IBinder>& binder) override;
+
+    // IBinder::DeathRecipient implementation.
+    void binderDied(const wp<IBinder> &who) override;
+
+    // Registers with Application Manager for UID gone event
+    // to track the termination of Applications.
+    void registerWithActivityManager();
+
+    /*
+     * For a list of input pids, it will check whether the corresponding
+     * processes are already terminated or not.
+     *
+     * @param[in] pids List of pids to check whether they are terminated.
+     * @param[out] terminatedPids List of pid of terminated processes.
+     *
+     * Upon return, terminatedPids returns list of all the termibated pids
+     * that will be a subset of input pids (in that order).
+     * If none of the input pids have terminated, terminatedPids will be empty.
+     */
+    void getTerminatedProcesses(const std::vector<int32_t>& pids,
+                                std::vector<int32_t>& terminatedPids);
+
+    bool mRegistered = false;
+    std::mutex mLock;
+    ActivityManager mAm;
+    // map of UID and all the PIDs associated with it
+    // as one UID could have multiple PIDs.
+    std::map<uid_t, std::set<int32_t>> mUids;
+    OnProcessTerminated mOnProcessTerminated;
+    sp<ProcessInfoInterface> mProcessInfo;
+};
+
+}  // namespace android
+
+#endif  //ANDROID_MEDIA_UIDOBSERVER_H_
diff --git a/services/mediaresourcemanager/aidl/android/media/ClientConfigParcel.aidl b/services/mediaresourcemanager/aidl/android/media/ClientConfigParcel.aidl
new file mode 100644
index 0000000..3c9c8c7
--- /dev/null
+++ b/services/mediaresourcemanager/aidl/android/media/ClientConfigParcel.aidl
@@ -0,0 +1,65 @@
+/**
+ * Copyright (c) 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.
+ */
+
+package android.media;
+
+import android.media.ClientInfoParcel;
+import android.media.MediaResourceSubType;
+
+/**
+ * Description of a Client(codec) configuration.
+ *
+ * {@hide}
+ */
+parcelable ClientConfigParcel {
+    /**
+     * Client info.
+     */
+    ClientInfoParcel clientInfo;
+
+    /**
+     * Type of codec (Audio/Video/Image).
+     */
+    MediaResourceSubType codecType;
+
+    /**
+     * true if this is an encoder, false if this is a decoder.
+     */
+    boolean isEncoder;
+
+    /**
+     * true if this is hardware codec, false otherwise.
+     */
+    boolean isHardware;
+
+    /*
+     * Video Resolution of the codec when it was configured, as width and height (in pixels).
+     */
+    int width;
+    int height;
+
+    /*
+     * Timestamp (in microseconds) when this configuration is created.
+     */
+    long timeStamp;
+    /*
+     * ID associated with the Codec.
+     * This will be used by the metrics:
+     * - Associate MediaCodecStarted with MediaCodecStopped Atom.
+     * - Correlate MediaCodecReported Atom for codec configuration parameters.
+     */
+    long id;
+}
diff --git a/services/mediaresourcemanager/aidl/android/media/IResourceManagerService.aidl b/services/mediaresourcemanager/aidl/android/media/IResourceManagerService.aidl
index 30ad41b..fcade38 100644
--- a/services/mediaresourcemanager/aidl/android/media/IResourceManagerService.aidl
+++ b/services/mediaresourcemanager/aidl/android/media/IResourceManagerService.aidl
@@ -20,6 +20,7 @@
 import android.media.MediaResourceParcel;
 import android.media.MediaResourcePolicyParcel;
 import android.media.ClientInfoParcel;
+import android.media.ClientConfigParcel;
 
 /**
  * ResourceManagerService interface that keeps track of media resource
@@ -125,4 +126,34 @@
      * @param pid pid from which resources will be reclaimed.
      */
     void reclaimResourcesFromClientsPendingRemoval(int pid);
+
+    /**
+     * Notify that the client has been created.
+     *
+     * This call is made to collect the (concurrent) metrics about the
+     * resources associated with the Codec (and also DRM sessions).
+     *
+     * @param clientInfo Information of the client.
+     */
+    void notifyClientCreated(in ClientInfoParcel clientInfo);
+
+    /**
+     * Notify that the client has been started.
+     *
+     * This call is made to collect the (concurrent) metrics about the
+     * resources associated with the Codec (and also DRM sessions).
+     *
+     * @param clientConfig Configuration information of the client.
+     */
+    void notifyClientStarted(in ClientConfigParcel clientConfig);
+
+    /**
+     * Notify that the client has been stopped.
+     *
+     * This call is made to collect the (concurrent) metrics about the
+     * resources associated with the Codec (and also DRM sessions).
+     *
+     * @param clientConfig Configuration information of the client.
+     */
+    void notifyClientStopped(in ClientConfigParcel clientConfig);
 }
diff --git a/services/mediaresourcemanager/fuzzer/Android.bp b/services/mediaresourcemanager/fuzzer/Android.bp
index 27d45d5..d98974f 100644
--- a/services/mediaresourcemanager/fuzzer/Android.bp
+++ b/services/mediaresourcemanager/fuzzer/Android.bp
@@ -45,6 +45,7 @@
         "libstats_media_metrics",
         "libstatspull",
         "libstatssocket",
+        "libactivitymanager_aidl",
     ],
     fuzz_config: {
         cc: [
diff --git a/services/mediaresourcemanager/test/Android.bp b/services/mediaresourcemanager/test/Android.bp
index 16c5a4c..f903c62 100644
--- a/services/mediaresourcemanager/test/Android.bp
+++ b/services/mediaresourcemanager/test/Android.bp
@@ -23,6 +23,7 @@
         "libstats_media_metrics",
         "libstatspull",
         "libstatssocket",
+        "libactivitymanager_aidl",
     ],
     include_dirs: [
         "frameworks/av/include",
@@ -72,6 +73,7 @@
         "libstats_media_metrics",
         "libstatspull",
         "libstatssocket",
+        "libactivitymanager_aidl",
     ],
     include_dirs: [
         "frameworks/av/include",
diff --git a/services/mediaresourcemanager/test/ResourceManagerServiceTestUtils.h b/services/mediaresourcemanager/test/ResourceManagerServiceTestUtils.h
index 8fe2505..474ff0f 100644
--- a/services/mediaresourcemanager/test/ResourceManagerServiceTestUtils.h
+++ b/services/mediaresourcemanager/test/ResourceManagerServiceTestUtils.h
@@ -15,6 +15,7 @@
  */
 
 #include <gtest/gtest.h>
+#include <android/binder_process.h>
 
 #include "ResourceManagerService.h"
 #include <aidl/android/media/BnResourceManagerClient.h>
@@ -197,13 +198,20 @@
         return static_cast<TestClient*>(testClient.get());
     }
 
-    ResourceManagerServiceTestBase()
-        : mSystemCB(new TestSystemCallback()),
-          mService(::ndk::SharedRefBase::make<ResourceManagerService>(
-                  new TestProcessInfo, mSystemCB)),
-          mTestClient1(::ndk::SharedRefBase::make<TestClient>(kTestPid1, kTestUid1, mService)),
-          mTestClient2(::ndk::SharedRefBase::make<TestClient>(kTestPid2, kTestUid2, mService)),
-          mTestClient3(::ndk::SharedRefBase::make<TestClient>(kTestPid2, kTestUid2, mService)) {
+    ResourceManagerServiceTestBase() {
+        ALOGI("ResourceManagerServiceTestBase created");
+    }
+
+    void SetUp() override {
+        // Need thread pool to receive callbacks, otherwise oneway callbacks are
+        // silently ignored.
+        ABinderProcess_startThreadPool();
+        mSystemCB = new TestSystemCallback();
+        mService = ::ndk::SharedRefBase::make<ResourceManagerService>(
+            new TestProcessInfo, mSystemCB);
+        mTestClient1 = ::ndk::SharedRefBase::make<TestClient>(kTestPid1, kTestUid1, mService);
+        mTestClient2 = ::ndk::SharedRefBase::make<TestClient>(kTestPid2, kTestUid2, mService);
+        mTestClient3 = ::ndk::SharedRefBase::make<TestClient>(kTestPid2, kTestUid2, mService);
     }
 
     std::shared_ptr<IResourceManagerClient> createTestClient(int pid, int uid) {
diff --git a/services/mediaresourcemanager/test/ResourceManagerService_test.cpp b/services/mediaresourcemanager/test/ResourceManagerService_test.cpp
index 41cccb8..4e575f0 100644
--- a/services/mediaresourcemanager/test/ResourceManagerService_test.cpp
+++ b/services/mediaresourcemanager/test/ResourceManagerService_test.cpp
@@ -1367,6 +1367,143 @@
         // CPU boost is not expected to be reclaimed when marked as pending removal
         EXPECT_FALSE(toTestClient(cpuBoostMarkedClient)->checkIfReclaimedAndReset());
     }
+
+    inline void initClientConfigParcel(bool encoder, bool hw,
+                                       int32_t width, int32_t height,
+                                       int64_t id,
+                                       const ClientInfoParcel& clientInfo,
+                                       ClientConfigParcel& clientConfig) {
+        clientConfig.codecType = MediaResource::SubType::kVideoCodec;
+        clientConfig.isEncoder = encoder;
+        clientConfig.isHardware = hw;
+        clientConfig.width = width;
+        clientConfig.height = height;
+        clientConfig.timeStamp = systemTime(SYSTEM_TIME_MONOTONIC) / 1000LL;
+        clientConfig.id = id;
+        clientConfig.clientInfo = clientInfo;
+    }
+
+    void testConcurrentCodecs() {
+        std::shared_ptr<IResourceManagerClient> testClient4 =
+            createTestClient(kTestPid1, kTestUid1);
+        ClientInfoParcel client1Info{.pid = static_cast<int32_t>(kTestPid1),
+                                     .uid = static_cast<int32_t>(kTestUid1),
+                                     .id = getId(mTestClient1),
+                                     .name = "none"};
+        ClientInfoParcel client2Info{.pid = static_cast<int32_t>(kTestPid2),
+                                     .uid = static_cast<int32_t>(kTestUid2),
+                                     .id = getId(mTestClient2),
+                                     .name = "none"};
+        ClientInfoParcel client3Info{.pid = static_cast<int32_t>(kTestPid2),
+                                     .uid = static_cast<int32_t>(kTestUid2),
+                                     .id = getId(mTestClient3),
+                                     .name = "none"};
+        ClientInfoParcel client4Info{.pid = static_cast<int32_t>(kTestPid1),
+                                     .uid = static_cast<int32_t>(kTestUid1),
+                                     .id = getId(testClient4),
+                                     .name = "none"};
+        ClientConfigParcel client1Config;
+        ClientConfigParcel client2Config;
+        ClientConfigParcel client3Config;
+        ClientConfigParcel client4Config;
+
+        // HW Video Encoder @ 1080P.
+        initClientConfigParcel(true, true, 1920, 1080, 11111111,
+                               client1Info, client1Config);
+        // HW Video Decoder @ 4K.
+        initClientConfigParcel(true, true, 2160, 3840, 22222222,
+                               client2Info, client2Config);
+        // SW Video Encoder @ 1080P.
+        initClientConfigParcel(true, true, 1920, 1080, 33333333,
+                               client3Info, client3Config);
+        // SW Video Decoder @ 4K.
+        initClientConfigParcel(true, true, 2160, 3840, 44444444,
+                               client4Info, client4Config);
+
+        // Start client1 at 1080P.
+        mService->notifyClientStarted(client1Config);
+        long peakPixelCountP1 = mService->getPeakConcurrentPixelCount(kTestPid1);
+        long currentPixelCountP1 = mService->getCurrentConcurrentPixelCount(kTestPid1);
+        EXPECT_TRUE(peakPixelCountP1 = client1Config.width * client1Config.height);
+        EXPECT_TRUE(currentPixelCountP1 = client1Config.width * client1Config.height);
+
+        // Stop client1.
+        mService->notifyClientStopped(client1Config);
+        peakPixelCountP1 = mService->getPeakConcurrentPixelCount(kTestPid1);
+        currentPixelCountP1 = mService->getCurrentConcurrentPixelCount(kTestPid1);
+        EXPECT_TRUE(peakPixelCountP1 == client1Config.width * client1Config.height);
+        EXPECT_TRUE(currentPixelCountP1 == 0);
+
+        // Start client1 at 1080P.
+        mService->notifyClientStarted(client1Config);
+        // Start client2 at 4K.
+        mService->notifyClientStarted(client2Config);
+
+        // Verify the Peak and Current Concurrent pixel count for both the process
+        // (kTestPid1, kTestPid2)
+        peakPixelCountP1 = mService->getPeakConcurrentPixelCount(kTestPid1);
+        currentPixelCountP1 = mService->getCurrentConcurrentPixelCount(kTestPid1);
+        long peakPixelCountP2 = mService->getPeakConcurrentPixelCount(kTestPid2);
+        long currentPixelCountP2 = mService->getCurrentConcurrentPixelCount(kTestPid2);
+        EXPECT_TRUE(peakPixelCountP1 == client1Config.width * client1Config.height);
+        EXPECT_TRUE(currentPixelCountP1 == client1Config.width * client1Config.height);
+        EXPECT_TRUE(peakPixelCountP2 == client2Config.width * client2Config.height);
+        EXPECT_TRUE(currentPixelCountP2 == client2Config.width * client2Config.height);
+
+        // Start client3 at 1080P.
+        mService->notifyClientStarted(client3Config);
+        // Start client4 at 4K.
+        mService->notifyClientStarted(client4Config);
+
+        // Verify the Peak and Current Concurrent pixel count for both the process
+        // (kTestPid1, kTestPid2)
+        peakPixelCountP1 = mService->getPeakConcurrentPixelCount(kTestPid1);
+        currentPixelCountP1 = mService->getCurrentConcurrentPixelCount(kTestPid1);
+        peakPixelCountP2 = mService->getPeakConcurrentPixelCount(kTestPid2);
+        currentPixelCountP2 = mService->getCurrentConcurrentPixelCount(kTestPid2);
+        EXPECT_TRUE(peakPixelCountP1 ==
+            (client1Config.width * client1Config.height +
+             client4Config.width * client4Config.height));
+        EXPECT_TRUE(currentPixelCountP1 ==
+            (client1Config.width * client1Config.height +
+             client4Config.width * client4Config.height));
+        EXPECT_TRUE(peakPixelCountP2 ==
+            (client2Config.width * client2Config.height +
+             client3Config.width * client3Config.height));
+        EXPECT_TRUE(currentPixelCountP2 ==
+            (client2Config.width * client2Config.height +
+             client3Config.width * client3Config.height));
+
+        // Stop client4
+        mService->notifyClientStopped(client4Config);
+        currentPixelCountP1 = mService->getCurrentConcurrentPixelCount(kTestPid1);
+        EXPECT_TRUE(currentPixelCountP1 == client1Config.width * client1Config.height);
+
+        // Stop client1
+        mService->notifyClientStopped(client1Config);
+
+        // Stop client2
+        mService->notifyClientStopped(client2Config);
+        currentPixelCountP2 = mService->getCurrentConcurrentPixelCount(kTestPid2);
+        EXPECT_TRUE(currentPixelCountP2 == client3Config.width * client3Config.height);
+        // Stop client3
+        mService->notifyClientStopped(client3Config);
+
+        // Verify the Peak and Current Concurrent pixel count for both the process
+        // (kTestPid1, kTestPid2)
+        peakPixelCountP1 = mService->getPeakConcurrentPixelCount(kTestPid1);
+        currentPixelCountP1 = mService->getCurrentConcurrentPixelCount(kTestPid1);
+        peakPixelCountP2 = mService->getPeakConcurrentPixelCount(kTestPid2);
+        currentPixelCountP2 = mService->getCurrentConcurrentPixelCount(kTestPid2);
+        EXPECT_TRUE(peakPixelCountP1 ==
+            (client1Config.width * client1Config.height +
+             client4Config.width * client4Config.height));
+        EXPECT_TRUE(currentPixelCountP1 == 0);
+        EXPECT_TRUE(peakPixelCountP2 ==
+            (client2Config.width * client2Config.height +
+             client3Config.width * client3Config.height));
+        EXPECT_TRUE(currentPixelCountP2 == 0);
+    }
 };
 
 TEST_F(ResourceManagerServiceTest, config) {
@@ -1451,4 +1588,8 @@
     testReclaimResourcesFromMarkedClients_removesBiggestMarkedClientForSomeResources();
 }
 
+TEST_F(ResourceManagerServiceTest, concurrentCodecs) {
+    testConcurrentCodecs();
+}
+
 } // namespace android
diff --git a/services/mediaresourcemanager/test/ResourceObserverService_test.cpp b/services/mediaresourcemanager/test/ResourceObserverService_test.cpp
index a0d728c..85769d5 100644
--- a/services/mediaresourcemanager/test/ResourceObserverService_test.cpp
+++ b/services/mediaresourcemanager/test/ResourceObserverService_test.cpp
@@ -166,11 +166,14 @@
 
 class ResourceObserverServiceTest : public ResourceManagerServiceTestBase {
 public:
-    ResourceObserverServiceTest() : ResourceManagerServiceTestBase(),
-        mObserverService(::ndk::SharedRefBase::make<ResourceObserverService>()),
-        mTestObserver1(::ndk::SharedRefBase::make<TestObserver>("observer1")),
-        mTestObserver2(::ndk::SharedRefBase::make<TestObserver>("observer2")),
-        mTestObserver3(::ndk::SharedRefBase::make<TestObserver>("observer3")) {
+    ResourceObserverServiceTest() : ResourceManagerServiceTestBase() {}
+
+    void SetUp() override {
+        ResourceManagerServiceTestBase::SetUp();
+        mObserverService = ::ndk::SharedRefBase::make<ResourceObserverService>();
+        mTestObserver1 = ::ndk::SharedRefBase::make<TestObserver>("observer1");
+        mTestObserver2 = ::ndk::SharedRefBase::make<TestObserver>("observer2");
+        mTestObserver3 = ::ndk::SharedRefBase::make<TestObserver>("observer3");
         mService->setObserverService(mObserverService);
     }