resourcemanager: define resource model

This change:
- defines a resource model interface
- defines a base resource model that implements the current (default) resource model
- integrates the resource model with the resource manager service
This change allows extending or replacing the resource models in the future.

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: Ifbdd3de90bf9fc5e21f2e1eaa9993dcc0983810a
diff --git a/services/mediaresourcemanager/ResourceTracker.cpp b/services/mediaresourcemanager/ResourceTracker.cpp
index c6255a2..2f93571 100644
--- a/services/mediaresourcemanager/ResourceTracker.cpp
+++ b/services/mediaresourcemanager/ResourceTracker.cpp
@@ -27,6 +27,45 @@
 
 namespace android {
 
+inline bool isHwCodec(MediaResource::SubType subType) {
+    return subType == MediaResource::SubType::kHwImageCodec ||
+           subType == MediaResource::SubType::kHwVideoCodec;
+}
+
+// Check whether a given resource (of type and subtype) is found in given resource list
+// that also has the given Primary SubType.
+static bool hasResourceType(MediaResource::Type type, MediaResource::SubType subType,
+                            const ResourceList& resources, MediaResource::SubType primarySubType) {
+    bool foundResource = false;
+    bool matchedPrimary =
+        (primarySubType == MediaResource::SubType::kUnspecifiedSubType) ?  true : false;
+    for (auto it = resources.begin(); it != resources.end(); it++) {
+        if (hasResourceType(type, subType, it->second)) {
+            foundResource = true;
+        } else if (it->second.subType == primarySubType) {
+            matchedPrimary = true;
+        } else if (isHwCodec(it->second.subType) == isHwCodec(primarySubType)) {
+            matchedPrimary = true;
+        }
+        if (matchedPrimary && foundResource) {
+            return true;
+        }
+    }
+    return false;
+}
+
+// See if the given client is already in the list of clients.
+inline bool contains(const std::vector<ClientInfo>& clients, const int64_t& clientId) {
+    std::vector<ClientInfo>::const_iterator found =
+        std::find_if(clients.begin(), clients.end(),
+                     [clientId](const ClientInfo& client) -> bool {
+                         return client.mClientId == clientId;
+                     });
+
+    return found != clients.end();
+}
+
+
 ResourceTracker::ResourceTracker(const std::shared_ptr<ResourceManagerServiceNew>& service,
                                  const sp<ProcessInfoInterface>& processInfo) :
         mService(service),
@@ -297,8 +336,10 @@
                                                    MediaResource::SubType::kHwImageCodec,
                                                    MediaResource::SubType::kSwImageCodec}) {
                 ClientInfo clientInfo;
-                if (getBiggestClient(pid, type, subType, clientInfo, true)) {
-                    targetClients.emplace_back(clientInfo);
+                if (getBiggestClientPendingRemoval(pid, type, subType, clientInfo)) {
+                    if (!contains(targetClients, clientInfo.mClientId)) {
+                        targetClients.emplace_back(clientInfo);
+                    }
                     continue;
                 }
             }
@@ -307,8 +348,10 @@
         default:
             ClientInfo clientInfo;
             MediaResource::SubType subType = MediaResource::SubType::kUnspecifiedSubType;
-            if (getBiggestClient(pid, type, subType, clientInfo, true)) {
-                targetClients.emplace_back(clientInfo);
+            if (getBiggestClientPendingRemoval(pid, type, subType, clientInfo)) {
+                if (!contains(targetClients, clientInfo.mClientId)) {
+                    targetClients.emplace_back(clientInfo);
+                }
             }
             break;
         }
@@ -358,16 +401,19 @@
 }
 
 bool ResourceTracker::getAllClients(const ResourceRequestInfo& resourceRequestInfo,
-                                    std::vector<ClientInfo>& clients) {
+                                    std::vector<ClientInfo>& clients,
+                                    MediaResource::SubType primarySubType) {
     MediaResource::Type type = resourceRequestInfo.mResource->type;
     MediaResource::SubType subType = resourceRequestInfo.mResource->subType;
     bool foundClient = false;
 
     for (auto& [pid, /* ResourceInfos */ infos] : mMap) {
         for (auto& [id, /* ResourceInfo */ info] : infos) {
-            if (hasResourceType(type, subType, info.resources)) {
-                clients.emplace_back(info.pid, info.uid, info.clientId);
-                foundClient = true;
+            if (hasResourceType(type, subType, info.resources, primarySubType)) {
+                if (!contains(clients, info.clientId)) {
+                    clients.emplace_back(info.pid, info.uid, info.clientId);
+                    foundClient = true;
+                }
             }
         }
     }
@@ -410,12 +456,38 @@
     return success;
 }
 
-bool ResourceTracker::getBiggestClient(int pid, MediaResource::Type type,
-                                       MediaResource::SubType subType,
-                                       ClientInfo& clientInfo, bool pendingRemovalOnly) {
+bool ResourceTracker::getLowestPriorityPid(const std::vector<ClientInfo>& clients,
+                                           int& lowestPriorityPid, int& lowestPriority) {
+    int pid = -1;
+    int priority = -1;
+    for (const ClientInfo& client : clients) {
+        int tempPriority = -1;
+        if (!getPriority(client.mPid, &tempPriority)) {
+            ALOGV("%s: can't get priority of pid %d, skipped", __func__, client.mPid);
+            // TODO: remove this pid from mMap?
+            continue;
+        }
+        if (pid == -1 || tempPriority > priority) {
+            // initial the value
+            pid = client.mPid;
+            priority = tempPriority;
+        }
+    }
+
+    bool success = (pid != -1);
+
+    if (success) {
+        lowestPriorityPid = pid;
+        lowestPriority = priority;
+    }
+    return success;
+}
+
+bool ResourceTracker::getBiggestClientPendingRemoval(int pid, MediaResource::Type type,
+                                                     MediaResource::SubType subType,
+                                                     ClientInfo& clientInfo) {
     std::map<int, ResourceInfos>::iterator found = mMap.find(pid);
     if (found == mMap.end()) {
-        ALOGE_IF(!pendingRemovalOnly, "%s: can't find resource info for pid %d", __func__, pid);
         return false;
     }
 
@@ -425,10 +497,48 @@
     const ResourceInfos& infos = found->second;
     for (const auto& [id, /* ResourceInfo */ info] : infos) {
         const ResourceList& resources = info.resources;
-        if (pendingRemovalOnly && !info.pendingRemoval) {
+        // Skip if the client is not marked pending removal.
+        if (!info.pendingRemoval) {
             continue;
         }
         for (auto it = resources.begin(); it != resources.end(); it++) {
+            const MediaResourceParcel& resource = it->second;
+            if (hasResourceType(type, subType, resource)) {
+                if (resource.value > largestValue) {
+                    largestValue = resource.value;
+                    clientId = info.clientId;
+                    uid = info.uid;
+                }
+            }
+        }
+    }
+
+    if (clientId == -1) {
+        return false;
+    }
+
+    clientInfo.mPid = pid;
+    clientInfo.mUid = uid;
+    clientInfo.mClientId = clientId;
+    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;
+    }
+
+    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 (auto it = resources.begin(); it != resources.end(); it++) {
             const MediaResourceParcel &resource = it->second;
             if (hasResourceType(type, subType, resource)) {
                 if (resource.value > largestValue) {
@@ -441,9 +551,8 @@
     }
 
     if (clientId == -1) {
-        ALOGE_IF(!pendingRemovalOnly,
-                 "%s: can't find resource type %s and subtype %s for pid %d",
-                 __func__, asString(type), asString(subType), pid);
+        ALOGE("%s: can't find resource type %s and subtype %s for pid %d",
+              __func__, asString(type), asString(subType), pid);
         return false;
     }