Merge "Revert "audio AIDL: Consider `BUS` devices as attached"" into main
diff --git a/media/codec2/components/aom/C2SoftAomEnc.cpp b/media/codec2/components/aom/C2SoftAomEnc.cpp
index e08bf43..71909e5 100644
--- a/media/codec2/components/aom/C2SoftAomEnc.cpp
+++ b/media/codec2/components/aom/C2SoftAomEnc.cpp
@@ -107,7 +107,7 @@
 
     addParameter(DefineParam(mProfileLevel, C2_PARAMKEY_PROFILE_LEVEL)
                          .withDefault(new C2StreamProfileLevelInfo::output(0u, PROFILE_AV1_0,
-                                                                           LEVEL_AV1_4_1))
+                                                                           LEVEL_AV1_2))
                          .withFields({
                                  C2F(mProfileLevel, profile).equalTo(PROFILE_AV1_0),
                                  C2F(mProfileLevel, level)
@@ -116,7 +116,7 @@
                                             LEVEL_AV1_3_2, LEVEL_AV1_3_3, LEVEL_AV1_4,
                                             LEVEL_AV1_4_1}),
                          })
-                         .withSetter(ProfileLevelSetter)
+                         .withSetter(ProfileLevelSetter, mSize, mFrameRate, mBitrate)
                          .build());
 
     std::vector<uint32_t> pixelFormats = {HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED,
@@ -201,12 +201,69 @@
 }
 
 C2R C2SoftAomEnc::IntfImpl::ProfileLevelSetter(bool mayBlock,
-                                               C2P<C2StreamProfileLevelInfo::output>& me) {
+                                               C2P<C2StreamProfileLevelInfo::output>& me,
+                                               const C2P<C2StreamPictureSizeInfo::input>& size,
+                                               const C2P<C2StreamFrameRateInfo::output>& frameRate,
+                                               const C2P<C2StreamBitrateInfo::output>& bitrate) {
     (void)mayBlock;
     if (!me.F(me.v.profile).supportsAtAll(me.v.profile)) {
         me.set().profile = PROFILE_AV1_0;
     }
+    struct LevelLimits {
+        C2Config::level_t level;
+        float samplesPerSec;
+        uint64_t samples;
+        uint32_t bitrate;
+        size_t maxHSize;
+        size_t maxVSize;
+    };
+    constexpr LevelLimits kLimits[] = {
+            {LEVEL_AV1_2, 4423680, 147456, 1500000, 2048, 1152},
+            {LEVEL_AV1_2_1, 8363520, 278784, 3000000, 2816, 1584},
+            {LEVEL_AV1_3, 19975680, 665856, 6000000, 4352, 2448},
+            {LEVEL_AV1_3_1, 37950720, 1065024, 10000000, 5504, 3096},
+            {LEVEL_AV1_4, 70778880, 2359296, 12000000, 6144, 3456},
+            {LEVEL_AV1_4_1, 141557760, 2359296, 20000000, 6144, 3456},
+    };
+
+    uint64_t samples = size.v.width * size.v.height;
+    float samplesPerSec = float(samples) * frameRate.v.value;
+
+    // Check if the supplied level meets the samples / bitrate requirements.
+    // If not, update the level with the lowest level meeting the requirements.
+    bool found = false;
+
+    // By default needsUpdate = false in case the supplied level does meet
+    // the requirements.
+    bool needsUpdate = false;
     if (!me.F(me.v.level).supportsAtAll(me.v.level)) {
+        needsUpdate = true;
+    }
+    for (const LevelLimits& limit : kLimits) {
+        if (samples <= limit.samples && samplesPerSec <= limit.samplesPerSec &&
+            bitrate.v.value <= limit.bitrate && size.v.width <= limit.maxHSize &&
+            size.v.height <= limit.maxVSize) {
+            // This is the lowest level that meets the requirements, and if
+            // we haven't seen the supplied level yet, that means we don't
+            // need the update.
+            if (needsUpdate) {
+                ALOGD("Given level %x does not cover current configuration: "
+                        "adjusting to %x",
+                        me.v.level, limit.level);
+                me.set().level = limit.level;
+            }
+            found = true;
+            break;
+        }
+        if (me.v.level == limit.level) {
+            // We break out of the loop when the lowest feasible level is
+            // found. The fact that we're here means that our level doesn't
+            // meet the requirement and needs to be updated.
+            needsUpdate = true;
+        }
+    }
+    if (!found) {
+        // We set to the highest supported level.
         me.set().level = LEVEL_AV1_4_1;
     }
     return C2R::Ok();
@@ -248,6 +305,10 @@
     return C2R::Ok();
 }
 
