1 /*
2 * Copyright (c) 2022 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 #include "low_memory_killer.h"
16 #include "memmgr_config_manager.h"
17 #include "memmgr_log.h"
18 #include "memmgr_ptr_util.h"
19 #include "kernel_interface.h"
20 #include "reclaim_priority_manager.h"
21
22 namespace OHOS {
23 namespace Memory {
24 namespace {
25 const std::string TAG = "LowMemoryKiller";
26 const int LOW_MEM_KILL_LEVELS = 5;
27 const int MAX_KILL_CNT_PER_EVENT = 3;
28 const int NOT_TO_KILL_DURING = 3;
29 /*
30 * LMKD_DBG_TRIGGER_FILE_PATH:
31 * print process meminfo when write 0/1 to the file,
32 * 0: print all info anyway. 1: print limited by interval.
33 * It is used before killing one bundle.
34 */
35 const std::string LMKD_DBG_TRIGGER_FILE_PATH = "/proc/lmkd_dbg_trigger";
36 }
37
38 IMPLEMENT_SINGLE_INSTANCE(LowMemoryKiller);
39
40 enum class MinPrioField {
41 MIN_BUFFER = 0,
42 MIN_PRIO,
43 MIN_PRIO_FIELD_COUNT,
44 };
45
46 static int g_minPrioTable[LOW_MEM_KILL_LEVELS][static_cast<int32_t>(MinPrioField::MIN_PRIO_FIELD_COUNT)] = {
47 {100 * 1024, 0}, // 100M buffer, 0 priority
48 {200 * 1024, 100}, // 200M buffer, 100 priority
49 {300 * 1024, 200}, // 300M buffer, 200 priority
50 {400 * 1024, 300}, // 400M buffer, 300 priority
51 {500 * 1024, 400} // 500M buffer, 400 priority
52 };
53
LowMemoryKiller()54 LowMemoryKiller::LowMemoryKiller()
55 {
56 initialized_ = GetEventHandler();
57 if (initialized_) {
58 HILOGI("init successed");
59 } else {
60 HILOGE("init failed");
61 }
62 }
63
GetEventHandler()64 bool LowMemoryKiller::GetEventHandler()
65 {
66 if (!handler_) {
67 MAKE_POINTER(handler_, shared, AppExecFwk::EventHandler, "failed to create event handler", return false,
68 AppExecFwk::EventRunner::Create());
69 }
70 return true;
71 }
72
GetKillLevel()73 int32_t LowMemoryKiller::GetKillLevel()
74 {
75 return killLevel_;
76 }
77
KillOneBundleByPrio(int minPrio)78 int LowMemoryKiller::KillOneBundleByPrio(int minPrio)
79 {
80 HILOGE("called. minPrio=%{public}d", minPrio);
81 int freedBuf = 0;
82 ReclaimPriorityManager::BunldeCopySet bundles;
83
84 ReclaimPriorityManager::GetInstance().GetOneKillableBundle(minPrio, bundles);
85 HILOGD("get BundlePrioSet size=%{public}zu", bundles.size());
86
87 int count = 0;
88 for (auto bundle : bundles) {
89 HILOGI("iter bundle %{public}d/%{public}zu, uid=%{public}d, name=%{public}s, priority=%{public}d",
90 count, bundles.size(), bundle.uid_, bundle.name_.c_str(), bundle.priority_);
91 if (bundle.priority_ < minPrio) {
92 HILOGD("finish to handle all bundles with priority bigger than %{public}d, break!", minPrio);
93 break;
94 }
95 if (KernelInterface::GetInstance().GetSystemCurTime() - bundle.GetCreateTime() < NOT_TO_KILL_DURING) {
96 HILOGD("bundle uid<%{public}d> <%{public}s> is protected, skiped.",
97 bundle.uid_, bundle.name_.c_str());
98 count++;
99 continue;
100 }
101 if (bundle.GetState() == BundleState::STATE_WAITING_FOR_KILL) {
102 HILOGD("bundle uid<%{public}d> <%{public}s> is waiting to kill, skiped.",
103 bundle.uid_, bundle.name_.c_str());
104 count++;
105 continue;
106 }
107
108 for (auto itrProcess = bundle.procs_.begin(); itrProcess != bundle.procs_.end(); itrProcess++) {
109 HILOGI("killing pid<%{public}d> with uid<%{public}d> of bundle<%{public}s>",
110 itrProcess->first, bundle.uid_, bundle.name_.c_str());
111 freedBuf += KernelInterface::GetInstance().KillOneProcessByPid(itrProcess->first);
112 }
113
114 ReclaimPriorityManager::GetInstance().SetBundleState(bundle.accountId_, bundle.uid_,
115 BundleState::STATE_WAITING_FOR_KILL);
116 if (freedBuf) {
117 HILOGD("freedBuf = %{public}d, break iter", freedBuf);
118 break;
119 }
120 count++;
121 }
122 HILOGD("iter bundles end");
123 return freedBuf;
124 }
125
QueryKillMemoryPriorityPair(unsigned int currBufferKB,unsigned int & targetBufKB,int & killLevel)126 std::pair<unsigned int, int> LowMemoryKiller::QueryKillMemoryPriorityPair(unsigned int currBufferKB,
127 unsigned int &targetBufKB, int &killLevel)
128 {
129 unsigned int minBufKB = 0;
130 int minPrio = RECLAIM_PRIORITY_UNKNOWN + 1;
131 int tempKillLevel = 0;
132
133 targetBufKB = 0; /* default val */
134 static const KillConfig::KillLevelsMap levelMap = MemmgrConfigManager::GetInstance().GetKillLevelsMap();
135 if (levelMap.empty()) { /* xml not config, using default table */
136 for (int i = 0; i < LOW_MEM_KILL_LEVELS; i++) {
137 int minBufInTable = g_minPrioTable[i][static_cast<int32_t>(MinPrioField::MIN_BUFFER)];
138 if (minBufInTable < 0) {
139 HILOGE("error: negative value(%{public}d) of mem in g_minPrioTable", minBufInTable);
140 continue;
141 }
142 tempKillLevel++;
143 if (currBufferKB < (unsigned int)minBufInTable) {
144 minBufKB = (unsigned int)minBufInTable;
145 minPrio = g_minPrioTable[i][static_cast<int32_t>(MinPrioField::MIN_PRIO)];
146 break;
147 }
148 }
149 /* set targetBufKB = max mem val in g_minPrioTable */
150 int maxMemInTable = g_minPrioTable[LOW_MEM_KILL_LEVELS - 1][static_cast<int32_t>(MinPrioField::MIN_BUFFER)];
151 targetBufKB = (maxMemInTable > 0 ? (unsigned int)maxMemInTable : 0);
152 killLevel = tempKillLevel;
153 return std::make_pair(minBufKB, minPrio);
154 }
155 /* query from xml */
156 for (auto it = levelMap.begin(); it != levelMap.end(); it++) {
157 tempKillLevel++;
158 if (currBufferKB < it->first) {
159 minBufKB = it->first;
160 minPrio = it->second;
161 break;
162 }
163 }
164 /* set targetBufKB = max mem val in levelMap */
165 targetBufKB = levelMap.rbegin()->first;
166 killLevel = tempKillLevel;
167 HILOGD("(%{public}u) return from xml mem:%{public}u prio:%{public}d target:%{public}u",
168 currBufferKB, minBufKB, minPrio, targetBufKB);
169 return std::make_pair(minBufKB, minPrio);
170 }
171
172 struct PsiHdlInfo {
173 unsigned int curBuf;
174 int availBuf;
175 int freedBuf;
176 unsigned int minBuf;
177 unsigned int targetBuf;
178 unsigned int targetKillKb;
179 unsigned int currKillKb;
180 int minPrio;
181 int killCnt;
182 };
183
184 /* Low memory killer core function */
PsiHandlerInner()185 void LowMemoryKiller::PsiHandlerInner()
186 {
187 HILOGD("[%{public}ld] called", ++calledCount_);
188 PsiHdlInfo psiHdlInfo = {0, 0, 0, 0, 0, 0, 0, RECLAIM_PRIORITY_MAX + 1, 0};
189
190 psiHdlInfo.curBuf = static_cast<unsigned int>(KernelInterface::GetInstance().GetCurrentBuffer());
191 HILOGE("[%{public}ld] current buffer = %{public}u KB", calledCount_, psiHdlInfo.curBuf);
192 if (psiHdlInfo.curBuf == MAX_BUFFER_KB) {
193 HILOGD("[%{public}ld] get buffer failed, skiped!", calledCount_);
194 return;
195 }
196
197 std::pair<unsigned int, int> memPrioPair = QueryKillMemoryPriorityPair(psiHdlInfo.curBuf,
198 psiHdlInfo.targetBuf, killLevel_);
199 psiHdlInfo.minBuf = memPrioPair.first;
200 psiHdlInfo.minPrio = memPrioPair.second;
201 if (psiHdlInfo.curBuf > 0 && psiHdlInfo.targetBuf > psiHdlInfo.curBuf) {
202 psiHdlInfo.targetKillKb = psiHdlInfo.targetBuf - psiHdlInfo.curBuf;
203 }
204
205 HILOGE("[%{public}ld] minPrio = %{public}d", calledCount_, psiHdlInfo.minPrio);
206
207 if (psiHdlInfo.minPrio < RECLAIM_PRIORITY_MIN || psiHdlInfo.minPrio > RECLAIM_PRIORITY_MAX) {
208 HILOGD("[%{public}ld] no minPrio, skiped!", calledCount_);
209 return;
210 }
211
212 do {
213 /* print process mem info in dmesg, 1 means it is limited by print interval. Ignore return val */
214 KernelInterface::GetInstance().EchoToPath(LMKD_DBG_TRIGGER_FILE_PATH.c_str(), "1");
215 if ((psiHdlInfo.freedBuf = KillOneBundleByPrio(psiHdlInfo.minPrio)) <= 0) {
216 HILOGD("[%{public}ld] Noting to kill above score %{public}d!", calledCount_, psiHdlInfo.minPrio);
217 goto out;
218 }
219 psiHdlInfo.currKillKb += (unsigned int)psiHdlInfo.freedBuf;
220 psiHdlInfo.killCnt++;
221 HILOGD("[%{public}ld] killCnt = %{public}d", calledCount_, psiHdlInfo.killCnt);
222
223 psiHdlInfo.availBuf = KernelInterface::GetInstance().GetCurrentBuffer();
224 if (psiHdlInfo.availBuf < 0 || psiHdlInfo.availBuf >= MAX_BUFFER_KB) {
225 HILOGE("[%{public}ld] get buffer failed, go out!", calledCount_);
226 goto out;
227 }
228 if ((unsigned int)psiHdlInfo.availBuf >= psiHdlInfo.targetBuf) {
229 killLevel_ = 0;
230 goto out;
231 }
232 } while (psiHdlInfo.currKillKb < psiHdlInfo.targetKillKb && psiHdlInfo.killCnt < MAX_KILL_CNT_PER_EVENT);
233
234 out:
235 if (psiHdlInfo.currKillKb > 0) {
236 HILOGI("[%{public}ld] Reclaimed %{public}uK when currBuff %{public}uK below %{public}uK target %{public}uK",
237 calledCount_, psiHdlInfo.currKillKb, psiHdlInfo.curBuf, psiHdlInfo.minBuf, psiHdlInfo.targetBuf);
238 }
239 }
240
PsiHandler()241 void LowMemoryKiller::PsiHandler()
242 {
243 if (!initialized_) {
244 HILOGE("is not initialized, return!");
245 return;
246 }
247 std::function<void()> func = std::bind(&LowMemoryKiller::PsiHandlerInner, this);
248 handler_->PostImmediateTask(func);
249 }
250 } // namespace Memory
251 } // namespace OHOS
252