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