blob: 61147ff13d6079641bb79775eab8560d1e49adc9 [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"
Ronghua Wua8ec8fc2015-05-07 13:58:22 -070032#include "ServiceLog.h"
Ronghua Wu231c3d12015-03-11 15:10:32 -070033
34namespace android {
35
36template <typename T>
37static String8 getString(const Vector<T> &items) {
38 String8 itemsStr;
39 for (size_t i = 0; i < items.size(); ++i) {
40 itemsStr.appendFormat("%s ", items[i].toString().string());
41 }
42 return itemsStr;
43}
44
45static bool hasResourceType(String8 type, Vector<MediaResource> resources) {
46 for (size_t i = 0; i < resources.size(); ++i) {
47 if (resources[i].mType == type) {
48 return true;
49 }
50 }
51 return false;
52}
53
54static bool hasResourceType(String8 type, ResourceInfos infos) {
55 for (size_t i = 0; i < infos.size(); ++i) {
56 if (hasResourceType(type, infos[i].resources)) {
57 return true;
58 }
59 }
60 return false;
61}
62
63static ResourceInfos& getResourceInfosForEdit(
64 int pid,
65 PidResourceInfosMap& map) {
66 ssize_t index = map.indexOfKey(pid);
67 if (index < 0) {
68 // new pid
69 ResourceInfos infosForPid;
70 map.add(pid, infosForPid);
71 }
72
73 return map.editValueFor(pid);
74}
75
76static ResourceInfo& getResourceInfoForEdit(
77 int64_t clientId,
78 const sp<IResourceManagerClient> client,
79 ResourceInfos& infos) {
80 for (size_t i = 0; i < infos.size(); ++i) {
81 if (infos[i].clientId == clientId) {
82 return infos.editItemAt(i);
83 }
84 }
85 ResourceInfo info;
86 info.clientId = clientId;
87 info.client = client;
88 infos.push_back(info);
89 return infos.editItemAt(infos.size() - 1);
90}
91
Ronghua Wua8ec8fc2015-05-07 13:58:22 -070092status_t ResourceManagerService::dump(int fd, const Vector<String16>& /* args */) {
Ronghua Wu8f9dd872015-04-23 15:24:25 -070093 Mutex::Autolock lock(mLock);
94
95 String8 result;
96 const size_t SIZE = 256;
97 char buffer[SIZE];
98
99 snprintf(buffer, SIZE, "ResourceManagerService: %p\n", this);
100 result.append(buffer);
101 result.append(" Policies:\n");
102 snprintf(buffer, SIZE, " SupportsMultipleSecureCodecs: %d\n", mSupportsMultipleSecureCodecs);
103 result.append(buffer);
104 snprintf(buffer, SIZE, " SupportsSecureWithNonSecureCodec: %d\n", mSupportsSecureWithNonSecureCodec);
105 result.append(buffer);
106
Ronghua Wua8ec8fc2015-05-07 13:58:22 -0700107 result.append(" Processes:\n");
Ronghua Wu8f9dd872015-04-23 15:24:25 -0700108 for (size_t i = 0; i < mMap.size(); ++i) {
109 snprintf(buffer, SIZE, " Pid: %d\n", mMap.keyAt(i));
110 result.append(buffer);
111
112 const ResourceInfos &infos = mMap.valueAt(i);
113 for (size_t j = 0; j < infos.size(); ++j) {
Ronghua Wua8ec8fc2015-05-07 13:58:22 -0700114 result.append(" Client:\n");
Ronghua Wu8f9dd872015-04-23 15:24:25 -0700115 snprintf(buffer, SIZE, " Id: %lld\n", (long long)infos[j].clientId);
116 result.append(buffer);
117
118 snprintf(buffer, SIZE, " Name: %s\n", infos[j].client->getName().string());
119 result.append(buffer);
120
121 Vector<MediaResource> resources = infos[j].resources;
Ronghua Wua8ec8fc2015-05-07 13:58:22 -0700122 result.append(" Resources:\n");
Ronghua Wu8f9dd872015-04-23 15:24:25 -0700123 for (size_t k = 0; k < resources.size(); ++k) {
124 snprintf(buffer, SIZE, " %s\n", resources[k].toString().string());
125 result.append(buffer);
126 }
127 }
128 }
Ronghua Wu022ed722015-05-11 15:15:09 -0700129 result.append(" Events logs (most recent at top):\n");
130 result.append(mServiceLog->toString(" " /* linePrefix */));
Ronghua Wu8f9dd872015-04-23 15:24:25 -0700131
132 write(fd, result.string(), result.size());
133 return OK;
134}
135
Ronghua Wu231c3d12015-03-11 15:10:32 -0700136ResourceManagerService::ResourceManagerService()
137 : mProcessInfo(new ProcessInfo()),
Ronghua Wua8ec8fc2015-05-07 13:58:22 -0700138 mServiceLog(new ServiceLog()),
Ronghua Wu231c3d12015-03-11 15:10:32 -0700139 mSupportsMultipleSecureCodecs(true),
140 mSupportsSecureWithNonSecureCodec(true) {}
141
142ResourceManagerService::ResourceManagerService(sp<ProcessInfoInterface> processInfo)
143 : mProcessInfo(processInfo),
Ronghua Wua8ec8fc2015-05-07 13:58:22 -0700144 mServiceLog(new ServiceLog()),
Ronghua Wu231c3d12015-03-11 15:10:32 -0700145 mSupportsMultipleSecureCodecs(true),
146 mSupportsSecureWithNonSecureCodec(true) {}
147
148ResourceManagerService::~ResourceManagerService() {}
149
150void ResourceManagerService::config(const Vector<MediaResourcePolicy> &policies) {
Ronghua Wua8ec8fc2015-05-07 13:58:22 -0700151 String8 log = String8::format("config(%s)", getString(policies).string());
152 mServiceLog->add(log);
Ronghua Wu231c3d12015-03-11 15:10:32 -0700153
154 Mutex::Autolock lock(mLock);
155 for (size_t i = 0; i < policies.size(); ++i) {
156 String8 type = policies[i].mType;
Ronghua Wu9ba21b92015-04-21 14:23:06 -0700157 String8 value = policies[i].mValue;
Ronghua Wu231c3d12015-03-11 15:10:32 -0700158 if (type == kPolicySupportsMultipleSecureCodecs) {
Ronghua Wu9ba21b92015-04-21 14:23:06 -0700159 mSupportsMultipleSecureCodecs = (value == "true");
Ronghua Wu231c3d12015-03-11 15:10:32 -0700160 } else if (type == kPolicySupportsSecureWithNonSecureCodec) {
Ronghua Wu9ba21b92015-04-21 14:23:06 -0700161 mSupportsSecureWithNonSecureCodec = (value == "true");
Ronghua Wu231c3d12015-03-11 15:10:32 -0700162 }
163 }
164}
165
166void ResourceManagerService::addResource(
167 int pid,
168 int64_t clientId,
169 const sp<IResourceManagerClient> client,
170 const Vector<MediaResource> &resources) {
Ronghua Wua8ec8fc2015-05-07 13:58:22 -0700171 String8 log = String8::format("addResource(pid %d, clientId %lld, resources %s)",
Ronghua Wu231c3d12015-03-11 15:10:32 -0700172 pid, (long long) clientId, getString(resources).string());
Ronghua Wua8ec8fc2015-05-07 13:58:22 -0700173 mServiceLog->add(log);
Ronghua Wu231c3d12015-03-11 15:10:32 -0700174
175 Mutex::Autolock lock(mLock);
176 ResourceInfos& infos = getResourceInfosForEdit(pid, mMap);
177 ResourceInfo& info = getResourceInfoForEdit(clientId, client, infos);
Ronghua Wu67e7f542015-03-13 10:47:08 -0700178 // TODO: do the merge instead of append.
Ronghua Wu231c3d12015-03-11 15:10:32 -0700179 info.resources.appendVector(resources);
180}
181
182void ResourceManagerService::removeResource(int64_t clientId) {
Ronghua Wua8ec8fc2015-05-07 13:58:22 -0700183 String8 log = String8::format("removeResource(%lld)", (long long) clientId);
184 mServiceLog->add(log);
Ronghua Wu231c3d12015-03-11 15:10:32 -0700185
186 Mutex::Autolock lock(mLock);
187 bool found = false;
188 for (size_t i = 0; i < mMap.size(); ++i) {
189 ResourceInfos &infos = mMap.editValueAt(i);
190 for (size_t j = 0; j < infos.size();) {
191 if (infos[j].clientId == clientId) {
192 j = infos.removeAt(j);
193 found = true;
194 } else {
195 ++j;
196 }
197 }
198 if (found) {
199 break;
200 }
201 }
202 if (!found) {
203 ALOGV("didn't find client");
204 }
205}
206
Ronghua Wu05d89f12015-07-07 16:47:42 -0700207void ResourceManagerService::getClientForResource_l(
208 int callingPid, const MediaResource *res, Vector<sp<IResourceManagerClient>> *clients) {
209 if (res == NULL) {
210 return;
211 }
212 sp<IResourceManagerClient> client;
213 if (getLowestPriorityBiggestClient_l(callingPid, res->mType, &client)) {
214 clients->push_back(client);
215 }
216}
217
Ronghua Wu231c3d12015-03-11 15:10:32 -0700218bool ResourceManagerService::reclaimResource(
219 int callingPid, const Vector<MediaResource> &resources) {
Ronghua Wua8ec8fc2015-05-07 13:58:22 -0700220 String8 log = String8::format("reclaimResource(callingPid %d, resources %s)",
Ronghua Wu231c3d12015-03-11 15:10:32 -0700221 callingPid, getString(resources).string());
Ronghua Wua8ec8fc2015-05-07 13:58:22 -0700222 mServiceLog->add(log);
Ronghua Wu231c3d12015-03-11 15:10:32 -0700223
224 Vector<sp<IResourceManagerClient>> clients;
225 {
226 Mutex::Autolock lock(mLock);
Ronghua Wu05d89f12015-07-07 16:47:42 -0700227 const MediaResource *secureCodec = NULL;
228 const MediaResource *nonSecureCodec = NULL;
229 const MediaResource *graphicMemory = NULL;
Ronghua Wu231c3d12015-03-11 15:10:32 -0700230 for (size_t i = 0; i < resources.size(); ++i) {
231 String8 type = resources[i].mType;
Ronghua Wu05d89f12015-07-07 16:47:42 -0700232 if (resources[i].mType == kResourceSecureCodec) {
233 secureCodec = &resources[i];
Ronghua Wu231c3d12015-03-11 15:10:32 -0700234 } else if (type == kResourceNonSecureCodec) {
Ronghua Wu05d89f12015-07-07 16:47:42 -0700235 nonSecureCodec = &resources[i];
236 } else if (type == kResourceGraphicMemory) {
237 graphicMemory = &resources[i];
238 }
239 }
240
241 // first pass to handle secure/non-secure codec conflict
242 if (secureCodec != NULL) {
243 if (!mSupportsMultipleSecureCodecs) {
244 if (!getAllClients_l(callingPid, String8(kResourceSecureCodec), &clients)) {
245 return false;
246 }
247 }
248 if (!mSupportsSecureWithNonSecureCodec) {
249 if (!getAllClients_l(callingPid, String8(kResourceNonSecureCodec), &clients)) {
250 return false;
251 }
252 }
253 }
254 if (nonSecureCodec != NULL) {
255 if (!mSupportsSecureWithNonSecureCodec) {
256 if (!getAllClients_l(callingPid, String8(kResourceSecureCodec), &clients)) {
257 return false;
Ronghua Wu231c3d12015-03-11 15:10:32 -0700258 }
259 }
260 }
261
262 if (clients.size() == 0) {
263 // if no secure/non-secure codec conflict, run second pass to handle other resources.
Ronghua Wu05d89f12015-07-07 16:47:42 -0700264 getClientForResource_l(callingPid, graphicMemory, &clients);
Ronghua Wu231c3d12015-03-11 15:10:32 -0700265 }
Ronghua Wu67e7f542015-03-13 10:47:08 -0700266
267 if (clients.size() == 0) {
268 // if we are here, run the third pass to free one codec with the same type.
Ronghua Wu05d89f12015-07-07 16:47:42 -0700269 getClientForResource_l(callingPid, secureCodec, &clients);
270 getClientForResource_l(callingPid, nonSecureCodec, &clients);
271 }
272
273 if (clients.size() == 0) {
274 // if we are here, run the fourth pass to free one codec with the different type.
275 if (secureCodec != NULL) {
276 MediaResource temp(String8(kResourceNonSecureCodec), 1);
277 getClientForResource_l(callingPid, &temp, &clients);
278 }
279 if (nonSecureCodec != NULL) {
280 MediaResource temp(String8(kResourceSecureCodec), 1);
281 getClientForResource_l(callingPid, &temp, &clients);
Ronghua Wu67e7f542015-03-13 10:47:08 -0700282 }
283 }
Ronghua Wu231c3d12015-03-11 15:10:32 -0700284 }
285
286 if (clients.size() == 0) {
287 return false;
288 }
289
Ronghua Wu67e7f542015-03-13 10:47:08 -0700290 sp<IResourceManagerClient> failedClient;
Ronghua Wu231c3d12015-03-11 15:10:32 -0700291 for (size_t i = 0; i < clients.size(); ++i) {
Ronghua Wua8ec8fc2015-05-07 13:58:22 -0700292 log = String8::format("reclaimResource from client %p", clients[i].get());
293 mServiceLog->add(log);
Ronghua Wu231c3d12015-03-11 15:10:32 -0700294 if (!clients[i]->reclaimResource()) {
Ronghua Wu67e7f542015-03-13 10:47:08 -0700295 failedClient = clients[i];
296 break;
Ronghua Wu231c3d12015-03-11 15:10:32 -0700297 }
298 }
Ronghua Wu67e7f542015-03-13 10:47:08 -0700299
300 {
301 Mutex::Autolock lock(mLock);
302 bool found = false;
303 for (size_t i = 0; i < mMap.size(); ++i) {
304 ResourceInfos &infos = mMap.editValueAt(i);
305 for (size_t j = 0; j < infos.size();) {
306 if (infos[j].client == failedClient) {
307 j = infos.removeAt(j);
308 found = true;
309 } else {
310 ++j;
311 }
312 }
313 if (found) {
314 break;
315 }
316 }
317 if (!found) {
318 ALOGV("didn't find failed client");
319 }
320 }
321
322 return (failedClient == NULL);
Ronghua Wu231c3d12015-03-11 15:10:32 -0700323}
324
325bool ResourceManagerService::getAllClients_l(
326 int callingPid, const String8 &type, Vector<sp<IResourceManagerClient>> *clients) {
327 Vector<sp<IResourceManagerClient>> temp;
328 for (size_t i = 0; i < mMap.size(); ++i) {
329 ResourceInfos &infos = mMap.editValueAt(i);
330 for (size_t j = 0; j < infos.size(); ++j) {
331 if (hasResourceType(type, infos[j].resources)) {
332 if (!isCallingPriorityHigher_l(callingPid, mMap.keyAt(i))) {
333 // some higher/equal priority process owns the resource,
334 // this request can't be fulfilled.
335 ALOGE("getAllClients_l: can't reclaim resource %s from pid %d",
336 type.string(), mMap.keyAt(i));
337 return false;
338 }
339 temp.push_back(infos[j].client);
340 }
341 }
342 }
343 if (temp.size() == 0) {
344 ALOGV("getAllClients_l: didn't find any resource %s", type.string());
345 return true;
346 }
347 clients->appendVector(temp);
348 return true;
349}
350
351bool ResourceManagerService::getLowestPriorityBiggestClient_l(
352 int callingPid, const String8 &type, sp<IResourceManagerClient> *client) {
353 int lowestPriorityPid;
354 int lowestPriority;
355 int callingPriority;
356 if (!mProcessInfo->getPriority(callingPid, &callingPriority)) {
357 ALOGE("getLowestPriorityBiggestClient_l: can't get process priority for pid %d",
358 callingPid);
359 return false;
360 }
361 if (!getLowestPriorityPid_l(type, &lowestPriorityPid, &lowestPriority)) {
362 return false;
363 }
364 if (lowestPriority <= callingPriority) {
365 ALOGE("getLowestPriorityBiggestClient_l: lowest priority %d vs caller priority %d",
366 lowestPriority, callingPriority);
367 return false;
368 }
369
370 if (!getBiggestClient_l(lowestPriorityPid, type, client)) {
371 return false;
372 }
373 return true;
374}
375
376bool ResourceManagerService::getLowestPriorityPid_l(
377 const String8 &type, int *lowestPriorityPid, int *lowestPriority) {
378 int pid = -1;
379 int priority = -1;
380 for (size_t i = 0; i < mMap.size(); ++i) {
381 if (mMap.valueAt(i).size() == 0) {
382 // no client on this process.
383 continue;
384 }
385 if (!hasResourceType(type, mMap.valueAt(i))) {
386 // doesn't have the requested resource type
387 continue;
388 }
389 int tempPid = mMap.keyAt(i);
390 int tempPriority;
391 if (!mProcessInfo->getPriority(tempPid, &tempPriority)) {
392 ALOGV("getLowestPriorityPid_l: can't get priority of pid %d, skipped", tempPid);
393 // TODO: remove this pid from mMap?
394 continue;
395 }
396 if (pid == -1 || tempPriority > priority) {
397 // initial the value
398 pid = tempPid;
399 priority = tempPriority;
400 }
401 }
402 if (pid != -1) {
403 *lowestPriorityPid = pid;
404 *lowestPriority = priority;
405 }
406 return (pid != -1);
407}
408
409bool ResourceManagerService::isCallingPriorityHigher_l(int callingPid, int pid) {
410 int callingPidPriority;
411 if (!mProcessInfo->getPriority(callingPid, &callingPidPriority)) {
412 return false;
413 }
414
415 int priority;
416 if (!mProcessInfo->getPriority(pid, &priority)) {
417 return false;
418 }
419
420 return (callingPidPriority < priority);
421}
422
423bool ResourceManagerService::getBiggestClient_l(
424 int pid, const String8 &type, sp<IResourceManagerClient> *client) {
425 ssize_t index = mMap.indexOfKey(pid);
426 if (index < 0) {
427 ALOGE("getBiggestClient_l: can't find resource info for pid %d", pid);
428 return false;
429 }
430
431 sp<IResourceManagerClient> clientTemp;
432 uint64_t largestValue = 0;
433 const ResourceInfos &infos = mMap.valueAt(index);
434 for (size_t i = 0; i < infos.size(); ++i) {
435 Vector<MediaResource> resources = infos[i].resources;
436 for (size_t j = 0; j < resources.size(); ++j) {
437 if (resources[j].mType == type) {
438 if (resources[j].mValue > largestValue) {
439 largestValue = resources[j].mValue;
440 clientTemp = infos[i].client;
441 }
442 }
443 }
444 }
445
446 if (clientTemp == NULL) {
447 ALOGE("getBiggestClient_l: can't find resource type %s for pid %d", type.string(), pid);
448 return false;
449 }
450
451 *client = clientTemp;
452 return true;
453}
454
455} // namespace android