1/* 2 * Copyright (C) 2015 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17//#define LOG_NDEBUG 0 18#define LOG_TAG "DrmSessionManager" 19#include <utils/Log.h> 20 21#include "DrmSessionManager.h" 22 23#include "DrmSessionClientInterface.h" 24#include <binder/IPCThreadState.h> 25#include <binder/IProcessInfoService.h> 26#include <binder/IServiceManager.h> 27#include <media/stagefright/ProcessInfo.h> 28#include <unistd.h> 29#include <utils/String8.h> 30 31namespace android { 32 33static String8 GetSessionIdString(const Vector<uint8_t> &sessionId) { 34 String8 sessionIdStr; 35 for (size_t i = 0; i < sessionId.size(); ++i) { 36 sessionIdStr.appendFormat("%u ", sessionId[i]); 37 } 38 return sessionIdStr; 39} 40 41bool isEqualSessionId(const Vector<uint8_t> &sessionId1, const Vector<uint8_t> &sessionId2) { 42 if (sessionId1.size() != sessionId2.size()) { 43 return false; 44 } 45 for (size_t i = 0; i < sessionId1.size(); ++i) { 46 if (sessionId1[i] != sessionId2[i]) { 47 return false; 48 } 49 } 50 return true; 51} 52 53sp<DrmSessionManager> DrmSessionManager::Instance() { 54 static sp<DrmSessionManager> drmSessionManager = new DrmSessionManager(); 55 return drmSessionManager; 56} 57 58DrmSessionManager::DrmSessionManager() 59 : mProcessInfo(new ProcessInfo()), 60 mTime(0) {} 61 62DrmSessionManager::DrmSessionManager(sp<ProcessInfoInterface> processInfo) 63 : mProcessInfo(processInfo), 64 mTime(0) {} 65 66DrmSessionManager::~DrmSessionManager() {} 67 68void DrmSessionManager::addSession( 69 int pid, sp<DrmSessionClientInterface> drm, const Vector<uint8_t> &sessionId) { 70 ALOGV("addSession(pid %d, drm %p, sessionId %s)", pid, drm.get(), 71 GetSessionIdString(sessionId).string()); 72 73 Mutex::Autolock lock(mLock); 74 SessionInfo info; 75 info.drm = drm; 76 info.sessionId = sessionId; 77 info.timeStamp = getTime_l(); 78 ssize_t index = mSessionMap.indexOfKey(pid); 79 if (index < 0) { 80 // new pid 81 SessionInfos infosForPid; 82 infosForPid.push_back(info); 83 mSessionMap.add(pid, infosForPid); 84 } else { 85 mSessionMap.editValueAt(index).push_back(info); 86 } 87} 88 89void DrmSessionManager::useSession(const Vector<uint8_t> &sessionId) { 90 ALOGV("useSession(%s)", GetSessionIdString(sessionId).string()); 91 92 Mutex::Autolock lock(mLock); 93 for (size_t i = 0; i < mSessionMap.size(); ++i) { 94 SessionInfos& infos = mSessionMap.editValueAt(i); 95 for (size_t j = 0; j < infos.size(); ++j) { 96 SessionInfo& info = infos.editItemAt(j); 97 if (isEqualSessionId(sessionId, info.sessionId)) { 98 info.timeStamp = getTime_l(); 99 return; 100 } 101 } 102 } 103} 104 105void DrmSessionManager::removeSession(const Vector<uint8_t> &sessionId) { 106 ALOGV("removeSession(%s)", GetSessionIdString(sessionId).string()); 107 108 Mutex::Autolock lock(mLock); 109 for (size_t i = 0; i < mSessionMap.size(); ++i) { 110 SessionInfos& infos = mSessionMap.editValueAt(i); 111 for (size_t j = 0; j < infos.size(); ++j) { 112 if (isEqualSessionId(sessionId, infos[j].sessionId)) { 113 infos.removeAt(j); 114 return; 115 } 116 } 117 } 118} 119 120void DrmSessionManager::removeDrm(sp<DrmSessionClientInterface> drm) { 121 ALOGV("removeDrm(%p)", drm.get()); 122 123 Mutex::Autolock lock(mLock); 124 bool found = false; 125 for (size_t i = 0; i < mSessionMap.size(); ++i) { 126 SessionInfos& infos = mSessionMap.editValueAt(i); 127 for (size_t j = 0; j < infos.size();) { 128 if (infos[j].drm == drm) { 129 ALOGV("removed session (%s)", GetSessionIdString(infos[j].sessionId).string()); 130 j = infos.removeAt(j); 131 found = true; 132 } else { 133 ++j; 134 } 135 } 136 if (found) { 137 break; 138 } 139 } 140} 141 142bool DrmSessionManager::reclaimSession(int callingPid) { 143 ALOGV("reclaimSession(%d)", callingPid); 144 145 sp<DrmSessionClientInterface> drm; 146 Vector<uint8_t> sessionId; 147 int lowestPriorityPid; 148 int lowestPriority; 149 { 150 Mutex::Autolock lock(mLock); 151 int callingPriority; 152 if (!mProcessInfo->getPriority(callingPid, &callingPriority)) { 153 return false; 154 } 155 if (!getLowestPriority_l(&lowestPriorityPid, &lowestPriority)) { 156 return false; 157 } 158 if (lowestPriority <= callingPriority) { 159 return false; 160 } 161 162 if (!getLeastUsedSession_l(lowestPriorityPid, &drm, &sessionId)) { 163 return false; 164 } 165 } 166 167 if (drm == NULL) { 168 return false; 169 } 170 171 ALOGV("reclaim session(%s) opened by pid %d", 172 GetSessionIdString(sessionId).string(), lowestPriorityPid); 173 174 return drm->reclaimSession(sessionId); 175} 176 177int64_t DrmSessionManager::getTime_l() { 178 return mTime++; 179} 180 181bool DrmSessionManager::getLowestPriority_l(int* lowestPriorityPid, int* lowestPriority) { 182 int pid = -1; 183 int priority = -1; 184 for (size_t i = 0; i < mSessionMap.size(); ++i) { 185 if (mSessionMap.valueAt(i).size() == 0) { 186 // no opened session by this process. 187 continue; 188 } 189 int tempPid = mSessionMap.keyAt(i); 190 int tempPriority; 191 if (!mProcessInfo->getPriority(tempPid, &tempPriority)) { 192 // shouldn't happen. 193 return false; 194 } 195 if (pid == -1) { 196 pid = tempPid; 197 priority = tempPriority; 198 } else { 199 if (tempPriority > priority) { 200 pid = tempPid; 201 priority = tempPriority; 202 } 203 } 204 } 205 if (pid != -1) { 206 *lowestPriorityPid = pid; 207 *lowestPriority = priority; 208 } 209 return (pid != -1); 210} 211 212bool DrmSessionManager::getLeastUsedSession_l( 213 int pid, sp<DrmSessionClientInterface>* drm, Vector<uint8_t>* sessionId) { 214 ssize_t index = mSessionMap.indexOfKey(pid); 215 if (index < 0) { 216 return false; 217 } 218 219 int leastUsedIndex = -1; 220 int64_t minTs = LLONG_MAX; 221 const SessionInfos& infos = mSessionMap.valueAt(index); 222 for (size_t j = 0; j < infos.size(); ++j) { 223 if (leastUsedIndex == -1) { 224 leastUsedIndex = j; 225 minTs = infos[j].timeStamp; 226 } else { 227 if (infos[j].timeStamp < minTs) { 228 leastUsedIndex = j; 229 minTs = infos[j].timeStamp; 230 } 231 } 232 } 233 if (leastUsedIndex != -1) { 234 *drm = infos[leastUsedIndex].drm; 235 *sessionId = infos[leastUsedIndex].sessionId; 236 } 237 return (leastUsedIndex != -1); 238} 239 240} // namespace android 241