Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 801a252a authored by Marco Nelissen's avatar Marco Nelissen Committed by Gerrit Code Review
Browse files

Merge "Implement DrmSessionManager w mediaresourcemanager"

parents e02ad01a 79673cfb
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -44,9 +44,11 @@ cc_library_shared {
        "libcutils",
        "libdl",
        "liblog",
        "libmedia",
        "libmediadrmmetrics_lite",
        "libmediametrics",
        "libmediautils",
        "libresourcemanagerservice",
        "libstagefright_foundation",
        "libutils",
        "android.hardware.drm@1.0",
+36 −30
Original line number Diff line number Diff line
@@ -295,38 +295,45 @@ static status_t toStatusT_1_2(Status_V1_2 status) {
    }
}


Mutex DrmHal::mLock;

struct DrmSessionClient : public DrmSessionClientInterface {
    explicit DrmSessionClient(DrmHal* drm) : mDrm(drm) {}

    virtual bool reclaimSession(const Vector<uint8_t>& sessionId) {
bool DrmHal::DrmSessionClient::reclaimResource() {
    sp<DrmHal> drm = mDrm.promote();
    if (drm == NULL) {
        return true;
    }
        status_t err = drm->closeSession(sessionId);
    status_t err = drm->closeSession(mSessionId);
    if (err != OK) {
        return false;
    }
    drm->sendEvent(EventType::SESSION_RECLAIMED,
                toHidlVec(sessionId), hidl_vec<uint8_t>());
            toHidlVec(mSessionId), hidl_vec<uint8_t>());
    return true;
}

protected:
    virtual ~DrmSessionClient() {}

private:
    wp<DrmHal> mDrm;
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;
}

    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) {
}

@@ -335,14 +342,13 @@ void DrmHal::closeOpenSessions() {
    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() {
@@ -748,9 +754,9 @@ status_t DrmHal::openSession(DrmPlugin::SecurityLevel level,
    } 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);
    }

@@ -767,7 +773,7 @@ status_t DrmHal::closeSession(Vector<uint8_t> const &sessionId) {
        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;
                }
+103 −144
Original line number Diff line number Diff line
@@ -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 @@ static String8 GetSessionIdString(const Vector<uint8_t> &sessionId) {
    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 @@ bool isEqualSessionId(const Vector<uint8_t> &sessionId1, const Vector<uint8_t> &

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();
    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);
    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;
        }

        if (!getLeastUsedSession_l(lowestPriorityPid, &drm, &sessionId)) {
            return false;
        }
    }
    // unlock early because reclaimResource might callback into removeSession
    mLock.lock();
    sp<IResourceManagerService> service(mService);
    mLock.unlock();

    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++;
}

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);
size_t DrmSessionManager::getSessionCount() const {
    Mutex::Autolock lock(mLock);
    return mSessionMap.size();
}

bool DrmSessionManager::getLeastUsedSession_l(
        int pid, sp<DrmSessionClientInterface>* drm, Vector<uint8_t>* sessionId) {
    ssize_t index = mSessionMap.indexOfKey(pid);
    if (index < 0) {
        return false;
bool DrmSessionManager::containsSession(const Vector<uint8_t>& sessionId) const {
    Mutex::Autolock lock(mLock);
    return mSessionMap.count(toStdVec(sessionId));
}

    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
+23 −3
Original line number Diff line number Diff line
@@ -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 @@ inline bool operator==(const Vector<uint8_t> &l, const Vector<uint8_t> &r) {
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 @@ struct DrmHal : public BnDrm,
private:
    static Mutex mLock;

    sp<DrmSessionClientInterface> mDrmSessionClient;

    sp<IDrmClient> mListener;
    mutable Mutex mEventLock;
    mutable Mutex mNotifyLock;
@@ -208,7 +228,7 @@ private:
    // Mutable to allow modification within GetPropertyByteArray.
    mutable MediaDrmMetrics mMetrics;

    Vector<Vector<uint8_t>> mOpenSessions;
    Vector<sp<DrmSessionClient>> mOpenSessions;
    void closeOpenSessions();
    void cleanup();

+25 −20
Original line number Diff line number Diff line
@@ -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;

    int64_t getTime_l();
    bool getLowestPriority_l(int* lowestPriorityPid, int* lowestPriority);
    bool getLeastUsedSession_l(
            int pid, sp<DrmSessionClientInterface>* drm, Vector<uint8_t>* sessionId);
    void init();

    sp<ProcessInfoInterface> mProcessInfo;
    sp<IResourceManagerService> mService;
    mutable Mutex mLock;
    PidSessionInfosMap mSessionMap;
    int64_t mTime;
    SessionInfoMap mSessionMap;
    bool mInitialized;

    DISALLOW_EVIL_CONSTRUCTORS(DrmSessionManager);
};
Loading