MediaCodec: clean up resources pending removal at init

Until we can track memory usage in ResourceManager, always clean up
resources pending removal at init so that we can reclaim memory
and any other resources that are untracked.

Bug: 169831745
Test: atest ResourceManagerService_test
Test: atest CtsMediaTestCases -- --module-arg CtsMediaTestCases:size:small
Merged-In: Ia515443379edb03e68dd2ff5cba07c405aacd433
Change-Id: Ia515443379edb03e68dd2ff5cba07c405aacd433
diff --git a/media/libmedia/aidl/android/media/IResourceManagerService.aidl b/media/libmedia/aidl/android/media/IResourceManagerService.aidl
index 1b2d522..621bd84 100644
--- a/media/libmedia/aidl/android/media/IResourceManagerService.aidl
+++ b/media/libmedia/aidl/android/media/IResourceManagerService.aidl
@@ -102,4 +102,11 @@
      * @param clientId clientId within the pid that will be removed.
      */
     void markClientForPendingRemoval(int pid, long clientId);
+
+    /**
+     * Reclaim resources from clients pending removal, if any.
+     *
+     * @param pid pid from which resources will be reclaimed.
+     */
+    void reclaimResourcesFromClientsPendingRemoval(int pid);
 }
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index 31c800e..0a8d18d 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -241,6 +241,9 @@
     }
 
     AIBinder_linkToDeath(mService->asBinder().get(), mDeathRecipient.get(), this);
+
+    // Kill clients pending removal.
+    mService->reclaimResourcesFromClientsPendingRemoval(mPid);
 }
 
 //static
diff --git a/services/mediaresourcemanager/ResourceManagerService.cpp b/services/mediaresourcemanager/ResourceManagerService.cpp
index 3d36f8e..db06a36 100644
--- a/services/mediaresourcemanager/ResourceManagerService.cpp
+++ b/services/mediaresourcemanager/ResourceManagerService.cpp
@@ -575,13 +575,19 @@
         }
     }
 
+    *_aidl_return = reclaimInternal(clients);
+    return Status::ok();
+}
+
+bool ResourceManagerService::reclaimInternal(
+        const Vector<std::shared_ptr<IResourceManagerClient>> &clients) {
     if (clients.size() == 0) {
-        return Status::ok();
+        return false;
     }
 
     std::shared_ptr<IResourceManagerClient> failedClient;
     for (size_t i = 0; i < clients.size(); ++i) {
-        log = String8::format("reclaimResource from client %p", clients[i].get());
+        String8 log = String8::format("reclaimResource from client %p", clients[i].get());
         mServiceLog->add(log);
         bool success;
         Status status = clients[i]->reclaimResource(&success);
@@ -592,8 +598,7 @@
     }
 
     if (failedClient == NULL) {
-        *_aidl_return = true;
-        return Status::ok();
+        return true;
     }
 
     {
@@ -618,7 +623,7 @@
         }
     }
 
-    return Status::ok();
+    return false;
 }
 
 Status ResourceManagerService::overridePid(
@@ -681,6 +686,36 @@
     return Status::ok();
 }
 
