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 <binder/IPCThreadState.h>
22 #include <binder/IProcessInfoService.h>
23 #include <binder/IServiceManager.h>
24 #include <media/stagefright/ProcessInfo.h>
25 #include <mediadrm/DrmSessionClientInterface.h>
26 #include <mediadrm/DrmSessionManager.h>
27 #include <unistd.h>
28 #include <utils/String8.h>
29
30 namespace android {
31
GetSessionIdString(const Vector<uint8_t> & sessionId)32 static String8 GetSessionIdString(const Vector<uint8_t> &sessionId) {
33 String8 sessionIdStr;
34 for (size_t i = 0; i < sessionId.size(); ++i) {
35 sessionIdStr.appendFormat("%u ", sessionId[i]);
36 }
37 return sessionIdStr;
38 }
39
isEqualSessionId(const Vector<uint8_t> & sessionId1,const Vector<uint8_t> & sessionId2)40 bool isEqualSessionId(const Vector<uint8_t> &sessionId1, const Vector<uint8_t> &sessionId2) {
41 if (sessionId1.size() != sessionId2.size()) {
42 return false;
43 }
44 for (size_t i = 0; i < sessionId1.size(); ++i) {
45 if (sessionId1[i] != sessionId2[i]) {
46 return false;
47 }
48 }
49 return true;
50 }
51
Instance()52 sp<DrmSessionManager> DrmSessionManager::Instance() {
53 static sp<DrmSessionManager> drmSessionManager = new DrmSessionManager();
54 return drmSessionManager;
55 }
56
DrmSessionManager()57 DrmSessionManager::DrmSessionManager()
58 : mProcessInfo(new ProcessInfo()),
59 mTime(0) {}
60
DrmSessionManager(sp<ProcessInfoInterface> processInfo)61 DrmSessionManager::DrmSessionManager(sp<ProcessInfoInterface> processInfo)
62 : mProcessInfo(processInfo),
63 mTime(0) {}
64
~DrmSessionManager()65 DrmSessionManager::~DrmSessionManager() {}
66
addSession(int pid,const sp<DrmSessionClientInterface> & drm,const Vector<uint8_t> & sessionId)67 void DrmSessionManager::addSession(
68 int pid, const sp<DrmSessionClientInterface>& drm, const Vector<uint8_t> &sessionId) {
69 ALOGV("addSession(pid %d, drm %p, sessionId %s)", pid, drm.get(),
70 GetSessionIdString(sessionId).string());
71
72 Mutex::Autolock lock(mLock);
73 SessionInfo info;
74 info.drm = drm;
75 info.sessionId = sessionId;
76 info.timeStamp = getTime_l();
77 ssize_t index = mSessionMap.indexOfKey(pid);
78 if (index < 0) {
79 // new pid
80 SessionInfos infosForPid;
81 infosForPid.push_back(info);
82 mSessionMap.add(pid, infosForPid);
83 } else {
84 mSessionMap.editValueAt(index).push_back(info);
85 }
86 }
87
useSession(const Vector<uint8_t> & sessionId)88 void DrmSessionManager::useSession(const Vector<uint8_t> &sessionId) {
89 ALOGV("useSession(%s)", GetSessionIdString(sessionId).string());
90
91 Mutex::Autolock lock(mLock);
92 for (size_t i = 0; i < mSessionMap.size(); ++i) {
93 SessionInfos& infos = mSessionMap.editValueAt(i);
94 for (size_t j = 0; j < infos.size(); ++j) {
95 SessionInfo& info = infos.editItemAt(j);
96 if (isEqualSessionId(sessionId, info.sessionId)) {
97 info.timeStamp = getTime_l();
98 return;
99 }
100 }
101 }
102 }
103
removeSession(const Vector<uint8_t> & sessionId)104 void DrmSessionManager::removeSession(const Vector<uint8_t> &sessionId) {
105 ALOGV("removeSession(%s)", GetSessionIdString(sessionId).string());
106
107 Mutex::Autolock lock(mLock);
108 for (size_t i = 0; i < mSessionMap.size(); ++i) {
109 SessionInfos& infos = mSessionMap.editValueAt(i);
110 for (size_t j = 0; j < infos.size(); ++j) {
111 if (isEqualSessionId(sessionId, infos[j].sessionId)) {
112 infos.removeAt(j);
113 return;
114 }
115 }
116 }
117 }
118
removeDrm(const sp<DrmSessionClientInterface> & drm)119 void DrmSessionManager::removeDrm(const sp<DrmSessionClientInterface>& drm) {
120 ALOGV("removeDrm(%p)", drm.get());
121
122 Mutex::Autolock lock(mLock);
123 bool found = false;
124 for (size_t i = 0; i < mSessionMap.size(); ++i) {
125 SessionInfos& infos = mSessionMap.editValueAt(i);
126 for (size_t j = 0; j < infos.size();) {
127 if (infos[j].drm == drm) {
128 ALOGV("removed session (%s)", GetSessionIdString(infos[j].sessionId).string());
129 j = infos.removeAt(j);
130 found = true;
131 } else {
132 ++j;
133 }
134 }
135 if (found) {
136 break;
137 }
138 }
139 }
140
reclaimSession(int callingPid)141 bool DrmSessionManager::reclaimSession(int callingPid) {
142 ALOGV("reclaimSession(%d)", callingPid);
143
144 sp<DrmSessionClientInterface> drm;
145 Vector<uint8_t> sessionId;
146 int lowestPriorityPid;
147 int lowestPriority;
148 {
149 Mutex::Autolock lock(mLock);
150 int callingPriority;
151 if (!mProcessInfo->getPriority(callingPid, &callingPriority)) {
152 return false;
153 }
154 if (!getLowestPriority_l(&lowestPriorityPid, &lowestPriority)) {
155 return false;
156 }
157 if (lowestPriority <= callingPriority) {
158 return false;
159 }
160
161 if (!getLeastUsedSession_l(lowestPriorityPid, &drm, &sessionId)) {
162 return false;
163 }
164 }
165
166 if (drm == NULL) {
167 return false;
168 }
169
170 ALOGV("reclaim session(%s) opened by pid %d",
171 GetSessionIdString(sessionId).string(), lowestPriorityPid);
172
173 return drm->reclaimSession(sessionId);
174 }
175
getTime_l()176 int64_t DrmSessionManager::getTime_l() {
177 return mTime++;
178 }
179
getLowestPriority_l(int * lowestPriorityPid,int * lowestPriority)180 bool DrmSessionManager::getLowestPriority_l(int* lowestPriorityPid, int* lowestPriority) {
181 int pid = -1;
182 int priority = -1;
183 for (size_t i = 0; i < mSessionMap.size(); ++i) {
184 if (mSessionMap.valueAt(i).size() == 0) {
185 // no opened session by this process.
186 continue;
187 }
188 int tempPid = mSessionMap.keyAt(i);
189 int tempPriority;
190 if (!mProcessInfo->getPriority(tempPid, &tempPriority)) {
191 // shouldn't happen.
192 return false;
193 }
194 if (pid == -1) {
195 pid = tempPid;
196 priority = tempPriority;
197 } else {
198 if (tempPriority > priority) {
199 pid = tempPid;
200 priority = tempPriority;
201 }
202 }
203 }
204 if (pid != -1) {
205 *lowestPriorityPid = pid;
206 *lowestPriority = priority;
207 }
208 return (pid != -1);
209 }
210
getLeastUsedSession_l(int pid,sp<DrmSessionClientInterface> * drm,Vector<uint8_t> * sessionId)211 bool DrmSessionManager::getLeastUsedSession_l(
212 int pid, sp<DrmSessionClientInterface>* drm, Vector<uint8_t>* sessionId) {
213 ssize_t index = mSessionMap.indexOfKey(pid);
214 if (index < 0) {
215 return false;
216 }
217
218 int leastUsedIndex = -1;
219 int64_t minTs = LLONG_MAX;
220 const SessionInfos& infos = mSessionMap.valueAt(index);
221 for (size_t j = 0; j < infos.size(); ++j) {
222 if (leastUsedIndex == -1) {
223 leastUsedIndex = j;
224 minTs = infos[j].timeStamp;
225 } else {
226 if (infos[j].timeStamp < minTs) {
227 leastUsedIndex = j;
228 minTs = infos[j].timeStamp;
229 }
230 }
231 }
232 if (leastUsedIndex != -1) {
233 *drm = infos[leastUsedIndex].drm;
234 *sessionId = infos[leastUsedIndex].sessionId;
235 }
236 return (leastUsedIndex != -1);
237 }
238
239 } // namespace android
240