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