+uint32_t C2SoftAomEnc::IntfImpl::getLevel_l() const {
+        return mProfileLevel->level - LEVEL_AV1_2;
+}
+
 C2SoftAomEnc::C2SoftAomEnc(const char* name, c2_node_id_t id,
                            const std::shared_ptr<IntfImpl>& intfImpl)
     : SimpleC2Component(std::make_shared<SimpleInterface<IntfImpl>>(name, id, intfImpl)),
@@ -324,6 +385,9 @@
 aom_codec_err_t C2SoftAomEnc::setupCodecParameters() {
     aom_codec_err_t codec_return = AOM_CODEC_OK;
 
+    codec_return = aom_codec_control(mCodecContext, AV1E_SET_TARGET_SEQ_LEVEL_IDX, mAV1EncLevel);
+    if (codec_return != AOM_CODEC_OK) goto BailOut;
+
     codec_return = aom_codec_control(mCodecContext, AOME_SET_CPUUSED,
                                      MapC2ComplexityToAOMSpeed(mComplexity->value));
     if (codec_return != AOM_CODEC_OK) goto BailOut;
@@ -478,6 +542,7 @@
         mColorAspects = mIntf->getCodedColorAspects_l();
         mQuality = mIntf->getQuality_l();
         mComplexity = mIntf->getComplexity_l();
+        mAV1EncLevel = mIntf->getLevel_l();
     }
 
 
diff --git a/media/codec2/components/aom/C2SoftAomEnc.h b/media/codec2/components/aom/C2SoftAomEnc.h
index 3067735..7e5ea63 100644
--- a/media/codec2/components/aom/C2SoftAomEnc.h
+++ b/media/codec2/components/aom/C2SoftAomEnc.h
@@ -98,6 +98,8 @@
 
     bool mIs10Bit;
 
+    uint32_t mAV1EncLevel;
+
     std::shared_ptr<C2StreamPictureSizeInfo::input> mSize;
     std::shared_ptr<C2StreamIntraRefreshTuning::output> mIntraRefresh;
     std::shared_ptr<C2StreamFrameRateInfo::output> mFrameRate;
@@ -120,7 +122,10 @@
     static C2R SizeSetter(bool mayBlock, const C2P<C2StreamPictureSizeInfo::input>& oldMe,
                           C2P<C2StreamPictureSizeInfo::input>& me);
 
-    static C2R ProfileLevelSetter(bool mayBlock, C2P<C2StreamProfileLevelInfo::output>& me);
+    static C2R ProfileLevelSetter(bool mayBlock, C2P<C2StreamProfileLevelInfo::output>& me,
+                                  const C2P<C2StreamPictureSizeInfo::input>& size,
+                                  const C2P<C2StreamFrameRateInfo::output>& frameRate,
+                                  const C2P<C2StreamBitrateInfo::output>& bitrate);
 
     // unsafe getters
     std::shared_ptr<C2StreamPictureSizeInfo::input> getSize_l() const { return mSize; }
@@ -149,6 +154,7 @@
     static C2R ColorAspectsSetter(bool mayBlock, C2P<C2StreamColorAspectsInfo::input>& me);
     static C2R CodedColorAspectsSetter(bool mayBlock, C2P<C2StreamColorAspectsInfo::output>& me,
                                        const C2P<C2StreamColorAspectsInfo::input>& coded);
