blob: 43346e092c3b330ec0c65a014081900013608266 [file] [log] [blame]
/*
* 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