drm: refactor resourcemanager death handling

media.resource.manager Binder death notification is refactored as it:
  - doesn't connect with the resource.manager upon death.

So, the following changes are made with this CL:
  - Reconnect with the resource.manager upon death
  - Re-register all the resources, so that resource.manager
    will have all the resource information to help with
    drm session reclaim.
  - Replacing the deprecated API AServiceManager_getService
    with AServiceManager_waitForService.

Bug: 284031542
Test: atest android.media.misc.cts.ResourceManagerTest
Test: atest android.resourcemanager.cts.ResourceManagerHostJUnit4Test
Test: DrmSessionManagerTest
Test: DrmSessionManager_test
Test: MediaDrmClearkeyTest.testGetNumberOfSessions
Merged-In: If0468444741a076321dbf3666628dc89833f2dc9
Change-Id: If0468444741a076321dbf3666628dc89833f2dc9
diff --git a/drm/libmediadrm/DrmSessionManager.cpp b/drm/libmediadrm/DrmSessionManager.cpp
index 301538f..6744e25 100644
--- a/drm/libmediadrm/DrmSessionManager.cpp
+++ b/drm/libmediadrm/DrmSessionManager.cpp
@@ -36,13 +36,6 @@
 using aidl::android::media::MediaResourceParcel;
 using aidl::android::media::ClientInfoParcel;
 
-namespace {
-void ResourceManagerServiceDied(void* cookie) {
-    auto thiz = static_cast<DrmSessionManager*>(cookie);
-    thiz->binderDied();
-}
-}
-
 using ::ndk::ScopedAStatus;
 
 static String8 GetSessionIdString(const Vector<uint8_t> &sessionId) {
@@ -60,6 +53,12 @@
     return vec;
 }
 
+static Vector<uint8_t> toAndroidVec(const std::vector<uint8_t>& array) {
+    Vector<uint8_t> vec;
+    vec.appendArray(array.data(), array.size());
+    return vec;
+}
+
 static std::vector<MediaResourceParcel> toResourceVec(
         const Vector<uint8_t> &sessionId, int64_t value) {
     using Type = aidl::android::media::MediaResourceType;
@@ -72,11 +71,6 @@
     return resources;
 }
 
