• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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