1 /*
2 * Copyright (c) 2024 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 "keep_alive_process_manager.h"
17
18 #include <utility>
19
20 #include "ability_util.h"
21 #include "ffrt.h"
22 #include "keep_alive_utils.h"
23 #include "main_element_utils.h"
24 #include "parameters.h"
25 #include "permission_constants.h"
26 #include "process_options.h"
27
28 namespace OHOS {
29 namespace AAFwk {
30 namespace {
31 constexpr char PRODUCT_ENTERPRISE_FEATURE_SETTING_ENABLED[] = "const.product.enterprisefeature.setting.enabled";
32 constexpr char FOUNDATION_PROCESS_NAME[] = "foundation";
33 constexpr int MAX_RETRY_TIMES = 3;
34 constexpr int RETRY_INTERVAL_MICRO_SECONDS = 200000; // 200ms
35 constexpr int CREATE_STATUS_BAR_TIMEOUT_MICRO_SECONDS = 5000000; // 5s
36 } // namespace
37
Cancel()38 void CheckStatusBarTask::Cancel()
39 {
40 std::lock_guard<ffrt::mutex> lock(cancelMutex_);
41 task_ = nullptr;
42 }
43
Run()44 void CheckStatusBarTask::Run()
45 {
46 std::lock_guard<ffrt::mutex> lock(cancelMutex_);
47 if (task_ == nullptr) {
48 TAG_LOGI(AAFwkTag::KEEP_ALIVE, "task is canceled");
49 return;
50 }
51
52 TAG_LOGI(AAFwkTag::KEEP_ALIVE, "run check task");
53 task_();
54 }
55
GetInstance()56 KeepAliveProcessManager &KeepAliveProcessManager::GetInstance()
57 {
58 static KeepAliveProcessManager instance;
59 return instance;
60 }
61
KeepAliveProcessManager()62 KeepAliveProcessManager::KeepAliveProcessManager() {}
63
~KeepAliveProcessManager()64 KeepAliveProcessManager::~KeepAliveProcessManager() {}
65
StartKeepAliveProcessWithMainElement(std::vector<AppExecFwk::BundleInfo> & bundleInfos,int32_t userId)66 void KeepAliveProcessManager::StartKeepAliveProcessWithMainElement(std::vector<AppExecFwk::BundleInfo> &bundleInfos,
67 int32_t userId)
68 {
69 for (const auto &bundleInfo : bundleInfos) {
70 StartKeepAliveProcessWithMainElementPerBundle(bundleInfo, userId);
71 }
72 }
73
StartKeepAliveProcessWithMainElementPerBundle(const AppExecFwk::BundleInfo & bundleInfo,int32_t userId)74 void KeepAliveProcessManager::StartKeepAliveProcessWithMainElementPerBundle(const AppExecFwk::BundleInfo &bundleInfo,
75 int32_t userId)
76 {
77 if (!IsKeepAliveBundle(bundleInfo.name, userId)) {
78 TAG_LOGE(AAFwkTag::KEEP_ALIVE, "bundle is not set keep-alive");
79 return;
80 }
81
82 std::string mainElementName;
83 if (!MainElementUtils::CheckMainUIAbility(bundleInfo, mainElementName)) {
84 TAG_LOGE(AAFwkTag::KEEP_ALIVE, "bundle has no main uiability");
85 return;
86 }
87 KeepAliveAbilityInfo info = {
88 .bundleName = bundleInfo.name,
89 .moduleName = bundleInfo.entryModuleName,
90 .abilityName = mainElementName,
91 .userId = userId,
92 .appCloneIndex = bundleInfo.appIndex,
93 .uid = bundleInfo.uid,
94 };
95 auto isMultiInstance =
96 bundleInfo.applicationInfo.multiAppMode.multiAppModeType == AppExecFwk::MultiAppModeType::MULTI_INSTANCE;
97 auto ret = StartKeepAliveMainAbility(info);
98 if (ret == ERR_OK) {
99 TAG_LOGI(AAFwkTag::KEEP_ALIVE, "start ok");
100 AfterStartKeepAliveApp(bundleInfo.name, bundleInfo.applicationInfo.accessTokenId,
101 bundleInfo.uid, userId, isMultiInstance);
102 return;
103 }
104
105 TAG_LOGE(AAFwkTag::KEEP_ALIVE, "StartKeepAliveMainAbility failed:%{public}d, retry", ret);
106 ffrt::submit([bundleName = bundleInfo.name, accessTokenId = bundleInfo.applicationInfo.accessTokenId,
107 uid = bundleInfo.uid, userId, info, ret, isMultiInstance]() mutable {
108 for (int tried = 0; tried < MAX_RETRY_TIMES && ret != ERR_OK; tried++) {
109 usleep(RETRY_INTERVAL_MICRO_SECONDS);
110 TAG_LOGI(AAFwkTag::KEEP_ALIVE, "retry attempt:%{public}d", tried + 1);
111 ret = KeepAliveProcessManager::GetInstance().StartKeepAliveMainAbility(info);
112 TAG_LOGI(AAFwkTag::KEEP_ALIVE, "retry result:%{public}d", ret);
113 }
114 if (ret != ERR_OK) {
115 TAG_LOGE(AAFwkTag::KEEP_ALIVE, "reach max retry, failed:%{public}d, unsetting keep-alive", ret);
116 KeepAliveProcessManager::GetInstance().SetApplicationKeepAlive(bundleName, userId, false, true, true);
117 return;
118 }
119 KeepAliveProcessManager::GetInstance().AfterStartKeepAliveApp(bundleName, accessTokenId, uid, userId,
120 isMultiInstance);
121 });
122 }
123
StartKeepAliveMainAbility(const KeepAliveAbilityInfo & info)124 int32_t KeepAliveProcessManager::StartKeepAliveMainAbility(const KeepAliveAbilityInfo &info)
125 {
126 Want want;
127 want.SetElementName(info.bundleName, info.abilityName);
128 want.SetParam(Want::PARAM_APP_CLONE_INDEX_KEY, info.appCloneIndex);
129 TAG_LOGI(AAFwkTag::KEEP_ALIVE, "call, bundleName: %{public}s, moduleName: %{public}s, mainElement: %{public}s"
130 " appCloneIndex: %{public}d", info.bundleName.c_str(), info.moduleName.c_str(), info.abilityName.c_str(),
131 info.appCloneIndex);
132 StartOptions options;
133 if (DelayedSingleton<AbilityManagerService>::GetInstance()->IsSupportStatusBar(info.uid)) {
134 options.processOptions = std::make_shared<ProcessOptions>();
135 options.processOptions->isRestartKeepAlive = true;
136 options.processOptions->startupVisibility = StartupVisibility::STARTUP_HIDE;
137 }
138 auto ret = IN_PROCESS_CALL(DelayedSingleton<AbilityManagerService>::GetInstance()->StartAbility(want,
139 options, nullptr, info.userId, DEFAULT_INVAL_VALUE));
140 MainElementUtils::UpdateMainElement(info.bundleName, info.moduleName, info.abilityName, true, info.userId);
141 return ret;
142 }
143
AfterStartKeepAliveApp(const std::string & bundleName,uint32_t accessTokenId,int32_t uid,int32_t userId,bool isMultiInstance)144 void KeepAliveProcessManager::AfterStartKeepAliveApp(const std::string &bundleName,
145 uint32_t accessTokenId, int32_t uid, int32_t userId, bool isMultiInstance)
146 {
147 // not support statusbar and don't need check after 5s
148 if (!DelayedSingleton<AbilityManagerService>::GetInstance()->IsSupportStatusBar(uid)) {
149 TAG_LOGI(AAFwkTag::KEEP_ALIVE, "not support statusBar, don't need check when keep alive");
150 return;
151 }
152
153 auto task = [bundleName, accessTokenId, uid, userId, isMultiInstance]() {
154 bool isStatusBarCreated =
155 DelayedSingleton<AbilityManagerService>::GetInstance()->IsInStatusBar(accessTokenId, uid, isMultiInstance);
156 (void)KeepAliveProcessManager::GetInstance().RemoveCheckStatusBarTask(uid, false);
157 if (isStatusBarCreated) {
158 TAG_LOGI(AAFwkTag::KEEP_ALIVE, "status bar is created");
159 return;
160 }
161 TAG_LOGE(AAFwkTag::KEEP_ALIVE, "timeout, status bar not created, unsetting keep-alive");
162 KeepAliveProcessManager::GetInstance().SetApplicationKeepAlive(bundleName, userId, false, true, true);
163 (void)DelayedSingleton<AppExecFwk::AppMgrClient>::GetInstance()->KillApplication(bundleName);
164 };
165
166 std::lock_guard<ffrt::mutex> lock(checkStatusBarTasksMutex_);
167 auto iter = std::find_if(checkStatusBarTasks_.begin(), checkStatusBarTasks_.end(),
168 [uid](const std::shared_ptr<CheckStatusBarTask> &curTask) {
169 return curTask != nullptr && curTask->GetUid() == uid;
170 });
171 if (iter != checkStatusBarTasks_.end()) {
172 TAG_LOGI(AAFwkTag::KEEP_ALIVE, "exists same task, canceling");
173 if (*iter != nullptr) {
174 (*iter)->Cancel();
175 }
176 checkStatusBarTasks_.erase(iter);
177 }
178 auto checkStatusBarTask = std::make_shared<CheckStatusBarTask>(uid, std::move(task));
179 checkStatusBarTasks_.push_back(checkStatusBarTask);
180 ffrt::task_attr attr;
181 attr.delay(CREATE_STATUS_BAR_TIMEOUT_MICRO_SECONDS);
182 ffrt::submit([checkStatusBarTask]() {
183 if (checkStatusBarTask != nullptr) {
184 checkStatusBarTask->Run();
185 }
186 }, attr);
187 }
188
RemoveCheckStatusBarTask(int32_t uid,bool shouldCancel)189 void KeepAliveProcessManager::RemoveCheckStatusBarTask(int32_t uid, bool shouldCancel)
190 {
191 std::lock_guard<ffrt::mutex> lock(checkStatusBarTasksMutex_);
192 auto iter = std::find_if(checkStatusBarTasks_.begin(), checkStatusBarTasks_.end(),
193 [uid](const std::shared_ptr<CheckStatusBarTask> &curTask) {
194 return curTask != nullptr && curTask->GetUid() == uid;
195 });
196 if (iter == checkStatusBarTasks_.end()) {
197 TAG_LOGI(AAFwkTag::KEEP_ALIVE, "not exist");
198 return;
199 }
200 if (*iter != nullptr && shouldCancel) {
201 (*iter)->Cancel();
202 }
203 checkStatusBarTasks_.erase(iter);
204 }
205
SetApplicationKeepAlive(const std::string & bundleName,int32_t userId,bool updateEnable,bool isByEDM,bool isInner)206 int32_t KeepAliveProcessManager::SetApplicationKeepAlive(const std::string &bundleName,
207 int32_t userId, bool updateEnable, bool isByEDM, bool isInner)
208 {
209 auto result = isByEDM ? CheckPermissionForEDM() : CheckPermission();
210 CHECK_RET_RETURN_RET(result, "permission denied");
211
212 CHECK_TRUE_RETURN_RET(bundleName.empty(), INVALID_PARAMETERS_ERR, "input parameter error");
213
214 auto bms = AbilityUtil::GetBundleManagerHelper();
215 CHECK_POINTER_AND_RETURN(bms, INNER_ERR);
216
217 userId = userId < 0 ? DelayedSingleton<AbilityManagerService>::GetInstance()->GetUserId() : userId;
218 AppExecFwk::BundleInfo bundleInfo;
219 if (!IN_PROCESS_CALL(bms->GetBundleInfo(
220 bundleName, AppExecFwk::BundleFlag::GET_BUNDLE_DEFAULT, bundleInfo, userId))) {
221 TAG_LOGE(AAFwkTag::KEEP_ALIVE, "get bundle info failed");
222 return ERR_TARGET_BUNDLE_NOT_EXIST;
223 }
224
225 auto appMgrClient = DelayedSingleton<AppExecFwk::AppMgrClient>::GetInstance();
226 CHECK_POINTER_AND_RETURN(appMgrClient, INNER_ERR);
227
228 bool localEnable = IsKeepAliveBundle(bundleName, userId);
229 if (updateEnable) {
230 std::string mainElementName;
231 CHECK_TRUE_RETURN_RET(!MainElementUtils::CheckMainUIAbility(bundleInfo, mainElementName),
232 ERR_NO_MAIN_ABILITY, "bundle has no main uiability");
233 if (DelayedSingleton<AbilityManagerService>::GetInstance()->IsSupportStatusBar(bundleInfo.uid)) {
234 CHECK_TRUE_RETURN_RET(!MainElementUtils::CheckStatusBarAbility(bundleInfo),
235 ERR_NO_STATUS_BAR_ABILITY, "app has no status bar");
236 bool isRunning = false;
237 result = IN_PROCESS_CALL(appMgrClient->IsAppRunningByBundleNameAndUserId(bundleName, userId, isRunning));
238 CHECK_RET_RETURN_RET(result, "IsAppRunning failed");
239 CHECK_TRUE_RETURN_RET((isRunning && !IsRunningAppInStatusBar(bundleInfo)),
240 ERR_NOT_ATTACHED_TO_STATUS_BAR, "app is not attached to status bar");
241 }
242 }
243
244 KeepAliveInfo info;
245 info.bundleName = bundleName;
246 info.userId = userId;
247 info.appType = bundleInfo.applicationInfo.isSystemApp ? KeepAliveAppType::SYSTEM : KeepAliveAppType::THIRD_PARTY;
248 info.setter = isByEDM ? KeepAliveSetter::SYSTEM : KeepAliveSetter::USER;
249 result = AbilityKeepAliveService::GetInstance().SetApplicationKeepAlive(info, updateEnable);
250 CHECK_RET_RETURN_RET(result, "set keep-alive failed");
251 IN_PROCESS_CALL_WITHOUT_RET(appMgrClient->SetKeepAliveDkv(bundleName, updateEnable, 0));
252 if (!updateEnable && localEnable) {
253 TAG_LOGI(AAFwkTag::KEEP_ALIVE, "unsetting keep-alive");
254 if (!isInner) {
255 RemoveCheckStatusBarTask(bundleInfo.uid, true);
256 }
257 std::vector<AppExecFwk::BundleInfo> bundleInfos{ bundleInfo };
258 KeepAliveUtils::NotifyDisableKeepAliveProcesses(bundleInfos, userId);
259 }
260 return ERR_OK;
261 }
262
IsRunningAppInStatusBar(const AppExecFwk::BundleInfo & bundleInfo)263 bool KeepAliveProcessManager::IsRunningAppInStatusBar(const AppExecFwk::BundleInfo &bundleInfo)
264 {
265 std::string mainElementName;
266 if (!MainElementUtils::CheckMainUIAbility(bundleInfo, mainElementName)) {
267 TAG_LOGE(AAFwkTag::KEEP_ALIVE, "bundle has no main uiability");
268 return false;
269 }
270 auto isMultiInstance =
271 bundleInfo.applicationInfo.multiAppMode.multiAppModeType == AppExecFwk::MultiAppModeType::MULTI_INSTANCE;
272 return DelayedSingleton<AbilityManagerService>::GetInstance()->IsInStatusBar(
273 bundleInfo.applicationInfo.accessTokenId, bundleInfo.uid, isMultiInstance);
274 }
275
OnAppStateChanged(const AppInfo & info)276 void KeepAliveProcessManager::OnAppStateChanged(const AppInfo &info)
277 {
278 if (info.state != AppState::BEGIN) {
279 TAG_LOGD(AAFwkTag::KEEP_ALIVE, "Not a state of concern. state: %{public}d", info.state);
280 return;
281 }
282
283 if (info.pid <= 0) {
284 TAG_LOGD(AAFwkTag::KEEP_ALIVE, "The obtained application pid is incorrect. state: %{public}d", info.pid);
285 return;
286 }
287
288 // user 0
289 int32_t uid = 0;
290 auto appScheduler = DelayedSingleton<AppScheduler>::GetInstance();
291 if (appScheduler == nullptr) {
292 TAG_LOGE(AAFwkTag::KEEP_ALIVE, "app scheduler error");
293 return;
294 }
295 std::string bundleName;
296 appScheduler->GetBundleNameByPid(info.pid, bundleName, uid);
297 if (bundleName.empty()) {
298 TAG_LOGE(AAFwkTag::KEEP_ALIVE, "get bundle name by pid failed");
299 return;
300 }
301
302 bool localEnable = IsKeepAliveBundle(bundleName, -1);
303 if (!localEnable) {
304 return;
305 }
306
307 auto appMgrClient = DelayedSingleton<AppExecFwk::AppMgrClient>::GetInstance();
308 if (appMgrClient == nullptr) {
309 TAG_LOGE(AAFwkTag::KEEP_ALIVE, "appMgrClient is null");
310 return;
311 }
312 IN_PROCESS_CALL_WITHOUT_RET(appMgrClient->SetKeepAliveDkv(bundleName, localEnable, uid));
313 }
314
IsKeepAliveBundle(const std::string & bundleName,int32_t userId)315 bool KeepAliveProcessManager::IsKeepAliveBundle(const std::string &bundleName, int32_t userId)
316 {
317 if (!system::GetBoolParameter(PRODUCT_ENTERPRISE_FEATURE_SETTING_ENABLED, false)) {
318 TAG_LOGI(AAFwkTag::KEEP_ALIVE, "not supported");
319 return false;
320 }
321 return AbilityKeepAliveService::GetInstance().IsKeepAliveApp(bundleName, userId);
322 }
323
GetKeepAliveBundleInfosForUser(std::vector<AppExecFwk::BundleInfo> & bundleInfos,int32_t userId)324 bool KeepAliveProcessManager::GetKeepAliveBundleInfosForUser(std::vector<AppExecFwk::BundleInfo> &bundleInfos,
325 int32_t userId)
326 {
327 if (!system::GetBoolParameter(PRODUCT_ENTERPRISE_FEATURE_SETTING_ENABLED, false)) {
328 TAG_LOGW(AAFwkTag::KEEP_ALIVE, "not supported");
329 return false;
330 }
331 auto bundleMgrHelper = DelayedSingleton<AppExecFwk::BundleMgrHelper>::GetInstance();
332 CHECK_POINTER_AND_RETURN(bundleMgrHelper, false);
333
334 std::vector<KeepAliveInfo> infoList;
335 auto ret = AbilityKeepAliveService::GetInstance().GetKeepAliveApplications(userId, infoList);
336 if (ret != ERR_OK) {
337 TAG_LOGE(AAFwkTag::KEEP_ALIVE, "failed get keep_alive bundle info: %{public}d", ret);
338 return false;
339 }
340 for (const auto &info: infoList) {
341 AppExecFwk::BundleInfo bundleInfo;
342 if (!IN_PROCESS_CALL(bundleMgrHelper->GetBundleInfo(info.bundleName,
343 AppExecFwk::BundleFlag::GET_BUNDLE_WITH_ABILITIES, bundleInfo, userId))) {
344 TAG_LOGW(AAFwkTag::KEEP_ALIVE, "failed get bundle info: %{public}s", info.bundleName.c_str());
345 continue;
346 }
347 bundleInfos.push_back(bundleInfo);
348 }
349
350 return !bundleInfos.empty();
351 }
352
QueryKeepAliveApplications(int32_t appType,int32_t userId,std::vector<KeepAliveInfo> & infoList,bool isByEDM)353 int32_t KeepAliveProcessManager::QueryKeepAliveApplications(int32_t appType, int32_t userId,
354 std::vector<KeepAliveInfo> &infoList, bool isByEDM)
355 {
356 auto result = isByEDM ? CheckPermissionForEDM() : CheckPermission();
357 CHECK_RET_RETURN_RET(result, "permission denied");
358 return AbilityKeepAliveService::GetInstance().QueryKeepAliveApplications(userId, appType, infoList);
359 }
360
CheckPermission()361 int32_t KeepAliveProcessManager::CheckPermission()
362 {
363 if (!system::GetBoolParameter(PRODUCT_ENTERPRISE_FEATURE_SETTING_ENABLED, false)) {
364 TAG_LOGE(AAFwkTag::KEEP_ALIVE, "not supported");
365 return ERR_CAPABILITY_NOT_SUPPORT;
366 }
367
368 if (!PermissionVerification::GetInstance()->JudgeCallerIsAllowedToUseSystemAPI()) {
369 TAG_LOGE(AAFwkTag::KEEP_ALIVE, "not use system-api");
370 return ERR_NOT_SYSTEM_APP;
371 }
372
373 if (!PermissionVerification::GetInstance()->VerifyCallingPermission(
374 PermissionConstants::PERMISSION_MANAGE_APP_KEEP_ALIVE)) {
375 TAG_LOGE(AAFwkTag::KEEP_ALIVE, "verify PERMISSION_MANAGE_APP_KEEP_ALIVE fail");
376 return CHECK_PERMISSION_FAILED;
377 }
378
379 return ERR_OK;
380 }
381
CheckPermissionForEDM()382 int32_t KeepAliveProcessManager::CheckPermissionForEDM()
383 {
384 if (!system::GetBoolParameter(PRODUCT_ENTERPRISE_FEATURE_SETTING_ENABLED, false)) {
385 TAG_LOGE(AAFwkTag::KEEP_ALIVE, "not supported");
386 return ERR_CAPABILITY_NOT_SUPPORT;
387 }
388 if (PermissionVerification::GetInstance()->CheckSpecificSystemAbilityAccessPermission(FOUNDATION_PROCESS_NAME)
389 || (PermissionVerification::GetInstance()->IsSACall()
390 && PermissionVerification::GetInstance()->VerifyCallingPermission(
391 PermissionConstants::PERMISSION_MANAGE_APP_KEEP_ALIVE_INTERNAL))) {
392 return ERR_OK;
393 }
394 TAG_LOGE(AAFwkTag::KEEP_ALIVE, "verify PERMISSION_MANAGE_APP_KEEP_ALIVE_INTERNAL fail");
395 return CHECK_PERMISSION_FAILED;
396 }
397 } // namespace AAFwk
398 } // namespace OHOS
399