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