+    uint32_t getLevel_l() const;
 
   private:
     std::shared_ptr<C2StreamUsageTuning::input> mUsage;
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index fa4808b..870ebdf 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -785,6 +785,7 @@
     kWhatOutputBuffersChanged = 'outC',
     kWhatFirstTunnelFrameReady = 'ftfR',
     kWhatPollForRenderedBuffers = 'plrb',
+    kWhatMetricsUpdated      = 'mtru',
 };
 
 class CryptoAsyncCallback : public CryptoAsync::CryptoAsyncCallback {
@@ -882,6 +883,7 @@
     virtual void onOutputFramesRendered(const std::list<FrameRenderTracker::Info> &done) override;
     virtual void onOutputBuffersChanged() override;
     virtual void onFirstTunnelFrameReady() override;
+    virtual void onMetricsUpdated(const sp<AMessage> &updatedMetrics) override;
 private:
     const sp<AMessage> mNotify;
 };
@@ -1008,6 +1010,13 @@
     notify->post();
 }
 
+void CodecCallback::onMetricsUpdated(const sp<AMessage> &updatedMetrics) {
+    sp<AMessage> notify(mNotify->dup());
+    notify->setInt32("what", kWhatMetricsUpdated);
+    notify->setMessage("updated-metrics", updatedMetrics);
+    notify->post();
+}
+
 static MediaResourceSubType toMediaResourceSubType(MediaCodec::Domain domain) {
     switch (domain) {
         case MediaCodec::DOMAIN_VIDEO: return MediaResourceSubType::kVideoCodec;
@@ -4381,6 +4390,49 @@
                     break;
                 }
 
+                case kWhatMetricsUpdated:
+                {
+                    sp<AMessage> updatedMetrics;
+                    CHECK(msg->findMessage("updated-metrics", &updatedMetrics));
+
+                    size_t numEntries = updatedMetrics->countEntries();
+                    AMessage::Type type;
+                    for (size_t i = 0; i < numEntries; ++i) {
+                        const char *name = updatedMetrics->getEntryNameAt(i, &type);
+                        AMessage::ItemData itemData = updatedMetrics->getEntryAt(i);
+                        switch (type) {
+                            case AMessage::kTypeInt32: {
+                                int32_t metricValue;
+                                itemData.find(&metricValue);
+                                mediametrics_setInt32(mMetricsHandle, name, metricValue);
+                                break;
+                            }
+                            case AMessage::kTypeInt64: {
+                                int64_t metricValue;
+                                itemData.find(&metricValue);
+                                mediametrics_setInt64(mMetricsHandle, name, metricValue);
+                                break;
+                            }
+                            case AMessage::kTypeDouble: {
+                                double metricValue;
+                                itemData.find(&metricValue);
+                                mediametrics_setDouble(mMetricsHandle, name, metricValue);
+                                break;
+                            }
+                            case AMessage::kTypeString: {
+                                AString metricValue;
+                                itemData.find(&metricValue);
+                                mediametrics_setCString(mMetricsHandle, name, metricValue.c_str());
+                                break;
+                            }
+                            // ToDo: add support for other types
+                            default:
+                                ALOGW("Updated metrics type not supported.");
+                        }
+                    }
+                    break;
+                }
+
                 case kWhatEOS:
                 {
                     // We already notify the client of this by using the
diff --git a/media/libstagefright/include/media/stagefright/CodecBase.h b/media/libstagefright/include/media/stagefright/CodecBase.h
index 916d41e..2a5989f 100644
--- a/media/libstagefright/include/media/stagefright/CodecBase.h
+++ b/media/libstagefright/include/media/stagefright/CodecBase.h
@@ -182,6 +182,12 @@
          * Notify MediaCodec that the first tunnel frame is ready.
          */
         virtual void onFirstTunnelFrameReady() = 0;
+        /**
+         * Notify MediaCodec that there are metrics to be updated.
+         *
+         * @param updatedMetrics metrics need to be updated.
+         */
+        virtual void onMetricsUpdated(const sp<AMessage> &updatedMetrics) = 0;
     };
 
     /**
diff --git a/media/module/extractors/mp4/MPEG4Extractor.cpp b/media/module/extractors/mp4/MPEG4Extractor.cpp
index ecd937d..a9ca078 100644
--- a/media/module/extractors/mp4/MPEG4Extractor.cpp
+++ b/media/module/extractors/mp4/MPEG4Extractor.cpp
@@ -185,6 +185,8 @@
     status_t parseSampleEncryption(off64_t offset, off64_t size);
     // returns -1 for invalid layer ID
     int32_t parseHEVCLayerId(const uint8_t *data, size_t size);
+    size_t getNALLengthSizeFromAvcCsd(const uint8_t *data, const size_t size) const;
+    size_t getNALLengthSizeFromHevcCsd(const uint8_t *data, const size_t size) const;
 
     struct TrackFragmentHeaderInfo {
         enum Flags {
@@ -5158,24 +5160,13 @@
         size_t size;
         CHECK(AMediaFormat_getBuffer(format, AMEDIAFORMAT_KEY_CSD_AVC, &data, &size));
 
-        const uint8_t *ptr = (const uint8_t *)data;
-
-        CHECK(size >= 7);
-        CHECK_EQ((unsigned)ptr[0], 1u);  // configurationVersion == 1
-
-        // The number of bytes used to encode the length of a NAL unit.
-        mNALLengthSize = 1 + (ptr[4] & 3);
+        mNALLengthSize = getNALLengthSizeFromAvcCsd((const uint8_t *)data, size);
     } else if (mIsHEVC) {
         void *data;
         size_t size;
         CHECK(AMediaFormat_getBuffer(format, AMEDIAFORMAT_KEY_CSD_HEVC, &data, &size));
 
-        const uint8_t *ptr = (const uint8_t *)data;
-
-        CHECK(size >= 22);
-        CHECK_EQ((unsigned)ptr[0], 1u);  // configurationVersion == 1
-
-        mNALLengthSize = 1 + (ptr[14 + 7] & 3);
+        mNALLengthSize = getNALLengthSizeFromHevcCsd((const uint8_t *)data, size);
     } else if (mIsDolbyVision) {
         ALOGV("%s DolbyVision stream detected", __FUNCTION__);
         void *data;
@@ -5190,27 +5181,25 @@
         CHECK(!((ptr[0] != 1 || ptr[1] != 0) && (ptr[0] != 2 || ptr[1] != 1)));
 
         const uint8_t profile = ptr[2] >> 1;
-        // profile == (unknown,1,9) --> AVC; profile = (2,3,4,5,6,7,8) --> HEVC;
-        // profile == (10) --> AV1
-        if (profile > 1 && profile < 9) {
+        // profile == (4,5,6,7,8) --> HEVC; profile == (9) --> AVC; profile == (10) --> AV1
+        if (profile > 3 && profile < 9) {
             CHECK(AMediaFormat_getBuffer(format, AMEDIAFORMAT_KEY_CSD_HEVC, &data, &size));
 
-            const uint8_t *ptr = (const uint8_t *)data;
+            mNALLengthSize = getNALLengthSizeFromHevcCsd((const uint8_t *)data, size);
+        } else if (9 == profile) {
+            CHECK(AMediaFormat_getBuffer(format, AMEDIAFORMAT_KEY_CSD_AVC, &data, &size));
 
-            CHECK(size >= 22);
-            CHECK_EQ((unsigned)ptr[0], 1u);  // configurationVersion == 1
-
-            mNALLengthSize = 1 + (ptr[14 + 7] & 3);
+            mNALLengthSize = getNALLengthSizeFromAvcCsd((const uint8_t *)data, size);
         } else if (10 == profile) {
             /* AV1 profile nothing to do */
         } else {
-            CHECK(AMediaFormat_getBuffer(format, AMEDIAFORMAT_KEY_CSD_AVC, &data, &size));
-            const uint8_t *ptr = (const uint8_t *)data;
-
-            CHECK(size >= 7);
-            CHECK_EQ((unsigned)ptr[0], 1u);  // configurationVersion == 1
-            // The number of bytes used to encode the length of a NAL unit.
-            mNALLengthSize = 1 + (ptr[4] & 3);
+            if (AMediaFormat_getBuffer(format, AMEDIAFORMAT_KEY_CSD_HEVC, &data, &size)) {
+                mNALLengthSize = getNALLengthSizeFromHevcCsd((const uint8_t *)data, size);
+            } else if (AMediaFormat_getBuffer(format, AMEDIAFORMAT_KEY_CSD_AVC, &data, &size)) {
+                mNALLengthSize = getNALLengthSizeFromAvcCsd((const uint8_t *)data, size);
+            } else {
+                LOG_ALWAYS_FATAL("Invalid Dolby Vision profile = %d", profile);
+            }
         }
     }
 
