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

Commit 10305cc6 authored by Ronghua Wu's avatar Ronghua Wu
Browse files

Add DRM session manager.

Bug: 19265536
Change-Id: Ia9f2c94c64ed6c1fe99d54de81d71c8973994865
parent 8f7b7fa4
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -10,6 +10,7 @@ LOCAL_SRC_FILES:= \
    ActivityManager.cpp         \
    Crypto.cpp                  \
    Drm.cpp                     \
    DrmSessionManager.cpp       \
    HDCP.cpp                    \
    MediaPlayerFactory.cpp      \
    MediaPlayerService.cpp      \
+34 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2015 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef DRM_PROXY_INTERFACE_H_
#define DRM_PROXY_INTERFACE_H_

#include <utils/RefBase.h>
#include <utils/Vector.h>

namespace android {

struct DrmSessionClientInterface : public RefBase {
    virtual bool reclaimSession(const Vector<uint8_t>& sessionId) = 0;

protected:
    virtual ~DrmSessionClientInterface() {}
};

}  // namespace android

#endif  // DRM_PROXY_INTERFACE_H_
+241 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2015 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

//#define LOG_NDEBUG 0
#define LOG_TAG "DrmSessionManager"
#include <utils/Log.h>

#include "DrmSessionManager.h"

#include "DrmSessionClientInterface.h"
#include "ProcessInfoInterface.h"
#include <binder/IPCThreadState.h>
#include <unistd.h>
#include <utils/String8.h>

namespace android {

static String8 GetSessionIdString(const Vector<uint8_t> &sessionId) {
    String8 sessionIdStr;
    for (size_t i = 0; i < sessionId.size(); ++i) {
        sessionIdStr.appendFormat("%u ", sessionId[i]);
    }
    return sessionIdStr;
}

struct ProcessInfo : public ProcessInfoInterface {
    ProcessInfo() {}

    virtual int getPriority(int pid) {
        // TODO: implement
        // Get process state to determine priority.
        // According to the define of PROCESS_STATE_***, higher the value lower
        // the priority. So we will do a converting from state to priority here.
        return -1;
    }

protected:
    virtual ~ProcessInfo() {}

private:
    DISALLOW_EVIL_CONSTRUCTORS(ProcessInfo);
};

bool isEqualSessionId(const Vector<uint8_t> &sessionId1, const Vector<uint8_t> &sessionId2) {
    if (sessionId1.size() != sessionId2.size()) {
        return false;
    }
    for (size_t i = 0; i < sessionId1.size(); ++i) {
        if (sessionId1[i] != sessionId2[i]) {
            return false;
        }
    }
    return true;
}

DrmSessionManager::DrmSessionManager()
    : mProcessInfo(new ProcessInfo()),
      mTime(0) {}

DrmSessionManager::DrmSessionManager(sp<ProcessInfoInterface> processInfo)
    : mProcessInfo(processInfo),
      mTime(0) {}

DrmSessionManager::~DrmSessionManager() {}

void DrmSessionManager::addSession(
        int pid, sp<DrmSessionClientInterface> drm, const Vector<uint8_t> &sessionId) {
    ALOGV("addSession(pid %d, drm %p, sessionId %s)", pid, 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);
    }
}

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

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

void DrmSessionManager::removeDrm(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;
        }
    }
}

bool DrmSessionManager::reclaimSession(int callingPid) {
    ALOGV("reclaimSession(%d)", callingPid);

    sp<DrmSessionClientInterface> drm;
    Vector<uint8_t> sessionId;
    {
        Mutex::Autolock lock(mLock);
        int callingPriority = mProcessInfo->getPriority(callingPid);
        int lowestPriorityPid;
        int lowestPriority;
        if (!getLowestPriority_l(&lowestPriorityPid, &lowestPriority)) {
            return false;
        }
        if (lowestPriority >= callingPriority) {
            return false;
        }

        if (!getLeastUsedSession_l(lowestPriorityPid, &drm, &sessionId)) {
            return false;
        }
    }

    if (drm == NULL) {
        return false;
    }

    return drm->reclaimSession(sessionId);
}

int64_t DrmSessionManager::getTime_l() {
    return mTime++;
}

bool DrmSessionManager::getLowestPriority_l(int* lowestPriorityPid, int* lowestPriority) {
    int pid = -1;
    int priority = INT_MAX;
    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 = mProcessInfo->getPriority(tempPid);
        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::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);
}

}  // namespace android
+75 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2015 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef DRM_SESSION_MANAGER_H_

#define DRM_SESSION_MANAGER_H_

#include <media/stagefright/foundation/ABase.h>
#include <utils/RefBase.h>
#include <utils/KeyedVector.h>
#include <utils/threads.h>
#include <utils/Vector.h>

namespace android {

class DrmSessionManagerTest;
struct DrmSessionClientInterface;
struct ProcessInfoInterface;

bool isEqualSessionId(const Vector<uint8_t> &sessionId1, const Vector<uint8_t> &sessionId2);

struct SessionInfo {
    sp<DrmSessionClientInterface> drm;
    Vector<uint8_t> sessionId;
    int64_t timeStamp;
};

typedef Vector<SessionInfo > SessionInfos;
typedef KeyedVector<int, SessionInfos > PidSessionInfosMap;

struct DrmSessionManager : public RefBase {
    DrmSessionManager();
    DrmSessionManager(sp<ProcessInfoInterface> processInfo);

    void addSession(int pid, sp<DrmSessionClientInterface> drm, const Vector<uint8_t>& sessionId);
    void useSession(const Vector<uint8_t>& sessionId);
    void removeSession(const Vector<uint8_t>& sessionId);
    void removeDrm(sp<DrmSessionClientInterface> drm);
    bool reclaimSession(int callingPid);

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

    sp<ProcessInfoInterface> mProcessInfo;
    mutable Mutex mLock;
    PidSessionInfosMap mSessionMap;
    int64_t mTime;

    DISALLOW_EVIL_CONSTRUCTORS(DrmSessionManager);
};

}  // namespace android

#endif  // DRM_SESSION_MANAGER_H_
+33 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2015 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef PROCESS_INFO_INTERFACE_H_
#define PROCESS_INFO_INTERFACE_H_

#include <utils/RefBase.h>

namespace android {

struct ProcessInfoInterface : public RefBase {
    virtual int getPriority(int pid) = 0;

protected:
    virtual ~ProcessInfoInterface() {}
};

}  // namespace android

#endif  // PROCESS_INFO_INTERFACE_H_
Loading