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

Commit 2129895b authored by Ronghua Wu's avatar Ronghua Wu Committed by Android (Google) Code Review
Browse files

Merge "Add DRM session manager."

parents d7dca050 10305cc6
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