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