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