• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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