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