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