1 /*
2 **
3 ** Copyright 2023, 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 "ResourceTracker"
20 #include <utils/Log.h>
21
22 #include <binder/IPCThreadState.h>
23 #include <mediautils/ProcessInfo.h>
24 #include "ResourceTracker.h"
25 #include "ResourceManagerServiceNew.h"
26 #include "ResourceObserverService.h"
27
28 namespace android {
29
isHwCodec(MediaResource::SubType subType)30 inline bool isHwCodec(MediaResource::SubType subType) {
31 return subType == MediaResource::SubType::kHwImageCodec ||
32 subType == MediaResource::SubType::kHwVideoCodec;
33 }
34
35 // Check whether a given resource (of type and subtype) is found in given resource list
36 // that also has the given Primary SubType.
hasResourceType(MediaResource::Type type,MediaResource::SubType subType,const ResourceList & resources,MediaResource::SubType primarySubType)37 static bool hasResourceType(MediaResource::Type type, MediaResource::SubType subType,
38 const ResourceList& resources, MediaResource::SubType primarySubType) {
39 bool foundResource = false;
40 bool matchedPrimary =
41 (primarySubType == MediaResource::SubType::kUnspecifiedSubType) ? true : false;
42 for (const MediaResourceParcel& res : resources.getResources()) {
43 if (hasResourceType(type, subType, res)) {
44 foundResource = true;
45 } else if (res.subType == primarySubType) {
46 matchedPrimary = true;
47 } else if (isHwCodec(res.subType) == isHwCodec(primarySubType)) {
48 matchedPrimary = true;
49 }
50 if (matchedPrimary && foundResource) {
51 return true;
52 }
53 }
54 return false;
55 }
56
57 // See if the given client is already in the list of clients.
contains(const std::vector<ClientInfo> & clients,const int64_t & clientId)58 inline bool contains(const std::vector<ClientInfo>& clients, const int64_t& clientId) {
59 std::vector<ClientInfo>::const_iterator found =
60 std::find_if(clients.begin(), clients.end(),
61 [clientId](const ClientInfo& client) -> bool {
62 return client.mClientId == clientId;
63 });
64
65 return found != clients.end();
66 }
67
68
ResourceTracker(const std::shared_ptr<ResourceManagerServiceNew> & service,const sp<ProcessInfoInterface> & processInfo)69 ResourceTracker::ResourceTracker(const std::shared_ptr<ResourceManagerServiceNew>& service,
70 const sp<ProcessInfoInterface>& processInfo) :
71 mService(service),
72 mProcessInfo(processInfo) {
73 }
74
~ResourceTracker()75 ResourceTracker::~ResourceTracker() {
76 }
77
setResourceObserverService(const std::shared_ptr<ResourceObserverService> & observerService)78 void ResourceTracker::setResourceObserverService(
79 const std::shared_ptr<ResourceObserverService>& observerService) {
80 mObserverService = observerService;
81 }
82
getResourceInfosForEdit(int pid)83 ResourceInfos& ResourceTracker::getResourceInfosForEdit(int pid) {
84 std::map<int, ResourceInfos>::iterator found = mMap.find(pid);
85 if (found == mMap.end()) {
86 // new pid
87 ResourceInfos infosForPid;
88 auto [it, inserted] = mMap.emplace(pid, infosForPid);
89 found = it;
90 }
91
92 return found->second;
93 }
94
addResource(const ClientInfoParcel & clientInfo,const std::shared_ptr<IResourceManagerClient> & client,const std::vector<MediaResourceParcel> & resources)95 bool ResourceTracker::addResource(const ClientInfoParcel& clientInfo,
96 const std::shared_ptr<IResourceManagerClient>& client,
97 const std::vector<MediaResourceParcel>& resources) {
98 int32_t pid = clientInfo.pid;
99 int32_t uid = clientInfo.uid;
100
101 if (!mProcessInfo->isPidUidTrusted(pid, uid)) {
102 pid_t callingPid = IPCThreadState::self()->getCallingPid();
103 uid_t callingUid = IPCThreadState::self()->getCallingUid();
104 ALOGW("%s called with untrusted pid %d or uid %d, using calling pid %d, uid %d",
105 __func__, pid, uid, callingPid, callingUid);
106 pid = callingPid;
107 uid = callingUid;
108 }
109 ResourceInfos& infos = getResourceInfosForEdit(pid);
110 ResourceInfo& info = getResourceInfoForEdit(clientInfo, client, infos);
111 ResourceList resourceAdded;
112
113 for (const MediaResourceParcel& res : resources) {
114 if (res.value < 0 && res.type != MediaResource::Type::kDrmSession) {
115 ALOGV("%s: Ignoring request to remove negative value of non-drm resource", __func__);
116 continue;
117 }
118 bool isNewEntry = false;
119 if (!info.resources.add(res, &isNewEntry)) {
120 continue;
121 }
122 if (isNewEntry) {
123 onFirstAdded(res, info.uid);
124 }
125
126 // Add it to the list of added resources for observers.
127 resourceAdded.add(res);
128 }
129 if (info.deathNotifier == nullptr && client != nullptr) {
130 info.deathNotifier = DeathNotifier::Create(client, mService, clientInfo);
131 }
132 if (mObserverService != nullptr && !resourceAdded.empty()) {
133 mObserverService->onResourceAdded(uid, pid, resourceAdded);
134 }
135
136 return !resourceAdded.empty();
137 }
138
updateResource(const aidl::android::media::ClientInfoParcel & clientInfo,const std::vector<::aidl::android::media::MediaResourceParcel> & resources)139 bool ResourceTracker::updateResource(
140 const aidl::android::media::ClientInfoParcel& clientInfo,
141 const std::vector<::aidl::android::media::MediaResourceParcel>& resources) {
142 ResourceInfos& infos = getResourceInfosForEdit(clientInfo.pid);
143
144 ResourceInfos::iterator found = infos.find(clientInfo.id);
145 if (found == infos.end()) {
146 return false;
147 }
148
149 ResourceInfo& info = found->second;
150 ResourceList resourceAdded;
151 ResourceList resourceRemoved;
152
153 for (const MediaResourceParcel& res : resources) {
154 if (res.value < 0) {
155 ALOGV("%s: Ignoring request to update negative value of resource", __func__);
156 continue;
157 }
158
159 // Since resource value/amount is non-negative, we are using this magic value (-1)
160 // to detect whether the resource has been removed or updated.
161 long removedEntryValue = -1;
162 if (info.resources.update(res, &removedEntryValue)) {
163 // Check if the removedEntryValue has been updated.
164 if (removedEntryValue != -1) {
165 // An entry was removed.
166 onLastRemoved(res, info.uid);
167 // Add it to the list of removed resources for observers.
168 MediaResourceParcel actualRemoved = res;
169 actualRemoved.value = removedEntryValue;
170 resourceRemoved.add(actualRemoved);
171 }
172 } else {
173 // A new entry is added.
174 onFirstAdded(res, info.uid);
175 // Add it to the list of added resources for observers.
176 resourceAdded.add(res);
177 }
178 }
179 if (mObserverService != nullptr) {
180 if (!resourceAdded.empty()) {
181 mObserverService->onResourceAdded(info.uid, clientInfo.pid, resourceAdded);
182 }
183 if (!resourceRemoved.empty()) {
184 mObserverService->onResourceRemoved(info.uid, clientInfo.pid, resourceRemoved);
185 }
186 }
187
188 return true;
189 }
190
updateClientImportance(const aidl::android::media::ClientInfoParcel & clientInfo)191 bool ResourceTracker::updateClientImportance(
192 const aidl::android::media::ClientInfoParcel& clientInfo) {
193 ResourceInfos& infos = getResourceInfosForEdit(clientInfo.pid);
194
195 ResourceInfos::iterator found = infos.find(clientInfo.id);
196 if (found == infos.end()) {
197 return false;
198 }
199 // Update the client importance.
200 found->second.importance = std::max(0, clientInfo.importance);
201 return true;
202 }
203
removeResource(const ClientInfoParcel & clientInfo,const std::vector<MediaResourceParcel> & resources)204 bool ResourceTracker::removeResource(const ClientInfoParcel& clientInfo,
205 const std::vector<MediaResourceParcel>& resources) {
206 int32_t pid = clientInfo.pid;
207 int64_t clientId = clientInfo.id;
208
209 if (!mProcessInfo->isPidTrusted(pid)) {
210 pid_t callingPid = IPCThreadState::self()->getCallingPid();
211 ALOGW("%s called with untrusted pid %d, using calling pid %d", __func__,
212 pid, callingPid);
213 pid = callingPid;
214 }
215 std::map<int, ResourceInfos>::iterator found = mMap.find(pid);
216 if (found == mMap.end()) {
217 ALOGV("%s: didn't find pid %d for clientId %lld", __func__, pid, (long long) clientId);
218 return false;
219 }
220
221 ResourceInfos& infos = found->second;
222 ResourceInfos::iterator foundClient = infos.find(clientId);
223 if (foundClient == infos.end()) {
224 ALOGV("%s: didn't find clientId %lld", __func__, (long long) clientId);
225 return false;
226 }
227
228 ResourceInfo& info = foundClient->second;
229 ResourceList resourceRemoved;
230 for (const MediaResourceParcel& res : resources) {
231 if (res.value < 0) {
232 ALOGV("%s: Ignoring request to remove negative value of resource", __func__);
233 continue;
234 }
235
236 long removedEntryValue = -1;
237 if (info.resources.remove(res, &removedEntryValue)) {
238 MediaResourceParcel actualRemoved = res;
239 if (removedEntryValue != -1) {
240 onLastRemoved(res, info.uid);
241 actualRemoved.value = removedEntryValue;
242 }
243
244 // Add it to the list of removed resources for observers.
245 resourceRemoved.add(actualRemoved);
246 }
247 }
248 if (mObserverService != nullptr && !resourceRemoved.empty()) {
249 mObserverService->onResourceRemoved(info.uid, pid, resourceRemoved);
250 }
251 return true;
252 }
253
removeResource(const ClientInfoParcel & clientInfo,bool validateCallingPid)254 bool ResourceTracker::removeResource(const ClientInfoParcel& clientInfo, bool validateCallingPid) {
255 int32_t pid = clientInfo.pid;
256 int64_t clientId = clientInfo.id;
257
258 if (validateCallingPid && !mProcessInfo->isPidTrusted(pid)) {
259 pid_t callingPid = IPCThreadState::self()->getCallingPid();
260 ALOGW("%s called with untrusted pid %d, using calling pid %d", __func__,
261 pid, callingPid);
262 pid = callingPid;
263 }
264 std::map<int, ResourceInfos>::iterator found = mMap.find(pid);
265 if (found == mMap.end()) {
266 ALOGV("%s: didn't find pid %d for clientId %lld", __func__, pid, (long long) clientId);
267 return false;
268 }
269
270 ResourceInfos& infos = found->second;
271 ResourceInfos::iterator foundClient = infos.find(clientId);
272 if (foundClient == infos.end()) {
273 ALOGV("%s: didn't find clientId %lld", __func__, (long long) clientId);
274 return false;
275 }
276
277 const ResourceInfo& info = foundClient->second;
278 for (const MediaResourceParcel& res : info.resources.getResources()) {
279 onLastRemoved(res, info.uid);
280 }
281
282 if (mObserverService != nullptr && !info.resources.empty()) {
283 mObserverService->onResourceRemoved(info.uid, pid, info.resources);
284 }
285
286 infos.erase(foundClient);
287 return true;
288 }
289
getClient(int pid,const int64_t & clientId) const290 std::shared_ptr<IResourceManagerClient> ResourceTracker::getClient(
291 int pid, const int64_t& clientId) const {
292 std::map<int, ResourceInfos>::const_iterator found = mMap.find(pid);
293 if (found == mMap.end()) {
294 ALOGV("%s: didn't find pid %d for clientId %lld", __func__, pid, (long long) clientId);
295 return nullptr;
296 }
297
298 const ResourceInfos& infos = found->second;
299 ResourceInfos::const_iterator foundClient = infos.find(clientId);
300 if (foundClient == infos.end()) {
301 ALOGV("%s: didn't find clientId %lld", __func__, (long long) clientId);
302 return nullptr;
303 }
304
305 return foundClient->second.client;
306 }
307
removeClient(int pid,const int64_t & clientId)308 bool ResourceTracker::removeClient(int pid, const int64_t& clientId) {
309 std::map<int, ResourceInfos>::iterator found = mMap.find(pid);
310 if (found == mMap.end()) {
311 ALOGV("%s: didn't find pid %d for clientId %lld", __func__, pid, (long long) clientId);
312 return false;
313 }
314
315 ResourceInfos& infos = found->second;
316 ResourceInfos::iterator foundClient = infos.find(clientId);
317 if (foundClient == infos.end()) {
318 ALOGV("%s: didn't find clientId %lld", __func__, (long long) clientId);
319 return false;
320 }
321
322 infos.erase(foundClient);
323 return true;
324 }
325
markClientForPendingRemoval(const ClientInfoParcel & clientInfo)326 bool ResourceTracker::markClientForPendingRemoval(const ClientInfoParcel& clientInfo) {
327 int32_t pid = clientInfo.pid;
328 int64_t clientId = clientInfo.id;
329
330 if (!mProcessInfo->isPidTrusted(pid)) {
331 pid_t callingPid = IPCThreadState::self()->getCallingPid();
332 ALOGW("%s called with untrusted pid %d, using calling pid %d", __func__,
333 pid, callingPid);
334 pid = callingPid;
335 }
336 std::map<int, ResourceInfos>::iterator found = mMap.find(pid);
337 if (found == mMap.end()) {
338 ALOGV("%s: didn't find pid %d for clientId %lld", __func__, pid, (long long)clientId);
339 return false;
340 }
341
342 ResourceInfos& infos = found->second;
343 ResourceInfos::iterator foundClient = infos.find(clientId);
344 if (foundClient == infos.end()) {
345 ALOGV("%s: didn't find clientId %lld", __func__, (long long) clientId);
346 return false;
347 }
348
349 ResourceInfo& info = foundClient->second;
350 info.pendingRemoval = true;
351 return true;
352 }
353
getClientsMarkedPendingRemoval(int32_t pid,std::vector<ClientInfo> & targetClients)354 bool ResourceTracker::getClientsMarkedPendingRemoval(int32_t pid,
355 std::vector<ClientInfo>& targetClients) {
356 if (!mProcessInfo->isPidTrusted(pid)) {
357 pid_t callingPid = IPCThreadState::self()->getCallingPid();
358 ALOGW("%s called with untrusted pid %d, using calling pid %d", __func__, pid, callingPid);
359 pid = callingPid;
360 }
361
362 // Go through all the MediaResource types (and corresponding subtypes for
363 // each, if applicable) and see if the process (with given pid) holds any
364 // such resources that are marked as pending removal.
365 // Since the use-case of this function is to get all such resources (pending
366 // removal) and reclaim them all - the order in which we look for the
367 // resource type doesn't matter.
368 for (MediaResource::Type type : {MediaResource::Type::kSecureCodec,
369 MediaResource::Type::kNonSecureCodec,
370 MediaResource::Type::kGraphicMemory,
371 MediaResource::Type::kDrmSession}) {
372 switch (type) {
373 // Codec resources are segregated by audio, video and image domains.
374 case MediaResource::Type::kSecureCodec:
375 case MediaResource::Type::kNonSecureCodec:
376 for (MediaResource::SubType subType : {MediaResource::SubType::kHwAudioCodec,
377 MediaResource::SubType::kSwAudioCodec,
378 MediaResource::SubType::kHwVideoCodec,
379 MediaResource::SubType::kSwVideoCodec,
380 MediaResource::SubType::kHwImageCodec,
381 MediaResource::SubType::kSwImageCodec}) {
382 ClientInfo clientInfo;
383 if (getBiggestClientPendingRemoval(pid, type, subType, clientInfo)) {
384 if (!contains(targetClients, clientInfo.mClientId)) {
385 targetClients.emplace_back(clientInfo);
386 }
387 continue;
388 }
389 }
390 break;
391 // Non-codec resources are shared by audio, video and image codecs (no subtype).
392 default:
393 ClientInfo clientInfo;
394 MediaResource::SubType subType = MediaResource::SubType::kUnspecifiedSubType;
395 if (getBiggestClientPendingRemoval(pid, type, subType, clientInfo)) {
396 if (!contains(targetClients, clientInfo.mClientId)) {
397 targetClients.emplace_back(clientInfo);
398 }
399 }
400 break;
401 }
402 }
403
404 return true;
405 }
406
overridePid(int originalPid,int newPid)407 bool ResourceTracker::overridePid(int originalPid, int newPid) {
408 mOverridePidMap.erase(originalPid);
409 if (newPid != -1) {
410 mOverridePidMap.emplace(originalPid, newPid);
411 return true;
412 }
413 return false;
414 }
415
overrideProcessInfo(const std::shared_ptr<IResourceManagerClient> & client,int pid,int procState,int oomScore)416 bool ResourceTracker::overrideProcessInfo(const std::shared_ptr<IResourceManagerClient>& client,
417 int pid, int procState, int oomScore) {
418 removeProcessInfoOverride(pid);
419
420 if (!mProcessInfo->overrideProcessInfo(pid, procState, oomScore)) {
421 // Override value is rejected by ProcessInfo.
422 return false;
423 }
424
425 ClientInfoParcel clientInfo{.pid = static_cast<int32_t>(pid),
426 .uid = 0,
427 .id = 0,
428 .name = "<unknown client>"};
429 std::shared_ptr<DeathNotifier> deathNotifier =
430 DeathNotifier::Create(client, mService, clientInfo, true);
431
432 mProcessInfoOverrideMap.emplace(pid, ProcessInfoOverride{deathNotifier, client});
433
434 return true;
435 }
436
removeProcessInfoOverride(int pid)437 void ResourceTracker::removeProcessInfoOverride(int pid) {
438 auto it = mProcessInfoOverrideMap.find(pid);
439 if (it == mProcessInfoOverrideMap.end()) {
440 return;
441 }
442
443 mProcessInfo->removeProcessInfoOverride(pid);
444 mProcessInfoOverrideMap.erase(pid);
445 }
446
getAllClients(const ResourceRequestInfo & resourceRequestInfo,std::vector<ClientInfo> & clients,MediaResource::SubType primarySubType)447 bool ResourceTracker::getAllClients(const ResourceRequestInfo& resourceRequestInfo,
448 std::vector<ClientInfo>& clients,
449 MediaResource::SubType primarySubType) {
450 MediaResource::Type type = resourceRequestInfo.mResource->type;
451 MediaResource::SubType subType = resourceRequestInfo.mResource->subType;
452 bool foundClient = false;
453
454 for (auto& [pid, /* ResourceInfos */ infos] : mMap) {
455 for (auto& [id, /* ResourceInfo */ info] : infos) {
456 if (hasResourceType(type, subType, info.resources, primarySubType)) {
457 if (!contains(clients, info.clientId)) {
458 clients.emplace_back(info.pid, info.uid, info.clientId);
459 foundClient = true;
460 }
461 }
462 }
463 }
464
465 return foundClient;
466 }
467
getLowestPriorityPid(MediaResource::Type type,MediaResource::SubType subType,int & lowestPriorityPid,int & lowestPriority)468 bool ResourceTracker::getLowestPriorityPid(MediaResource::Type type, MediaResource::SubType subType,
469 int& lowestPriorityPid, int& lowestPriority) {
470 int pid = -1;
471 int priority = -1;
472 for (auto& [tempPid, /* ResourceInfos */ infos] : mMap) {
473 if (infos.size() == 0) {
474 // no client on this process.
475 continue;
476 }
477 if (!hasResourceType(type, subType, infos)) {
478 // doesn't have the requested resource type
479 continue;
480 }
481 int tempPriority = -1;
482 if (!getPriority(tempPid, &tempPriority)) {
483 ALOGV("%s: can't get priority of pid %d, skipped", __func__, tempPid);
484 // TODO: remove this pid from mMap?
485 continue;
486 }
487 if (pid == -1 || tempPriority > priority) {
488 // initial the value
489 pid = tempPid;
490 priority = tempPriority;
491 }
492 }
493
494 bool success = (pid != -1);
495
496 if (success) {
497 lowestPriorityPid = pid;
498 lowestPriority = priority;
499 }
500 return success;
501 }
502
getLowestPriorityPid(MediaResource::Type type,MediaResource::SubType subType,MediaResource::SubType primarySubType,const std::vector<ClientInfo> & clients,int & lowestPriorityPid,int & lowestPriority)503 bool ResourceTracker::getLowestPriorityPid(MediaResource::Type type, MediaResource::SubType subType,
504 MediaResource::SubType primarySubType,
505 const std::vector<ClientInfo>& clients,
506 int& lowestPriorityPid, int& lowestPriority) {
507 int pid = -1;
508 int priority = -1;
509 for (const ClientInfo& client : clients) {
510 const ResourceInfo* info = getResourceInfo(client.mPid, client.mClientId);
511 if (info == nullptr) {
512 continue;
513 }
514 if (!hasResourceType(type, subType, info->resources, primarySubType)) {
515 // doesn't have the requested resource type
516 continue;
517 }
518 int tempPriority = -1;
519 if (!getPriority(client.mPid, &tempPriority)) {
520 ALOGV("%s: can't get priority of pid %d, skipped", __func__, client.mPid);
521 // TODO: remove this pid from mMap?
522 continue;
523 }
524 if (pid == -1 || tempPriority > priority) {
525 // initial the value
526 pid = client.mPid;
527 priority = tempPriority;
528 }
529 }
530
531 bool success = (pid != -1);
532
533 if (success) {
534 lowestPriorityPid = pid;
535 lowestPriority = priority;
536 }
537 return success;
538 }
539
getBiggestClientPendingRemoval(int pid,MediaResource::Type type,MediaResource::SubType subType,ClientInfo & clientInfo)540 bool ResourceTracker::getBiggestClientPendingRemoval(int pid, MediaResource::Type type,
541 MediaResource::SubType subType,
542 ClientInfo& clientInfo) {
543 std::map<int, ResourceInfos>::iterator found = mMap.find(pid);
544 if (found == mMap.end()) {
545 return false;
546 }
547
548 uid_t uid = -1;
549 int64_t clientId = -1;
550 uint64_t largestValue = 0;
551 const ResourceInfos& infos = found->second;
552 for (const auto& [id, /* ResourceInfo */ info] : infos) {
553 const ResourceList& resources = info.resources;
554 // Skip if the client is not marked pending removal.
555 if (!info.pendingRemoval) {
556 continue;
557 }
558 for (const MediaResourceParcel& resource : resources.getResources()) {
559 if (hasResourceType(type, subType, resource)) {
560 if (resource.value > largestValue) {
561 largestValue = resource.value;
562 clientId = info.clientId;
563 uid = info.uid;
564 }
565 }
566 }
567 }
568
569 if (clientId == -1) {
570 return false;
571 }
572
573 clientInfo.mPid = pid;
574 clientInfo.mUid = uid;
575 clientInfo.mClientId = clientId;
576 return true;
577 }
578
getBiggestClient(int targetPid,MediaResource::Type type,MediaResource::SubType subType,const std::vector<ClientInfo> & clients,ClientInfo & clientInfo,MediaResource::SubType primarySubType)579 bool ResourceTracker::getBiggestClient(int targetPid,
580 MediaResource::Type type, MediaResource::SubType subType,
581 const std::vector<ClientInfo>& clients,
582 ClientInfo& clientInfo,
583 MediaResource::SubType primarySubType) {
584 uid_t uid = -1;
585 int64_t clientId = -1;
586 uint64_t largestValue = 0;
587
588 for (const ClientInfo& client : clients) {
589 // Skip the clients that doesn't belong go the targetPid
590 if (client.mPid != targetPid) {
591 continue;
592 }
593 const ResourceInfo* info = getResourceInfo(client.mPid, client.mClientId);
594 if (info == nullptr) {
595 continue;
596 }
597
598 const ResourceList& resources = info->resources;
599 bool matchedPrimary =
600 (primarySubType == MediaResource::SubType::kUnspecifiedSubType) ? true : false;
601 for (const MediaResourceParcel& resource : resources.getResources()) {
602 if (resource.subType == primarySubType) {
603 matchedPrimary = true;
604 break;
605 } else if (isHwCodec(resource.subType) == isHwCodec(primarySubType)) {
606 matchedPrimary = true;
607 break;
608 }
609 }
610 // Primary type doesn't match, skip the client
611 if (!matchedPrimary) {
612 continue;
613 }
614 for (const MediaResourceParcel& resource : resources.getResources()) {
615 if (hasResourceType(type, subType, resource)) {
616 if (resource.value > largestValue) {
617 largestValue = resource.value;
618 clientId = info->clientId;
619 uid = info->uid;
620 }
621 }
622 }
623 }
624
625 if (clientId == -1) {
626 ALOGE("%s: can't find resource type %s and subtype %s for pid %d",
627 __func__, asString(type), asString(subType), targetPid);
628 return false;
629 }
630
631 clientInfo.mPid = targetPid;
632 clientInfo.mUid = uid;
633 clientInfo.mClientId = clientId;
634 return true;
635 }
636
getLeastImportantBiggestClient(int targetPid,int32_t importance,MediaResource::Type type,MediaResource::SubType subType,MediaResource::SubType primarySubType,const std::vector<ClientInfo> & clients,ClientInfo & clientInfo)637 bool ResourceTracker::getLeastImportantBiggestClient(int targetPid, int32_t importance,
638 MediaResource::Type type,
639 MediaResource::SubType subType,
640 MediaResource::SubType primarySubType,
641 const std::vector<ClientInfo>& clients,
642 ClientInfo& clientInfo) {
643 uid_t uid = -1;
644 int64_t clientId = -1;
645 uint64_t largestValue = 0;
646
647 for (const ClientInfo& client : clients) {
648 // Skip the clients that doesn't belong go the targetPid
649 if (client.mPid != targetPid) {
650 continue;
651 }
652 const ResourceInfo* info = getResourceInfo(client.mPid, client.mClientId);
653 if (info == nullptr) {
654 continue;
655 }
656
657 // Make sure the importance is lower.
658 if (info->importance <= importance) {
659 continue;
660 }
661 const ResourceList& resources = info->resources;
662 bool matchedPrimary =
663 (primarySubType == MediaResource::SubType::kUnspecifiedSubType) ? true : false;
664 for (const MediaResourceParcel& resource : resources.getResources()) {
665 if (resource.subType == primarySubType) {
666 matchedPrimary = true;
667 } else if (isHwCodec(resource.subType) == isHwCodec(primarySubType)) {
668 matchedPrimary = true;
669 }
670 }
671 // Primary type doesn't match, skip the client
672 if (!matchedPrimary) {
673 continue;
674 }
675 for (const MediaResourceParcel& resource : resources.getResources()) {
676 if (hasResourceType(type, subType, resource)) {
677 if (resource.value > largestValue) {
678 largestValue = resource.value;
679 clientId = info->clientId;
680 uid = info->uid;
681 }
682 }
683 }
684 }
685
686 if (clientId == -1) {
687 ALOGE("%s: can't find resource type %s and subtype %s for pid %d",
688 __func__, asString(type), asString(subType), targetPid);
689 return false;
690 }
691
692 clientInfo.mPid = targetPid;
693 clientInfo.mUid = uid;
694 clientInfo.mClientId = clientId;
695 return true;
696 }
697
dump(std::string & resourceLogs)698 void ResourceTracker::dump(std::string& resourceLogs) {
699 const size_t SIZE = 256;
700 char buffer[SIZE];
701 resourceLogs.append(" Processes:\n");
702 for (const auto& [pid, /* ResourceInfos */ infos] : mMap) {
703 snprintf(buffer, SIZE, " Pid: %d\n", pid);
704 resourceLogs.append(buffer);
705 int priority = 0;
706 if (getPriority(pid, &priority)) {
707 snprintf(buffer, SIZE, " Priority: %d\n", priority);
708 } else {
709 snprintf(buffer, SIZE, " Priority: <unknown>\n");
710 }
711 resourceLogs.append(buffer);
712
713 for (const auto& [infoKey, /* ResourceInfo */ info] : infos) {
714 resourceLogs.append(" Client:\n");
715 snprintf(buffer, SIZE, " Id: %lld\n", (long long)info.clientId);
716 resourceLogs.append(buffer);
717
718 std::string clientName = info.name;
719 snprintf(buffer, SIZE, " Name: %s\n", clientName.c_str());
720 resourceLogs.append(buffer);
721
722 const ResourceList& resources = info.resources;
723 resourceLogs.append(" Resources:\n");
724 resourceLogs.append(resources.toString());
725 }
726 }
727 resourceLogs.append(" Process Pid override:\n");
728 for (const auto& [oldPid, newPid] : mOverridePidMap) {
729 snprintf(buffer, SIZE, " Original Pid: %d, Override Pid: %d\n", oldPid, newPid);
730 resourceLogs.append(buffer);
731 }
732 }
733
onFirstAdded(const MediaResourceParcel & resource,uid_t uid)734 void ResourceTracker::onFirstAdded(const MediaResourceParcel& resource, uid_t uid) {
735 std::shared_ptr<ResourceManagerServiceNew> service = mService.lock();
736 if (service == nullptr) {
737 ALOGW("%s: ResourceManagerService is invalid!", __func__);
738 return;
739 }
740
741 service->onFirstAdded(resource, uid);
742 }
743
onLastRemoved(const MediaResourceParcel & resource,uid_t uid)744 void ResourceTracker::onLastRemoved(const MediaResourceParcel& resource, uid_t uid) {
745 std::shared_ptr<ResourceManagerServiceNew> service = mService.lock();
746 if (service == nullptr) {
747 ALOGW("%s: ResourceManagerService is invalid!", __func__);
748 return;
749 }
750
751 service->onLastRemoved(resource, uid);
752 }
753
getPriority(int pid,int * priority)754 bool ResourceTracker::getPriority(int pid, int* priority) {
755 int newPid = pid;
756
757 if (mOverridePidMap.find(pid) != mOverridePidMap.end()) {
758 newPid = mOverridePidMap[pid];
759 ALOGD("%s: use override pid %d instead original pid %d", __func__, newPid, pid);
760 }
761
762 return mProcessInfo->getPriority(newPid, priority);
763 }
764
getNonConflictingClients(const ResourceRequestInfo & resourceRequestInfo,std::vector<ClientInfo> & clients)765 bool ResourceTracker::getNonConflictingClients(const ResourceRequestInfo& resourceRequestInfo,
766 std::vector<ClientInfo>& clients) {
767 MediaResource::Type type = resourceRequestInfo.mResource->type;
768 MediaResource::SubType subType = resourceRequestInfo.mResource->subType;
769 for (auto& [pid, /* ResourceInfos */ infos] : mMap) {
770 for (const auto& [id, /* ResourceInfo */ info] : infos) {
771 if (pid == resourceRequestInfo.mCallingPid && id == resourceRequestInfo.mClientId) {
772 ALOGI("%s: Skip the client[%jd] for which the resource request is made",
773 __func__, id);
774 continue;
775 }
776 if (hasResourceType(type, subType, info.resources)) {
777 if (!isCallingPriorityHigher(resourceRequestInfo.mCallingPid, pid)) {
778 // some higher/equal priority process owns the resource,
779 // this is a conflict.
780 ALOGE("%s: The resource (%s) request from pid %d is conflicting",
781 __func__, asString(type), pid);
782 clients.clear();
783 return false;
784 } else {
785 if (!contains(clients, info.clientId)) {
786 clients.emplace_back(info.pid, info.uid, info.clientId);
787 }
788 }
789 }
790 }
791 }
792
793 return true;
794 }
795
getResourceInfo(int pid,const int64_t & clientId) const796 const ResourceInfo* ResourceTracker::getResourceInfo(int pid, const int64_t& clientId) const {
797 std::map<int, ResourceInfos>::const_iterator found = mMap.find(pid);
798 if (found == mMap.end()) {
799 ALOGV("%s: didn't find pid %d for clientId %lld", __func__, pid, (long long) clientId);
800 return nullptr;
801 }
802
803 const ResourceInfos& infos = found->second;
804 ResourceInfos::const_iterator foundClient = infos.find(clientId);
805 if (foundClient == infos.end()) {
806 ALOGV("%s: didn't find clientId %lld", __func__, (long long) clientId);
807 return nullptr;
808 }
809
810 return &foundClient->second;
811 }
812
isCallingPriorityHigher(int callingPid,int pid)813 bool ResourceTracker::isCallingPriorityHigher(int callingPid, int pid) {
814 int callingPidPriority;
815 if (!getPriority(callingPid, &callingPidPriority)) {
816 return false;
817 }
818
819 int priority;
820 if (!getPriority(pid, &priority)) {
821 return false;
822 }
823
824 return (callingPidPriority < priority);
825 }
826
getMediaResourceUsageReport(std::vector<MediaResourceParcel> * resources) const827 void ResourceTracker::getMediaResourceUsageReport(
828 std::vector<MediaResourceParcel>* resources) const {
829 ResourceList resourceUsageList;
830
831 // Add up all the resource usage by every process into resourceUsageList
832 for (const auto& [pid, /* ResourceInfos */ infos] : mMap) {
833 for (const auto& [infoKey, /* ResourceInfo */ info] : infos) {
834 for (const MediaResourceParcel& res : info.resources.getResources()) {
835 resourceUsageList.add(res);
836 }
837 }
838 }
839
840 *resources = resourceUsageList.getResources();
841 }
842
843 } // namespace android
844