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
31 namespace android {
32
GetSessionIdString(const Vector<uint8_t> & sessionId)33 static 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
isEqualSessionId(const Vector<uint8_t> & sessionId1,const Vector<uint8_t> & sessionId2)41 bool 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
Instance()53 sp<DrmSessionManager> DrmSessionManager::Instance() {
54 static sp<DrmSessionManager> drmSessionManager = new DrmSessionManager();
55 return drmSessionManager;
56 }
57
DrmSessionManager()58 DrmSessionManager::DrmSessionManager()
59 : mProcessInfo(new ProcessInfo()),
60 mTime(0) {}
61
DrmSessionManager(sp<ProcessInfoInterface> processInfo)62 DrmSessionManager::DrmSessionManager(sp<ProcessInfoInterface> processInfo)
63 : mProcessInfo(processInfo),
64 mTime(0) {}
65
~DrmSessionManager()66 DrmSessionManager::~DrmSessionManager() {}
67
addSession(int pid,sp<DrmSessionClientInterface> drm,const Vector<uint8_t> & sessionId)68 void 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
useSession(const Vector<uint8_t> & sessionId)89 void 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
removeSession(const Vector<uint8_t> & sessionId)105 void 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
removeDrm(sp<DrmSessionClientInterface> drm)120 void 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
reclaimSession(int callingPid)142 bool 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
getTime_l()177 int64_t DrmSessionManager::getTime_l() {
178 return mTime++;
179 }
180
getLowestPriority_l(int * lowestPriorityPid,int * lowestPriority)181 bool 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
getLeastUsedSession_l(int pid,sp<DrmSessionClientInterface> * drm,Vector<uint8_t> * sessionId)212 bool 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