@@ -6135,6 +6124,24 @@
     return 0;
 }
 
+size_t MPEG4Source::getNALLengthSizeFromAvcCsd(const uint8_t *data, const size_t size) const {
+    CHECK(data != nullptr);
+    CHECK(size >= 7);
+    CHECK_EQ((unsigned)data[0], 1u);  // configurationVersion == 1
+
+    // The number of bytes used to encode the length of a NAL unit.
+    return 1 + (data[4] & 3);
+}
+
+size_t MPEG4Source::getNALLengthSizeFromHevcCsd(const uint8_t *data, const size_t size) const {
+    CHECK(data != nullptr);
+    CHECK(size >= 22);
+    CHECK_EQ((unsigned)data[0], 1u);  // configurationVersion == 1
+
+    // The number of bytes used to encode the length of a NAL unit.
+    return 1 + (data[14 + 7] & 3);
+}
+
 media_status_t MPEG4Source::read(
         MediaBufferHelper **out, const ReadOptions *options) {
     Mutex::Autolock autoLock(mLock);
diff --git a/services/mediaresourcemanager/Android.bp b/services/mediaresourcemanager/Android.bp
index a2bd5e1..73a96e9 100644
--- a/services/mediaresourcemanager/Android.bp
+++ b/services/mediaresourcemanager/Android.bp
@@ -77,6 +77,7 @@
         "ResourceManagerMetrics.cpp",
         "ResourceManagerService.cpp",
         "ResourceObserverService.cpp",
+        "ResourceManagerServiceUtils.cpp",
         "ServiceLog.cpp",
         "UidObserver.cpp",
 
diff --git a/services/mediaresourcemanager/ResourceManagerService.cpp b/services/mediaresourcemanager/ResourceManagerService.cpp
index 5d1ba2b..9552e25 100644
--- a/services/mediaresourcemanager/ResourceManagerService.cpp
+++ b/services/mediaresourcemanager/ResourceManagerService.cpp
@@ -39,6 +39,7 @@
 #include "IMediaResourceMonitor.h"
 #include "ResourceManagerMetrics.h"
 #include "ResourceManagerService.h"
+#include "ResourceManagerServiceUtils.h"
 #include "ResourceObserverService.h"
 #include "ServiceLog.h"
 
@@ -160,87 +161,6 @@
     service->removeProcessInfoOverride(mClientInfo.pid);
 }
 