-static std::shared_ptr<IResourceManagerService> getResourceManagerService() {
-    ::ndk::SpAIBinder binder(AServiceManager_getService("media.resource_manager"));
-    return IResourceManagerService::fromBinder(binder);
-}
-
 bool isEqualSessionId(const Vector<uint8_t> &sessionId1, const Vector<uint8_t> &sessionId2) {
     if (sessionId1.size() != sessionId2.size()) {
         return false;
@@ -96,16 +90,15 @@
 }
 
 DrmSessionManager::DrmSessionManager()
-    : DrmSessionManager(getResourceManagerService()) {
+    : DrmSessionManager(nullptr) {
 }
 
 DrmSessionManager::DrmSessionManager(const std::shared_ptr<IResourceManagerService> &service)
     : mService(service),
-      mInitialized(false),
-      mDeathRecipient(AIBinder_DeathRecipient_new(ResourceManagerServiceDied)) {
-    if (mService == NULL) {
-        ALOGE("Failed to init ResourceManagerService");
-    }
+      mDeathRecipient(::ndk::ScopedAIBinder_DeathRecipient(
+          AIBinder_DeathRecipient_new(ResourceManagerServiceDied))) {
+    // Setting callback notification when DeathRecipient gets deleted.
+    AIBinder_DeathRecipient_setOnUnlinked(mDeathRecipient.get(), BinderUnlinkedCallback);
 }
 
 DrmSessionManager::~DrmSessionManager() {
@@ -114,14 +107,64 @@
     }
 }
 
-void DrmSessionManager::init() {
+status_t DrmSessionManager::init() {
     Mutex::Autolock lock(mLock);
-    if (mInitialized) {
+    getResourceManagerService_l();
+    if (mService == nullptr) {
+        ALOGE("Failed to init ResourceManagerService");
+        return DEAD_OBJECT;
+    }
+
+    return OK;
+}
+
+void DrmSessionManager::getResourceManagerService_l() {
+    if (mService != nullptr) {
         return;
     }
-    mInitialized = true;
-    if (mService != NULL) {
-        AIBinder_linkToDeath(mService->asBinder().get(), mDeathRecipient.get(), this);
+
+    // Get binder interface to resource manager.
+    ::ndk::SpAIBinder binder(AServiceManager_waitForService("media.resource_manager"));
+    mService = IResourceManagerService::fromBinder(binder);
+    if (mService == nullptr) {
+        ALOGE("Failed to get ResourceManagerService");
+        return;
+    }
+
+    // Create the context that is passed as cookie to the binder death notification.
+    // The context gets deleted at BinderUnlinkedCallback.
+    BinderDiedContext* context = new BinderDiedContext{
+        .mDrmSessionManager = wp<DrmSessionManager>::fromExisting(this)};
+    // Register for the callbacks by linking to death notification.
+    AIBinder_linkToDeath(mService->asBinder().get(), mDeathRecipient.get(), context);
+
+    // If the RM was restarted, re-register all the resources.
+    if (mBinderDied) {
+        reRegisterAllResources_l();
+        mBinderDied = false;
+    }
+}
+
+void DrmSessionManager::reRegisterAllResources_l() {
+    if (mSessionMap.empty()) {
+        // Nothing to register.
+        ALOGV("No resources to add");
+        return;
+    }
+
+    if (mService == nullptr) {
+        ALOGW("Service isn't available");
+        return;
+    }
+
+    // Go through the session map and re-register all the resources for those sessions.
+    for (SessionInfoMap::const_iterator iter = mSessionMap.begin();
+         iter != mSessionMap.end(); ++iter) {
+        ClientInfoParcel clientInfo{.pid = static_cast<int32_t>(iter->second.pid),
+                                    .uid = static_cast<int32_t>(iter->second.uid),
+                                    .id = iter->second.clientId};
+        mService->addResource(clientInfo, iter->second.drm,
+                              toResourceVec(toAndroidVec(iter->first), iter->second.resourceValue));
     }
 }
 
@@ -137,7 +180,7 @@
     }
 
     static int64_t clientId = 0;
-    mSessionMap[toStdVec(sessionId)] = (SessionInfo){pid, uid, clientId};
+    mSessionMap[toStdVec(sessionId)] = (SessionInfo){pid, uid, clientId, drm, INT64_MAX};
     ClientInfoParcel clientInfo{.pid = static_cast<int32_t>(pid),
                                 .uid = static_cast<int32_t>(uid),
                                 .id = clientId++};
@@ -154,6 +197,7 @@
     }
 
     auto info = it->second;
+    info.resourceValue = -1;
     ClientInfoParcel clientInfo{.pid = static_cast<int32_t>(info.pid),
                                 .uid = static_cast<int32_t>(info.uid),
                                 .id = info.clientId};
@@ -215,7 +259,31 @@
 void DrmSessionManager::binderDied() {
     ALOGW("ResourceManagerService died.");
     Mutex::Autolock lock(mLock);
-    mService.reset();
+    mService = nullptr;
+    mBinderDied = true;
+    // start an async operation that will reconnect with the RM and
+    // re-registers all the resources.
+    mGetServiceFuture = std::async(std::launch::async, [this] { getResourceManagerService(); });
+}
+
+void DrmSessionManager::ResourceManagerServiceDied(void* cookie) {
+    BinderDiedContext* context = reinterpret_cast<BinderDiedContext*>(cookie);
+
+    // Validate the context and check if the DrmSessionManager object is still in scope.
+    if (context != nullptr) {
+        sp<DrmSessionManager> thiz = context->mDrmSessionManager.promote();
+        if (thiz != nullptr) {
+            thiz->binderDied();
+        } else {
+            ALOGI("DrmSessionManager is out of scope already");
+        }
+    }
+}
+
+void DrmSessionManager::BinderUnlinkedCallback(void* cookie) {
+    BinderDiedContext* context = reinterpret_cast<BinderDiedContext*>(cookie);
+    // Since we don't need the context anymore, we are deleting it now.
+    delete context;
 }
 
 }  // namespace android
diff --git a/drm/libmediadrm/include/mediadrm/DrmSessionManager.h b/drm/libmediadrm/include/mediadrm/DrmSessionManager.h
index c56bf01..025261d 100644
--- a/drm/libmediadrm/include/mediadrm/DrmSessionManager.h
+++ b/drm/libmediadrm/include/mediadrm/DrmSessionManager.h
@@ -27,8 +27,10 @@
 #include <utils/threads.h>
 #include <utils/Vector.h>
 
+#include <future>
 #include <map>
 #include <memory>
+#include <set>
 #include <utility>
 #include <vector>
 
@@ -38,6 +40,7 @@
 
 using aidl::android::media::IResourceManagerClient;
 using aidl::android::media::IResourceManagerService;
+using aidl::android::media::MediaResourceParcel;
 
 bool isEqualSessionId(const Vector<uint8_t> &sessionId1, const Vector<uint8_t> &sessionId2);
 
@@ -45,6 +48,9 @@
     pid_t pid;
     uid_t uid;
     int64_t clientId;
+    std::shared_ptr<IResourceManagerClient> drm;
+    int64_t resourceValue;
+
 };
 
 typedef std::map<std::vector<uint8_t>, SessionInfo> SessionInfoMap;
@@ -66,20 +72,52 @@
     size_t getSessionCount() const;
     bool containsSession(const Vector<uint8_t>& sessionId) const;
 
-    // implements DeathRecipient
-    void binderDied();
-
 protected:
     virtual ~DrmSessionManager();
 
 private:
-    void init();
+    status_t init();
 
-    std::shared_ptr<IResourceManagerService> mService;
+    // To set up the binder interface with the resource manager service.
+    void getResourceManagerService() {
+        Mutex::Autolock lock(mLock);
+        getResourceManagerService_l();
+    }
+    void getResourceManagerService_l();
+
+    // To add/register all the resources currently added/registered with
+    // the ResourceManagerService.
+    // This function will be called right after the death of the Resource
+    // Manager to make sure that the newly started ResourceManagerService
+    // knows about the current resource usage.
+    void reRegisterAllResources_l();
+
+    // For binder death handling
+    static void ResourceManagerServiceDied(void* cookie);
+    static void BinderUnlinkedCallback(void* cookie);
+    void binderDied();
+
+    // BinderDiedContext defines the cookie that is passed as DeathRecipient.
+    // Since this can maintain more context than a raw pointer, we can
+    // validate the scope of DrmSessionManager,
+    // before deferencing it upon the binder death.
+    struct BinderDiedContext {
+        wp<DrmSessionManager> mDrmSessionManager;
+    };
+
+    std::shared_ptr<IResourceManagerService> mService = nullptr;
     mutable Mutex mLock;
     SessionInfoMap mSessionMap;
-    bool mInitialized;
+    bool mBinderDied = false;
     ::ndk::ScopedAIBinder_DeathRecipient mDeathRecipient;
+    /**
+     * Reconnecting with the ResourceManagerService, after its binder interface dies,
+     * is done asynchronously. It will also make sure that, all the resources
+     * asssociated with this DrmSessionManager are added with the new instance
+     * of the ResourceManagerService to persist the state of resources.
+     * We must store the reference of the furture to guarantee real asynchronous operation.
+     */
+    std::future<void> mGetServiceFuture;
 
     DISALLOW_EVIL_CONSTRUCTORS(DrmSessionManager);
 };
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index b02a1e8..457c625 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -448,17 +448,18 @@
 
 void MediaCodec::ResourceManagerServiceProxy::reRegisterAllResources_l() {
     if (mMediaResourceParcel.empty()) {
-        ALOGV("%s:%d:%p No resources to add", __func__, __LINE__, this);
+        ALOGV("No resources to add");
+        return;
+    }
+
+    if (mService == nullptr) {
+        ALOGW("Service isn't available");
         return;
     }
 
     std::vector<MediaResourceParcel> resources;
     std::copy(mMediaResourceParcel.begin(), mMediaResourceParcel.end(),
               std::back_inserter(resources));
-    if (mService == nullptr) {
-        ALOGW("%s:%d:%p Serice isn't available", __func__, __LINE__, this);
-        return;
-    }
     ClientInfoParcel clientInfo{.pid = static_cast<int32_t>(mPid),
                                 .uid = static_cast<int32_t>(mUid),
                                 .id = getId(mClient),
@@ -491,7 +492,7 @@
     std::scoped_lock lock{mLock};
     std::shared_ptr<IResourceManagerService> service = getService_l();
     if (service == nullptr) {
-        ALOGW("%s:%d:%p Serice isn't available", __func__, __LINE__, this);
+        ALOGW("Service isn't available");
         return;
     }
     std::vector<MediaResourceParcel> resources;
@@ -509,7 +510,7 @@
     std::scoped_lock lock{mLock};
     std::shared_ptr<IResourceManagerService> service = getService_l();
     if (service == nullptr) {
-        ALOGW("%s:%d:%p Serice isn't available", __func__, __LINE__, this);
+        ALOGW("Service isn't available");
         return;
     }
     std::vector<MediaResourceParcel> resources;
@@ -526,7 +527,7 @@
     std::scoped_lock lock{mLock};
     std::shared_ptr<IResourceManagerService> service = getService_l();
     if (service == nullptr) {
-        ALOGW("%s:%d:%p Serice isn't available", __func__, __LINE__, this);
+        ALOGW("Service isn't available");
         return;
     }
     ClientInfoParcel clientInfo{.pid = static_cast<int32_t>(mPid),
@@ -541,7 +542,7 @@
     std::scoped_lock lock{mLock};
     std::shared_ptr<IResourceManagerService> service = getService_l();
     if (service == nullptr) {
-        ALOGW("%s:%d:%p Serice isn't available", __func__, __LINE__, this);
+        ALOGW("Service isn't available");
         return;
     }
     ClientInfoParcel clientInfo{.pid = static_cast<int32_t>(mPid),
@@ -557,7 +558,7 @@
     std::scoped_lock lock{mLock};
     std::shared_ptr<IResourceManagerService> service = getService_l();
     if (service == nullptr) {
-        ALOGW("%s:%d:%p Service isn't available", __func__, __LINE__, this);
+        ALOGW("Service isn't available");
         return false;
     }
     bool success;
@@ -573,7 +574,7 @@
     std::scoped_lock lock{mLock};
     std::shared_ptr<IResourceManagerService> service = getService_l();
     if (service == nullptr) {
-        ALOGW("%s:%d:%p Serice isn't available", __func__, __LINE__, this);
+        ALOGW("Service isn't available");
         return;
     }
     ClientInfoParcel clientInfo{.pid = static_cast<int32_t>(mPid),
@@ -588,7 +589,7 @@
     std::scoped_lock lock{mLock};
     std::shared_ptr<IResourceManagerService> service = getService_l();
     if (service == nullptr) {
-        ALOGW("%s:%d:%p Serice isn't available", __func__, __LINE__, this);
+        ALOGW("Service isn't available");
         return;
     }
     clientConfig.clientInfo.pid = static_cast<int32_t>(mPid);
@@ -603,7 +604,7 @@
     std::scoped_lock lock{mLock};
     std::shared_ptr<IResourceManagerService> service = getService_l();
     if (service == nullptr) {
-        ALOGW("%s:%d:%p Serice isn't available", __func__, __LINE__, this);
+        ALOGW("Service isn't available");
         return;
     }
     clientConfig.clientInfo.pid = static_cast<int32_t>(mPid);
@@ -618,7 +619,7 @@
     std::scoped_lock lock{mLock};
     std::shared_ptr<IResourceManagerService> service = getService_l();
     if (service == nullptr) {
-        ALOGW("%s:%d:%p Serice isn't available", __func__, __LINE__, this);
+        ALOGW("Service isn't available");
         return;
     }
     clientConfig.clientInfo.pid = static_cast<int32_t>(mPid);