resourcemanager: define reclaim policy

Refactor the current design of the ResourceManagerService to
introduce Reclaim Policies.
This defines and implements the priority (oom score) of the process
as the default reclaim policy.
This change allows extending reclaim policies.

Bug: 294886363
Test: atest android.media.misc.cts.ResourceManagerTest
      atest android.media.misc.cts.ResourceManagerMultiTest
      /data/nativetest64/ResourceManagerService_test/ResourceManagerService_test
      /data/nativetest64/ResourceObserverService_test/ResourceObserverService_test
Change-Id: I0de0d86c08b1b148e2f813b884aa693b1643900c
diff --git a/services/mediaresourcemanager/Android.bp b/services/mediaresourcemanager/Android.bp
index 3ede5d2..794bda0 100644
--- a/services/mediaresourcemanager/Android.bp
+++ b/services/mediaresourcemanager/Android.bp
@@ -75,6 +75,7 @@
 
     srcs: [
         "DefaultResourceModel.cpp",
+        "ProcessPriorityReclaimPolicy.cpp",
         "ResourceManagerMetrics.cpp",
         "ResourceManagerService.cpp",
         "ResourceManagerServiceNew.cpp",
diff --git a/services/mediaresourcemanager/IReclaimPolicy.h b/services/mediaresourcemanager/IReclaimPolicy.h
new file mode 100644
index 0000000..dfbfc12
--- /dev/null
+++ b/services/mediaresourcemanager/IReclaimPolicy.h
@@ -0,0 +1,58 @@
+/*
+**
+** 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_IRECLAIMPOLICY_H_
+#define ANDROID_MEDIA_IRECLAIMPOLICY_H_
+
+#include <memory>
+#include <aidl/android/media/IResourceManagerClient.h>
+
+namespace android {
+
+struct ClientInfo;
+struct ReclaimRequestInfo;
+
+/*
+ * Interface that defines Reclaim Policy.
+ *
+ * This provides an interface to select/identify a client based on a specific
+ * Reclaim policy.
+ */
+class IReclaimPolicy {
+public:
+    IReclaimPolicy() {}
+
+    virtual ~IReclaimPolicy() {}
+
+    /*
+     * Based on the Reclaim policy, identify and return a client from the list
+     * of given clients that satisfy the resource requested.
+     *
+     * @param[in]  reclaimRequestInfo Information about the resource request
+     * @param[in]  client List of clients to select from.
+     * @param[out] targetClients Upon success, this will have the list of identified client(s).
+     *
+     * @return true on success, false otherwise
+     */
+    virtual bool getClients(const ReclaimRequestInfo& reclaimRequestInfo,
+                            const std::vector<ClientInfo>& clients,
+                            std::vector<ClientInfo>& targetClients) = 0;
+};
+
+} // namespace android
+
+#endif  // ANDROID_MEDIA_IRECLAIMPOLICY_H_
diff --git a/services/mediaresourcemanager/ProcessPriorityReclaimPolicy.cpp b/services/mediaresourcemanager/ProcessPriorityReclaimPolicy.cpp
new file mode 100644
index 0000000..5b776a6
--- /dev/null
+++ b/services/mediaresourcemanager/ProcessPriorityReclaimPolicy.cpp
@@ -0,0 +1,135 @@
+/*
+**
+** 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 "ProcessPriorityReclaimPolicy"
+#include <utils/Log.h>
+
+#include "ResourceTracker.h"
+#include "ResourceManagerService.h"
+#include "ProcessPriorityReclaimPolicy.h"
+
+namespace android {
+
+using aidl::android::media::IResourceManagerClient;
+
+ProcessPriorityReclaimPolicy::ProcessPriorityReclaimPolicy(
+        const std::shared_ptr<ResourceTracker>& resourceTracker)
+    : mResourceTracker(resourceTracker) {
+}
+
+ProcessPriorityReclaimPolicy::~ProcessPriorityReclaimPolicy() {
+}
+
+// Process priority (oom score) based reclaim:
+//   - Find a process with lowest priority (than that of calling process).
+//   - Find the bigegst client (with required resources) from that process.
+bool ProcessPriorityReclaimPolicy::getClients(const ReclaimRequestInfo& reclaimRequestInfo,
+                                              const std::vector<ClientInfo>& clients,
+                                              std::vector<ClientInfo>& targetClients) {
+    // NOTE: This is the behavior of the existing reclaim policy.
+    // We can alter it to select more than one client to reclaim from, depending
+    // on the reclaim polocy.
+
+    MediaResource::Type type = reclaimRequestInfo.mResources[0].type;
+    MediaResource::SubType subType = reclaimRequestInfo.mResources[0].subType;
+    // Find one client to reclaim the needed resources from.
+    // 1. Get the priority of the (reclaim) requesting process.
+    int callingPid = reclaimRequestInfo.mCallingPid;
+    int callingPriority = -1;
+    if (!mResourceTracker->getPriority(callingPid, &callingPriority)) {
+        ALOGE("%s: can't get process priority for pid %d", __func__, callingPid);
+        return false;
+    }
+
+    ClientInfo clientInfo;
+    // 2 Look to find the biggest client from the lowest priority process that
+    // has the other resources and with the given primary type.
+    bool found = false;
+    int lowestPriority = -1;
+    MediaResource::SubType primarySubType = subType;
+    for (size_t index = 1; !found && (index < reclaimRequestInfo.mResources.size()); index++) {
+        MediaResource::Type type = reclaimRequestInfo.mResources[index].type;
+        MediaResource::SubType subType = reclaimRequestInfo.mResources[index].subType;
+        found = getBiggestClientFromLowestPriority(callingPid, callingPriority,
+                                                   type, subType, primarySubType,
+                                                   clients, clientInfo, lowestPriority);
+    }
+    // 3 If we haven't found a client yet, then select the biggest client of primary type.
+    if (!found) {
+        found = getBiggestClientFromLowestPriority(callingPid, callingPriority,
+                                                   type, subType,
+                                                   MediaResource::SubType::kUnspecifiedSubType,
+                                                   clients, clientInfo, lowestPriority);
+    }
+    // 4 If we haven't found a client yet, then select the biggest client of different type.
+    // This is applicable for code type only.
+    if (!found) {
+        if (type != MediaResource::Type::kSecureCodec &&
+            type != MediaResource::Type::kNonSecureCodec) {
+            return false;
+        }
+        MediaResourceType otherType = (type == MediaResource::Type::kSecureCodec) ?
+            MediaResource::Type::kNonSecureCodec : MediaResource::Type::kSecureCodec;
+        if (!getBiggestClientFromLowestPriority(callingPid, callingPriority,
+                                                otherType, subType,
+                                                MediaResource::SubType::kUnspecifiedSubType,
+                                                clients, clientInfo, lowestPriority)) {
+            return false;
+        }
+    }
+
+    targetClients.emplace_back(clientInfo);
+    ALOGI("%s: CallingProcess(%d:%d) will reclaim from the lowestPriorityProcess(%d:%d)",
+          __func__, callingPid, callingPriority, clientInfo.mPid, lowestPriority);
+
+    return true;
+}
+
+bool ProcessPriorityReclaimPolicy::getBiggestClientFromLowestPriority(
+        pid_t callingPid,
+        int callingPriority,
+        MediaResource::Type type, MediaResource::SubType subType,
+        MediaResource::SubType primarySubType,
+        const std::vector<ClientInfo>& clients,
+        ClientInfo& targetClient,
+        int& lowestPriority) {
+    // 1. Find the lowest priority process among all the clients with the
+    // requested resource type.
+    int lowestPriorityPid = -1;
+    lowestPriority = -1;
+    if (!mResourceTracker->getLowestPriorityPid(type, subType, primarySubType, clients,
+                                                lowestPriorityPid, lowestPriority)) {
+        ALOGD("%s: can't find a process with lower priority than that of the process[%d:%d]",
+              __func__, callingPid, callingPriority);
+        return false;
+    }
+
+    // 2. Make sure that the priority of the target process is less than
+    // requesting process.
+    if (lowestPriority <= callingPriority) {
+        ALOGD("%s: lowest priority %d vs caller priority %d",
+              __func__, lowestPriority, callingPriority);
+        return false;
+    }
+
+    // 3. Look to find the biggest client from that process for the given resources
+    return mResourceTracker->getBiggestClient(lowestPriorityPid, type, subType,
+                                              clients, targetClient, primarySubType);
+}
+
+} // namespace android
diff --git a/services/mediaresourcemanager/ProcessPriorityReclaimPolicy.h b/services/mediaresourcemanager/ProcessPriorityReclaimPolicy.h
new file mode 100644
index 0000000..77bf7e1
--- /dev/null
+++ b/services/mediaresourcemanager/ProcessPriorityReclaimPolicy.h
@@ -0,0 +1,89 @@
+/*
+**
+** 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_PROCESSPRIORITYRECLAIMPOLICY_H_
+#define ANDROID_MEDIA_PROCESSPRIORITYRECLAIMPOLICY_H_
+
+#include <media/MediaResource.h>
+#include "IReclaimPolicy.h"
+
+namespace android {
+
+class ResourceTracker;
+struct ClientInfo;
+
+/*
+ * Implementation of the Reclaim Policy based on the process priority.
+ *
+ * Find the lowest priority process (lower than the calling/requesting process’s priority)
+ * that has the required resources.
+ * From that process, find the biggest client and return the same for reclaiming.
+ * If there is a codec co-existence policy, that is addressed as below:
+ *   - if these are any conflicting codecs, reclaim all those conflicting clients.
+ * If no conflicting codecs, the reclaim policy will select a client in the order of:
+ *   - Find the biggest client from the lowest priority process that
+ *     has the other resources and with the given primary type.
+ *   - select the biggest client from the lower priority process that
+ *     has the primary type.
+ *   - If it's a codec reclaim request, then:
+ *      - select the biggest client from the lower priority process that
+ *        has the othe type (for example secure for a non-secure and vice versa).
+ */
+class ProcessPriorityReclaimPolicy : public IReclaimPolicy {
+public:
+    ProcessPriorityReclaimPolicy(const std::shared_ptr<ResourceTracker>& resourceTracker);
+
+    virtual ~ProcessPriorityReclaimPolicy();
+
+    /*
+     * Based on the process priority, identify and return a client from the list
+     * of given clients that satisfy the resource requested.
+     *
+     * @param[in]  reclaimRequestInfo Information about the resource request
+     * @param[in]  client List of clients to select from.
+     * @param[out] targetClients Upon success, this will have the list of identified client(s).
+     *
+     * @return true on success, false otherwise
+     */
+    bool getClients(const ReclaimRequestInfo& reclaimRequestInfo,
+                    const std::vector<ClientInfo>& clients,
+                    std::vector<ClientInfo>& targetClients) override;
+
+private:
+
+    // Get the biggest client with the given resources from the given list of clients.
+    // The client should belong to lowest possible priority than that of the
+    // calling/requesting process.
+    // returns true on success, false otherwise
+    //
+    bool getBiggestClientFromLowestPriority(
+        pid_t callingPid,
+        int callingPriority,
+        MediaResource::Type type,
+        MediaResource::SubType subType,
+        MediaResource::SubType primarySubType,
+        const std::vector<ClientInfo>& clients,
+        ClientInfo& targetClient,
+        int& lowestPriority);
+
+private:
+    std::shared_ptr<ResourceTracker> mResourceTracker;
+};
+
+} // namespace android
+
+#endif  // ANDROID_MEDIA_PROCESSPRIORITYRECLAIMPOLICY_H_
diff --git a/services/mediaresourcemanager/ResourceManagerServiceNew.cpp b/services/mediaresourcemanager/ResourceManagerServiceNew.cpp
index a819237..dde389a 100644
--- a/services/mediaresourcemanager/ResourceManagerServiceNew.cpp
+++ b/services/mediaresourcemanager/ResourceManagerServiceNew.cpp
@@ -22,6 +22,7 @@
 #include <mediautils/ProcessInfo.h>
 
 #include "DefaultResourceModel.h"
