Implement DrmSessionManager w mediaresourcemanager

Bug: 134787536
Test: DrmSessionManagerTest
Test: DrmSessionManager_test
Test: ResourceManagerService_test
Change-Id: Iab9f4f681c83f46b043cefc8633bb3e513a8e75a
diff --git a/drm/libmediadrm/Android.bp b/drm/libmediadrm/Android.bp
index 39b048a..8507729 100644
--- a/drm/libmediadrm/Android.bp
+++ b/drm/libmediadrm/Android.bp
@@ -40,9 +40,11 @@
         "libcutils",
         "libdl",
         "liblog",
+        "libmedia",
         "libmediadrmmetrics_lite",
         "libmediametrics",
         "libmediautils",
+        "libresourcemanagerservice",
         "libstagefright_foundation",
         "libutils",
         "android.hardware.drm@1.0",
diff --git a/drm/libmediadrm/DrmHal.cpp b/drm/libmediadrm/DrmHal.cpp
index 7cfe900..bd4b521 100644
--- a/drm/libmediadrm/DrmHal.cpp
+++ b/drm/libmediadrm/DrmHal.cpp
@@ -293,38 +293,45 @@
     }
 }
 
-
 Mutex DrmHal::mLock;
 
-struct DrmSessionClient : public DrmSessionClientInterface {
-    explicit DrmSessionClient(DrmHal* drm) : mDrm(drm) {}
-
-    virtual bool reclaimSession(const Vector<uint8_t>& sessionId) {
-        sp<DrmHal> drm = mDrm.promote();
-        if (drm == NULL) {
-            return true;
-        }
-        status_t err = drm->closeSession(sessionId);
-        if (err != OK) {
-            return false;
-        }
-        drm->sendEvent(EventType::SESSION_RECLAIMED,
-                toHidlVec(sessionId), hidl_vec<uint8_t>());
+bool DrmHal::DrmSessionClient::reclaimResource() {
+    sp<DrmHal> drm = mDrm.promote();
+    if (drm == NULL) {
         return true;
     }
+    status_t err = drm->closeSession(mSessionId);
+    if (err != OK) {
+        return false;
+    }
+    drm->sendEvent(EventType::SESSION_RECLAIMED,
+            toHidlVec(mSessionId), hidl_vec<uint8_t>());
+    return true;
+}
 
-protected:
-    virtual ~DrmSessionClient() {}
+String8 DrmHal::DrmSessionClient::getName() {
+    String8 name;
+    sp<DrmHal> drm = mDrm.promote();
+    if (drm == NULL) {
+        name.append("<deleted>");
+    } else if (drm->getPropertyStringInternal(String8("vendor"), name) != OK
+        || name.isEmpty()) {
+      name.append("<Get vendor failed or is empty>");
+    }
+    name.append("[");
+    for (size_t i = 0; i < mSessionId.size(); ++i) {
+        name.appendFormat("%02x", mSessionId[i]);
+    }
+    name.append("]");
+    return name;
+}
 
-private:
-    wp<DrmHal> mDrm;
-
-    DISALLOW_EVIL_CONSTRUCTORS(DrmSessionClient);
-};
+DrmHal::DrmSessionClient::~DrmSessionClient() {
+    DrmSessionManager::Instance()->removeSession(mSessionId);
+}
 
 DrmHal::DrmHal()
-   : mDrmSessionClient(new DrmSessionClient(this)),
-     mFactories(makeDrmFactories()),
+   : mFactories(makeDrmFactories()),
      mInitCheck((mFactories.size() == 0) ? ERROR_UNSUPPORTED : NO_INIT) {
 }
 
@@ -333,14 +340,13 @@
     auto openSessions = mOpenSessions;
     for (size_t i = 0; i < openSessions.size(); i++) {
         mLock.unlock();
-        closeSession(openSessions[i]);
+        closeSession(openSessions[i]->mSessionId);
         mLock.lock();
     }
     mOpenSessions.clear();
 }
 
 DrmHal::~DrmHal() {
-    DrmSessionManager::Instance()->removeDrm(mDrmSessionClient);
 }
 
 void DrmHal::cleanup() {
@@ -746,9 +752,9 @@
     } while (retry);
 
     if (err == OK) {
-        DrmSessionManager::Instance()->addSession(getCallingPid(),
-                mDrmSessionClient, sessionId);
-        mOpenSessions.push(sessionId);
+        sp<DrmSessionClient> client(new DrmSessionClient(this, sessionId));
+        DrmSessionManager::Instance()->addSession(getCallingPid(), client, sessionId);
+        mOpenSessions.push(client);
         mMetrics.SetSessionStart(sessionId);
     }
 
