blob: 17aac4e976f10141ebb3dd856491ea7b25a5743f [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
Ronghua Wu8f9dd872015-04-23 15:24:25 -070091status_t ResourceManagerService::dump(int fd, const Vector<String16>& args) {
92 Mutex::Autolock lock(mLock);
93
94 String8 result;
95 const size_t SIZE = 256;
96 char buffer[SIZE];
97
98 snprintf(buffer, SIZE, "ResourceManagerService: %p\n", this);
99 result.append(buffer);
100 result.append(" Policies:\n");
101 snprintf(buffer, SIZE, " SupportsMultipleSecureCodecs: %d\n", mSupportsMultipleSecureCodecs);
102 result.append(buffer);
103 snprintf(buffer, SIZE, " SupportsSecureWithNonSecureCodec: %d\n", mSupportsSecureWithNonSecureCodec);
104 result.append(buffer);
105
106 snprintf(buffer, SIZE, " Processes:\n");
107 result.append(buffer);
108 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) {
114 snprintf(buffer, SIZE, " Client:\n");
115 result.append(buffer);
116 snprintf(buffer, SIZE, " Id: %lld\n", (long long)infos[j].clientId);
117 result.append(buffer);
118
119 snprintf(buffer, SIZE, " Name: %s\n", infos[j].client->getName().string());
120 result.append(buffer);
121
122 Vector<MediaResource> resources = infos[j].resources;
123 snprintf(buffer, SIZE, " Resources:\n");
124 result.append(buffer);
125 for (size_t k = 0; k < resources.size(); ++k) {
126 snprintf(buffer, SIZE, " %s\n", resources[k].toString().string());
127 result.append(buffer);
128 }
129 }
130 }
131
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()),
138 mSupportsMultipleSecureCodecs(true),
139 mSupportsSecureWithNonSecureCodec(true) {}
140
141ResourceManagerService::ResourceManagerService(sp<ProcessInfoInterface> processInfo)
142 : mProcessInfo(processInfo),
143 mSupportsMultipleSecureCodecs(true),
144 mSupportsSecureWithNonSecureCodec(true) {}
145
146ResourceManagerService::~ResourceManagerService() {}
147
148void ResourceManagerService::config(const Vector<MediaResourcePolicy> &policies) {
149 ALOGV("config(%s)", getString(policies).string());
150
151 Mutex::Autolock lock(mLock);
152 for (size_t i = 0; i < policies.size(); ++i) {
153 String8 type = policies[i].mType;
154 uint64_t value = policies[i].mValue;
155 if (type == kPolicySupportsMultipleSecureCodecs) {
156 mSupportsMultipleSecureCodecs = (value != 0);
157 } else if (type == kPolicySupportsSecureWithNonSecureCodec) {
158 mSupportsSecureWithNonSecureCodec = (value != 0);
159 }
160 }
161}
162
163void ResourceManagerService::addResource(
164 int pid,
165 int64_t clientId,
166 const sp<IResourceManagerClient> client,
167 const Vector<MediaResource> &resources) {
168 ALOGV("addResource(pid %d, clientId %lld, resources %s)",
169 pid, (long long) clientId, getString(resources).string());
170
171 Mutex::Autolock lock(mLock);
172 ResourceInfos& infos = getResourceInfosForEdit(pid, mMap);
173 ResourceInfo& info = getResourceInfoForEdit(clientId, client, infos);
Ronghua Wu67e7f542015-03-13 10:47:08 -0700174 // TODO: do the merge instead of append.
Ronghua Wu231c3d12015-03-11 15:10:32 -0700175 info.resources.appendVector(resources);
176}
177
178void ResourceManagerService::removeResource(int64_t clientId) {
179 ALOGV("removeResource(%lld)", (long long) clientId);
180
181 Mutex::Autolock lock(mLock);
182 bool found = false;
183 for (size_t i = 0; i < mMap.size(); ++i) {
184 ResourceInfos &infos = mMap.editValueAt(i);
185 for (size_t j = 0; j < infos.size();) {
186 if (infos[j].clientId == clientId) {
187 j = infos.removeAt(j);
188 found = true;
189 } else {
190 ++j;
191 }
192 }
193 if (found) {
194 break;
195 }
196 }
197 if (!found) {
198 ALOGV("didn't find client");
199 }
200}
201
202bool ResourceManagerService::reclaimResource(
203 int callingPid, const Vector<MediaResource> &resources) {
204 ALOGV("reclaimResource(callingPid %d, resources %s)",
205 callingPid, getString(resources).string());
206
207 Vector<sp<IResourceManagerClient>> clients;
208 {
209 Mutex::Autolock lock(mLock);
210 // first pass to handle secure/non-secure codec conflict
211 for (size_t i = 0; i < resources.size(); ++i) {
212 String8 type = resources[i].mType;
213 if (type == kResourceSecureCodec) {
214 if (!mSupportsMultipleSecureCodecs) {
215 if (!getAllClients_l(callingPid, String8(kResourceSecureCodec), &clients)) {
216 return false;
217 }
218 }
219 if (!mSupportsSecureWithNonSecureCodec) {
220 if (!getAllClients_l(callingPid, String8(kResourceNonSecureCodec), &clients)) {
221 return false;
222 }
223 }
224 } else if (type == kResourceNonSecureCodec) {
225 if (!mSupportsSecureWithNonSecureCodec) {
226 if (!getAllClients_l(callingPid, String8(kResourceSecureCodec), &clients)) {
227 return false;
228 }
229 }
230 }
231 }
232
233 if (clients.size() == 0) {
234 // if no secure/non-secure codec conflict, run second pass to handle other resources.
235 for (size_t i = 0; i < resources.size(); ++i) {
236 String8 type = resources[i].mType;
237 if (type == kResourceGraphicMemory) {
238 sp<IResourceManagerClient> client;
239 if (!getLowestPriorityBiggestClient_l(callingPid, type, &client)) {
240 return false;
241 }
242 clients.push_back(client);
243 }
244 }
245 }
Ronghua Wu67e7f542015-03-13 10:47:08 -0700246
247 if (clients.size() == 0) {
248 // if we are here, run the third pass to free one codec with the same type.
249 for (size_t i = 0; i < resources.size(); ++i) {
250 String8 type = resources[i].mType;
251 if (type == kResourceSecureCodec || type == kResourceNonSecureCodec) {
252 sp<IResourceManagerClient> client;
253 if (!getLowestPriorityBiggestClient_l(callingPid, type, &client)) {
254 return false;
255 }
256 clients.push_back(client);
257 }
258 }
259 }
Ronghua Wu231c3d12015-03-11 15:10:32 -0700260 }
261
262 if (clients.size() == 0) {
263 return false;
264 }
265
Ronghua Wu67e7f542015-03-13 10:47:08 -0700266 sp<IResourceManagerClient> failedClient;
Ronghua Wu231c3d12015-03-11 15:10:32 -0700267 for (size_t i = 0; i < clients.size(); ++i) {
268 ALOGV("reclaimResource from client %p", clients[i].get());
269 if (!clients[i]->reclaimResource()) {
Ronghua Wu67e7f542015-03-13 10:47:08 -0700270 failedClient = clients[i];
271 break;
Ronghua Wu231c3d12015-03-11 15:10:32 -0700272 }
273 }
Ronghua Wu67e7f542015-03-13 10:47:08 -0700274
275 {
276 Mutex::Autolock lock(mLock);
277 bool found = false;
278 for (size_t i = 0; i < mMap.size(); ++i) {
279 ResourceInfos &infos = mMap.editValueAt(i);
280 for (size_t j = 0; j < infos.size();) {
281 if (infos[j].client == failedClient) {
282 j = infos.removeAt(j);
283 found = true;
284 } else {
285 ++j;
286 }
287 }
288 if (found) {
289 break;
290 }
291 }
292 if (!found) {
293 ALOGV("didn't find failed client");
294 }
295 }
296
297 return (failedClient == NULL);
Ronghua Wu231c3d12015-03-11 15:10:32 -0700298}
299
300bool ResourceManagerService::getAllClients_l(
301 int callingPid, const String8 &type, Vector<sp<IResourceManagerClient>> *clients) {
302 Vector<sp<IResourceManagerClient>> temp;
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(); ++j) {
306 if (hasResourceType(type, infos[j].resources)) {
307 if (!isCallingPriorityHigher_l(callingPid, mMap.keyAt(i))) {
308 // some higher/equal priority process owns the resource,
309 // this request can't be fulfilled.
310 ALOGE("getAllClients_l: can't reclaim resource %s from pid %d",
311 type.string(), mMap.keyAt(i));
312 return false;
313 }
314 temp.push_back(infos[j].client);
315 }
316 }
317 }
318 if (temp.size() == 0) {
319 ALOGV("getAllClients_l: didn't find any resource %s", type.string());
320 return true;
321 }
322 clients->appendVector(temp);
323 return true;
324}
325
326bool ResourceManagerService::getLowestPriorityBiggestClient_l(
327 int callingPid, const String8 &type, sp<IResourceManagerClient> *client) {
328 int lowestPriorityPid;
329 int lowestPriority;
330 int callingPriority;
331 if (!mProcessInfo->getPriority(callingPid, &callingPriority)) {
332 ALOGE("getLowestPriorityBiggestClient_l: can't get process priority for pid %d",
333 callingPid);
334 return false;
335 }
336 if (!getLowestPriorityPid_l(type, &lowestPriorityPid, &lowestPriority)) {
337 return false;
338 }
339 if (lowestPriority <= callingPriority) {
340 ALOGE("getLowestPriorityBiggestClient_l: lowest priority %d vs caller priority %d",
341 lowestPriority, callingPriority);
342 return false;
343 }
344
345 if (!getBiggestClient_l(lowestPriorityPid, type, client)) {
346 return false;
347 }
348 return true;
349}
350
351bool ResourceManagerService::getLowestPriorityPid_l(
352 const String8 &type, int *lowestPriorityPid, int *lowestPriority) {
353 int pid = -1;
354 int priority = -1;
355 for (size_t i = 0; i < mMap.size(); ++i) {
356 if (mMap.valueAt(i).size() == 0) {
357 // no client on this process.
358 continue;
359 }
360 if (!hasResourceType(type, mMap.valueAt(i))) {
361 // doesn't have the requested resource type
362 continue;
363 }
364 int tempPid = mMap.keyAt(i);
365 int tempPriority;
366 if (!mProcessInfo->getPriority(tempPid, &tempPriority)) {
367 ALOGV("getLowestPriorityPid_l: can't get priority of pid %d, skipped", tempPid);
368 // TODO: remove this pid from mMap?
369 continue;
370 }
371 if (pid == -1 || tempPriority > priority) {
372 // initial the value
373 pid = tempPid;
374 priority = tempPriority;
375 }
376 }
377 if (pid != -1) {
378 *lowestPriorityPid = pid;
379 *lowestPriority = priority;
380 }
381 return (pid != -1);
382}
383
384bool ResourceManagerService::isCallingPriorityHigher_l(int callingPid, int pid) {
385 int callingPidPriority;
386 if (!mProcessInfo->getPriority(callingPid, &callingPidPriority)) {
387 return false;
388 }
389
390 int priority;
391 if (!mProcessInfo->getPriority(pid, &priority)) {
392 return false;
393 }
394
395 return (callingPidPriority < priority);
396}
397
398bool ResourceManagerService::getBiggestClient_l(
399 int pid, const String8 &type, sp<IResourceManagerClient> *client) {
400 ssize_t index = mMap.indexOfKey(pid);
401 if (index < 0) {
402 ALOGE("getBiggestClient_l: can't find resource info for pid %d", pid);
403 return false;
404 }
405
406 sp<IResourceManagerClient> clientTemp;
407 uint64_t largestValue = 0;
408 const ResourceInfos &infos = mMap.valueAt(index);
409 for (size_t i = 0; i < infos.size(); ++i) {
410 Vector<MediaResource> resources = infos[i].resources;
411 for (size_t j = 0; j < resources.size(); ++j) {
412 if (resources[j].mType == type) {
413 if (resources[j].mValue > largestValue) {
414 largestValue = resources[j].mValue;
415 clientTemp = infos[i].client;
416 }
417 }
418 }
419 }
420
421 if (clientTemp == NULL) {
422 ALOGE("getBiggestClient_l: can't find resource type %s for pid %d", type.string(), pid);
423 return false;
424 }
425
426 *client = clientTemp;
427 return true;
428}
429
430} // namespace android