+#include "ProcessPriorityReclaimPolicy.h"
 #include "ResourceManagerServiceNew.h"
 #include "ResourceTracker.h"
 #include "ServiceLog.h"
@@ -40,6 +41,7 @@
     mResourceTracker = std::make_shared<ResourceTracker>(ref<ResourceManagerServiceNew>(),
                                                          mProcessInfo);
     setUpResourceModels();
+    setUpReclaimPolicies();
 }
 
 void ResourceManagerServiceNew::setUpResourceModels() {
@@ -57,6 +59,12 @@
     }
 }
 
+void ResourceManagerServiceNew::setUpReclaimPolicies() {
+    mReclaimPolicies.clear();
+    // Process priority (oom score) as the Default reclaim policy.
+    mReclaimPolicies.push_back(std::make_unique<ProcessPriorityReclaimPolicy>(mResourceTracker));
+}
+
 Status ResourceManagerServiceNew::config(const std::vector<MediaResourcePolicyParcel>& policies) {
     Status status = ResourceManagerService::config(policies);
     // Change in the config dictates update to the resource model.
@@ -241,6 +249,7 @@
         // Since there was a conflict, we need to reclaim all elements.
         targetClients = std::move(clients);
     } else {
+        // Select a client among those have the needed resources.
         getClientForResource_l(reclaimRequestInfo, clients, targetClients);
     }
     return !targetClients.empty();
