1 /*
2  * Copyright (c) 2022 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 #include "memory_level_manager.h"
16 
17 #include "app_mem_info.h"
18 #include "app_mgr_client.h"
19 #include "if_system_ability_manager.h"
20 #include "iservice_registry.h"
21 #include "kernel_interface.h"
22 #include "memmgr_config_manager.h"
23 #include "memmgr_log.h"
24 #include "memmgr_ptr_util.h"
25 #include "reclaim_priority_manager.h"
26 #ifdef USE_PURGEABLE_MEMORY
27 #include "purgeable_mem_manager.h"
28 #endif
29 
30 namespace OHOS {
31 namespace Memory {
32 namespace {
33 const std::string TAG = "MemoryLevelManager";
34 }
35 
36 IMPLEMENT_SINGLE_INSTANCE(MemoryLevelManager);
37 
MemoryLevelManager()38 MemoryLevelManager::MemoryLevelManager()
39 {
40     initialized_ = GetEventHandler();
41     if (initialized_) {
42         HILOGI("init succeeded");
43     } else {
44         HILOGE("init failed");
45     }
46 }
47 
GetEventHandler()48 bool MemoryLevelManager::GetEventHandler()
49 {
50     if (!handler_) {
51         MAKE_POINTER(handler_, shared, AppExecFwk::EventHandler, "failed to create event handler", return false,
52                      AppExecFwk::EventRunner::Create());
53     }
54     return true;
55 }
56 
CalcSystemMemoryLevel(SystemMemoryInfo & info)57 bool MemoryLevelManager::CalcSystemMemoryLevel(SystemMemoryInfo &info)
58 {
59     int currentBuffer = KernelInterface::GetInstance().GetCurrentBuffer();
60     std::shared_ptr<SystemMemoryLevelConfig> config =
61         std::make_shared<SystemMemoryLevelConfig>(MemmgrConfigManager::GetInstance().GetSystemMemoryLevelConfig());
62     if (config == nullptr) {
63         HILOGE("The SystemMemoryLevelConfig is NULL.");
64         return false;
65     }
66 
67     if (currentBuffer <= config->GetCritical()) {
68         info.level = SystemMemoryLevel::MEMORY_LEVEL_CRITICAL;
69     } else if (currentBuffer <= config->GetLow()) {
70         info.level = SystemMemoryLevel::MEMORY_LEVEL_LOW;
71     } else if (currentBuffer <= config->GetModerate()) {
72         info.level = SystemMemoryLevel::MEMORY_LEVEL_MODERATE;
73     } else if (currentBuffer <= config->GetPurgeable()) {
74         info.level = SystemMemoryLevel::MEMORY_LEVEL_PURGEABLE;
75     } else {
76         return false;
77     }
78 
79     HILOGI("critical:%{public}d low:%{public}d moderate:%{public}d purgeable:%{public}d in config, curBuf:%{public}dKB,"
80            "level:%{public}d.",
81            config->GetCritical(), config->GetLow(), config->GetModerate(), config->GetPurgeable(), currentBuffer,
82            static_cast<int>(info.level));
83     return true;
84 }
85 
CalcReclaimAppList(std::vector<std::shared_ptr<AppEntity>> & appList)86 bool MemoryLevelManager::CalcReclaimAppList(std::vector<std::shared_ptr<AppEntity>> &appList)
87 {
88     ReclaimPriorityManager::BunldeCopySet bundleSet;
89     ReclaimPriorityManager::GetInstance().GetBundlePrioSet(bundleSet);
90     for (auto bundleInfo : bundleSet) {
91         std::shared_ptr<AppEntity> app;
92         MAKE_POINTER(app, shared, AppEntity, "make shared failed", return false, bundleInfo.uid_, bundleInfo.name_);
93         appList.push_back(app);
94         HILOGI("The app will be reclaimed, uid:%{public}d, name:%{public}s.", app->uid_, app->name_.c_str());
95     }
96     return true;
97 }
98 
NotifyMemoryLevel(SystemMemoryInfo & info)99 void MemoryLevelManager::NotifyMemoryLevel(SystemMemoryInfo &info)
100 {
101     HILOGD("called!");
102     DECLARE_UNIQUE_POINTER(AppExecFwk::AppMgrClient, appMgrClient_);
103     MAKE_POINTER(appMgrClient_, unique, AppExecFwk::AppMgrClient, "make unique failed", return,
104         /* no param */);
105     bool isNotifyMemoryLevelToSaMgr = false;
106     switch (info.level) {
107         case SystemMemoryLevel::MEMORY_LEVEL_PURGEABLE: {
108             // no need notify appMgrClient_
109             break;
110         }
111         case SystemMemoryLevel::MEMORY_LEVEL_MODERATE: {
112             isNotifyMemoryLevelToSaMgr = true;
113             appMgrClient_->NotifyMemoryLevel(AppExecFwk::MemoryLevel::MEMORY_LEVEL_MODERATE);
114             break;
115         }
116         case SystemMemoryLevel::MEMORY_LEVEL_LOW: {
117             isNotifyMemoryLevelToSaMgr = true;
118             appMgrClient_->NotifyMemoryLevel(AppExecFwk::MemoryLevel::MEMORY_LEVEL_LOW);
119             break;
120         }
121         case SystemMemoryLevel::MEMORY_LEVEL_CRITICAL: {
122             isNotifyMemoryLevelToSaMgr = true;
123             appMgrClient_->NotifyMemoryLevel(AppExecFwk::MemoryLevel::MEMORY_LEVEL_CRITICAL);
124             break;
125         }
126         default:
127             return;
128     }
129     if (isNotifyMemoryLevelToSaMgr) {
130         NotifyMemoryLevelToSystemAbilityManager();
131     }
132 #ifdef USE_PURGEABLE_MEMORY
133     PurgeableMemManager::GetInstance().NotifyMemoryLevel(info);
134 #endif
135 }
136 
NotifyMemoryLevelToSystemAbilityManager()137 void MemoryLevelManager::NotifyMemoryLevelToSystemAbilityManager()
138 {
139     sptr<ISystemAbilityManager> systemAbilityManager =
140         SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
141     if (!systemAbilityManager) {
142         HILOGE("get system ability manager failed!");
143         return;
144     }
145 
146     int32_t ret = systemAbilityManager->UnloadAllIdleSystemAbility();
147     if (ret != ERR_OK) {
148         HILOGE("notify system ability manager failed!");
149         return;
150     }
151     HILOGI("notify system ability manager succ!");
152 }
153 
TriggerMemoryLevelByDump(SystemMemoryInfo & info)154 void MemoryLevelManager::TriggerMemoryLevelByDump(SystemMemoryInfo &info)
155 {
156     HILOGD("called!");
157     if (info.source != MemorySource::MANUAL_DUMP) {
158         HILOGE("error: trigger not by dump!");
159         return;
160     }
161     NotifyMemoryLevel(info);
162 }
163 
PsiHandlerInner()164 void MemoryLevelManager::PsiHandlerInner()
165 {
166     HILOGD("[%{public}ld] called", ++calledCount_);
167 
168     /* Calculate the system memory level */
169     SystemMemoryInfo info = {MemorySource::PSI_MEMORY, SystemMemoryLevel::UNKNOWN};
170     if (!CalcSystemMemoryLevel(info)) {
171         return;
172     }
173     NotifyMemoryLevel(info);
174 }
175 
PsiHandler()176 void MemoryLevelManager::PsiHandler()
177 {
178     if (!initialized_) {
179         HILOGE("is not initialized, return!");
180         return;
181     }
182     handler_->PostImmediateTask([this] { this->PsiHandlerInner(); });
183 }
184 } // namespace Memory
185 } // namespace OHOS
186