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 "ProcessPriorityReclaimPolicy"
20 #include <utils/Log.h>
21 
22 #include "ResourceTracker.h"
23 #include "ResourceManagerService.h"
24 #include "ProcessPriorityReclaimPolicy.h"
25 
26 namespace android {
27 
28 using aidl::android::media::IResourceManagerClient;
29 
ProcessPriorityReclaimPolicy(const std::shared_ptr<ResourceTracker> & resourceTracker)30 ProcessPriorityReclaimPolicy::ProcessPriorityReclaimPolicy(
31         const std::shared_ptr<ResourceTracker>& resourceTracker)
32     : mResourceTracker(resourceTracker) {
33 }
34 
~ProcessPriorityReclaimPolicy()35 ProcessPriorityReclaimPolicy::~ProcessPriorityReclaimPolicy() {
36 }
37 
38 // Process priority (oom score) based reclaim:
39 //   - Find a process with lowest priority (than that of calling process).
40 //   - Find the bigegst client (with required resources) from that process.
getClients(const ReclaimRequestInfo & reclaimRequestInfo,const std::vector<ClientInfo> & clients,std::vector<ClientInfo> & targetClients)41 bool ProcessPriorityReclaimPolicy::getClients(const ReclaimRequestInfo& reclaimRequestInfo,
42                                               const std::vector<ClientInfo>& clients,
43                                               std::vector<ClientInfo>& targetClients) {
44     // NOTE: This is the behavior of the existing reclaim policy.
45     // We can alter it to select more than one client to reclaim from, depending
46     // on the reclaim polocy.
47 
48     MediaResource::Type type = reclaimRequestInfo.mResources[0].type;
49     MediaResource::SubType subType = reclaimRequestInfo.mResources[0].subType;
50     // Find one client to reclaim the needed resources from.
51     // 1. Get the priority of the (reclaim) requesting process.
52     int callingPid = reclaimRequestInfo.mCallingPid;
53     int callingPriority = -1;
54     if (!mResourceTracker->getPriority(callingPid, &callingPriority)) {
55         ALOGE("%s: can't get process priority for pid %d", __func__, callingPid);
56         return false;
57     }
58 
59     ClientInfo clientInfo;
60     // 2 Look to find the biggest client from the lowest priority process that
61     // has the other resources and with the given primary type.
62     bool found = false;
63     int lowestPriority = -1;
64     MediaResource::SubType primarySubType = subType;
65     for (size_t index = 1; !found && (index < reclaimRequestInfo.mResources.size()); index++) {
66         MediaResource::Type type = reclaimRequestInfo.mResources[index].type;
67         MediaResource::SubType subType = reclaimRequestInfo.mResources[index].subType;
68         found = getBiggestClientFromLowestPriority(callingPid, callingPriority,
69                                                    type, subType, primarySubType,
70                                                    clients, clientInfo, lowestPriority);
71     }
72     // 3 If we haven't found a client yet, then select the biggest client of primary type.
73     if (!found) {
74         found = getBiggestClientFromLowestPriority(callingPid, callingPriority,
75                                                    type, subType,
76                                                    MediaResource::SubType::kUnspecifiedSubType,
77                                                    clients, clientInfo, lowestPriority);
78     }
79     // 4 If we haven't found a client yet, then select the biggest client of different type.
80     // This is applicable for code type only.
81     if (!found) {
82         if (type != MediaResource::Type::kSecureCodec &&
83             type != MediaResource::Type::kNonSecureCodec) {
84             return false;
85         }
86         MediaResourceType otherType = (type == MediaResource::Type::kSecureCodec) ?
87             MediaResource::Type::kNonSecureCodec : MediaResource::Type::kSecureCodec;
88         if (!getBiggestClientFromLowestPriority(callingPid, callingPriority,
89                                                 otherType, subType,
90                                                 MediaResource::SubType::kUnspecifiedSubType,
91                                                 clients, clientInfo, lowestPriority)) {
92             return false;
93         }
94     }
95 
96     targetClients.emplace_back(clientInfo);
97     ALOGI("%s: CallingProcess(%d:%d) will reclaim from the lowestPriorityProcess(%d:%d)",
98           __func__, callingPid, callingPriority, clientInfo.mPid, lowestPriority);
99 
100     return true;
101 }
102 
getBiggestClientFromLowestPriority(pid_t callingPid,int callingPriority,MediaResource::Type type,MediaResource::SubType subType,MediaResource::SubType primarySubType,const std::vector<ClientInfo> & clients,ClientInfo & targetClient,int & lowestPriority)103 bool ProcessPriorityReclaimPolicy::getBiggestClientFromLowestPriority(
104         pid_t callingPid,
105         int callingPriority,
106         MediaResource::Type type, MediaResource::SubType subType,
107         MediaResource::SubType primarySubType,
108         const std::vector<ClientInfo>& clients,
109         ClientInfo& targetClient,
110         int& lowestPriority) {
111     // 1. Find the lowest priority process among all the clients with the
112     // requested resource type.
113     int lowestPriorityPid = -1;
114     lowestPriority = -1;
115     if (!mResourceTracker->getLowestPriorityPid(type, subType, primarySubType, clients,
116                                                 lowestPriorityPid, lowestPriority)) {
117         ALOGD("%s: can't find a process with lower priority than that of the process[%d:%d]",
118               __func__, callingPid, callingPriority);
119         return false;
120     }
121 
122     // 2. Make sure that the priority of the target process is less than
123     // requesting process.
124     if (lowestPriority <= callingPriority) {
125         ALOGD("%s: lowest priority %d vs caller priority %d",
126               __func__, lowestPriority, callingPriority);
127         return false;
128     }
129 
130     // 3. Look to find the biggest client from that process for the given resources
131     return mResourceTracker->getBiggestClient(lowestPriorityPid, type, subType,
132                                               clients, targetClient, primarySubType);
133 }
134 
135 } // namespace android
136