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