@@ -263,59 +272,14 @@
         }
     }
 
-    // Now find client(s) from a lowest priority process that has needed resources.
-    ResourceRequestInfo resourceRequestInfo {callingPid, nullptr};
-    for (const MediaResourceParcel& resource : reclaimRequestInfo.mResources) {
-        resourceRequestInfo.mResource = &resource;
-        if (getLowestPriorityProcessBiggestClient_l(resourceRequestInfo, clients, targetClient)) {
-            targetClients.emplace_back(targetClient);
+    // Run through all the reclaim policies until a client to reclaim from is identified.
+    for (std::unique_ptr<IReclaimPolicy>& reclaimPolicy : mReclaimPolicies) {
+        if (reclaimPolicy->getClients(reclaimRequestInfo, clients, targetClients)) {
             return;
         }
     }
 }
 
-// Process priority (oom score) based reclaim:
-//   - Find a process with lowest priority (than that of calling process).
-//   - Find the bigegst client (with required resources) from that process.
-bool ResourceManagerServiceNew::getLowestPriorityProcessBiggestClient_l(
-        const ResourceRequestInfo& resourceRequestInfo,
-        const std::vector<ClientInfo>& clients,
-        ClientInfo& clientInfo) {
-    int callingPid = resourceRequestInfo.mCallingPid;
-    MediaResource::Type type = resourceRequestInfo.mResource->type;
-    MediaResource::SubType subType = resourceRequestInfo.mResource->subType;
-    int lowestPriorityPid;
-    int lowestPriority;
-    int callingPriority;
-
-    if (!mResourceTracker->getPriority(callingPid, &callingPriority)) {
-        ALOGE("%s: can't get process priority for pid %d", __func__, callingPid);
-        return false;
-    }
-
-    // Find the lowest priority process among all the clients.
-    if (!mResourceTracker->getLowestPriorityPid(clients, lowestPriorityPid, lowestPriority)) {
-        ALOGE("%s: can't find a process with lower priority than that of the process[%d:%d]",
-              __func__, callingPid, callingPriority);
-        return false;
-    }
-
-    if (lowestPriority <= callingPriority) {
-        ALOGE("%s: lowest priority %d vs caller priority %d",
-              __func__, lowestPriority, callingPriority);
-        return false;
-    }
-
-    // Get the biggest client from this process.
-    if (!mResourceTracker->getBiggestClient(lowestPriorityPid, type, subType, clientInfo)) {
-        return false;
-    }
-
-    ALOGI("%s: CallingProcess(%d:%d) will reclaim from the lowestPriorityProcess(%d:%d)",
-          __func__, callingPid, callingPriority, lowestPriorityPid, lowestPriority);
-    return true;
-}
-
 bool ResourceManagerServiceNew::getLowestPriorityBiggestClient_l(
         const ResourceRequestInfo& resourceRequestInfo,
         ClientInfo& clientInfo) {
@@ -323,11 +287,25 @@
     if (resourceRequestInfo.mResource == nullptr) {
         return false;
     }
+
+    // Use the DefaultResourceModel to get all the clients with the resources requested.
     std::vector<MediaResourceParcel> resources{*resourceRequestInfo.mResource};
     ReclaimRequestInfo reclaimRequestInfo{resourceRequestInfo.mCallingPid, resources};
     std::vector<ClientInfo> clients;
     mDefaultResourceModel->getAllClients(reclaimRequestInfo, clients);
-    return getLowestPriorityProcessBiggestClient_l(resourceRequestInfo, clients, clientInfo);
+
+    // Use the ProcessPriorityReclaimPolicy to select a client to reclaim from.
+    std::unique_ptr<IReclaimPolicy> reclaimPolicy
+        = std::make_unique<ProcessPriorityReclaimPolicy>(mResourceTracker);
+    std::vector<ClientInfo> targetClients;
+    if (reclaimPolicy->getClients(reclaimRequestInfo, clients, targetClients)) {
+        if (!targetClients.empty()) {
+            clientInfo = targetClients[0];
+            return true;
+        }
+    }
+
+    return false;
 }
 
 bool ResourceManagerServiceNew::getPriority_l(int pid, int* priority) const {
diff --git a/services/mediaresourcemanager/ResourceManagerServiceNew.h b/services/mediaresourcemanager/ResourceManagerServiceNew.h
index 8522c4b..20c3d6e 100644
--- a/services/mediaresourcemanager/ResourceManagerServiceNew.h
+++ b/services/mediaresourcemanager/ResourceManagerServiceNew.h
@@ -22,6 +22,7 @@
 
 namespace android {
 
+class IReclaimPolicy;
 class IResourceModel;
 class ResourceTracker;
 
@@ -86,20 +87,15 @@
     // Set up the Resource models.
     void setUpResourceModels();
 
+    // Set up the Reclaim Policies.
+    void setUpReclaimPolicies();
+
     // From the list of clients, pick/select client(s) based on the reclaim policy.
     void getClientForResource_l(
         const ReclaimRequestInfo& reclaimRequestInfo,
         const std::vector<ClientInfo>& clients,
         std::vector<ClientInfo>& targetClients);
 
-    // Gets the client who owns specified resource type from lowest possible priority process.
-    // Returns false if the calling process priority is not higher than the lowest process
-    // priority. The client will remain unchanged if returns false.
-    bool getLowestPriorityProcessBiggestClient_l(
-        const ResourceRequestInfo& resourceRequestInfo,
-        const std::vector<ClientInfo>& clients,
-        ClientInfo& clientInfo);
-
     // Initializes the internal state of the ResourceManagerService
     void init() override;
 
@@ -164,6 +160,7 @@
 private:
     std::shared_ptr<ResourceTracker> mResourceTracker;
     std::unique_ptr<IResourceModel> mDefaultResourceModel;
+    std::vector<std::unique_ptr<IReclaimPolicy>> mReclaimPolicies;
 };
 
 // ----------------------------------------------------------------------------
diff --git a/services/mediaresourcemanager/ResourceTracker.cpp b/services/mediaresourcemanager/ResourceTracker.cpp
index 2f93571..8dc13cc 100644
--- a/services/mediaresourcemanager/ResourceTracker.cpp
+++ b/services/mediaresourcemanager/ResourceTracker.cpp
@@ -456,11 +456,21 @@
     return success;
 }
 
-bool ResourceTracker::getLowestPriorityPid(const std::vector<ClientInfo>& clients,
+bool ResourceTracker::getLowestPriorityPid(MediaResource::Type type, MediaResource::SubType subType,
+                                           MediaResource::SubType primarySubType,
+                                           const std::vector<ClientInfo>& clients,
                                            int& lowestPriorityPid, int& lowestPriority) {
     int pid = -1;
     int priority = -1;
     for (const ClientInfo& client : clients) {
+        const ResourceInfo* info = getResourceInfo(client.mPid, client.mClientId);
+        if (info == nullptr) {
+            continue;
+        }
+        if (!hasResourceType(type, subType, info->resources, primarySubType)) {
+            // doesn't have the requested resource type
+            continue;
+        }
         int tempPriority = -1;
         if (!getPriority(client.mPid, &tempPriority)) {
             ALOGV("%s: can't get priority of pid %d, skipped", __func__, client.mPid);
@@ -523,28 +533,46 @@
     return true;
 }
 
-bool ResourceTracker::getBiggestClient(int pid, MediaResource::Type type,
-                                       MediaResource::SubType subType,
-                                       ClientInfo& clientInfo) {
-    std::map<int, ResourceInfos>::iterator found = mMap.find(pid);
-    if (found == mMap.end()) {
-        ALOGE("%s: can't find resource info for pid %d", __func__, pid);
-        return false;
-    }
-
+bool ResourceTracker::getBiggestClient(int targetPid,
+                                       MediaResource::Type type, MediaResource::SubType subType,
+                                       const std::vector<ClientInfo>& clients,
+                                       ClientInfo& clientInfo,
+                                       MediaResource::SubType primarySubType) {
     uid_t   uid = -1;
     int64_t clientId = -1;
     uint64_t largestValue = 0;
-    const ResourceInfos& infos = found->second;
-    for (const auto& [id, info] : infos) {
-        const ResourceList& resources = info.resources;
+
+    for (const ClientInfo& client : clients) {
+        // Skip the clients that doesn't belong go the targetPid
+        if (client.mPid != targetPid) {
+            continue;
+        }
+        const ResourceInfo* info = getResourceInfo(client.mPid, client.mClientId);
+        if (info == nullptr) {
+            continue;
+        }
+
+        const ResourceList& resources = info->resources;
+        bool matchedPrimary =
+            (primarySubType == MediaResource::SubType::kUnspecifiedSubType) ?  true : false;
+        for (auto it = resources.begin(); !matchedPrimary && it != resources.end(); it++) {
+            if (it->second.subType == primarySubType) {
+                matchedPrimary = true;
+            } else if (isHwCodec(it->second.subType) == isHwCodec(primarySubType)) {
+                matchedPrimary = true;
+            }
+        }
+        // Primary type doesn't match, skip the client
+        if (!matchedPrimary) {
+            continue;
+        }
         for (auto it = resources.begin(); it != resources.end(); it++) {
-            const MediaResourceParcel &resource = it->second;
+            const MediaResourceParcel& resource = it->second;
             if (hasResourceType(type, subType, resource)) {
                 if (resource.value > largestValue) {
                     largestValue = resource.value;
-                    clientId = info.clientId;
-                    uid = info.uid;
+                    clientId = info->clientId;
+                    uid = info->uid;
                 }
             }
         }
@@ -552,11 +580,11 @@
 
     if (clientId == -1) {
         ALOGE("%s: can't find resource type %s and subtype %s for pid %d",
-              __func__, asString(type), asString(subType), pid);
+                 __func__, asString(type), asString(subType), targetPid);
         return false;
     }
 
-    clientInfo.mPid = pid;
+    clientInfo.mPid = targetPid;
     clientInfo.mUid = uid;
     clientInfo.mClientId = clientId;
     return true;
@@ -647,7 +675,9 @@
                     clients.clear();
                     return false;
                 } else {
-                    clients.emplace_back(info.pid, info.uid, info.clientId);
+                    if (!contains(clients, info.clientId)) {
+                        clients.emplace_back(info.pid, info.uid, info.clientId);
+                    }
                 }
             }
         }
@@ -656,6 +686,23 @@
     return true;
 }
 
+const ResourceInfo* ResourceTracker::getResourceInfo(int pid, const int64_t& clientId) const {
+    std::map<int, ResourceInfos>::const_iterator found = mMap.find(pid);
+    if (found == mMap.end()) {
+        ALOGV("%s: didn't find pid %d for clientId %lld", __func__, pid, (long long) clientId);
+        return nullptr;
+    }
+
+    const ResourceInfos& infos = found->second;
+    ResourceInfos::const_iterator foundClient = infos.find(clientId);
+    if (foundClient == infos.end()) {
+        ALOGV("%s: didn't find clientId %lld", __func__, (long long) clientId);
+        return nullptr;
+    }
+
+    return &foundClient->second;
+}
+
 bool ResourceTracker::isCallingPriorityHigher(int callingPid, int pid) {
     int callingPidPriority;
     if (!getPriority(callingPid, &callingPidPriority)) {
diff --git a/services/mediaresourcemanager/ResourceTracker.h b/services/mediaresourcemanager/ResourceTracker.h
index eb89d12..e5f33ec 100644
--- a/services/mediaresourcemanager/ResourceTracker.h
+++ b/services/mediaresourcemanager/ResourceTracker.h
@@ -102,8 +102,8 @@
     // Override the process info {state, oom score} of the process with pid.
     // returns true on success, false otherwise.
     bool overrideProcessInfo(
-        const std::shared_ptr<aidl::android::media::IResourceManagerClient>& client,
-        int pid, int procState, int oomScore);
+            const std::shared_ptr<aidl::android::media::IResourceManagerClient>& client,
+            int pid, int procState, int oomScore);
 
     // Remove the overridden process info.
     void removeProcessInfoOverride(int pid);
@@ -115,9 +115,9 @@
     // returns true upon finding at lease one client with the given resource request info,
     // false otherwise (no clients)
     bool getAllClients(
-        const ResourceRequestInfo& resourceRequestInfo,
-        std::vector<ClientInfo>& clients,
-        MediaResource::SubType primarySubType = MediaResource::SubType::kUnspecifiedSubType);
+            const ResourceRequestInfo& resourceRequestInfo,
+            std::vector<ClientInfo>& clients,
+            MediaResource::SubType primarySubType = MediaResource::SubType::kUnspecifiedSubType);
 
     // Look for the lowest priority process with the given resources.
     // Upon success lowestPriorityPid and lowestPriority are
@@ -127,31 +127,42 @@
     bool getLowestPriorityPid(MediaResource::Type type, MediaResource::SubType subType,
                               int& lowestPriorityPid, int& lowestPriority);
 
-    // Look for the lowest priority process with the given client list.
+    // Look for the lowest priority process with the given resources
+    // among the given client list.
+    // If applicable, match the primary type too.
     // returns true on success, false otherwise.
-    bool getLowestPriorityPid(const std::vector<ClientInfo>& clients,
-                              int& lowestPriorityPid, int& lowestPriority);
+    bool getLowestPriorityPid(
+            MediaResource::Type type, MediaResource::SubType subType,
+            MediaResource::SubType primarySubType,
+            const std::vector<ClientInfo>& clients,
+            int& lowestPriorityPid, int& lowestPriority);
 
     // Find the biggest client of the given process with given resources,
     // that is marked as pending to be removed.
     // returns true on success, false otherwise.
     bool getBiggestClientPendingRemoval(
-        int pid, MediaResource::Type type, MediaResource::SubType subType,
-        ClientInfo& clientInfo);
+            int pid, MediaResource::Type type,
+            MediaResource::SubType subType,
+            ClientInfo& clientInfo);
 
-    // Find the biggest client of the given process with given resources.
-    // If pendingRemovalOnly is set, then it will look for only those clients
-    // that are marked for removing.
+    // Find the biggest client from the process pid, selecting them from the list of clients.
+    // If applicable, match the primary type too.
     // Returns true when a client is found and clientInfo is updated accordingly.
     // Upon failure to find a client, it will return false without updating
     // clientInfo.
-    bool getBiggestClient(int pid, MediaResource::Type type, MediaResource::SubType subType,
-                          ClientInfo& clientInfo);
+    // Upon failure to find a client, it will return false.
+    bool getBiggestClient(
+            int targetPid,
+            MediaResource::Type type,
+            MediaResource::SubType subType,
+            const std::vector<ClientInfo>& clients,
+            ClientInfo& clientInfo,
+            MediaResource::SubType primarySubType = MediaResource::SubType::kUnspecifiedSubType);
 
     // Find the client that belongs to given process(pid) and with the given clientId.
     // A nullptr is returned upon failure to find the client.
     std::shared_ptr<::aidl::android::media::IResourceManagerClient> getClient(
-        int pid, const int64_t& clientId) const;
+            int pid, const int64_t& clientId) const;
 
     // Removes the client from the given process(pid) with the given clientId.
     // returns true on success, false otherwise.
@@ -160,7 +171,7 @@
     // Set the resource observer service, to which to notify when the resources
     // are added and removed.
     void setResourceObserverService(
-        const std::shared_ptr<ResourceObserverService>& observerService);
+            const std::shared_ptr<ResourceObserverService>& observerService);
 
     // Dump all the resource allocations for all the processes into a given string
     void dump(std::string& resourceLogs);
@@ -195,6 +206,10 @@
     // Returns false otherwise.
     bool isCallingPriorityHigher(int callingPid, int pid);
 
+    // Locate the resource info corresponding to the process pid and
+    // the client clientId.
+    const ResourceInfo* getResourceInfo(int pid, const int64_t& clientId) const;
+
     // Notify when a resource is added for the first time.
     void onFirstAdded(const MediaResourceParcel& resource, uid_t uid);
     // Notify when a resource is removed for the last time.