-template <typename T>
-static String8 getString(const std::vector<T>& items) {
-    String8 itemsStr;
-    for (size_t i = 0; i < items.size(); ++i) {
-        itemsStr.appendFormat("%s ", toString(items[i]).c_str());
-    }
-    return itemsStr;
-}
-
-static bool hasResourceType(MediaResource::Type type, MediaResource::SubType subType,
-        const MediaResourceParcel& resource) {
-    if (type != resource.type) {
-      return false;
-    }
-    switch (type) {
-        // Codec subtypes (e.g. video vs. audio) are each considered separate resources, so
-        // compare the subtypes as well.
-        case MediaResource::Type::kSecureCodec:
-        case MediaResource::Type::kNonSecureCodec:
-            if (resource.subType == subType) {
-                return true;
-            }
-            break;
-        // Non-codec resources are not segregated by the subtype (e.g. video vs. audio).
-        default:
-            return true;
-    }
-    return false;
-}
-
-static bool hasResourceType(MediaResource::Type type, MediaResource::SubType subType,
-        const ResourceList& resources) {
-    for (auto it = resources.begin(); it != resources.end(); it++) {
-        if (hasResourceType(type, subType, it->second)) {
-            return true;
-        }
-    }
-    return false;
-}
-
-static bool hasResourceType(MediaResource::Type type, MediaResource::SubType subType,
-        const ResourceInfos& infos) {
-    for (const auto& [id, info] : infos) {
-        if (hasResourceType(type, subType, info.resources)) {
-            return true;
-        }
-    }
-    return false;
-}
-
-static ResourceInfos& getResourceInfosForEdit(int pid, PidResourceInfosMap& map) {
-    PidResourceInfosMap::iterator found = map.find(pid);
-    if (found == map.end()) {
-        // new pid
-        ResourceInfos infosForPid;
-        auto [it, inserted] = map.emplace(pid, infosForPid);
-        found = it;
-    }
-
-    return found->second;
-}
-
-static ResourceInfo& getResourceInfoForEdit(uid_t uid, int64_t clientId,
-                                            const std::string& name,
-        const std::shared_ptr<IResourceManagerClient>& client, ResourceInfos& infos) {
-    ResourceInfos::iterator found = infos.find(clientId);
-
-    if (found == infos.end()) {
-        ResourceInfo info{.uid = uid,
-                          .clientId = clientId,
-                          .name = name.empty()? "<unknown client>" : name,
-                          .client = client,
-                          .deathNotifier = nullptr,
-                          .pendingRemoval = false};
-        auto [it, inserted] = infos.emplace(clientId, info);
-        found = it;
-    }
-
-    return found->second;
-}
-
 static void notifyResourceGranted(int pid, const std::vector<MediaResourceParcel>& resources) {
     static const char* const kServiceName = "media_resource_monitor";
     sp<IBinder> binder = defaultServiceManager()->checkService(String16(kServiceName));
@@ -488,7 +408,6 @@
     int32_t pid = clientInfo.pid;
     int32_t uid = clientInfo.uid;
     int64_t clientId = clientInfo.id;
-    const std::string& name = clientInfo.name;
     String8 log = String8::format("addResource(pid %d, uid %d clientId %lld, resources %s)",
             pid, uid, (long long) clientId, getString(resources).c_str());
     mServiceLog->add(log);
@@ -503,7 +422,7 @@
         uid = callingUid;
     }
     ResourceInfos& infos = getResourceInfosForEdit(pid, mMap);
