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 std::function<void()> initMultiAccountManagerFunc = std::bind(&MultiAccountManager::Init, this);
81 handler_->PostTask(initMultiAccountManagerFunc, SLEEP_TIME, AppExecFwk::EventQueue::Priority::LOW);
82 HILOGE("Manager initial failed, try again after 3s!, retryTimes = %{public}d/10", retryTimes_);
83 }
84 }
85
SetAccountPriority(int accountId,std::string accountName,AccountSA::OsAccountType accountType,bool isActived)86 bool MultiAccountManager::SetAccountPriority(int accountId, std::string accountName,
87 AccountSA::OsAccountType accountType, bool isActived)
88 {
89 std::shared_ptr<AccountPriorityInfo> accountInfo = GetAccountPriorityInfo(accountId);
90 if (accountInfo == nullptr) {
91 MAKE_POINTER(accountInfo, shared, AccountPriorityInfo, "make shared failed", return false,
92 accountId, accountName, accountType, isActived);
93 AddAccountPriorityInfo(accountInfo);
94 } else {
95 accountInfo->SetName(accountName);
96 accountInfo->SetType(accountType);
97 accountInfo->SetIsActived(isActived);
98 }
99
100 if (strategy_ == nullptr) {
101 HILOGI("Set account priority failed, strategy is null.");
102 return false;
103 }
104
105 int oldPriority = accountInfo->GetPriority();
106 if (!strategy_->SetAccountPriority(accountInfo)) {
107 HILOGI("Set account priority failed, accountId = %{public}d.", accountId);
108 return false;
109 }
110
111 HILOGI("Set acccount priority succeed, accountId = %{public}d, old = %{public}d, new = %{public}d.",
112 accountId, oldPriority, accountInfo->GetPriority());
113 ReclaimStrategyManager::GetInstance().NotifyAccountPriorityChanged(accountId, accountInfo->GetPriority());
114 return true;
115 }
116
RecalcBundlePriority(int accountId,int bundlePriority)117 int MultiAccountManager::RecalcBundlePriority(int accountId, int bundlePriority)
118 {
119 std::shared_ptr<AccountPriorityInfo> accountInfo = GetAccountPriorityInfo(accountId);
120 if (accountInfo == nullptr) {
121 HILOGI("Repeat calculate bundle priority failed, account non-exist, accountId = %{public}d.", accountId);
122 return RECLAIM_PRIORITY_MAX;
123 }
124
125 if (strategy_ == nullptr) {
126 HILOGI("Repeat calculate bundle priority failed, strategy is null.");
127 return RECLAIM_PRIORITY_MAX;
128 }
129
130 int recalcPriority = strategy_->RecalcBundlePriority(accountInfo, bundlePriority);
131 if (recalcPriority > RECLAIM_PRIORITY_MAX) {
132 recalcPriority = RECLAIM_PRIORITY_MAX;
133 }
134 if (recalcPriority < RECLAIM_PRIORITY_FOREGROUND) {
135 recalcPriority = RECLAIM_PRIORITY_FOREGROUND;
136 }
137 return recalcPriority;
138 }
139
AddAccountPriorityInfo(std::shared_ptr<AccountPriorityInfo> accountPriorityInfo)140 void MultiAccountManager::AddAccountPriorityInfo(std::shared_ptr<AccountPriorityInfo> accountPriorityInfo)
141 {
142 accountMap_.insert(std::pair<int, std::shared_ptr<AccountPriorityInfo>>(accountPriorityInfo->GetId(),
143 accountPriorityInfo));
144 HILOGI("Add account information succeed, accountId = %{public}d.", accountPriorityInfo->GetId());
145 }
146
GetAccountPriorityInfo(int accountId)147 std::shared_ptr<AccountPriorityInfo> MultiAccountManager::GetAccountPriorityInfo(int accountId)
148 {
149 std::map<int, std::shared_ptr<AccountPriorityInfo>>::iterator iter = accountMap_.find(accountId);
150 if (iter != accountMap_.end()) {
151 return iter->second;
152 }
153 return nullptr;
154 }
155
GetMultiAccountStratgy()156 std::shared_ptr<MultiAccountStrategy> MultiAccountManager::GetMultiAccountStratgy()
157 {
158 return strategy_;
159 }
160
SetMultiAccountStrategy(std::shared_ptr<MultiAccountStrategy> strategy)161 bool MultiAccountManager::SetMultiAccountStrategy(std::shared_ptr<MultiAccountStrategy> strategy)
162 {
163 if (strategy == nullptr) {
164 HILOGI("Set the multiple account strategy failed because the strategy is null.");
165 return false;
166 }
167
168 strategy_ = strategy;
169 return true;
170 }
171
GetSwitchedAccountIds(std::vector<int> & accountIds)172 bool MultiAccountManager::GetSwitchedAccountIds(std::vector<int> &accountIds)
173 {
174 std::vector<int> newActiveAccountIds;
175 ErrCode errCode = AccountSA::OsAccountManager::QueryActiveOsAccountIds(newActiveAccountIds);
176 if (errCode != ERR_OK) {
177 HILOGI("Query active os accountIds failed, err = %{public}d.", static_cast<int>(errCode));
178 return false;
179 }
180
181 for (int oldId : oldActiveAccountIds_) {
182 if (std::find(newActiveAccountIds.begin(), newActiveAccountIds.end(), oldId) == newActiveAccountIds.end()) {
183 accountIds.push_back(oldId);
184 HILOGI("Get the switched account succeed, accountId = %{public}d.", oldId);
185 }
186 }
187
188 oldActiveAccountIds_ = newActiveAccountIds;
189 return true;
190 }
191
UpdateAccountPriorityInfo(std::vector<int> & accountIds)192 bool MultiAccountManager::UpdateAccountPriorityInfo(std::vector<int> &accountIds)
193 {
194 for (int accountId : accountIds) {
195 AccountSA::OsAccountInfo osAccountInfo;
196 ErrCode errCode = AccountSA::OsAccountManager::QueryOsAccountById(accountId, osAccountInfo);
197 if (errCode != ERR_OK) {
198 HILOGI("Get os account failed, accountId = %{public}d, err = %{public}d.",
199 accountId, static_cast<int>(errCode));
200 return false;
201 }
202 if (!SetAccountPriority(accountId, osAccountInfo.GetLocalName(), osAccountInfo.GetType(),
203 osAccountInfo.GetIsActived())) {
204 HILOGI("Set account priority failed, accountId = %{public}d.", accountId);
205 return false;
206 }
207 }
208 return true;
209 }
210
GetAccountBundleInfo(int accountId,std::map<int,std::shared_ptr<AccountBundleInfo>> & osAccountsInfoMap_)211 std::shared_ptr<AccountBundleInfo> MultiAccountManager::GetAccountBundleInfo(int accountId,
212 std::map<int, std::shared_ptr<AccountBundleInfo>> &osAccountsInfoMap_)
213 {
214 std::map<int, std::shared_ptr<AccountBundleInfo>>::iterator iter = osAccountsInfoMap_.find(accountId);
215 if (iter != osAccountsInfoMap_.end()) {
216 return iter->second;
217 }
218 return nullptr;
219 }
220
KillProcessesOfAccount(int accountId,std::map<int,std::shared_ptr<AccountBundleInfo>> & osAccountsInfoMap_)221 void MultiAccountManager::KillProcessesOfAccount(int accountId,
222 std::map<int, std::shared_ptr<AccountBundleInfo>> &osAccountsInfoMap_)
223 {
224 std::shared_ptr<AccountBundleInfo> accountBundleInfo = GetAccountBundleInfo(accountId, osAccountsInfoMap_);
225 if (accountBundleInfo == nullptr) {
226 HILOGI("Kill proccess of the account failed because the account non-exist, accountId = %{public}d.", accountId);
227 return;
228 }
229
230 for (auto iter1 : accountBundleInfo->bundleIdInfoMapping_) {
231 for (auto iter2 : iter1.second->procs_) {
232 pid_t pid = iter2.first;
233 if (!KernelInterface::GetInstance().KillOneProcessByPid(pid)) {
234 HILOGI("Kill the process failed, pid = %{public}d.", pid);
235 continue;
236 }
237 HILOGI("Kill the process succeed, pid = %{public}d.", pid);
238 }
239 }
240 }
241
HandleAccountColdSwitch(std::vector<int> & switchedAccountIds,std::map<int,std::shared_ptr<AccountBundleInfo>> & osAccountsInfoMap_)242 bool MultiAccountManager::HandleAccountColdSwitch(std::vector<int> &switchedAccountIds,
243 std::map<int, std::shared_ptr<AccountBundleInfo>> &osAccountsInfoMap_)
244 {
245 for (int accountId : switchedAccountIds) {
246 HILOGI("Account cold switch account = %{public}d.", accountId);
247 KillProcessesOfAccount(accountId, osAccountsInfoMap_);
248 ReclaimStrategyManager::GetInstance().NotifyAccountDied(accountId);
249 }
250 return true;
251 }
252
HandleAccountHotSwitch(std::vector<int> & updatedAccountIds,std::map<int,std::shared_ptr<AccountBundleInfo>> & osAccountsInfoMap_)253 bool MultiAccountManager::HandleAccountHotSwitch(std::vector<int> &updatedAccountIds,
254 std::map<int, std::shared_ptr<AccountBundleInfo>> &osAccountsInfoMap_)
255 {
256 for (int accountId : updatedAccountIds) {
257 std::shared_ptr<AccountBundleInfo> accountBundleInfo = GetAccountBundleInfo(accountId, osAccountsInfoMap_);
258 if (accountBundleInfo == nullptr) {
259 HILOGI("Search account bundle info failed, accountId = %{public}d.", accountId);
260 continue;
261 }
262
263 if (accountBundleInfo->bundleIdInfoMapping_.empty()) {
264 HILOGI("The bundle list of the account = %{public}d is empty.", accountId);
265 continue;
266 }
267
268 for (auto iter : accountBundleInfo->bundleIdInfoMapping_) {
269 std::shared_ptr<BundlePriorityInfo> bundleInfo = iter.second;
270 int oldPriority = bundleInfo->priority_;
271 bundleInfo->priority_ = RecalcBundlePriority(accountId, oldPriority);
272 HILOGI("account = %{public}d bundle = %{public}d old = %{public}d new = %{public}d.",
273 accountId, iter.first, oldPriority, bundleInfo->priority_);
274 bundleInfo->IncreaseProcsPriority(bundleInfo->priority_ - oldPriority);
275 OomScoreAdjUtils::WriteOomScoreAdjToKernel(bundleInfo);
276 }
277 }
278 return true;
279 }
280
HandleOsAccountsChanged(int accountId,AccountSA::OS_ACCOUNT_SWITCH_MOD switchMod,std::map<int,std::shared_ptr<AccountBundleInfo>> & osAccountsInfoMap_)281 bool MultiAccountManager::HandleOsAccountsChanged(int accountId, AccountSA::OS_ACCOUNT_SWITCH_MOD switchMod,
282 std::map<int, std::shared_ptr<AccountBundleInfo>> &osAccountsInfoMap_)
283 {
284 if (!initialized_) {
285 HILOGI("The MultiAccountManager uninitialized.");
286 return false;
287 }
288
289 std::vector<int> switchedAccountIds;
290 if (!GetSwitchedAccountIds(switchedAccountIds)) {
291 HILOGI("Get switched accountIds failed.");
292 return false;
293 }
294
295 std::vector<int> updatedAccountIds = switchedAccountIds;
296 updatedAccountIds.push_back(accountId);
297 if (!UpdateAccountPriorityInfo(updatedAccountIds)) {
298 HILOGI("Update account priority information failed.");
299 return false;
300 }
301
302 switch (switchMod) {
303 case AccountSA::COLD_SWITCH:
304 return HandleAccountColdSwitch(switchedAccountIds, osAccountsInfoMap_);
305 case AccountSA::HOT_SWITCH:
306 return HandleAccountHotSwitch(updatedAccountIds, osAccountsInfoMap_);
307 default:
308 HILOGI("Switch mode incorrect, mode = %{public}d.", static_cast<int>(switchMod));
309 return false;
310 }
311 }
312 } // namespace Memory
313 } // namespace OHOS
314