1 /*
2 * Copyright (c) 2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15 #ifndef OHOS_MEMORY_DUMP_COMMAND_DISPATCHER_H
16 #define OHOS_MEMORY_DUMP_COMMAND_DISPATCHER_H
17
18 #include "memory_level_constants.h"
19 #include "memory_level_manager.h"
20 #include "purgeable_mem_manager.h"
21
22 namespace OHOS {
23 namespace Memory {
24 constexpr unsigned int ONTRIM_LEVEL_PARAM_SIZE = 1;
25 constexpr unsigned int RECLAIM_TYPE_PARAM_SIZE = 1;
26 constexpr unsigned int RECLAIM_HEAP_ID_PARAM_SIZE = 2;
27 constexpr unsigned int RECLAIM_ASHM_ID_PARAM_SIZE = 2;
28 constexpr unsigned int RECLAIM_SUBSCRIBER_ID_PARAM_SIZE = 1;
29 constexpr unsigned int FIRST_INDEX = 0;
30 constexpr unsigned int SECOND_INDEX = 1;
31 constexpr unsigned int THIRD_INDEX = 2;
32 constexpr unsigned int APP_STATE_PARAM_SIZE = 3;
33
34 #define CHECK_SIZE(container, len, fd, actionIfFailed) \
35 do { \
36 if ((container).size() != (len)) { \
37 dprintf(fd, "size error\n"); \
38 actionIfFailed; \
39 } \
40 } while (0)
41
HasCommand(const std::map<std::string,std::vector<std::string>> & keyValuesMapping,const std::string & command)42 inline bool HasCommand(const std::map<std::string, std::vector<std::string>> &keyValuesMapping,
43 const std::string &command)
44 {
45 return keyValuesMapping.find(command) != keyValuesMapping.end();
46 }
47
ShowHelpInfo(const int fd)48 void ShowHelpInfo(const int fd)
49 {
50 dprintf(fd, "Usage:\n");
51 dprintf(fd, "-h |help for memmgrservice dumper\n");
52 dprintf(fd, "-a |dump all info\n");
53 dprintf(fd, "-e |dump event observer\n");
54 dprintf(fd, "-r |dump reclaim info and adj\n");
55 dprintf(fd, "-c |dump config\n");
56 dprintf(fd, "-m |show malloc state\n");
57 #ifdef USE_PURGEABLE_MEMORY
58 dprintf(fd, "-s |show subscriber all the pid which can be reclaimed\n");
59 dprintf(fd, "-d {pid} {uid} {state} |trigger appstate changed\n\n");
60 dprintf(fd, "-t trigger memory onTrim:\n"
61 "-t 1 ---------------------- level_purgeable\n"
62 "-t 2 ---------------------- level_moderate\n"
63 "-t 3 ---------------------- level_low\n"
64 "-t 4 ---------------------- level_critical\n\n");
65 dprintf(fd, "-f trigger purgeable memory Reclaim:\n"
66 "-f 1 ---------------------- purg_heap all\n"
67 "-f 2 ---------------------- purg_ashmem all\n"
68 "-f 3 ---------------------- purg_subscriber all\n"
69 "-f 4 ---------------------- purg all purgeable memory\n"
70 "-f 1 -id {userId} {size} -- purg_heap by memCG and size(KB). if userId=0, reclaim system_lru\n"
71 "-f 2 -id {ashmId} {time} -- purg_ashm by ashmId, which can get from /proc/purgeable_ashmem_trigger\n"
72 "-f 3 -id {pid} ------------ purg_subscriber by pid. if pid=0, reclaim subscriber all\n\n");
73 #endif
74 }
75
76 #ifdef USE_PURGEABLE_MEMORY
PrintOntrimError(const int fd)77 void PrintOntrimError(const int fd)
78 {
79 dprintf(fd, "\n error: unrecognized memory level, please input correct format as follows:\n"
80 "-t 1 ---------------------- level_purgeable\n"
81 "-t 2 ---------------------- level_moderate\n"
82 "-t 3 ---------------------- level_low\n"
83 "-t 4 ---------------------- level_critical\n");
84 }
85
PrintReclaimError(const int fd)86 void PrintReclaimError(const int fd)
87 {
88 dprintf(fd, "\n error: trigger force reclaim failed, please input correct info as follows:\n"
89 "-f 1 ---------------------- purg_heap all\n"
90 "-f 2 ---------------------- purg_ashmem all\n"
91 "-f 3 ---------------------- purg_subscriber all\n"
92 "-f 4 ---------------------- purg all purgeable memory\n"
93 "-f 1 -id {userId} {size} -- purg_heap by memCG and size(KB). if userId=0, reclaim system_lru\n"
94 "-f 2 -id {ashmId} {time} -- purg_ashm by ashmId, which can get from /proc/purgeable_ashmem_trigger\n"
95 "-f 3 -id {pid} ------------ purg_subscriber by pid. if pid=0, reclaim subscriber all\n");
96 }
97
DispatchTriggerMemLevel(const int fd,std::map<std::string,std::vector<std::string>> & keyValuesMapping)98 void DispatchTriggerMemLevel(const int fd, std::map<std::string, std::vector<std::string>> &keyValuesMapping)
99 {
100 std::vector<std::string> values = keyValuesMapping["-t"];
101 CHECK_SIZE(values, ONTRIM_LEVEL_PARAM_SIZE, fd, return);
102
103 int level;
104 try {
105 level = std::stoi(values[FIRST_INDEX]);
106 } catch (...) {
107 PrintOntrimError(fd);
108 return;
109 }
110
111 SystemMemoryInfo info = {MemorySource::MANUAL_DUMP, SystemMemoryLevel::UNKNOWN};
112 switch (level) {
113 case MEMORY_LEVEL_PURGEABLE:
114 info.level = SystemMemoryLevel::MEMORY_LEVEL_PURGEABLE;
115 break;
116 case MEMORY_LEVEL_MODERATE:
117 info.level = SystemMemoryLevel::MEMORY_LEVEL_MODERATE;
118 break;
119 case MEMORY_LEVEL_LOW:
120 info.level = SystemMemoryLevel::MEMORY_LEVEL_LOW;
121 break;
122 case MEMORY_LEVEL_CRITICAL:
123 info.level = SystemMemoryLevel::MEMORY_LEVEL_CRITICAL;
124 break;
125 default:
126 PrintOntrimError(fd);
127 return;
128 }
129 MemoryLevelManager::GetInstance().TriggerMemoryLevelByDump(info);
130 }
131
ParseForceReclaimType(const int fd,std::map<std::string,std::vector<std::string>> & keyValuesMapping,DumpReclaimInfo & dumpInfo)132 void ParseForceReclaimType(const int fd, std::map<std::string, std::vector<std::string>> &keyValuesMapping,
133 DumpReclaimInfo &dumpInfo)
134 {
135 dumpInfo.reclaimType = PurgeableMemoryType::UNKNOWN;
136 dumpInfo.ifReclaimTypeAll = true;
137
138 std::vector<std::string> values = keyValuesMapping["-f"];
139 CHECK_SIZE(values, RECLAIM_TYPE_PARAM_SIZE, fd, return);
140
141 int type;
142 try {
143 type = std::stoi(values[FIRST_INDEX]);
144 } catch (...) {
145 return;
146 }
147 switch (type) {
148 case PURGEABLE_TYPE_HEAP:
149 dumpInfo.reclaimType = PurgeableMemoryType::PURGEABLE_HEAP;
150 break;
151 case PURGEABLE_TYPE_ASHMEM:
152 dumpInfo.reclaimType = PurgeableMemoryType::PURGEABLE_ASHMEM;
153 break;
154 case PURGEABLE_TYPE_SUBSCRIBER:
155 dumpInfo.reclaimType = PurgeableMemoryType::PURGEABLE_SUBSCRIBER;
156 break;
157 case PURGEABLE_TYPE_ALL:
158 dumpInfo.reclaimType = PurgeableMemoryType::PURGEABLE_ALL;
159 break;
160 default:
161 return;
162 }
163 }
164
ParseForceReclaimId(const int fd,std::map<std::string,std::vector<std::string>> & keyValuesMapping,DumpReclaimInfo & dumpInfo)165 bool ParseForceReclaimId(const int fd, std::map<std::string, std::vector<std::string>> &keyValuesMapping,
166 DumpReclaimInfo &dumpInfo)
167 {
168 dumpInfo.ifReclaimTypeAll = false;
169 std::vector<std::string> values = keyValuesMapping["-id"];
170 switch (dumpInfo.reclaimType) {
171 case PurgeableMemoryType::PURGEABLE_HEAP:
172 CHECK_SIZE(values, RECLAIM_HEAP_ID_PARAM_SIZE, fd, return false); // {userId} {size}
173 try {
174 dumpInfo.memcgUserId = std::stoi(values[FIRST_INDEX]);
175 dumpInfo.reclaimHeapSizeKB = std::stoi(values[SECOND_INDEX]);
176 } catch (...) {
177 return false;
178 }
179 break;
180 case PurgeableMemoryType::PURGEABLE_ASHMEM:
181 CHECK_SIZE(values, RECLAIM_ASHM_ID_PARAM_SIZE, fd, return false); // {ashmId} {time}
182 try {
183 dumpInfo.ashmId = std::stoul(values[FIRST_INDEX]);
184 dumpInfo.ashmTime = std::stoul(values[SECOND_INDEX]);
185 } catch (...) {
186 return false;
187 }
188 break;
189 case PurgeableMemoryType::PURGEABLE_SUBSCRIBER:
190 CHECK_SIZE(values, RECLAIM_SUBSCRIBER_ID_PARAM_SIZE, fd, return false); // {pid}
191 if (values[0] == std::string("0")) { // reclaim subscriber all when pid = 0
192 dumpInfo.ifReclaimTypeAll = true;
193 return true;
194 }
195 try {
196 dumpInfo.subscriberPid = std::stoi(values[FIRST_INDEX]);
197 } catch (...) {
198 return false;
199 }
200 break;
201 default:
202 return false;
203 }
204 return true;
205 }
206
PurgeableMemoryDump(int fd,std::map<std::string,std::vector<std::string>> & keyValuesMapping)207 bool PurgeableMemoryDump(int fd, std::map<std::string, std::vector<std::string>> &keyValuesMapping)
208 {
209 if (HasCommand(keyValuesMapping, "-s")) {
210 PurgeableMemManager::GetInstance().DumpSubscribers(fd);
211 return true;
212 }
213 if (HasCommand(keyValuesMapping, "-t")) {
214 DispatchTriggerMemLevel(fd, keyValuesMapping);
215 return true;
216 }
217 if (HasCommand(keyValuesMapping, "-f")) {
218 DumpReclaimInfo dumpInfo;
219 ParseForceReclaimType(fd, keyValuesMapping, dumpInfo);
220 if (HasCommand(keyValuesMapping, "-id") && !ParseForceReclaimId(fd, keyValuesMapping, dumpInfo)) {
221 dumpInfo.reclaimType = PurgeableMemoryType::UNKNOWN;
222 }
223 if (PurgeableMemManager::GetInstance().ForceReclaimByDump(dumpInfo)) {
224 dprintf(fd, "trigger force reclaim success!\n");
225 } else {
226 PrintReclaimError(fd);
227 }
228 return true;
229 }
230 if (HasCommand(keyValuesMapping, "-d")) {
231 std::vector<std::string> appState = keyValuesMapping["-d"];
232 if (appState.size() < APP_STATE_PARAM_SIZE) {
233 dprintf(fd, "params number is less than %{publid}d!\n", APP_STATE_PARAM_SIZE);
234 return true;
235 }
236 int32_t pid = std::stoi(appState[FIRST_INDEX]);
237 int32_t uid = std::stoi(appState[SECOND_INDEX]);
238 int32_t state = std::stoi(appState[THIRD_INDEX]);
239 PurgeableMemManager::GetInstance().ChangeAppState(pid, uid, state);
240 return true;
241 }
242 return false;
243 }
244 #endif // USE_PURGEABLE_MEMORY
245
DispatchDumpCommand(const int fd,std::map<std::string,std::vector<std::string>> & keyValuesMapping)246 void DispatchDumpCommand(const int fd, std::map<std::string, std::vector<std::string>> &keyValuesMapping)
247 {
248 if (keyValuesMapping.empty() || HasCommand(keyValuesMapping, "-h")) {
249 ShowHelpInfo(fd);
250 return;
251 }
252 if (HasCommand(keyValuesMapping, "-a")) {
253 MemMgrEventCenter::GetInstance().Dump(fd);
254 ReclaimPriorityManager::GetInstance().Dump(fd);
255 return;
256 }
257 if (HasCommand(keyValuesMapping, "-e")) {
258 MemMgrEventCenter::GetInstance().Dump(fd);
259 return;
260 }
261 if (HasCommand(keyValuesMapping, "-r")) {
262 ReclaimPriorityManager::GetInstance().Dump(fd);
263 return;
264 }
265 if (HasCommand(keyValuesMapping, "-c")) {
266 MemmgrConfigManager::GetInstance().Dump(fd);
267 return;
268 }
269 #ifdef USE_PURGEABLE_MEMORY
270 if (PurgeableMemoryDump(fd, keyValuesMapping)) {
271 return;
272 }
273 #endif
274 }
275
276 } // namespace Memory
277 } // namespace OHOS
278 #endif // OHOS_MEMORY_DUMP_COMMAND_DISPATCHER_H