blob: 75a69edc7abe2c0cd4968d9a8fe151f651c6ebef [file] [log] [blame]
Ronghua Wu231c3d12015-03-11 15:10:32 -07001/*
2**
3** Copyright 2015, The Android Open Source Project
4**
5** Licensed under the Apache License, Version 2.0 (the "License");
6** you may not use this file except in compliance with the License.
7** You may obtain a copy of the License at
8**
9** http://www.apache.org/licenses/LICENSE-2.0
10**
11** Unless required by applicable law or agreed to in writing, software
12** distributed under the License is distributed on an "AS IS" BASIS,
13** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14** See the License for the specific language governing permissions and
15** limitations under the License.
16*/
17
18//#define LOG_NDEBUG 0
19#define LOG_TAG "ResourceManagerService"
20#include <utils/Log.h>
21
22#include <binder/IServiceManager.h>
23#include <dirent.h>
24#include <media/stagefright/ProcessInfo.h>
25#include <string.h>
26#include <sys/types.h>
27#include <sys/stat.h>
28#include <sys/time.h>
29#include <unistd.h>
30
31#include "ResourceManagerService.h"
32
33namespace android {
34
35template <typename T>
36static String8 getString(const Vector<T> &items) {
37 String8 itemsStr;
38 for (size_t i = 0; i < items.size(); ++i) {
39 itemsStr.appendFormat("%s ", items[i].toString().string());
40 }
41 return itemsStr;
42}
43
44static bool hasResourceType(String8 type, Vector<MediaResource> resources) {
45 for (size_t i = 0; i < resources.size(); ++i) {
46 if (resources[i].mType == type) {
47 return true;
48 }
49 }
50 return false;
51}
52
53static bool hasResourceType(String8 type, ResourceInfos infos) {
54 for (size_t i = 0; i < infos.size(); ++i) {
55 if (hasResourceType(type, infos[i].resources)) {
56 return true;
57 }
58 }
59 return false;
60}
61
62static ResourceInfos& getResourceInfosForEdit(
63 int pid,
64 PidResourceInfosMap& map) {
65 ssize_t index = map.indexOfKey(pid);
66 if (index < 0) {
67 // new pid
68 ResourceInfos infosForPid;
69 map.add(pid, infosForPid);
70 }
71
72 return map.editValueFor(pid);
73}
74
75static ResourceInfo& getResourceInfoForEdit(
76 int64_t clientId,
77 const sp<IResourceManagerClient> client,
78 ResourceInfos& infos) {
79 for (size_t i = 0; i < infos.size(); ++i) {
80 if (infos[i].clientId == clientId) {
81 return infos.editItemAt(i);
82 }
83 }
84 ResourceInfo info;
85 info.clientId = clientId;
86 info.client = client;
87 infos.push_back(info);
88 return infos.editItemAt(infos.size() - 1);
89}
90
91ResourceManagerService::ResourceManagerService()
92 : mProcessInfo(new ProcessInfo()),
93 mSupportsMultipleSecureCodecs(true),
94 mSupportsSecureWithNonSecureCodec(true) {}
95
96ResourceManagerService::ResourceManagerService(sp<ProcessInfoInterface> processInfo)
97 : mProcessInfo(processInfo),
98 mSupportsMultipleSecureCodecs(true),
99 mSupportsSecureWithNonSecureCodec(true) {}
100
101ResourceManagerService::~ResourceManagerService() {}
102
103void ResourceManagerService::config(const Vector<MediaResourcePolicy> &policies) {
104 ALOGV("config(%s)", getString(policies).string());
105
106 Mutex::Autolock lock(mLock);
107 for (size_t i = 0; i < policies.size(); ++i) {
108 String8 type = policies[i].mType;
109 uint64_t value = policies[i].mValue;
110 if (type == kPolicySupportsMultipleSecureCodecs) {
111 mSupportsMultipleSecureCodecs = (value != 0);
112 } else if (type == kPolicySupportsSecureWithNonSecureCodec) {
113 mSupportsSecureWithNonSecureCodec = (value != 0);
114 }
115 }
116}
117
118void ResourceManagerService::addResource(
119 int pid,
120 int64_t clientId,
121 const sp<IResourceManagerClient> client,
122 const Vector<MediaResource> &resources) {
123 ALOGV("addResource(pid %d, clientId %lld, resources %s)",
124 pid, (long long) clientId, getString(resources).string());
125
126 Mutex::Autolock lock(mLock);
127 ResourceInfos& infos = getResourceInfosForEdit(pid, mMap);
128 ResourceInfo& info = getResourceInfoForEdit(clientId, client, infos);
Ronghua Wu67e7f542015-03-13 10:47:08 -0700129 // TODO: do the merge instead of append.
Ronghua Wu231c3d12015-03-11 15:10:32 -0700130 info.resources.appendVector(resources);
131}
132
133void ResourceManagerService::removeResource(int64_t clientId) {
134 ALOGV("removeResource(%lld)", (long long) clientId);
135
136 Mutex::Autolock lock(mLock);
137 bool found = false;
138 for (size_t i = 0; i < mMap.size(); ++i) {
139 ResourceInfos &infos = mMap.editValueAt(i);
140 for (size_t j = 0; j < infos.size();) {
141 if (infos[j].clientId == clientId) {
142 j = infos.removeAt(j);
143 found = true;
144 } else {
145 ++j;
146 }
147 }
148 if (found) {
149 break;
150 }
151 }
152 if (!found) {
153 ALOGV("didn't find client");
154 }
155}
156
157bool ResourceManagerService::reclaimResource(
158 int callingPid, const Vector<MediaResource> &resources) {
159 ALOGV("reclaimResource(callingPid %d, resources %s)",
160 callingPid, getString(resources).string());
161
162 Vector<sp<IResourceManagerClient>> clients;
163 {
164 Mutex::Autolock lock(mLock);
165 // first pass to handle secure/non-secure codec conflict
166 for (size_t i = 0; i < resources.size(); ++i) {
167 String8 type = resources[i].mType;
168 if (type == kResourceSecureCodec) {
169 if (!mSupportsMultipleSecureCodecs) {
170 if (!getAllClients_l(callingPid, String8(kResourceSecureCodec), &clients)) {
171 return false;
172 }
173 }
174 if (!mSupportsSecureWithNonSecureCodec) {
175 if (!getAllClients_l(callingPid, String8(kResourceNonSecureCodec), &clients)) {
176 return false;
177 }
178 }
179 } else if (type == kResourceNonSecureCodec) {
180 if (!mSupportsSecureWithNonSecureCodec) {
181 if (!getAllClients_l(callingPid, String8(kResourceSecureCodec), &clients)) {
182 return false;
183 }
184 }
185 }
186 }
187
188 if (clients.size() == 0) {
189 // if no secure/non-secure codec conflict, run second pass to handle other resources.
190 for (size_t i = 0; i < resources.size(); ++i) {
191 String8 type = resources[i].mType;
192 if (type == kResourceGraphicMemory) {
193 sp<IResourceManagerClient> client;
194 if (!getLowestPriorityBiggestClient_l(callingPid, type, &client)) {
195 return false;
196 }
197 clients.push_back(client);
198 }
199 }
200 }
Ronghua Wu67e7f542015-03-13 10:47:08 -0700201
202 if (clients.size() == 0) {
203 // if we are here, run the third pass to free one codec with the same type.
204 for (size_t i = 0; i < resources.size(); ++i) {
205 String8 type = resources[i].mType;
206 if (type == kResourceSecureCodec || type == kResourceNonSecureCodec) {
207 sp<IResourceManagerClient> client;
208 if (!getLowestPriorityBiggestClient_l(callingPid, type, &client)) {
209 return false;
210 }
211 clients.push_back(client);
212 }
213 }
214 }
Ronghua Wu231c3d12015-03-11 15:10:32 -0700215 }
216
217 if (clients.size() == 0) {
218 return false;
219 }
220
Ronghua Wu67e7f542015-03-13 10:47:08 -0700221 sp<IResourceManagerClient> failedClient;
Ronghua Wu231c3d12015-03-11 15:10:32 -0700222 for (size_t i = 0; i < clients.size(); ++i) {
223 ALOGV("reclaimResource from client %p", clients[i].get());
224 if (!clients[i]->reclaimResource()) {
Ronghua Wu67e7f542015-03-13 10:47:08 -0700225 failedClient = clients[i];
226 break;
Ronghua Wu231c3d12015-03-11 15:10:32 -0700227 }
228 }
Ronghua Wu67e7f542015-03-13 10:47:08 -0700229
230 {
231 Mutex::Autolock lock(mLock);
232 bool found = false;
233 for (size_t i = 0; i < mMap.size(); ++i) {
234 ResourceInfos &infos = mMap.editValueAt(i);
235 for (size_t j = 0; j < infos.size();) {
236 if (infos[j].client == failedClient) {
237 j = infos.removeAt(j);
238 found = true;
239 } else {
240 ++j;
241 }
242 }
243 if (found) {
244 break;
245 }
246 }
247 if (!found) {
248 ALOGV("didn't find failed client");
249 }
250 }
251
252 return (failedClient == NULL);
Ronghua Wu231c3d12015-03-11 15:10:32 -0700253}
254
255bool ResourceManagerService::getAllClients_l(
256 int callingPid, const String8 &type, Vector<sp<IResourceManagerClient>> *clients) {
257 Vector<sp<IResourceManagerClient>> temp;
258 for (size_t i = 0; i < mMap.size(); ++i) {
259 ResourceInfos &infos = mMap.editValueAt(i);
260 for (size_t j = 0; j < infos.size(); ++j) {
261 if (hasResourceType(type, infos[j].resources)) {
262 if (!isCallingPriorityHigher_l(callingPid, mMap.keyAt(i))) {
263 // some higher/equal priority process owns the resource,
264 // this request can't be fulfilled.
265 ALOGE("getAllClients_l: can't reclaim resource %s from pid %d",
266 type.string(), mMap.keyAt(i));
267 return false;
268 }
269 temp.push_back(infos[j].client);
270 }
271 }
272 }
273 if (temp.size() == 0) {
274 ALOGV("getAllClients_l: didn't find any resource %s", type.string());
275 return true;
276 }
277 clients->appendVector(temp);
278 return true;
279}
280
281bool ResourceManagerService::getLowestPriorityBiggestClient_l(
282 int callingPid, const String8 &type, sp<IResourceManagerClient> *client) {
283 int lowestPriorityPid;
284 int lowestPriority;
285 int callingPriority;
286 if (!mProcessInfo->getPriority(callingPid, &callingPriority)) {
287 ALOGE("getLowestPriorityBiggestClient_l: can't get process priority for pid %d",
288 callingPid);
289 return false;
290 }
291 if (!getLowestPriorityPid_l(type, &lowestPriorityPid, &lowestPriority)) {
292 return false;
293 }
294 if (lowestPriority <= callingPriority) {
295 ALOGE("getLowestPriorityBiggestClient_l: lowest priority %d vs caller priority %d",
296 lowestPriority, callingPriority);
297 return false;
298 }
299
300 if (!getBiggestClient_l(lowestPriorityPid, type, client)) {
301 return false;
302 }
303 return true;
304}
305
306bool ResourceManagerService::getLowestPriorityPid_l(
307 const String8 &type, int *lowestPriorityPid, int *lowestPriority) {
308 int pid = -1;
309 int priority = -1;
310 for (size_t i = 0; i < mMap.size(); ++i) {
311 if (mMap.valueAt(i).size() == 0) {
312 // no client on this process.
313 continue;
314 }
315 if (!hasResourceType(type, mMap.valueAt(i))) {
316 // doesn't have the requested resource type
317 continue;
318 }
319 int tempPid = mMap.keyAt(i);
320 int tempPriority;
321 if (!mProcessInfo->getPriority(tempPid, &tempPriority)) {
322 ALOGV("getLowestPriorityPid_l: can't get priority of pid %d, skipped", tempPid);
323 // TODO: remove this pid from mMap?
324 continue;
325 }
326 if (pid == -1 || tempPriority > priority) {
327 // initial the value
328 pid = tempPid;
329 priority = tempPriority;
330 }
331 }
332 if (pid != -1) {
333 *lowestPriorityPid = pid;
334 *lowestPriority = priority;
335 }
336 return (pid != -1);
337}
338
339bool ResourceManagerService::isCallingPriorityHigher_l(int callingPid, int pid) {
340 int callingPidPriority;
341 if (!mProcessInfo->getPriority(callingPid, &callingPidPriority)) {
342 return false;
343 }
344
345 int priority;
346 if (!mProcessInfo->getPriority(pid, &priority)) {
347 return false;
348 }
349
350 return (callingPidPriority < priority);
351}
352
353bool ResourceManagerService::getBiggestClient_l(
354 int pid, const String8 &type, sp<IResourceManagerClient> *client) {
355 ssize_t index = mMap.indexOfKey(pid);
356 if (index < 0) {
357 ALOGE("getBiggestClient_l: can't find resource info for pid %d", pid);
358 return false;
359 }
360
361 sp<IResourceManagerClient> clientTemp;
362 uint64_t largestValue = 0;
363 const ResourceInfos &infos = mMap.valueAt(index);
364 for (size_t i = 0; i < infos.size(); ++i) {
365 Vector<MediaResource> resources = infos[i].resources;
366 for (size_t j = 0; j < resources.size(); ++j) {
367 if (resources[j].mType == type) {
368 if (resources[j].mValue > largestValue) {
369 largestValue = resources[j].mValue;
370 clientTemp = infos[i].client;
371 }
372 }
373 }
374 }
375
376 if (clientTemp == NULL) {
377 ALOGE("getBiggestClient_l: can't find resource type %s for pid %d", type.string(), pid);
378 return false;
379 }
380
381 *client = clientTemp;
382 return true;
383}
384
385} // namespace android