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 "memmgr_log.h"
17 #include "memmgr_ptr_util.h"
18 #include "default_multi_account_strategy.h"
19 #include "reclaim_strategy_manager.h"
20 #include "kernel_interface.h"
21 #include "oom_score_adj_utils.h"
22 #include "reclaim_priority_constants.h"
23 #include "multi_account_manager.h"
24 
25 namespace OHOS {
26 namespace Memory {
27 namespace {
28 const std::string TAG = "MultiAccountManager";
29 const int MAX_RETRY_TIMES = 10;
30 const int SLEEP_TIME = 3000;
31 }
32 
33 IMPLEMENT_SINGLE_INSTANCE(MultiAccountManager);
34 
MultiAccountManager()35 MultiAccountManager::MultiAccountManager()
36 {
37     MAKE_POINTER(strategy_, shared, DefaultMultiAccountStrategy, "make shared failed", return, /* no param */);
38     MAKE_POINTER(handler_, shared, AppExecFwk::EventHandler, "failed to create event handler", return,
39         AppExecFwk::EventRunner::Create());
40 }
41 
~MultiAccountManager()42 MultiAccountManager::~MultiAccountManager()
43 {
44     if (strategy_) {
45         strategy_ = nullptr;
46     }
47 }
48 
Init()49 void MultiAccountManager::Init()
50 {
51     retryTimes_++;
52     initialized_ = false;
53     do {
54         oldActiveAccountIds_.clear();
55         ErrCode errCode = AccountSA::OsAccountManager::QueryActiveOsAccountIds(oldActiveAccountIds_);
56         if (errCode != ERR_OK) {
57             HILOGI("The manager initial failed, err = %{public}d.", static_cast<int>(errCode));
58             break;
59         }
60 
61         if (!UpdateAccountPriorityInfo(oldActiveAccountIds_)) {
62             HILOGI("The manager initial failed.");
63             break;
64         }
65 
66         initialized_ = true;
67     } while (0);
68 
69     if (initialized_) {
70         HILOGI("The manager initial succeed, accountCount = %{public}zu.", oldActiveAccountIds_.size());
71         return;
72     }
73 
74     if (retryTimes_ < MAX_RETRY_TIMES) {
75         if (handler_ == nullptr) {
76             HILOGE("The manager initial failed and couldn't retry, because the handler is null.");
77             return;
78         }
79 
80         handler_->PostTask([this] { this->Init(); }, SLEEP_TIME, AppExecFwk::EventQueue::Priority::LOW);
81         HILOGE("Manager initial failed, try again after 3s!, retryTimes = %{public}d/10", retryTimes_);
82     }
83 }
84 
SetAccountPriority(int accountId,std::string accountName,AccountSA::OsAccountType accountType,bool isActived)85 bool MultiAccountManager::SetAccountPriority(int accountId, std::string accountName,
86                                              AccountSA::OsAccountType accountType, bool isActived)
87 {
88     std::shared_ptr<AccountPriorityInfo> accountInfo = GetAccountPriorityInfo(accountId);
89     if (accountInfo == nullptr) {
90         MAKE_POINTER(accountInfo, shared, AccountPriorityInfo, "make shared failed", return false,
91             accountId, accountName, accountType, isActived);
92         AddAccountPriorityInfo(accountInfo);
93     } else {
94         accountInfo->SetName(accountName);
95         accountInfo->SetType(accountType);
96         accountInfo->SetIsActived(isActived);
97     }
98 
99     if (strategy_ == nullptr) {
100         HILOGI("Set account priority failed, strategy is null.");
101         return false;
102     }
103 
104     int oldPriority = accountInfo->GetPriority();
105     if (!strategy_->SetAccountPriority(accountInfo)) {
106         HILOGI("Set account priority failed, accountId = %{public}d.", accountId);
107         return false;
108     }
109 
110     HILOGI("Set acccount priority succeed, accountId = %{public}d, old = %{public}d, new = %{public}d.",
111            accountId, oldPriority, accountInfo->GetPriority());
112 #ifdef USE_HYPERHOLD_MEMORY
113     ReclaimStrategyManager::GetInstance().NotifyAccountPriorityChanged(accountId, accountInfo->GetPriority());
114 #endif
115     return true;
116 }
117 
RecalcBundlePriority(int accountId,int bundlePriority)118 int MultiAccountManager::RecalcBundlePriority(int accountId, int bundlePriority)
119 {
120     std::shared_ptr<AccountPriorityInfo> accountInfo = GetAccountPriorityInfo(accountId);
121     if (accountInfo == nullptr) {
122         HILOGI("Repeat calculate bundle priority failed, account non-exist, accountId = %{public}d.", accountId);
123         return RECLAIM_PRIORITY_MAX;
124     }
125 
126     if (strategy_ == nullptr) {
127         HILOGI("Repeat calculate bundle priority failed, strategy is null.");
128         return RECLAIM_PRIORITY_MAX;
129     }
130 
131     int recalcPriority = strategy_->RecalcBundlePriority(accountInfo, bundlePriority);
132     if (recalcPriority > RECLAIM_PRIORITY_MAX) {
133         recalcPriority = RECLAIM_PRIORITY_MAX;
134     }
135     if (recalcPriority < RECLAIM_PRIORITY_FOREGROUND) {
136         recalcPriority = RECLAIM_PRIORITY_FOREGROUND;
137     }
138     return recalcPriority;
139 }
140 
AddAccountPriorityInfo(std::shared_ptr<AccountPriorityInfo> accountPriorityInfo)141 void MultiAccountManager::AddAccountPriorityInfo(std::shared_ptr<AccountPriorityInfo> accountPriorityInfo)
142 {
143     accountMap_.insert(std::pair<int, std::shared_ptr<AccountPriorityInfo>>(accountPriorityInfo->GetId(),
144                                                                             accountPriorityInfo));
145     HILOGI("Add account information succeed, accountId = %{public}d.", accountPriorityInfo->GetId());
146 }
147 
GetAccountPriorityInfo(int accountId)148 std::shared_ptr<AccountPriorityInfo> MultiAccountManager::GetAccountPriorityInfo(int accountId)
149 {
150     std::map<int, std::shared_ptr<AccountPriorityInfo>>::iterator iter = accountMap_.find(accountId);
151     if (iter != accountMap_.end()) {
152         return iter->second;
153     }
154     return nullptr;
155 }
156 
GetMultiAccountStratgy()157 std::shared_ptr<MultiAccountStrategy> MultiAccountManager::GetMultiAccountStratgy()
158 {
159     return strategy_;
160 }
161 
SetMultiAccountStrategy(std::shared_ptr<MultiAccountStrategy> strategy)162 bool MultiAccountManager::SetMultiAccountStrategy(std::shared_ptr<MultiAccountStrategy> strategy)
163 {
164     if (strategy == nullptr) {
165         HILOGI("Set the multiple account strategy failed because the strategy is null.");
166         return false;
167     }
168 
169     strategy_ = strategy;
170     return true;
171 }
172 
GetSwitchedAccountIds(std::vector<int> & accountIds)173 bool MultiAccountManager::GetSwitchedAccountIds(std::vector<int> &accountIds)
174 {
175     std::vector<int> newActiveAccountIds;
176     ErrCode errCode = AccountSA::OsAccountManager::QueryActiveOsAccountIds(newActiveAccountIds);
177     if (errCode != ERR_OK) {
178         HILOGI("Query active os accountIds failed, err = %{public}d.", static_cast<int>(errCode));
179         return false;
180     }
181 
182     for (int oldId : oldActiveAccountIds_) {
183         if (std::find(newActiveAccountIds.begin(), newActiveAccountIds.end(), oldId) == newActiveAccountIds.end()) {
184             accountIds.push_back(oldId);
185             HILOGI("Get the switched account succeed, accountId = %{public}d.", oldId);
186         }
187     }
188 
189     oldActiveAccountIds_ = newActiveAccountIds;
190     return true;
191 }
192 
UpdateAccountPriorityInfo(std::vector<int> & accountIds)193 bool MultiAccountManager::UpdateAccountPriorityInfo(std::vector<int> &accountIds)
194 {
195     for (int accountId : accountIds) {
196         AccountSA::OsAccountInfo osAccountInfo;
197         ErrCode errCode = AccountSA::OsAccountManager::QueryOsAccountById(accountId, osAccountInfo);
198         if (errCode != ERR_OK) {
199             HILOGI("Get os account failed, accountId = %{public}d, err = %{public}d.",
200                    accountId, static_cast<int>(errCode));
201             return false;
202         }
203         if (!SetAccountPriority(accountId, osAccountInfo.GetLocalName(), osAccountInfo.GetType(),
204                                 osAccountInfo.GetIsActived())) {
205             HILOGI("Set account priority failed, accountId = %{public}d.", accountId);
206             return false;
207         }
208     }
209     return true;
210 }
211 
GetAccountBundleInfo(int accountId,std::map<int,std::shared_ptr<AccountBundleInfo>> & osAccountsInfoMap_)212 std::shared_ptr<AccountBundleInfo> MultiAccountManager::GetAccountBundleInfo(int accountId,
213     std::map<int, std::shared_ptr<AccountBundleInfo>> &osAccountsInfoMap_)
214 {
215     std::map<int, std::shared_ptr<AccountBundleInfo>>::iterator iter = osAccountsInfoMap_.find(accountId);
216     if (iter != osAccountsInfoMap_.end()) {
217         return iter->second;
218     }
219     return nullptr;
220 }
221 
KillProcessesOfAccount(int accountId,std::map<int,std::shared_ptr<AccountBundleInfo>> & osAccountsInfoMap_)222 void MultiAccountManager::KillProcessesOfAccount(int accountId,
223     std::map<int, std::shared_ptr<AccountBundleInfo>> &osAccountsInfoMap_)
224 {
225     std::shared_ptr<AccountBundleInfo> accountBundleInfo = GetAccountBundleInfo(accountId, osAccountsInfoMap_);
226     if (accountBundleInfo == nullptr) {
227         HILOGI("Kill proccess of the account failed because the account non-exist, accountId = %{public}d.", accountId);
228         return;
229     }
230 
231     for (auto iter1 : accountBundleInfo->bundleIdInfoMapping_) {
232         for (auto iter2 : iter1.second->procs_) {
233             pid_t pid = iter2.first;
234             if (!KernelInterface::GetInstance().KillOneProcessByPid(pid)) {
235                 HILOGI("Kill the process failed, pid = %{public}d.", pid);
236                 continue;
237             }
238             HILOGI("Kill the process succeed, pid = %{public}d.", pid);
239         }
240     }
241 }
242 
HandleAccountColdSwitch(std::vector<int> & switchedAccountIds,std::map<int,std::shared_ptr<AccountBundleInfo>> & osAccountsInfoMap_)243 bool MultiAccountManager::HandleAccountColdSwitch(std::vector<int> &switchedAccountIds,
244     std::map<int, std::shared_ptr<AccountBundleInfo>> &osAccountsInfoMap_)
245 {
246     for (int accountId : switchedAccountIds) {
247         HILOGI("Account cold switch account = %{public}d.", accountId);
248         KillProcessesOfAccount(accountId, osAccountsInfoMap_);
249 #ifdef USE_HYPERHOLD_MEMORY
250         ReclaimStrategyManager::GetInstance().NotifyAccountDied(accountId);
251 #endif
252     }
253     return true;
254 }
255 
HandleAccountHotSwitch(std::vector<int> & updatedAccountIds,std::map<int,std::shared_ptr<AccountBundleInfo>> & osAccountsInfoMap_)256 bool MultiAccountManager::HandleAccountHotSwitch(std::vector<int> &updatedAccountIds,
257     std::map<int, std::shared_ptr<AccountBundleInfo>> &osAccountsInfoMap_)
258 {
259     for (int accountId : updatedAccountIds) {
260         std::shared_ptr<AccountBundleInfo> accountBundleInfo = GetAccountBundleInfo(accountId, osAccountsInfoMap_);
261         if (accountBundleInfo == nullptr) {
262             HILOGI("Search account bundle info failed, accountId = %{public}d.", accountId);
263             continue;
264         }
265 
266         if (accountBundleInfo->bundleIdInfoMapping_.empty()) {
267             HILOGI("The bundle list of the account = %{public}d is empty.", accountId);
268             continue;
269         }
270 
271         for (auto iter : accountBundleInfo->bundleIdInfoMapping_) {
272             std::shared_ptr<BundlePriorityInfo> bundleInfo = iter.second;
273             int oldPriority = bundleInfo->priority_;
274             bundleInfo->priority_ = RecalcBundlePriority(accountId, oldPriority);
275             HILOGI("account = %{public}d bundle = %{public}d old = %{public}d new = %{public}d.",
276                    accountId, iter.first, oldPriority, bundleInfo->priority_);
277             bundleInfo->IncreaseProcsPriority(bundleInfo->priority_ - oldPriority);
278             OomScoreAdjUtils::WriteOomScoreAdjToKernel(bundleInfo);
279         }
280     }
281     return true;
282 }
283 
HandleOsAccountsChanged(int accountId,AccountSA::OS_ACCOUNT_SWITCH_MOD switchMod,std::map<int,std::shared_ptr<AccountBundleInfo>> & osAccountsInfoMap_)284 bool MultiAccountManager::HandleOsAccountsChanged(int accountId, AccountSA::OS_ACCOUNT_SWITCH_MOD switchMod,
285                                                   std::map<int, std::shared_ptr<AccountBundleInfo>> &osAccountsInfoMap_)
286 {
287     if (!initialized_) {
288         HILOGI("The MultiAccountManager uninitialized.");
289         return false;
290     }
291 
292     std::vector<int> switchedAccountIds;
293     if (!GetSwitchedAccountIds(switchedAccountIds)) {
294         HILOGI("Get switched accountIds failed.");
295         return false;
296     }
297 
298     std::vector<int> updatedAccountIds = switchedAccountIds;
299     updatedAccountIds.push_back(accountId);
300     if (!UpdateAccountPriorityInfo(updatedAccountIds)) {
301         HILOGI("Update account priority information failed.");
302         return false;
303     }
304 
305     switch (switchMod) {
306         case AccountSA::COLD_SWITCH:
307             return HandleAccountColdSwitch(switchedAccountIds, osAccountsInfoMap_);
308         case AccountSA::HOT_SWITCH:
309             return HandleAccountHotSwitch(updatedAccountIds, osAccountsInfoMap_);
310         default:
311             HILOGI("Switch mode incorrect, mode = %{public}d.", static_cast<int>(switchMod));
312             return false;
313     }
314 }
315 } // namespace Memory
316 } // namespace OHOS
317