blob: 6e17eb18522cfb52a39e5b2e6ed481100e5136ee [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>
Ronghua Wu5c3da202015-02-22 08:45:28 -080026#include <binder/IProcessInfoService.h>
27#include <binder/IServiceManager.h>
Ronghua Wu10305cc2015-02-22 07:55:32 -080028#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
41struct ProcessInfo : public ProcessInfoInterface {
42 ProcessInfo() {}
43
Ronghua Wu5c3da202015-02-22 08:45:28 -080044 virtual bool getPriority(int pid, int* priority) {
45 sp<IBinder> binder = defaultServiceManager()->getService(String16("processinfo"));
46 sp<IProcessInfoService> service = interface_cast<IProcessInfoService>(binder);
47
48 size_t length = 1;
49 int32_t states;
50 status_t err = service->getProcessStatesFromPids(length, &pid, &states);
51 if (err != OK) {
52 ALOGE("getProcessStatesFromPids failed");
53 return false;
54 }
55 ALOGV("pid %d states %d", pid, states);
56 if (states < 0) {
57 return false;
58 }
59
60 // Use process state as the priority. Lower the value, higher the priority.
61 *priority = states;
62 return true;
Ronghua Wu10305cc2015-02-22 07:55:32 -080063 }
64
65protected:
66 virtual ~ProcessInfo() {}
67
68private:
69 DISALLOW_EVIL_CONSTRUCTORS(ProcessInfo);
70};
71
72bool isEqualSessionId(const Vector<uint8_t> &sessionId1, const Vector<uint8_t> &sessionId2) {
73 if (sessionId1.size() != sessionId2.size()) {
74 return false;
75 }
76 for (size_t i = 0; i < sessionId1.size(); ++i) {
77 if (sessionId1[i] != sessionId2[i]) {
78 return false;
79 }
80 }
81 return true;
82}
83
Ronghua Wu5c3da202015-02-22 08:45:28 -080084sp<DrmSessionManager> DrmSessionManager::Instance() {
85 static sp<DrmSessionManager> drmSessionManager = new DrmSessionManager();
86 return drmSessionManager;
87}
88
Ronghua Wu10305cc2015-02-22 07:55:32 -080089DrmSessionManager::DrmSessionManager()
90 : mProcessInfo(new ProcessInfo()),
91 mTime(0) {}
92
93DrmSessionManager::DrmSessionManager(sp<ProcessInfoInterface> processInfo)
94 : mProcessInfo(processInfo),
95 mTime(0) {}
96
97DrmSessionManager::~DrmSessionManager() {}
98
99void DrmSessionManager::addSession(
100 int pid, sp<DrmSessionClientInterface> drm, const Vector<uint8_t> &sessionId) {
101 ALOGV("addSession(pid %d, drm %p, sessionId %s)", pid, drm.get(),
102 GetSessionIdString(sessionId).string());
103
104 Mutex::Autolock lock(mLock);
105 SessionInfo info;
106 info.drm = drm;
107 info.sessionId = sessionId;
108 info.timeStamp = getTime_l();
109 ssize_t index = mSessionMap.indexOfKey(pid);
110 if (index < 0) {
111 // new pid
112 SessionInfos infosForPid;
113 infosForPid.push_back(info);
114 mSessionMap.add(pid, infosForPid);
115 } else {
116 mSessionMap.editValueAt(index).push_back(info);
117 }
118}
119
120void DrmSessionManager::useSession(const Vector<uint8_t> &sessionId) {
121 ALOGV("useSession(%s)", GetSessionIdString(sessionId).string());
122
123 Mutex::Autolock lock(mLock);
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(); ++j) {
127 SessionInfo& info = infos.editItemAt(j);
128 if (isEqualSessionId(sessionId, info.sessionId)) {
129 info.timeStamp = getTime_l();
130 return;
131 }
132 }
133 }
134}
135
136void DrmSessionManager::removeSession(const Vector<uint8_t> &sessionId) {
137 ALOGV("removeSession(%s)", GetSessionIdString(sessionId).string());
138
139 Mutex::Autolock lock(mLock);
140 for (size_t i = 0; i < mSessionMap.size(); ++i) {
141 SessionInfos& infos = mSessionMap.editValueAt(i);
142 for (size_t j = 0; j < infos.size(); ++j) {
143 if (isEqualSessionId(sessionId, infos[j].sessionId)) {
144 infos.removeAt(j);
145 return;
146 }
147 }
148 }
149}
150
151void DrmSessionManager::removeDrm(sp<DrmSessionClientInterface> drm) {
152 ALOGV("removeDrm(%p)", drm.get());
153
154 Mutex::Autolock lock(mLock);
155 bool found = false;
156 for (size_t i = 0; i < mSessionMap.size(); ++i) {
157 SessionInfos& infos = mSessionMap.editValueAt(i);
158 for (size_t j = 0; j < infos.size();) {
159 if (infos[j].drm == drm) {
160 ALOGV("removed session (%s)", GetSessionIdString(infos[j].sessionId).string());
161 j = infos.removeAt(j);
162 found = true;
163 } else {
164 ++j;
165 }
166 }
167 if (found) {
168 break;
169 }
170 }
171}
172
173bool DrmSessionManager::reclaimSession(int callingPid) {
174 ALOGV("reclaimSession(%d)", callingPid);
175
176 sp<DrmSessionClientInterface> drm;
177 Vector<uint8_t> sessionId;
Ronghua Wu5c3da202015-02-22 08:45:28 -0800178 int lowestPriorityPid;
179 int lowestPriority;
Ronghua Wu10305cc2015-02-22 07:55:32 -0800180 {
181 Mutex::Autolock lock(mLock);
Ronghua Wu5c3da202015-02-22 08:45:28 -0800182 int callingPriority;
183 if (!mProcessInfo->getPriority(callingPid, &callingPriority)) {
184 return false;
185 }
Ronghua Wu10305cc2015-02-22 07:55:32 -0800186 if (!getLowestPriority_l(&lowestPriorityPid, &lowestPriority)) {
187 return false;
188 }
Ronghua Wu5c3da202015-02-22 08:45:28 -0800189 if (lowestPriority <= callingPriority) {
Ronghua Wu10305cc2015-02-22 07:55:32 -0800190 return false;
191 }
192
193 if (!getLeastUsedSession_l(lowestPriorityPid, &drm, &sessionId)) {
194 return false;
195 }
196 }
197
198 if (drm == NULL) {
199 return false;
200 }
201
Ronghua Wu5c3da202015-02-22 08:45:28 -0800202 ALOGV("reclaim session(%s) opened by pid %d",
203 GetSessionIdString(sessionId).string(), lowestPriorityPid);
204
Ronghua Wu10305cc2015-02-22 07:55:32 -0800205 return drm->reclaimSession(sessionId);
206}
207
208int64_t DrmSessionManager::getTime_l() {
209 return mTime++;
210}
211
212bool DrmSessionManager::getLowestPriority_l(int* lowestPriorityPid, int* lowestPriority) {
213 int pid = -1;
Ronghua Wu5c3da202015-02-22 08:45:28 -0800214 int priority = -1;
Ronghua Wu10305cc2015-02-22 07:55:32 -0800215 for (size_t i = 0; i < mSessionMap.size(); ++i) {
216 if (mSessionMap.valueAt(i).size() == 0) {
217 // no opened session by this process.
218 continue;
219 }
220 int tempPid = mSessionMap.keyAt(i);
Ronghua Wu5c3da202015-02-22 08:45:28 -0800221 int tempPriority;
222 if (!mProcessInfo->getPriority(tempPid, &tempPriority)) {
223 // shouldn't happen.
224 return false;
225 }
Ronghua Wu10305cc2015-02-22 07:55:32 -0800226 if (pid == -1) {
227 pid = tempPid;
228 priority = tempPriority;
229 } else {
Ronghua Wu5c3da202015-02-22 08:45:28 -0800230 if (tempPriority > priority) {
Ronghua Wu10305cc2015-02-22 07:55:32 -0800231 pid = tempPid;
232 priority = tempPriority;
233 }
234 }
235 }
236 if (pid != -1) {
237 *lowestPriorityPid = pid;
238 *lowestPriority = priority;
239 }
240 return (pid != -1);
241}
242
243bool DrmSessionManager::getLeastUsedSession_l(
244 int pid, sp<DrmSessionClientInterface>* drm, Vector<uint8_t>* sessionId) {
245 ssize_t index = mSessionMap.indexOfKey(pid);
246 if (index < 0) {
247 return false;
248 }
249
250 int leastUsedIndex = -1;
251 int64_t minTs = LLONG_MAX;
252 const SessionInfos& infos = mSessionMap.valueAt(index);
253 for (size_t j = 0; j < infos.size(); ++j) {
254 if (leastUsedIndex == -1) {
255 leastUsedIndex = j;
256 minTs = infos[j].timeStamp;
257 } else {
258 if (infos[j].timeStamp < minTs) {
259 leastUsedIndex = j;
260 minTs = infos[j].timeStamp;
261 }
262 }
263 }
264 if (leastUsedIndex != -1) {
265 *drm = infos[leastUsedIndex].drm;
266 *sessionId = infos[leastUsedIndex].sessionId;
267 }
268 return (leastUsedIndex != -1);
269}
270
271} // namespace android