+Status ResourceManagerService::reclaimResourcesFromClientsPendingRemoval(int32_t pid) {
+    String8 log = String8::format("reclaimResourcesFromClientsPendingRemoval(pid %d)", pid);
+    mServiceLog->add(log);
+
+    Vector<std::shared_ptr<IResourceManagerClient>> clients;
+    {
+        Mutex::Autolock lock(mLock);
+        if (!mProcessInfo->isValidPid(pid)) {
+            ALOGE("Rejected reclaimResourcesFromClientsPendingRemoval call with invalid pid.");
+            return Status::fromServiceSpecificError(BAD_VALUE);
+        }
+
+        for (MediaResource::Type type : {MediaResource::Type::kSecureCodec,
+                                         MediaResource::Type::kNonSecureCodec,
+                                         MediaResource::Type::kGraphicMemory,
+                                         MediaResource::Type::kDrmSession}) {
+            std::shared_ptr<IResourceManagerClient> client;
+            if (getBiggestClient_l(pid, type, &client, true /* pendingRemovalOnly */)) {
+                clients.add(client);
+                break;
+            }
+        }
+    }
+
+    if (!clients.empty()) {
+        reclaimInternal(clients);
+    }
+    return Status::ok();
+}
+
 bool ResourceManagerService::getPriority_l(int pid, int* priority) {
     int newPid = pid;
 
@@ -804,7 +839,8 @@
         bool pendingRemovalOnly) {
     ssize_t index = mMap.indexOfKey(pid);
     if (index < 0) {
-        ALOGE("getBiggestClient_l: can't find resource info for pid %d", pid);
+        ALOGE_IF(!pendingRemovalOnly,
+                 "getBiggestClient_l: can't find resource info for pid %d", pid);
         return false;
     }
 
@@ -828,7 +864,9 @@
     }
 
     if (clientTemp == NULL) {
-        ALOGE("getBiggestClient_l: can't find resource type %s for pid %d", asString(type), pid);
+        ALOGE_IF(!pendingRemovalOnly,
+                 "getBiggestClient_l: can't find resource type %s for pid %d",
+                 asString(type), pid);
         return false;
     }
 
diff --git a/services/mediaresourcemanager/ResourceManagerService.h b/services/mediaresourcemanager/ResourceManagerService.h
index ee982b7..3972d23 100644
--- a/services/mediaresourcemanager/ResourceManagerService.h
+++ b/services/mediaresourcemanager/ResourceManagerService.h
@@ -127,11 +127,18 @@
 
     Status markClientForPendingRemoval(int32_t pid, int64_t clientId) override;
 
+    Status reclaimResourcesFromClientsPendingRemoval(int32_t pid) override;
+
     Status removeResource(int pid, int64_t clientId, bool checkValid);
 
 private:
     friend class ResourceManagerServiceTest;
 
+    // Reclaims resources from |clients|. Returns true if reclaim succeeded
+    // for all clients.
+    bool reclaimInternal(
+            const Vector<std::shared_ptr<IResourceManagerClient>> &clients);
+
     // Gets the list of all the clients who own the specified resource type.
     // Returns false if any client belongs to a process with higher priority than the
     // calling process. The clients will remain unchanged if returns false.
diff --git a/services/mediaresourcemanager/test/ResourceManagerService_test.cpp b/services/mediaresourcemanager/test/ResourceManagerService_test.cpp
index 702935d..a6ecc09 100644
--- a/services/mediaresourcemanager/test/ResourceManagerService_test.cpp
+++ b/services/mediaresourcemanager/test/ResourceManagerService_test.cpp
@@ -520,6 +520,30 @@
             // clean up client 3 which still left
             mService->removeClient(kTestPid2, getId(mTestClient3));
         }
+
+        {
+            addResource();
+            mService->mSupportsSecureWithNonSecureCodec = true;
+
+            mService->markClientForPendingRemoval(kTestPid2, getId(mTestClient2));
+
+            // client marked for pending removal got reclaimed
+            EXPECT_TRUE(mService->reclaimResourcesFromClientsPendingRemoval(kTestPid2).isOk());
+            verifyClients(false /* c1 */, true /* c2 */, false /* c3 */);
+
+            // No more clients marked for removal
+            EXPECT_TRUE(mService->reclaimResourcesFromClientsPendingRemoval(kTestPid2).isOk());
+            verifyClients(false /* c1 */, false /* c2 */, false /* c3 */);
+
+            mService->markClientForPendingRemoval(kTestPid2, getId(mTestClient3));
+
+            // client marked for pending removal got reclaimed
+            EXPECT_TRUE(mService->reclaimResourcesFromClientsPendingRemoval(kTestPid2).isOk());
+            verifyClients(false /* c1 */, false /* c2 */, true /* c3 */);
+
+            // clean up client 1 which still left
+            mService->removeClient(kTestPid1, getId(mTestClient1));
+        }
     }
 
     void testRemoveClient() {