@@ -765,7 +771,7 @@
         if (status == Status::OK) {
             DrmSessionManager::Instance()->removeSession(sessionId);
             for (size_t i = 0; i < mOpenSessions.size(); i++) {
-                if (mOpenSessions[i] == sessionId) {
+                if (isEqualSessionId(mOpenSessions[i]->mSessionId, sessionId)) {
                     mOpenSessions.removeAt(i);
                     break;
                 }
diff --git a/drm/libmediadrm/DrmSessionManager.cpp b/drm/libmediadrm/DrmSessionManager.cpp
index 375644c..0b927ef 100644
--- a/drm/libmediadrm/DrmSessionManager.cpp
+++ b/drm/libmediadrm/DrmSessionManager.cpp
@@ -21,12 +21,17 @@
 #include <binder/IPCThreadState.h>
 #include <binder/IProcessInfoService.h>
 #include <binder/IServiceManager.h>
-#include <media/stagefright/ProcessInfo.h>
-#include <mediadrm/DrmSessionClientInterface.h>
+#include <cutils/properties.h>
+#include <media/IResourceManagerClient.h>
+#include <media/MediaResource.h>
 #include <mediadrm/DrmSessionManager.h>
 #include <unistd.h>
 #include <utils/String8.h>
 
+#include <vector>
+
+#include "ResourceManagerService.h"
+
 namespace android {
 
 static String8 GetSessionIdString(const Vector<uint8_t> &sessionId) {
@@ -37,6 +42,35 @@
     return sessionIdStr;
 }
 
+static std::vector<uint8_t> toStdVec(const Vector<uint8_t> &vector) {
+    const uint8_t *v = vector.array();
+    std::vector<uint8_t> vec(v, v + vector.size());
+    return vec;
+}
+
+static uint64_t toClientId(const sp<IResourceManagerClient>& drm) {
+    return reinterpret_cast<int64_t>(drm.get());
+}
+
+static Vector<MediaResource> toResourceVec(const Vector<uint8_t> &sessionId) {
+    Vector<MediaResource> resources;
+    // use UINT64_MAX to decrement through addition overflow
+    resources.push_back(MediaResource(MediaResource::kDrmSession, toStdVec(sessionId), UINT64_MAX));
+    return resources;
+}
+
+static sp<IResourceManagerService> getResourceManagerService() {
+    if (property_get_bool("persist.device_config.media_native.mediadrmserver", 1)) {
+        return new ResourceManagerService();
+    }
+    sp<IServiceManager> sm = defaultServiceManager();
+    if (sm == NULL) {
+        return NULL;
+    }
+    sp<IBinder> binder = sm->getService(String16("media.resource_manager"));
+    return interface_cast<IResourceManagerService>(binder);
+}
+
 bool isEqualSessionId(const Vector<uint8_t> &sessionId1, const Vector<uint8_t> &sessionId2) {
     if (sessionId1.size() != sessionId2.size()) {
         return false;
@@ -51,189 +85,114 @@
 
 sp<DrmSessionManager> DrmSessionManager::Instance() {
     static sp<DrmSessionManager> drmSessionManager = new DrmSessionManager();
+    drmSessionManager->init();
     return drmSessionManager;
 }
 
 DrmSessionManager::DrmSessionManager()
-    : mProcessInfo(new ProcessInfo()),
-      mTime(0) {}
+    : DrmSessionManager(getResourceManagerService()) {
+}
 
-DrmSessionManager::DrmSessionManager(sp<ProcessInfoInterface> processInfo)
-    : mProcessInfo(processInfo),
-      mTime(0) {}
+DrmSessionManager::DrmSessionManager(const sp<IResourceManagerService> &service)
+    : mService(service),
+      mInitialized(false) {
+    if (mService == NULL) {
+        ALOGE("Failed to init ResourceManagerService");
+    }
+}
 
-DrmSessionManager::~DrmSessionManager() {}
+DrmSessionManager::~DrmSessionManager() {
+    if (mService != NULL) {
+        IInterface::asBinder(mService)->unlinkToDeath(this);
+    }
+}
 
-void DrmSessionManager::addSession(
-        int pid, const sp<DrmSessionClientInterface>& drm, const Vector<uint8_t> &sessionId) {
-    ALOGV("addSession(pid %d, drm %p, sessionId %s)", pid, drm.get(),
+void DrmSessionManager::init() {
+    Mutex::Autolock lock(mLock);
+    if (mInitialized) {
+        return;
+    }
+    mInitialized = true;
+    if (mService != NULL) {
+        IInterface::asBinder(mService)->linkToDeath(this);
+    }
+}
+
+void DrmSessionManager::addSession(int pid,
+        const sp<IResourceManagerClient>& drm, const Vector<uint8_t> &sessionId) {
+    uid_t uid = IPCThreadState::self()->getCallingUid();
+    ALOGV("addSession(pid %d, uid %d, drm %p, sessionId %s)", pid, uid, drm.get(),
             GetSessionIdString(sessionId).string());
 
     Mutex::Autolock lock(mLock);
-    SessionInfo info;
-    info.drm = drm;
-    info.sessionId = sessionId;
-    info.timeStamp = getTime_l();
-    ssize_t index = mSessionMap.indexOfKey(pid);
-    if (index < 0) {
-        // new pid
-        SessionInfos infosForPid;
-        infosForPid.push_back(info);
-        mSessionMap.add(pid, infosForPid);
-    } else {
-        mSessionMap.editValueAt(index).push_back(info);
+    if (mService == NULL) {
+        return;
     }
+
+    int64_t clientId = toClientId(drm);
+    mSessionMap[toStdVec(sessionId)] = (SessionInfo){pid, uid, clientId};
+    mService->addResource(pid, uid, clientId, drm, toResourceVec(sessionId));
 }
 
 void DrmSessionManager::useSession(const Vector<uint8_t> &sessionId) {
     ALOGV("useSession(%s)", GetSessionIdString(sessionId).string());
 
     Mutex::Autolock lock(mLock);
-    for (size_t i = 0; i < mSessionMap.size(); ++i) {
-        SessionInfos& infos = mSessionMap.editValueAt(i);
-        for (size_t j = 0; j < infos.size(); ++j) {
-            SessionInfo& info = infos.editItemAt(j);
-            if (isEqualSessionId(sessionId, info.sessionId)) {
-                info.timeStamp = getTime_l();
-                return;
-            }
-        }
+    auto it = mSessionMap.find(toStdVec(sessionId));
+    if (mService == NULL || it == mSessionMap.end()) {
+        return;
     }
+
+    auto info = it->second;
+    mService->addResource(info.pid, info.uid, info.clientId, NULL, toResourceVec(sessionId));
 }
 
 void DrmSessionManager::removeSession(const Vector<uint8_t> &sessionId) {
     ALOGV("removeSession(%s)", GetSessionIdString(sessionId).string());
 
     Mutex::Autolock lock(mLock);
-    for (size_t i = 0; i < mSessionMap.size(); ++i) {
-        SessionInfos& infos = mSessionMap.editValueAt(i);
-        for (size_t j = 0; j < infos.size(); ++j) {
-            if (isEqualSessionId(sessionId, infos[j].sessionId)) {
-                infos.removeAt(j);
-                return;
-            }
-        }
+    auto it = mSessionMap.find(toStdVec(sessionId));
+    if (mService == NULL || it == mSessionMap.end()) {
+        return;
     }
-}
 
-void DrmSessionManager::removeDrm(const sp<DrmSessionClientInterface>& drm) {
-    ALOGV("removeDrm(%p)", drm.get());
-
-    Mutex::Autolock lock(mLock);
-    bool found = false;
-    for (size_t i = 0; i < mSessionMap.size(); ++i) {
-        SessionInfos& infos = mSessionMap.editValueAt(i);
-        for (size_t j = 0; j < infos.size();) {
-            if (infos[j].drm == drm) {
-                ALOGV("removed session (%s)", GetSessionIdString(infos[j].sessionId).string());
-                j = infos.removeAt(j);
-                found = true;
-            } else {
-                ++j;
-            }
-        }
-        if (found) {
-            break;
-        }
-    }
+    auto info = it->second;
+    mService->removeResource(info.pid, info.clientId, toResourceVec(sessionId));
+    mSessionMap.erase(it);
 }
 
 bool DrmSessionManager::reclaimSession(int callingPid) {
     ALOGV("reclaimSession(%d)", callingPid);
 
-    sp<DrmSessionClientInterface> drm;
-    Vector<uint8_t> sessionId;
-    int lowestPriorityPid;
-    int lowestPriority;
-    {
-        Mutex::Autolock lock(mLock);
-        int callingPriority;
-        if (!mProcessInfo->getPriority(callingPid, &callingPriority)) {
-            return false;
-        }
-        if (!getLowestPriority_l(&lowestPriorityPid, &lowestPriority)) {
-            return false;
-        }
-        if (lowestPriority <= callingPriority) {
-            return false;
-        }
+    // unlock early because reclaimResource might callback into removeSession
+    mLock.lock();
+    sp<IResourceManagerService> service(mService);
+    mLock.unlock();
 
-        if (!getLeastUsedSession_l(lowestPriorityPid, &drm, &sessionId)) {
-            return false;
-        }
-    }
-
-    if (drm == NULL) {
+    if (service == NULL) {
         return false;
     }
 
-    ALOGV("reclaim session(%s) opened by pid %d",
-            GetSessionIdString(sessionId).string(), lowestPriorityPid);
-
-    return drm->reclaimSession(sessionId);
+    // cannot update mSessionMap because we do not know which sessionId is reclaimed;
+    // we rely on IResourceManagerClient to removeSession in reclaimResource
+    Vector<uint8_t> dummy;
+    return service->reclaimResource(callingPid, toResourceVec(dummy));
 }
 
-int64_t DrmSessionManager::getTime_l() {
-    return mTime++;
+size_t DrmSessionManager::getSessionCount() const {
+    Mutex::Autolock lock(mLock);
+    return mSessionMap.size();
 }
 
-bool DrmSessionManager::getLowestPriority_l(int* lowestPriorityPid, int* lowestPriority) {
-    int pid = -1;
-    int priority = -1;
-    for (size_t i = 0; i < mSessionMap.size(); ++i) {
-        if (mSessionMap.valueAt(i).size() == 0) {
-            // no opened session by this process.
-            continue;
-        }
-        int tempPid = mSessionMap.keyAt(i);
-        int tempPriority;
-        if (!mProcessInfo->getPriority(tempPid, &tempPriority)) {
-            // shouldn't happen.
-            return false;
-        }
-        if (pid == -1) {
-            pid = tempPid;
-            priority = tempPriority;
-        } else {
-            if (tempPriority > priority) {
-                pid = tempPid;
-                priority = tempPriority;
-            }
-        }
-    }
-    if (pid != -1) {
-        *lowestPriorityPid = pid;
-        *lowestPriority = priority;
-    }
-    return (pid != -1);
+bool DrmSessionManager::containsSession(const Vector<uint8_t>& sessionId) const {
+    Mutex::Autolock lock(mLock);
+    return mSessionMap.count(toStdVec(sessionId));
 }
 
-bool DrmSessionManager::getLeastUsedSession_l(
-        int pid, sp<DrmSessionClientInterface>* drm, Vector<uint8_t>* sessionId) {
-    ssize_t index = mSessionMap.indexOfKey(pid);
-    if (index < 0) {
-        return false;
-    }
-
-    int leastUsedIndex = -1;
-    int64_t minTs = LLONG_MAX;
-    const SessionInfos& infos = mSessionMap.valueAt(index);
-    for (size_t j = 0; j < infos.size(); ++j) {
-        if (leastUsedIndex == -1) {
-            leastUsedIndex = j;
-            minTs = infos[j].timeStamp;
-        } else {
-            if (infos[j].timeStamp < minTs) {
-                leastUsedIndex = j;
-                minTs = infos[j].timeStamp;
-            }
-        }
-    }
-    if (leastUsedIndex != -1) {
-        *drm = infos[leastUsedIndex].drm;
-        *sessionId = infos[leastUsedIndex].sessionId;
-    }
-    return (leastUsedIndex != -1);
+void DrmSessionManager::binderDied(const wp<IBinder>& /*who*/) {
+    ALOGW("ResourceManagerService died.");
+    Mutex::Autolock lock(mLock);
+    mService.clear();
 }
 
 }  // namespace android
diff --git a/drm/libmediadrm/include/mediadrm/DrmHal.h b/drm/libmediadrm/include/mediadrm/DrmHal.h
index bdf1b30..542d300 100644
--- a/drm/libmediadrm/include/mediadrm/DrmHal.h
+++ b/drm/libmediadrm/include/mediadrm/DrmHal.h
@@ -26,8 +26,10 @@
 #include <android/hardware/drm/1.2/IDrmPlugin.h>
 #include <android/hardware/drm/1.2/IDrmPluginListener.h>
 
+#include <media/IResourceManagerService.h>
 #include <media/MediaAnalyticsItem.h>
 #include <mediadrm/DrmMetrics.h>
+#include <mediadrm/DrmSessionManager.h>
 #include <mediadrm/IDrm.h>
 #include <mediadrm/IDrmClient.h>
 #include <utils/threads.h>
@@ -59,6 +61,26 @@
 struct DrmHal : public BnDrm,
                 public IBinder::DeathRecipient,
                 public IDrmPluginListener_V1_2 {
+
+    struct DrmSessionClient : public BnResourceManagerClient {
+        explicit DrmSessionClient(DrmHal* drm, const Vector<uint8_t>& sessionId)
+          : mSessionId(sessionId),
+            mDrm(drm) {}
+
+        virtual bool reclaimResource();
+        virtual String8 getName();
+
+        const Vector<uint8_t> mSessionId;
+
+    protected:
+        virtual ~DrmSessionClient();
+
+    private:
+        wp<DrmHal> mDrm;
+
+        DISALLOW_EVIL_CONSTRUCTORS(DrmSessionClient);
+    };
+
     DrmHal();
     virtual ~DrmHal();
 
@@ -193,8 +215,6 @@
 private:
     static Mutex mLock;
 
-    sp<DrmSessionClientInterface> mDrmSessionClient;
-
     sp<IDrmClient> mListener;
     mutable Mutex mEventLock;
     mutable Mutex mNotifyLock;
@@ -208,7 +228,7 @@
     // Mutable to allow modification within GetPropertyByteArray.
     mutable MediaDrmMetrics mMetrics;
 
-    Vector<Vector<uint8_t>> mOpenSessions;
+    Vector<sp<DrmSessionClient>> mOpenSessions;
     void closeOpenSessions();
     void cleanup();
 
diff --git a/drm/libmediadrm/include/mediadrm/DrmSessionManager.h b/drm/libmediadrm/include/mediadrm/DrmSessionManager.h
index ba27199..b1ad580 100644
--- a/drm/libmediadrm/include/mediadrm/DrmSessionManager.h
+++ b/drm/libmediadrm/include/mediadrm/DrmSessionManager.h
@@ -18,56 +18,61 @@
 
 #define DRM_SESSION_MANAGER_H_
 
+#include <binder/IBinder.h>
+#include <media/IResourceManagerService.h>
 #include <media/stagefright/foundation/ABase.h>
 #include <utils/RefBase.h>
 #include <utils/KeyedVector.h>
 #include <utils/threads.h>
 #include <utils/Vector.h>
 
+#include <map>
+#include <utility>
+#include <vector>
+
 namespace android {
 
 class DrmSessionManagerTest;
-struct DrmSessionClientInterface;
-struct ProcessInfoInterface;
+class IResourceManagerClient;
 
 bool isEqualSessionId(const Vector<uint8_t> &sessionId1, const Vector<uint8_t> &sessionId2);
 
 struct SessionInfo {
-    sp<DrmSessionClientInterface> drm;
-    Vector<uint8_t> sessionId;
-    int64_t timeStamp;
+    pid_t pid;
+    uid_t uid;
+    int64_t clientId;
 };
 
-typedef Vector<SessionInfo > SessionInfos;
-typedef KeyedVector<int, SessionInfos > PidSessionInfosMap;
+typedef std::map<std::vector<uint8_t>, SessionInfo> SessionInfoMap;
 
-struct DrmSessionManager : public RefBase {
+struct DrmSessionManager : public IBinder::DeathRecipient {
     static sp<DrmSessionManager> Instance();
 
     DrmSessionManager();
-    explicit DrmSessionManager(sp<ProcessInfoInterface> processInfo);
+    explicit DrmSessionManager(const sp<IResourceManagerService> &service);
 
-    void addSession(int pid, const sp<DrmSessionClientInterface>& drm, const Vector<uint8_t>& sessionId);
+    void addSession(int pid, const sp<IResourceManagerClient>& drm, const Vector<uint8_t>& sessionId);
     void useSession(const Vector<uint8_t>& sessionId);
     void removeSession(const Vector<uint8_t>& sessionId);
-    void removeDrm(const sp<DrmSessionClientInterface>& drm);
     bool reclaimSession(int callingPid);
 
+    // sanity check APIs
+    size_t getSessionCount() const;
+    bool containsSession(const Vector<uint8_t>& sessionId) const;
+
+    // implements DeathRecipient
+    virtual void binderDied(const wp<IBinder>& /*who*/);
+
 protected:
     virtual ~DrmSessionManager();
 
 private:
-    friend class DrmSessionManagerTest;
+    void init();
 
-    int64_t getTime_l();
-    bool getLowestPriority_l(int* lowestPriorityPid, int* lowestPriority);
-    bool getLeastUsedSession_l(
-            int pid, sp<DrmSessionClientInterface>* drm, Vector<uint8_t>* sessionId);
-
-    sp<ProcessInfoInterface> mProcessInfo;
+    sp<IResourceManagerService> mService;
     mutable Mutex mLock;
-    PidSessionInfosMap mSessionMap;
-    int64_t mTime;
+    SessionInfoMap mSessionMap;
+    bool mInitialized;
 
     DISALLOW_EVIL_CONSTRUCTORS(DrmSessionManager);
 };