blob: 6781a367e324cc86d9afa8a0d4ef17926aac8b5e [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 String8 result;
Ronghua Wu8f9dd872015-04-23 15:24:25 -070094
dcashman014e91e2015-09-11 09:33:01 -070095 if (checkCallingPermission(String16("android.permission.DUMP")) == false) {
96 result.format("Permission Denial: "
97 "can't dump ResourceManagerService from pid=%d, uid=%d\n",
98 IPCThreadState::self()->getCallingPid(),
99 IPCThreadState::self()->getCallingUid());
100 write(fd, result.string(), result.size());
101 return PERMISSION_DENIED;
102 }
103
Ronghua Wu76d4c7f2015-10-23 15:01:53 -0700104 PidResourceInfosMap mapCopy;
105 bool supportsMultipleSecureCodecs;
106 bool supportsSecureWithNonSecureCodec;
107 String8 serviceLog;
108 {
109 Mutex::Autolock lock(mLock);
110 mapCopy = mMap; // Shadow copy, real copy will happen on write.
111 supportsMultipleSecureCodecs = mSupportsMultipleSecureCodecs;
112 supportsSecureWithNonSecureCodec = mSupportsSecureWithNonSecureCodec;
113 serviceLog = mServiceLog->toString(" " /* linePrefix */);
114 }
115
116 const size_t SIZE = 256;
117 char buffer[SIZE];
Ronghua Wu8f9dd872015-04-23 15:24:25 -0700118 snprintf(buffer, SIZE, "ResourceManagerService: %p\n", this);
119 result.append(buffer);
120 result.append(" Policies:\n");
Ronghua Wu76d4c7f2015-10-23 15:01:53 -0700121 snprintf(buffer, SIZE, " SupportsMultipleSecureCodecs: %d\n", supportsMultipleSecureCodecs);
Ronghua Wu8f9dd872015-04-23 15:24:25 -0700122 result.append(buffer);
Ronghua Wu76d4c7f2015-10-23 15:01:53 -0700123 snprintf(buffer, SIZE, " SupportsSecureWithNonSecureCodec: %d\n",
124 supportsSecureWithNonSecureCodec);
Ronghua Wu8f9dd872015-04-23 15:24:25 -0700125 result.append(buffer);
126
Ronghua Wua8ec8fc2015-05-07 13:58:22 -0700127 result.append(" Processes:\n");
Ronghua Wu76d4c7f2015-10-23 15:01:53 -0700128 for (size_t i = 0; i < mapCopy.size(); ++i) {
129 snprintf(buffer, SIZE, " Pid: %d\n", mapCopy.keyAt(i));
Ronghua Wu8f9dd872015-04-23 15:24:25 -0700130 result.append(buffer);
131
Ronghua Wu76d4c7f2015-10-23 15:01:53 -0700132 const ResourceInfos &infos = mapCopy.valueAt(i);
Ronghua Wu8f9dd872015-04-23 15:24:25 -0700133 for (size_t j = 0; j < infos.size(); ++j) {
Ronghua Wua8ec8fc2015-05-07 13:58:22 -0700134 result.append(" Client:\n");
Ronghua Wu8f9dd872015-04-23 15:24:25 -0700135 snprintf(buffer, SIZE, " Id: %lld\n", (long long)infos[j].clientId);
136 result.append(buffer);
137
138 snprintf(buffer, SIZE, " Name: %s\n", infos[j].client->getName().string());
139 result.append(buffer);
140
141 Vector<MediaResource> resources = infos[j].resources;
Ronghua Wua8ec8fc2015-05-07 13:58:22 -0700142 result.append(" Resources:\n");
Ronghua Wu8f9dd872015-04-23 15:24:25 -0700143 for (size_t k = 0; k < resources.size(); ++k) {
144 snprintf(buffer, SIZE, " %s\n", resources[k].toString().string());
145 result.append(buffer);
146 }
147 }
148 }
Ronghua Wu022ed722015-05-11 15:15:09 -0700149 result.append(" Events logs (most recent at top):\n");
Ronghua Wu76d4c7f2015-10-23 15:01:53 -0700150 result.append(serviceLog);
Ronghua Wu8f9dd872015-04-23 15:24:25 -0700151
152 write(fd, result.string(), result.size());
153 return OK;
154}
155
Ronghua Wu231c3d12015-03-11 15:10:32 -0700156ResourceManagerService::ResourceManagerService()
157 : mProcessInfo(new ProcessInfo()),
Ronghua Wua8ec8fc2015-05-07 13:58:22 -0700158 mServiceLog(new ServiceLog()),
Ronghua Wu231c3d12015-03-11 15:10:32 -0700159 mSupportsMultipleSecureCodecs(true),
160 mSupportsSecureWithNonSecureCodec(true) {}
161
162ResourceManagerService::ResourceManagerService(sp<ProcessInfoInterface> processInfo)
163 : mProcessInfo(processInfo),
Ronghua Wua8ec8fc2015-05-07 13:58:22 -0700164 mServiceLog(new ServiceLog()),
Ronghua Wu231c3d12015-03-11 15:10:32 -0700165 mSupportsMultipleSecureCodecs(true),
166 mSupportsSecureWithNonSecureCodec(true) {}
167
168ResourceManagerService::~ResourceManagerService() {}
169
170void ResourceManagerService::config(const Vector<MediaResourcePolicy> &policies) {
Ronghua Wua8ec8fc2015-05-07 13:58:22 -0700171 String8 log = String8::format("config(%s)", getString(policies).string());
172 mServiceLog->add(log);
Ronghua Wu231c3d12015-03-11 15:10:32 -0700173
174 Mutex::Autolock lock(mLock);
175 for (size_t i = 0; i < policies.size(); ++i) {
176 String8 type = policies[i].mType;
Ronghua Wu9ba21b92015-04-21 14:23:06 -0700177 String8 value = policies[i].mValue;
Ronghua Wu231c3d12015-03-11 15:10:32 -0700178 if (type == kPolicySupportsMultipleSecureCodecs) {
Ronghua Wu9ba21b92015-04-21 14:23:06 -0700179 mSupportsMultipleSecureCodecs = (value == "true");
Ronghua Wu231c3d12015-03-11 15:10:32 -0700180 } else if (type == kPolicySupportsSecureWithNonSecureCodec) {
Ronghua Wu9ba21b92015-04-21 14:23:06 -0700181 mSupportsSecureWithNonSecureCodec = (value == "true");
Ronghua Wu231c3d12015-03-11 15:10:32 -0700182 }
183 }
184}
185
186void ResourceManagerService::addResource(
187 int pid,
188 int64_t clientId,
189 const sp<IResourceManagerClient> client,
190 const Vector<MediaResource> &resources) {
Ronghua Wua8ec8fc2015-05-07 13:58:22 -0700191 String8 log = String8::format("addResource(pid %d, clientId %lld, resources %s)",
Ronghua Wu231c3d12015-03-11 15:10:32 -0700192 pid, (long long) clientId, getString(resources).string());
Ronghua Wua8ec8fc2015-05-07 13:58:22 -0700193 mServiceLog->add(log);
Ronghua Wu231c3d12015-03-11 15:10:32 -0700194
195 Mutex::Autolock lock(mLock);
196 ResourceInfos& infos = getResourceInfosForEdit(pid, mMap);
197 ResourceInfo& info = getResourceInfoForEdit(clientId, client, infos);
Ronghua Wu67e7f542015-03-13 10:47:08 -0700198 // TODO: do the merge instead of append.
Ronghua Wu231c3d12015-03-11 15:10:32 -0700199 info.resources.appendVector(resources);
200}
201
Ronghua Wu37c89242015-07-15 12:23:48 -0700202void ResourceManagerService::removeResource(int pid, int64_t clientId) {
203 String8 log = String8::format(
204 "removeResource(pid %d, clientId %lld)",
205 pid, (long long) clientId);
Ronghua Wua8ec8fc2015-05-07 13:58:22 -0700206 mServiceLog->add(log);
Ronghua Wu231c3d12015-03-11 15:10:32 -0700207
208 Mutex::Autolock lock(mLock);
Ronghua Wu37c89242015-07-15 12:23:48 -0700209 ssize_t index = mMap.indexOfKey(pid);
210 if (index < 0) {
211 ALOGV("removeResource: didn't find pid %d for clientId %lld", pid, (long long) clientId);
212 return;
213 }
Ronghua Wu231c3d12015-03-11 15:10:32 -0700214 bool found = false;
Ronghua Wu37c89242015-07-15 12:23:48 -0700215 ResourceInfos &infos = mMap.editValueAt(index);
216 for (size_t j = 0; j < infos.size(); ++j) {
217 if (infos[j].clientId == clientId) {
218 j = infos.removeAt(j);
219 found = true;
Ronghua Wu231c3d12015-03-11 15:10:32 -0700220 break;
221 }
222 }
223 if (!found) {
224 ALOGV("didn't find client");
225 }
226}
227
Ronghua Wu05d89f12015-07-07 16:47:42 -0700228void ResourceManagerService::getClientForResource_l(
229 int callingPid, const MediaResource *res, Vector<sp<IResourceManagerClient>> *clients) {
230 if (res == NULL) {
231 return;
232 }
233 sp<IResourceManagerClient> client;
234 if (getLowestPriorityBiggestClient_l(callingPid, res->mType, &client)) {
235 clients->push_back(client);
236 }
237}
238
Ronghua Wu231c3d12015-03-11 15:10:32 -0700239bool ResourceManagerService::reclaimResource(
240 int callingPid, const Vector<MediaResource> &resources) {
Ronghua Wua8ec8fc2015-05-07 13:58:22 -0700241 String8 log = String8::format("reclaimResource(callingPid %d, resources %s)",
Ronghua Wu231c3d12015-03-11 15:10:32 -0700242 callingPid, getString(resources).string());
Ronghua Wua8ec8fc2015-05-07 13:58:22 -0700243 mServiceLog->add(log);
Ronghua Wu231c3d12015-03-11 15:10:32 -0700244
245 Vector<sp<IResourceManagerClient>> clients;
246 {
247 Mutex::Autolock lock(mLock);
Ronghua Wu05d89f12015-07-07 16:47:42 -0700248 const MediaResource *secureCodec = NULL;
249 const MediaResource *nonSecureCodec = NULL;
250 const MediaResource *graphicMemory = NULL;
Ronghua Wu231c3d12015-03-11 15:10:32 -0700251 for (size_t i = 0; i < resources.size(); ++i) {
252 String8 type = resources[i].mType;
Ronghua Wu05d89f12015-07-07 16:47:42 -0700253 if (resources[i].mType == kResourceSecureCodec) {
254 secureCodec = &resources[i];
Ronghua Wu231c3d12015-03-11 15:10:32 -0700255 } else if (type == kResourceNonSecureCodec) {
Ronghua Wu05d89f12015-07-07 16:47:42 -0700256 nonSecureCodec = &resources[i];
257 } else if (type == kResourceGraphicMemory) {
258 graphicMemory = &resources[i];
259 }
260 }
261
262 // first pass to handle secure/non-secure codec conflict
263 if (secureCodec != NULL) {
264 if (!mSupportsMultipleSecureCodecs) {
265 if (!getAllClients_l(callingPid, String8(kResourceSecureCodec), &clients)) {
266 return false;
267 }
268 }
269 if (!mSupportsSecureWithNonSecureCodec) {
270 if (!getAllClients_l(callingPid, String8(kResourceNonSecureCodec), &clients)) {
271 return false;
272 }
273 }
274 }
275 if (nonSecureCodec != NULL) {
276 if (!mSupportsSecureWithNonSecureCodec) {
277 if (!getAllClients_l(callingPid, String8(kResourceSecureCodec), &clients)) {
278 return false;
Ronghua Wu231c3d12015-03-11 15:10:32 -0700279 }
280 }
281 }
282
283 if (clients.size() == 0) {
284 // if no secure/non-secure codec conflict, run second pass to handle other resources.
Ronghua Wu05d89f12015-07-07 16:47:42 -0700285 getClientForResource_l(callingPid, graphicMemory, &clients);
Ronghua Wu231c3d12015-03-11 15:10:32 -0700286 }
Ronghua Wu67e7f542015-03-13 10:47:08 -0700287
288 if (clients.size() == 0) {
289 // if we are here, run the third pass to free one codec with the same type.
Ronghua Wu05d89f12015-07-07 16:47:42 -0700290 getClientForResource_l(callingPid, secureCodec, &clients);
291 getClientForResource_l(callingPid, nonSecureCodec, &clients);
292 }
293
294 if (clients.size() == 0) {
295 // if we are here, run the fourth pass to free one codec with the different type.
296 if (secureCodec != NULL) {
297 MediaResource temp(String8(kResourceNonSecureCodec), 1);
298 getClientForResource_l(callingPid, &temp, &clients);
299 }
300 if (nonSecureCodec != NULL) {
301 MediaResource temp(String8(kResourceSecureCodec), 1);
302 getClientForResource_l(callingPid, &temp, &clients);
Ronghua Wu67e7f542015-03-13 10:47:08 -0700303 }
304 }
Ronghua Wu231c3d12015-03-11 15:10:32 -0700305 }
306
307 if (clients.size() == 0) {
308 return false;
309 }
310
Ronghua Wu67e7f542015-03-13 10:47:08 -0700311 sp<IResourceManagerClient> failedClient;
Ronghua Wu231c3d12015-03-11 15:10:32 -0700312 for (size_t i = 0; i < clients.size(); ++i) {
Ronghua Wua8ec8fc2015-05-07 13:58:22 -0700313 log = String8::format("reclaimResource from client %p", clients[i].get());
314 mServiceLog->add(log);
Ronghua Wu231c3d12015-03-11 15:10:32 -0700315 if (!clients[i]->reclaimResource()) {
Ronghua Wu67e7f542015-03-13 10:47:08 -0700316 failedClient = clients[i];
317 break;
Ronghua Wu231c3d12015-03-11 15:10:32 -0700318 }
319 }
Ronghua Wu67e7f542015-03-13 10:47:08 -0700320
Ronghua Wu76d4c7f2015-10-23 15:01:53 -0700321 if (failedClient == NULL) {
322 return true;
323 }
324
Ronghua Wu67e7f542015-03-13 10:47:08 -0700325 {
326 Mutex::Autolock lock(mLock);
327 bool found = false;
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();) {
331 if (infos[j].client == failedClient) {
332 j = infos.removeAt(j);
333 found = true;
334 } else {
335 ++j;
336 }
337 }
338 if (found) {
339 break;
340 }
341 }
342 if (!found) {
343 ALOGV("didn't find failed client");
344 }
345 }
346
Ronghua Wu76d4c7f2015-10-23 15:01:53 -0700347 return false;
Ronghua Wu231c3d12015-03-11 15:10:32 -0700348}
349
350bool ResourceManagerService::getAllClients_l(
351 int callingPid, const String8 &type, Vector<sp<IResourceManagerClient>> *clients) {
352 Vector<sp<IResourceManagerClient>> temp;
353 for (size_t i = 0; i < mMap.size(); ++i) {
354 ResourceInfos &infos = mMap.editValueAt(i);
355 for (size_t j = 0; j < infos.size(); ++j) {
356 if (hasResourceType(type, infos[j].resources)) {
357 if (!isCallingPriorityHigher_l(callingPid, mMap.keyAt(i))) {
358 // some higher/equal priority process owns the resource,
359 // this request can't be fulfilled.
360 ALOGE("getAllClients_l: can't reclaim resource %s from pid %d",
361 type.string(), mMap.keyAt(i));
362 return false;
363 }
364 temp.push_back(infos[j].client);
365 }
366 }
367 }
368 if (temp.size() == 0) {
369 ALOGV("getAllClients_l: didn't find any resource %s", type.string());
370 return true;
371 }
372 clients->appendVector(temp);
373 return true;
374}
375
376bool ResourceManagerService::getLowestPriorityBiggestClient_l(
377 int callingPid, const String8 &type, sp<IResourceManagerClient> *client) {
378 int lowestPriorityPid;
379 int lowestPriority;
380 int callingPriority;
381 if (!mProcessInfo->getPriority(callingPid, &callingPriority)) {
382 ALOGE("getLowestPriorityBiggestClient_l: can't get process priority for pid %d",
383 callingPid);
384 return false;
385 }
386 if (!getLowestPriorityPid_l(type, &lowestPriorityPid, &lowestPriority)) {
387 return false;
388 }
389 if (lowestPriority <= callingPriority) {
390 ALOGE("getLowestPriorityBiggestClient_l: lowest priority %d vs caller priority %d",
391 lowestPriority, callingPriority);
392 return false;
393 }
394
395 if (!getBiggestClient_l(lowestPriorityPid, type, client)) {
396 return false;
397 }
398 return true;
399}
400
401bool ResourceManagerService::getLowestPriorityPid_l(
402 const String8 &type, int *lowestPriorityPid, int *lowestPriority) {
403 int pid = -1;
404 int priority = -1;
405 for (size_t i = 0; i < mMap.size(); ++i) {
406 if (mMap.valueAt(i).size() == 0) {
407 // no client on this process.
408 continue;
409 }
410 if (!hasResourceType(type, mMap.valueAt(i))) {
411 // doesn't have the requested resource type
412 continue;
413 }
414 int tempPid = mMap.keyAt(i);
415 int tempPriority;
416 if (!mProcessInfo->getPriority(tempPid, &tempPriority)) {
417 ALOGV("getLowestPriorityPid_l: can't get priority of pid %d, skipped", tempPid);
418 // TODO: remove this pid from mMap?
419 continue;
420 }
421 if (pid == -1 || tempPriority > priority) {
422 // initial the value
423 pid = tempPid;
424 priority = tempPriority;
425 }
426 }
427 if (pid != -1) {
428 *lowestPriorityPid = pid;
429 *lowestPriority = priority;
430 }
431 return (pid != -1);
432}
433
434bool ResourceManagerService::isCallingPriorityHigher_l(int callingPid, int pid) {
435 int callingPidPriority;
436 if (!mProcessInfo->getPriority(callingPid, &callingPidPriority)) {
437 return false;
438 }
439
440 int priority;
441 if (!mProcessInfo->getPriority(pid, &priority)) {
442 return false;
443 }
444
445 return (callingPidPriority < priority);
446}
447
448bool ResourceManagerService::getBiggestClient_l(
449 int pid, const String8 &type, sp<IResourceManagerClient> *client) {
450 ssize_t index = mMap.indexOfKey(pid);
451 if (index < 0) {
452 ALOGE("getBiggestClient_l: can't find resource info for pid %d", pid);
453 return false;
454 }
455
456 sp<IResourceManagerClient> clientTemp;
457 uint64_t largestValue = 0;
458 const ResourceInfos &infos = mMap.valueAt(index);
459 for (size_t i = 0; i < infos.size(); ++i) {
460 Vector<MediaResource> resources = infos[i].resources;
461 for (size_t j = 0; j < resources.size(); ++j) {
462 if (resources[j].mType == type) {
463 if (resources[j].mValue > largestValue) {
464 largestValue = resources[j].mValue;
465 clientTemp = infos[i].client;
466 }
467 }
468 }
469 }
470
471 if (clientTemp == NULL) {
472 ALOGE("getBiggestClient_l: can't find resource type %s for pid %d", type.string(), pid);
473 return false;
474 }
475
476 *client = clientTemp;
477 return true;
478}
479
480} // namespace android