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
16 #include "purgeable_mem_manager.h"
17
18 #include <algorithm>
19
20 #include "accesstoken_kit.h"
21 #include "app_mem_info.h"
22 #include "app_mgr_constants.h"
23 #include "ipc_skeleton.h"
24 #include "memcg_mgr.h"
25 #include "memmgr_config_manager.h"
26 #include "memmgr_log.h"
27 #include "memmgr_ptr_util.h"
28 #include "reclaim_priority_manager.h"
29 #include "system_memory_level_config.h"
30 #include "purgeablemem_config.h"
31
32 namespace OHOS {
33 namespace Memory {
34 namespace {
35 const std::string TAG = "PurgeableMemManager";
36 }
37
38 IMPLEMENT_SINGLE_INSTANCE(PurgeableMemManager);
39
PurgeableMemManager()40 PurgeableMemManager::PurgeableMemManager()
41 {
42 initialized_ = GetEventHandler();
43 if (initialized_) {
44 HILOGI("init succeeded");
45 } else {
46 HILOGE("init failed");
47 }
48 appList_.clear();
49 }
50
GetEventHandler()51 bool PurgeableMemManager::GetEventHandler()
52 {
53 if (!handler_) {
54 MAKE_POINTER(handler_, shared, AppExecFwk::EventHandler, "failed to create event handler", return false,
55 AppExecFwk::EventRunner::Create());
56 }
57 return true;
58 }
59
AddSubscriberInner(const sptr<IAppStateSubscriber> & subscriber)60 void PurgeableMemManager::AddSubscriberInner(const sptr<IAppStateSubscriber> &subscriber)
61 {
62 auto remoteObj = subscriber->AsObject();
63 if (remoteObj == nullptr) {
64 HILOGE("subscriber object is null");
65 return;
66 }
67
68 auto findSubscriber = [&remoteObj](const auto &target) { return remoteObj == target->AsObject(); };
69 std::lock_guard<std::mutex> lockSubscriber(mutexSubscribers_);
70 auto subscriberIter = std::find_if(appStateSubscribers_.begin(), appStateSubscribers_.end(), findSubscriber);
71 if (subscriberIter != appStateSubscribers_.end()) {
72 HILOGE("target subscriber already exist");
73 return;
74 }
75
76 if (appStateSubscribers_.size() >= PURGEABLE_SUBSCRIBER_MAX_NUM) {
77 HILOGE("the number of registered subscribers has reach the upper limit");
78 return;
79 }
80
81 appStateSubscribers_.emplace_back(subscriber);
82 if (subscriberRecipients_.find(subscriber->AsObject()) != subscriberRecipients_.end()) {
83 HILOGE("subscriberRecipients_ don't find subscriber");
84 return;
85 }
86 sptr<RemoteDeathRecipient> deathRecipient = new (std::nothrow)
87 RemoteDeathRecipient([this] (const wptr<IRemoteObject> &remote) { this->OnRemoteSubscriberDied(remote); });
88 if (!deathRecipient) {
89 HILOGE("create death recipient failed");
90 return;
91 }
92
93 subscriber->AsObject()->AddDeathRecipient(deathRecipient);
94 subscriberRecipients_.emplace(subscriber->AsObject(), deathRecipient);
95 subscriber->OnConnected();
96 HILOGI("add app state subscriber succeed, subscriber list size is: %{public}d",
97 static_cast<int>(appStateSubscribers_.size()));
98 }
99
AddSubscriber(const sptr<IAppStateSubscriber> & subscriber)100 void PurgeableMemManager::AddSubscriber(const sptr<IAppStateSubscriber> &subscriber)
101 {
102 if (!CheckCallingToken()) {
103 HILOGW("AddSubscriber not allowed");
104 return;
105 }
106 if (!initialized_) {
107 HILOGE("is not initialized");
108 return;
109 }
110 if (subscriber == nullptr) {
111 HILOGE("subscriber is null");
112 return;
113 }
114 std::function<void()> func = std::bind(&PurgeableMemManager::AddSubscriberInner, this, subscriber);
115 handler_->PostImmediateTask(func);
116 }
117
RemoveSubscriberInner(const sptr<IAppStateSubscriber> & subscriber)118 void PurgeableMemManager::RemoveSubscriberInner(const sptr<IAppStateSubscriber> &subscriber)
119 {
120 auto remote = subscriber->AsObject();
121 if (remote == nullptr) {
122 HILOGE("subscriber object is null");
123 return;
124 }
125 auto findSubscriber = [&remote] (const auto &targetSubscriber) { return remote == targetSubscriber->AsObject(); };
126
127 std::lock_guard<std::mutex> lockSubscriber(mutexSubscribers_);
128 auto subscriberIter = find_if(appStateSubscribers_.begin(), appStateSubscribers_.end(), findSubscriber);
129 if (subscriberIter == appStateSubscribers_.end()) {
130 HILOGE("subscriber to remove is not exists");
131 return;
132 }
133
134 auto iter = subscriberRecipients_.find(remote);
135 if (iter != subscriberRecipients_.end()) {
136 iter->first->RemoveDeathRecipient(iter->second);
137 subscriberRecipients_.erase(iter);
138 }
139 subscriber->OnDisconnected();
140 appStateSubscribers_.erase(subscriberIter);
141 HILOGI("remove subscriber succeed, subscriber list size is: %{public}d",
142 static_cast<int>(appStateSubscribers_.size()));
143 }
144
RemoveSubscriber(const sptr<IAppStateSubscriber> & subscriber)145 void PurgeableMemManager::RemoveSubscriber(const sptr<IAppStateSubscriber> &subscriber)
146 {
147 if (!CheckCallingToken()) {
148 HILOGW("RemoveSubscriber not allowed");
149 return;
150 }
151 if (!initialized_) {
152 HILOGE("is not initialized");
153 return;
154 }
155 if (subscriber == nullptr) {
156 HILOGE("subscriber is null");
157 return;
158 }
159 RemoveSubscriberInner(subscriber);
160 }
161
OnRemoteSubscriberDiedInner(const wptr<IRemoteObject> & object)162 void PurgeableMemManager::OnRemoteSubscriberDiedInner(const wptr<IRemoteObject> &object)
163 {
164 sptr<IRemoteObject> objectProxy = object.promote();
165 if (!objectProxy) {
166 HILOGE("get remote object failed");
167 return;
168 }
169 std::lock_guard<std::mutex> lockSubscriber(mutexSubscribers_);
170 auto iter = appStateSubscribers_.begin();
171 while (iter != appStateSubscribers_.end()) {
172 if ((*iter)->AsObject() == objectProxy) {
173 iter = appStateSubscribers_.erase(iter);
174 HILOGI("remove the subscriber");
175 } else {
176 iter++;
177 }
178 }
179 HILOGI("recipients remove the subscriber, subscriber list size is : %{public}d",
180 static_cast<int>(appStateSubscribers_.size()));
181 subscriberRecipients_.erase(objectProxy);
182 }
183
OnRemoteSubscriberDied(const wptr<IRemoteObject> & object)184 void PurgeableMemManager::OnRemoteSubscriberDied(const wptr<IRemoteObject> &object)
185 {
186 if (object == nullptr) {
187 HILOGE("remote object is null");
188 return;
189 }
190
191 handler_->PostSyncTask([this, &object]() { this->OnRemoteSubscriberDiedInner(object); });
192 }
193
RegisterActiveAppsInner(int32_t pid,int32_t uid)194 void PurgeableMemManager::RegisterActiveAppsInner(int32_t pid, int32_t uid)
195 {
196 std::lock_guard<std::mutex> lockAppList(mutexAppList_);
197 if (appList_.size() >= PURGEABLE_APPSTATE_MAX_NUM) {
198 HILOGE("the number of registered apps has reached the upper limit");
199 return;
200 }
201
202 if (appList_.find(pid) != appList_.end()) {
203 HILOGE("the app has already registered");
204 return;
205 }
206 int32_t state = static_cast<int32_t>(AppExecFwk::ApplicationState::APP_STATE_FOREGROUND);
207 std::pair<int32_t, int32_t> appinfo = std::make_pair(uid, state);
208 appList_[pid] = appinfo;
209 HILOGI("the app is registered, pid is: %{public}d, uid is %{public}d", pid, uid);
210 }
211
RegisterActiveApps(int32_t pid,int32_t uid)212 void PurgeableMemManager::RegisterActiveApps(int32_t pid, int32_t uid)
213 {
214 if (!CheckCallingToken()) {
215 HILOGW("AddSubscriber not allowed");
216 return;
217 }
218 if (!initialized_) {
219 HILOGE("is not initialized");
220 return;
221 }
222 std::function<void()> func = std::bind(&PurgeableMemManager::RegisterActiveAppsInner, this, pid, uid);
223 handler_->PostImmediateTask(func);
224 }
225
DeregisterActiveAppsInner(int32_t pid,int32_t uid)226 void PurgeableMemManager::DeregisterActiveAppsInner(int32_t pid, int32_t uid)
227 {
228 std::lock_guard<std::mutex> lockAppList(mutexAppList_);
229 if (appList_.find(pid) == appList_.end()) {
230 HILOGE("the app is not registered");
231 return;
232 }
233 std::pair<int32_t, int32_t> appinfo = appList_[pid];
234 if (appinfo.first != uid) {
235 HILOGE("uid don't match the pid");
236 return;
237 }
238 appList_.erase(pid);
239 HILOGI("the app is deregistered, pid is: %{public}d, uid is %{public}d", pid, uid);
240 }
241
DeregisterActiveApps(int32_t pid,int32_t uid)242 void PurgeableMemManager::DeregisterActiveApps(int32_t pid, int32_t uid)
243 {
244 if (!CheckCallingToken()) {
245 HILOGW("AddSubscriber not allowed");
246 return;
247 }
248 if (!initialized_) {
249 HILOGE("is not initialized");
250 return;
251 }
252 std::function<void()> func = std::bind(&PurgeableMemManager::DeregisterActiveAppsInner, this, pid, uid);
253 handler_->PostImmediateTask(func);
254 }
255
ChangeAppStateInner(int32_t pid,int32_t uid,int32_t state)256 void PurgeableMemManager::ChangeAppStateInner(int32_t pid, int32_t uid, int32_t state)
257 {
258 {
259 std::lock_guard<std::mutex> lockAppList(mutexAppList_);
260 if (appList_.find(pid) == appList_.end()) {
261 HILOGE("the app is not registered");
262 return;
263 }
264 std::pair<int32_t, int32_t> appinfo = appList_[pid];
265 if (appinfo.first != uid) {
266 HILOGE("uid don't match the pid");
267 return;
268 }
269 int32_t oldState = appList_[pid].second;
270 appList_[pid].second = state;
271 HILOGI("state is changed, old state: %{public}d, new state: %{public}d pid: %{public}d, uid: %{public}d",
272 oldState, appList_[pid].second, pid, uid);
273 }
274
275 std::lock_guard<std::mutex> lockSubscriber(mutexSubscribers_);
276 auto iter = appStateSubscribers_.begin();
277 while (iter != appStateSubscribers_.end()) {
278 HILOGI("do OnAppStateChanged");
279 (*iter)->OnAppStateChanged(pid, uid, state);
280 iter++;
281 }
282 }
283
ChangeAppState(int32_t pid,int32_t uid,int32_t state)284 void PurgeableMemManager::ChangeAppState(int32_t pid, int32_t uid, int32_t state)
285 {
286 if (!initialized_) {
287 HILOGE("is not initialized");
288 return;
289 }
290 std::function<void()> func = std::bind(&PurgeableMemManager::ChangeAppStateInner, this, pid, uid, state);
291 handler_->PostImmediateTask(func);
292 }
293
TrimAllSubscribers(const SystemMemoryLevel & level)294 void PurgeableMemManager::TrimAllSubscribers(const SystemMemoryLevel &level)
295 {
296 HILOGD("enter! onTrim memory level is %{public}d \n", level);
297 std::lock_guard<std::mutex> lockSubscriber(mutexSubscribers_);
298 auto iter = appStateSubscribers_.begin();
299 while (iter != appStateSubscribers_.end()) {
300 (*iter)->OnTrim(level);
301 iter++;
302 }
303 }
304
CheckCallingToken()305 bool PurgeableMemManager::CheckCallingToken()
306 {
307 Security::AccessToken::AccessTokenID tokenId = IPCSkeleton::GetCallingTokenID();
308 auto tokenFlag = Security::AccessToken::AccessTokenKit::GetTokenTypeFlag(tokenId);
309 if (tokenFlag == Security::AccessToken::ATokenTypeEnum::TOKEN_NATIVE ||
310 tokenFlag == Security::AccessToken::ATokenTypeEnum::TOKEN_SHELL) {
311 return true;
312 }
313 return false;
314 }
315
ReclaimSubscriberAll()316 void PurgeableMemManager::ReclaimSubscriberAll()
317 {
318 HILOGD("enter! Force Subscribers Reclaim all");
319 std::lock_guard<std::mutex> lockSubscriber(mutexSubscribers_);
320 std::lock_guard<std::mutex> lockAppList(mutexAppList_);
321 auto subscriberIter = appStateSubscribers_.begin();
322 int pid = -1;
323 int uid = -1;
324 while (subscriberIter != appStateSubscribers_.end()) {
325 HILOGI("do ForceReclaim");
326 auto appListIter = appList_.begin();
327 while (appListIter != appList_.end()) {
328 pid = appListIter->first;
329 std::pair<int32_t, int32_t> appinfo = appListIter->second;
330 uid = appinfo.first;
331 (*subscriberIter)->ForceReclaim(pid, uid);
332 appListIter++;
333 }
334 subscriberIter++;
335 }
336 }
337
ReclaimSubscriberProc(const int32_t pid)338 void PurgeableMemManager::ReclaimSubscriberProc(const int32_t pid)
339 {
340 HILOGD("enter! Force Subscribers Reclaim: pid=%{public}d", pid);
341 int32_t uid = -1;
342 {
343 std::lock_guard<std::mutex> lockAppList(mutexAppList_);
344 if (appList_.find(pid) == appList_.end()) {
345 HILOGE("the app is not registered");
346 return;
347 }
348
349 std::pair<int32_t, int32_t> appinfo = appList_[pid];
350 uid = appinfo.first;
351 }
352 std::lock_guard<std::mutex> lockSubscriber(mutexSubscribers_);
353 auto iter = appStateSubscribers_.begin();
354 while (iter != appStateSubscribers_.end()) {
355 HILOGI("do ForceReclaim");
356 (*iter)->ForceReclaim(pid, uid);
357 iter++;
358 }
359 }
360
GetPurgeableInfo(PurgeableMemoryInfo & info)361 bool PurgeableMemManager::GetPurgeableInfo(PurgeableMemoryInfo &info)
362 {
363 switch (info.type) {
364 case PurgeableMemoryType::PURGEABLE_HEAP:
365 return PurgeableMemUtils::GetInstance().GetPurgeableHeapInfo(info.reclaimableKB);
366 case PurgeableMemoryType::PURGEABLE_ASHMEM:
367 return PurgeableMemUtils::GetInstance().GetPurgeableAshmInfo(info.reclaimableKB, info.ashmInfoToReclaim);
368 case PurgeableMemoryType::PURGEABLE_SUBSCRIBER:
369 return false;
370 default:
371 break;
372 }
373 return false;
374 }
375
GetMemcgPathByUserId(const int userId,std::string & memcgPath)376 bool PurgeableMemManager::GetMemcgPathByUserId(const int userId, std::string &memcgPath)
377 {
378 if (userId == 0) { // get system memcg path when userId = 0
379 memcgPath = KernelInterface::MEMCG_BASE_PATH;
380 return true;
381 }
382 UserMemcg *memcg = MemcgMgr::GetInstance().GetUserMemcg(userId);
383 if (memcg == nullptr) {
384 return false;
385 }
386 memcgPath = memcg->GetMemcgPath_();
387 return true;
388 }
389
PurgeTypeAll(const PurgeableMemoryType & type)390 bool PurgeableMemManager::PurgeTypeAll(const PurgeableMemoryType &type)
391 {
392 switch (type) {
393 case PurgeableMemoryType::PURGEABLE_HEAP:
394 return PurgeableMemUtils::GetInstance().PurgeHeapAll();
395 case PurgeableMemoryType::PURGEABLE_ASHMEM:
396 return PurgeableMemUtils::GetInstance().PurgeAshmAll();
397 case PurgeableMemoryType::PURGEABLE_SUBSCRIBER:
398 return false;
399 default:
400 break;
401 }
402 return false;
403 }
404
PurgeHeap(const int userId,const int size)405 bool PurgeableMemManager::PurgeHeap(const int userId, const int size)
406 {
407 std::string memcgPath;
408 if (!GetMemcgPathByUserId(userId, memcgPath)) {
409 return false;
410 }
411 return PurgeableMemUtils::GetInstance().PurgeHeapMemcg(memcgPath, size);
412 }
413
PurgeAshm(const unsigned int ashmId,const unsigned int time)414 bool PurgeableMemManager::PurgeAshm(const unsigned int ashmId, const unsigned int time)
415 {
416 std::string ashmIdWithTime = std::to_string(ashmId) + std::string(" ") + std::to_string(time);
417 return PurgeableMemUtils::GetInstance().PurgeAshmByIdWithTime(ashmIdWithTime);
418 }
419
PurgHeapOneMemcg(const std::vector<int> & memcgPids,const std::string & memcgPath,const int reclaimTargetKB,int & reclaimResultKB)420 bool PurgeableMemManager::PurgHeapOneMemcg(const std::vector<int> &memcgPids, const std::string &memcgPath,
421 const int reclaimTargetKB, int &reclaimResultKB)
422 {
423 if (reclaimResultKB >= reclaimTargetKB) {
424 return true;
425 }
426
427 int unPinedSizeKB = 0;
428 for (auto &pid : memcgPids) {
429 int reclaimableKB = 0;
430 if (!PurgeableMemUtils::GetInstance().GetProcPurgeableHeapInfo(pid, reclaimableKB)) {
431 continue;
432 }
433 unPinedSizeKB += reclaimableKB;
434 }
435
436 int toReclaimSize = 0;
437 if (reclaimResultKB + unPinedSizeKB <= reclaimTargetKB) {
438 toReclaimSize = unPinedSizeKB;
439 } else {
440 toReclaimSize = reclaimTargetKB - reclaimResultKB;
441 }
442
443 if (toReclaimSize > 0 && PurgeableMemUtils::GetInstance().PurgeHeapMemcg(memcgPath, toReclaimSize)) {
444 HILOGI("reclaim purgeable [HEAP] for memcg[%{public}s], recult=%{public}d KB", memcgPath.c_str(),
445 toReclaimSize);
446 reclaimResultKB += toReclaimSize;
447 if (reclaimResultKB >= reclaimTargetKB) {
448 return true;
449 }
450 }
451 return false;
452 }
453
PurgHeapMemcgOneByOne(const int reclaimTargetKB,int & reclaimResultKB)454 void PurgeableMemManager::PurgHeapMemcgOneByOne(const int reclaimTargetKB, int &reclaimResultKB)
455 {
456 reclaimResultKB = 0;
457 std::vector<int> memcgPids;
458 std::string memcgPath;
459 std::vector<int> userIds;
460 KernelInterface::GetInstance().GetAllUserIds(userIds);
461 for (auto userId : userIds) {
462 memcgPath = KernelInterface::GetInstance().JoinPath(KernelInterface::MEMCG_BASE_PATH, std::to_string(userId));
463 memcgPids.clear();
464 if (!KernelInterface::GetInstance().GetMemcgPids(memcgPath, memcgPids) || memcgPids.size() == 0) {
465 continue;
466 }
467 if (PurgHeapOneMemcg(memcgPids, memcgPath, reclaimTargetKB, reclaimResultKB)) {
468 return;
469 }
470 }
471
472 memcgPids.clear();
473 if (KernelInterface::GetInstance().GetMemcgPids(KernelInterface::MEMCG_BASE_PATH, memcgPids) &&
474 memcgPids.size() > 0) {
475 PurgHeapOneMemcg(memcgPids, KernelInterface::MEMCG_BASE_PATH, reclaimTargetKB, reclaimResultKB);
476 }
477 }
478
AshmReclaimPriorityCompare(const PurgeableAshmInfo & left,const PurgeableAshmInfo & right)479 bool PurgeableMemManager::AshmReclaimPriorityCompare(const PurgeableAshmInfo &left, const PurgeableAshmInfo &right)
480 {
481 if (left.minPriority != right.minPriority) {
482 return left.minPriority > right.minPriority;
483 } else {
484 return left.sizeKB > right.sizeKB;
485 }
486 }
487
PurgAshmIdOneByOne(std::vector<PurgeableAshmInfo> & ashmInfoToReclaim,const int reclaimTargetKB,int & reclaimResultKB)488 void PurgeableMemManager::PurgAshmIdOneByOne(std::vector<PurgeableAshmInfo> &ashmInfoToReclaim,
489 const int reclaimTargetKB, int &reclaimResultKB)
490 {
491 if (!ashmInfoToReclaim.empty()) {
492 std::sort(ashmInfoToReclaim.begin(), ashmInfoToReclaim.end(),
493 [this](const auto &lhs, const auto &rhs) { return AshmReclaimPriorityCompare(lhs, rhs); });
494 }
495
496 reclaimResultKB = 0;
497 for (auto &it : ashmInfoToReclaim) {
498 if (!IsPurgeWhiteApp(it.curAppName)) {
499 HILOGD("[%{public}s] is not in purgeable app white list!", it.curAppName.c_str());
500 continue;
501 }
502 if (PurgeableMemUtils::GetInstance().PurgeAshmByIdWithTime(it.idWithTime)) {
503 HILOGI("reclaim purgeable [ASHM] for ashmem_id[%{public}s], adj=%{public}d, result=%{public}d KB",
504 it.idWithTime.c_str(), it.minPriority, it.sizeKB);
505 reclaimResultKB += it.sizeKB;
506 if (reclaimResultKB >= reclaimTargetKB) {
507 return;
508 }
509 }
510 }
511 }
512
PurgeByTypeAndTarget(const PurgeableMemoryType & type,const int reclaimTargetKB)513 int PurgeableMemManager::PurgeByTypeAndTarget(const PurgeableMemoryType &type, const int reclaimTargetKB)
514 {
515 std::string typeDesc = PurgMemType2String(type);
516 PurgeableMemoryInfo info;
517 info.type = type;
518 if (!GetPurgeableInfo(info)) {
519 HILOGD("GetPurgeableInfo with type[%{public}s] failed!", typeDesc.c_str());
520 return 0;
521 }
522 if (info.reclaimableKB <= 0) {
523 HILOGD("no unpined purgeable [%{public}s] to reclaim!", typeDesc.c_str());
524 return 0;
525 }
526 HILOGI("purgeable[%{public}s]: reclaimableKB=%{public}dKB, target=%{public}dKB", typeDesc.c_str(),
527 info.reclaimableKB, reclaimTargetKB);
528
529 int reclaimResultKB = 0;
530
531 // reclaim all unpined purgeable of this type
532 if (type != PurgeableMemoryType::PURGEABLE_ASHMEM &&
533 info.reclaimableKB <= reclaimTargetKB && PurgeTypeAll(type)) {
534 reclaimResultKB = info.reclaimableKB;
535 HILOGI("reclaim all purgeable [%{public}s], result=%{public}d KB", typeDesc.c_str(), reclaimResultKB);
536 return reclaimResultKB;
537 }
538
539 // reclaim one by one
540 switch (type) {
541 case PurgeableMemoryType::PURGEABLE_HEAP:
542 PurgHeapMemcgOneByOne(reclaimTargetKB, reclaimResultKB);
543 break;
544 case PurgeableMemoryType::PURGEABLE_ASHMEM:
545 PurgAshmIdOneByOne(info.ashmInfoToReclaim, reclaimTargetKB, reclaimResultKB);
546 break;
547 case PurgeableMemoryType::PURGEABLE_SUBSCRIBER:
548 break;
549 default:
550 break;
551 }
552 return reclaimResultKB;
553 }
554
PurgMemType2String(const PurgeableMemoryType & type)555 std::string PurgeableMemManager::PurgMemType2String(const PurgeableMemoryType &type)
556 {
557 switch (type) {
558 case PurgeableMemoryType::PURGEABLE_HEAP:
559 return "HEAP";
560 case PurgeableMemoryType::PURGEABLE_ASHMEM:
561 return "ASHM";
562 case PurgeableMemoryType::PURGEABLE_SUBSCRIBER:
563 return "SUBSCRIBER";
564 default:
565 return "";
566 }
567 }
568
569 #define CHECK_RECLAIM_CONDITION(reclaimTargetKB, action) \
570 do { \
571 if ((reclaimTargetKB) <= 0) { \
572 action; \
573 } \
574 } while (0)
575
TriggerByPsi(const SystemMemoryInfo & info)576 void PurgeableMemManager::TriggerByPsi(const SystemMemoryInfo &info)
577 {
578 HILOGD("called");
579 time_t now = time(0);
580 if (lastTriggerTime_ != 0 && (now - lastTriggerTime_) < TRIGGER_INTERVAL_SECOND) {
581 HILOGD("Less than %{public}u s from last trigger, no action is required.", TRIGGER_INTERVAL_SECOND);
582 return;
583 } else {
584 lastTriggerTime_ = now;
585 }
586
587 unsigned int currentBuffer = static_cast<unsigned int>(KernelInterface::GetInstance().GetCurrentBuffer());
588 DECLARE_SHARED_POINTER(SystemMemoryLevelConfig, config);
589 MAKE_POINTER(config, shared, SystemMemoryLevelConfig, "The SystemMemoryLevelConfig is NULL.", return,
590 MemmgrConfigManager::GetInstance().GetSystemMemoryLevelConfig());
591
592 // cal target reclaim count
593 unsigned int targetBuffer = config->GetPurgeable();
594 int reclaimTargetKB = targetBuffer - currentBuffer;
595 CHECK_RECLAIM_CONDITION(reclaimTargetKB, return);
596 HILOGI("reclaim purgeable memory start: currentBuffer=%{public}uKB, purgeableLevel=%{public}uKB, "
597 "reclaimTarget=%{public}dKB", currentBuffer, targetBuffer, reclaimTargetKB);
598
599 std::vector<PurgeableMemoryType> sequence = {PurgeableMemoryType::PURGEABLE_HEAP,
600 PurgeableMemoryType::PURGEABLE_ASHMEM,
601 PurgeableMemoryType::PURGEABLE_SUBSCRIBER};
602
603 int totalReclaimedKB = 0;
604 for (auto typePtr = sequence.begin(); typePtr < sequence.end(); typePtr++) {
605 int reclaimed = PurgeByTypeAndTarget(*typePtr, reclaimTargetKB);
606 HILOGI("reclaimed %{public}dKB purgeable [%{public}s]", reclaimed, PurgMemType2String(*typePtr).c_str());
607 reclaimTargetKB -= reclaimed;
608 totalReclaimedKB += reclaimed;
609 if (reclaimTargetKB <= 0) {
610 HILOGI("total reclaimed %{public}dKB purgeable memory, reached target size!", totalReclaimedKB);
611 return;
612 }
613 }
614 HILOGI("purgeable_heap and purgeable_ashmem total reclaimed %{public}dKB, not reach target size!",
615 totalReclaimedKB);
616
617 TrimAllSubscribers(info.level); // heap和ashmem类型的purgeable内存全部回收完依然不够target时,触发onTrim
618 }
619
TriggerByManualDump(const SystemMemoryInfo & info)620 void PurgeableMemManager::TriggerByManualDump(const SystemMemoryInfo &info)
621 {
622 HILOGD("enter!\n");
623 if (info.level > SystemMemoryLevel::UNKNOWN && info.level <= SystemMemoryLevel::MEMORY_LEVEL_CRITICAL) {
624 TrimAllSubscribers(info.level);
625 }
626 }
627
628 /*
629 * There are three ways to trigger me;
630 * 1. By command of "hidumper -s 1909", see MemMgrService::Dump
631 * 2. By trigger of kernel memory psi, see MemoryLevelManager
632 * 3. By trigger of kswapd uploading, see KswapdObserver
633 */
NotifyMemoryLevelInner(const SystemMemoryInfo & info)634 void PurgeableMemManager::NotifyMemoryLevelInner(const SystemMemoryInfo &info)
635 {
636 switch (info.source) {
637 case MemorySource::MANUAL_DUMP:
638 TriggerByManualDump(info);
639 break;
640 case MemorySource::KSWAPD: // fall through
641 case MemorySource::PSI_MEMORY:
642 TriggerByPsi(info);
643 break;
644 default:
645 HILOGE("unsupported source:%{public}d", info.source);
646 break;
647 }
648 }
649
NotifyMemoryLevel(const SystemMemoryInfo & info)650 void PurgeableMemManager::NotifyMemoryLevel(const SystemMemoryInfo &info)
651 {
652 if (!initialized_) {
653 HILOGE("is not initialized");
654 return;
655 }
656 std::function<void()> func = std::bind(&PurgeableMemManager::NotifyMemoryLevelInner, this, info);
657 handler_->PostImmediateTask(func);
658 }
659
ForceReclaimByDump(const DumpReclaimInfo & dumpInfo)660 bool PurgeableMemManager::ForceReclaimByDump(const DumpReclaimInfo &dumpInfo)
661 {
662 if (dumpInfo.reclaimType == PurgeableMemoryType::UNKNOWN) {
663 return false;
664 }
665
666 bool ret;
667 switch (dumpInfo.reclaimType) {
668 case PurgeableMemoryType::PURGEABLE_HEAP:
669 if (dumpInfo.ifReclaimTypeAll) {
670 return PurgeableMemUtils::GetInstance().PurgeHeapAll();
671 } else {
672 return PurgeHeap(dumpInfo.memcgUserId, dumpInfo.reclaimHeapSizeKB);
673 }
674 case PurgeableMemoryType::PURGEABLE_ASHMEM:
675 if (dumpInfo.ifReclaimTypeAll) {
676 return PurgeableMemUtils::GetInstance().PurgeAshmAll();
677 } else {
678 return PurgeAshm(dumpInfo.ashmId, dumpInfo.ashmTime);
679 }
680 case PurgeableMemoryType::PURGEABLE_SUBSCRIBER:
681 if (dumpInfo.ifReclaimTypeAll) {
682 ReclaimSubscriberAll();
683 } else {
684 ReclaimSubscriberProc(dumpInfo.subscriberPid);
685 }
686 return true;
687 case PurgeableMemoryType::PURGEABLE_ALL:
688 ret = PurgeableMemUtils::GetInstance().PurgeHeapAll();
689 ret = ret && PurgeableMemUtils::GetInstance().PurgeAshmAll();
690 ReclaimSubscriberAll();
691 return ret;
692 default:
693 return false;
694 }
695 }
696
DumpSubscribers(const int fd)697 void PurgeableMemManager::DumpSubscribers(const int fd)
698 {
699 HILOGD("enter!\n");
700 std::lock_guard<std::mutex> lockAppList(mutexAppList_);
701 int32_t pid;
702 int32_t uid;
703 int32_t state;
704 auto appListIter = appList_.begin();
705 while (appListIter != appList_.end()) {
706 pid = appListIter->first;
707 std::pair<int32_t, int32_t> appinfo = appListIter->second;
708 uid = appinfo.first;
709 state = appinfo.second;
710 dprintf(fd, "pid:%d, uid:%d state:%s\n", pid, uid, (state == APP_STATE_FOREGROUND) ?
711 "Foreground" : "Background");
712 appListIter++;
713 }
714 }
715
IsPurgeWhiteApp(const std::string & curAppName)716 bool PurgeableMemManager::IsPurgeWhiteApp(const std::string &curAppName)
717 {
718 PurgeablememConfig pmc = MemmgrConfigManager::GetInstance().GetPurgeablememConfig();
719 std::set<std::string> purgeWhiteAppSet = pmc.GetPurgeWhiteAppSet();
720 for (auto it = purgeWhiteAppSet.begin(); it != purgeWhiteAppSet.end(); it++) {
721 if (curAppName == *it) {
722 return true;
723 }
724 }
725 return false;
726 }
727 } // namespace Memory
728 } // namespace OHOS