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