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