• 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     /*
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