-    ResourceInfo& info = getResourceInfoForEdit(uid, clientId, name, client, infos);
+    ResourceInfo& info = getResourceInfoForEdit(clientInfo, client, infos);
     ResourceList resourceAdded;
 
     for (size_t i = 0; i < resources.size(); ++i) {
diff --git a/services/mediaresourcemanager/ResourceManagerServiceUtils.cpp b/services/mediaresourcemanager/ResourceManagerServiceUtils.cpp
new file mode 100644
index 0000000..892b1b3
--- /dev/null
+++ b/services/mediaresourcemanager/ResourceManagerServiceUtils.cpp
@@ -0,0 +1,98 @@
+/*
+**
+** 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 "ResourceManagerServiceUtils"
+#include <utils/Log.h>
+
+#include "ResourceManagerService.h"
+#include "ResourceManagerServiceUtils.h"
+
+namespace android {
+
+bool hasResourceType(MediaResource::Type type, MediaResource::SubType subType,
+        const MediaResourceParcel& resource) {
+    if (type != resource.type) {
+      return false;
+    }
+    switch (type) {
+        // Codec subtypes (e.g. video vs. audio) are each considered separate resources, so
+        // compare the subtypes as well.
+        case MediaResource::Type::kSecureCodec:
+        case MediaResource::Type::kNonSecureCodec:
+            if (resource.subType == subType) {
+                return true;
+            }
+            break;
+        // Non-codec resources are not segregated by the subtype (e.g. video vs. audio).
+        default:
+            return true;
+    }
+    return false;
+}
+
+bool hasResourceType(MediaResource::Type type, MediaResource::SubType subType,
+        const ResourceList& resources) {
+    for (auto it = resources.begin(); it != resources.end(); it++) {
+        if (hasResourceType(type, subType, it->second)) {
+            return true;
+        }
+    }
+    return false;
+}
+
+bool hasResourceType(MediaResource::Type type, MediaResource::SubType subType,
+        const ResourceInfos& infos) {
+    for (const auto& [id, info] : infos) {
+        if (hasResourceType(type, subType, info.resources)) {
+            return true;
+        }
+    }
+    return false;
+}
+
+ResourceInfos& getResourceInfosForEdit(int pid, PidResourceInfosMap& map) {
+    PidResourceInfosMap::iterator found = map.find(pid);
+    if (found == map.end()) {
+        // new pid
+        ResourceInfos infosForPid;
+        auto [it, inserted] = map.emplace(pid, infosForPid);
+        found = it;
+    }
+
+    return found->second;
+}
+
+ResourceInfo& getResourceInfoForEdit(const ClientInfoParcel& clientInfo,
+        const std::shared_ptr<IResourceManagerClient>& client, ResourceInfos& infos) {
+    ResourceInfos::iterator found = infos.find(clientInfo.id);
+
+    if (found == infos.end()) {
+        ResourceInfo info{.uid = static_cast<uid_t>(clientInfo.uid),
+                          .clientId = clientInfo.id,
+                          .name = clientInfo.name.empty()? "<unknown client>" : clientInfo.name,
+                          .client = client,
+                          .deathNotifier = nullptr,
+                          .pendingRemoval = false};
+        auto [it, inserted] = infos.emplace(clientInfo.id, info);
+        found = it;
+    }
+
+    return found->second;
+}
+
+} // namespace android
diff --git a/services/mediaresourcemanager/ResourceManagerServiceUtils.h b/services/mediaresourcemanager/ResourceManagerServiceUtils.h
new file mode 100644
index 0000000..bbc26de
--- /dev/null
+++ b/services/mediaresourcemanager/ResourceManagerServiceUtils.h
@@ -0,0 +1,62 @@
+/*
+**
+** 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_RESOURCEMANAGERSERVICEUTILS_H_
+#define ANDROID_MEDIA_RESOURCEMANAGERSERVICEUTILS_H_
+
+#include <vector>
+#include <utils/String8.h>
+
+namespace android {
+
+// templated function to stringify the given vector of items.
+template <typename T>
+String8 getString(const std::vector<T>& items) {
+    String8 itemsStr;
+    for (size_t i = 0; i < items.size(); ++i) {
+        itemsStr.appendFormat("%s ", toString(items[i]).c_str());
+    }
+    return itemsStr;
+}
+
+// Bunch of utility functions that looks for a specific Resource.
+
+//Check whether a given resource (of type and subtype) is found in given resource parcel.
+bool hasResourceType(MediaResource::Type type, MediaResource::SubType subType,
+        const MediaResourceParcel& resource);
+
+//Check whether a given resource (of type and subtype) is found in given resource list.
+bool hasResourceType(MediaResource::Type type, MediaResource::SubType subType,
+        const ResourceList& resources);
+
+//Check whether a given resource (of type and subtype) is found in given resource info list.
+bool hasResourceType(MediaResource::Type type, MediaResource::SubType subType,
+        const ResourceInfos& infos);
+
+// Return modifiable list of ResourceInfo for a given process (look up by pid)
+// from the map of ResourceInfos.
+ResourceInfos& getResourceInfosForEdit(int pid, PidResourceInfosMap& map);
+
+// Return modifiable ResourceInfo for a given process (look up by pid)
+// from the map of ResourceInfos.
+// If the item is not in the map, create one and add it to the map.
+ResourceInfo& getResourceInfoForEdit(const ClientInfoParcel& clientInfo,
+        const std::shared_ptr<IResourceManagerClient>& client, ResourceInfos& infos);
+
+} // namespace android
+
+#endif //ANDROID_MEDIA_RESOURCEMANAGERSERVICEUTILS_H_