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 "interceptor/ability_jump_interceptor.h"
17 
18 #include "ability_util.h"
19 #include "accesstoken_kit.h"
20 #include "hitrace_meter.h"
21 #include "permission_constants.h"
22 #include "start_ability_utils.h"
23 #include "system_dialog_scheduler.h"
24 
25 namespace OHOS {
26 namespace AAFwk {
27 namespace {
28 constexpr const char* JUMP_DIALOG_CALLER_BUNDLE_NAME = "interceptor_callerBundleName";
29 constexpr const char* JUMP_DIALOG_CALLER_MODULE_NAME = "interceptor_callerModuleName";
30 constexpr const char* JUMP_DIALOG_CALLER_LABEL_ID = "interceptor_callerLabelId";
31 constexpr const char* JUMP_DIALOG_TARGET_MODULE_NAME = "interceptor_targetModuleName";
32 constexpr const char* JUMP_DIALOG_TARGET_LABEL_ID = "interceptor_targetLabelId";
33 }
DoProcess(AbilityInterceptorParam param)34 ErrCode AbilityJumpInterceptor::DoProcess(AbilityInterceptorParam param)
35 {
36     if (!param.isWithUI) {
37         TAG_LOGI(AAFwkTag::ABILITYMGR, "This startup is not foreground, keep going.");
38         return ERR_OK;
39     }
40     bool isStartIncludeAtomicService = AbilityUtil::IsStartIncludeAtomicService(param.want, param.userId);
41     if (isStartIncludeAtomicService) {
42         TAG_LOGI(AAFwkTag::ABILITYMGR, "This startup contain atomic service, keep going.");
43         return ERR_OK;
44     }
45     // get bms
46     auto bundleMgrHelper = AbilityUtil::GetBundleManagerHelper();
47     if (bundleMgrHelper == nullptr) {
48         TAG_LOGE(AAFwkTag::ABILITYMGR, "The bundleMgrHelper is nullptr.");
49         return ERR_OK;
50     }
51     AppExecFwk::AbilityInfo targetAbilityInfo;
52     if (StartAbilityUtils::startAbilityInfo != nullptr &&
53         StartAbilityUtils::startAbilityInfo->abilityInfo.bundleName == param.want.GetBundle() &&
54         StartAbilityUtils::startAbilityInfo->abilityInfo.name == param.want.GetElement().GetAbilityName()) {
55         targetAbilityInfo = StartAbilityUtils::startAbilityInfo->abilityInfo;
56     } else {
57         IN_PROCESS_CALL_WITHOUT_RET(bundleMgrHelper->QueryAbilityInfo(param.want,
58             AppExecFwk::AbilityInfoFlag::GET_ABILITY_INFO_WITH_APPLICATION, param.userId, targetAbilityInfo));
59     }
60     if (targetAbilityInfo.type != AppExecFwk::AbilityType::PAGE) {
61         TAG_LOGI(AAFwkTag::ABILITYMGR,
62             "Target is not page Ability, keep going, abilityType:%{public}d.", targetAbilityInfo.type);
63         return ERR_OK;
64     }
65     AppExecFwk::AppJumpControlRule controlRule;
66     if (CheckControl(bundleMgrHelper, param.want, param.userId, controlRule)) {
67 #ifdef SUPPORT_GRAPHICS
68         TAG_LOGI(AAFwkTag::ABILITYMGR, "app jump need to be intercepted, caller:%{public}s, target:%{public}s",
69             controlRule.callerPkg.c_str(), controlRule.targetPkg.c_str());
70         auto sysDialogScheduler = DelayedSingleton<SystemDialogScheduler>::GetInstance();
71         Want targetWant = param.want;
72         Want dialogWant = sysDialogScheduler->GetJumpInterceptorDialogWant(targetWant);
73         AbilityUtil::ParseJumpInterceptorWant(dialogWant, controlRule.callerPkg);
74         LoadAppLabelInfo(dialogWant, controlRule, param.userId);
75         int ret = IN_PROCESS_CALL(AbilityManagerClient::GetInstance()->StartAbility(dialogWant,
76             param.requestCode, param.userId));
77         if (ret != ERR_OK) {
78             TAG_LOGI(AAFwkTag::ABILITYMGR, "appInterceptor Dialog StartAbility error, ret:%{public}d", ret);
79             return ret;
80         }
81 #endif
82         return ERR_APP_JUMP_INTERCEPTOR_STATUS;
83     }
84     return ERR_OK;
85 }
86 
CheckControl(std::shared_ptr<AppExecFwk::BundleMgrHelper> & bundleMgrHelper,const Want & want,int32_t userId,AppExecFwk::AppJumpControlRule & controlRule)87 bool AbilityJumpInterceptor::CheckControl(std::shared_ptr<AppExecFwk::BundleMgrHelper> &bundleMgrHelper,
88     const Want &want, int32_t userId, AppExecFwk::AppJumpControlRule &controlRule)
89 {
90     HITRACE_METER_NAME(HITRACE_TAG_ABILITY_MANAGER, __PRETTY_FUNCTION__);
91     int callerUid = IPCSkeleton::GetCallingUid();
92     std::string callerBundleName;
93     auto result = IN_PROCESS_CALL(bundleMgrHelper->GetNameForUid(callerUid, callerBundleName));
94     std::string targetBundleName = want.GetBundle();
95     controlRule.callerPkg = callerBundleName;
96     controlRule.targetPkg = targetBundleName;
97     if (result != ERR_OK) {
98         TAG_LOGE(AAFwkTag::ABILITYMGR, "GetBundleName from bms fail.");
99         return false;
100     }
101     if (controlRule.callerPkg.empty() || controlRule.targetPkg.empty()) {
102         TAG_LOGI(AAFwkTag::ABILITYMGR, "This startup is not explicitly, keep going.");
103         return false;
104     }
105     if (controlRule.callerPkg == controlRule.targetPkg) {
106         TAG_LOGI(AAFwkTag::ABILITYMGR, "Jump within the same app.");
107         return false;
108     }
109     if (CheckIfJumpExempt(controlRule, userId)) {
110         TAG_LOGI(AAFwkTag::ABILITYMGR, "Jump from or to system or exempt apps.");
111         return false;
112     }
113     // get disposed status
114     auto appControlMgr = bundleMgrHelper->GetAppControlProxy();
115     if (appControlMgr == nullptr) {
116         TAG_LOGE(AAFwkTag::ABILITYMGR, "Get appControlMgr failed.");
117         return false;
118     }
119 
120     if (IN_PROCESS_CALL(appControlMgr->GetAppJumpControlRule(callerBundleName, targetBundleName,
121         userId, controlRule)) != ERR_OK) {
122         TAG_LOGI(AAFwkTag::ABILITYMGR, "No jump control rule found.");
123         return true;
124     }
125     TAG_LOGI(AAFwkTag::ABILITYMGR, "Get appJumpControlRule, jumpMode:%d.", controlRule.jumpMode);
126     return controlRule.jumpMode != AppExecFwk::AbilityJumpMode::DIRECT;
127 }
128 
CheckIfJumpExempt(AppExecFwk::AppJumpControlRule & controlRule,int32_t userId)129 bool AbilityJumpInterceptor::CheckIfJumpExempt(AppExecFwk::AppJumpControlRule &controlRule, int32_t userId)
130 {
131     if (CheckIfExemptByBundleName(controlRule.callerPkg,
132         PermissionConstants::PERMISSION_EXEMPT_AS_CALLER, userId)) {
133         TAG_LOGI(AAFwkTag::ABILITYMGR, "Jump from exempt caller app, No need to intercept.");
134         return true;
135     }
136     if (CheckIfExemptByBundleName(controlRule.targetPkg,
137         PermissionConstants::PERMISSION_EXEMPT_AS_TARGET, userId)) {
138         TAG_LOGI(AAFwkTag::ABILITYMGR, "Jump to exempt target app, No need to intercept.");
139         return true;
140     }
141     TAG_LOGI(AAFwkTag::ABILITYMGR, "Third-party apps jump to third-party apps.");
142     return false;
143 }
144 
CheckIfExemptByBundleName(const std::string & bundleName,const std::string & permission,int32_t userId)145 bool AbilityJumpInterceptor::CheckIfExemptByBundleName(const std::string &bundleName,
146     const std::string &permission, int32_t userId)
147 {
148     HITRACE_METER_NAME(HITRACE_TAG_ABILITY_MANAGER, __PRETTY_FUNCTION__);
149     AppExecFwk::ApplicationInfo appInfo;
150     if (!StartAbilityUtils::GetApplicationInfo(bundleName, userId, appInfo)) {
151         TAG_LOGE(AAFwkTag::ABILITYMGR, "failed to get application info.");
152         return false;
153     }
154 
155     if (appInfo.isSystemApp) {
156         TAG_LOGI(AAFwkTag::ABILITYMGR, "Bundle:%{public}s is system app.", bundleName.c_str());
157         return true;
158     }
159     int32_t ret = Security::AccessToken::AccessTokenKit::VerifyAccessToken(appInfo.accessTokenId, permission, false);
160     if (ret == Security::AccessToken::PermissionState::PERMISSION_DENIED) {
161         TAG_LOGD(AAFwkTag::ABILITYMGR, "VerifyPermission %{public}d: PERMISSION_DENIED.", appInfo.accessTokenId);
162         return false;
163     }
164     TAG_LOGI(AAFwkTag::ABILITYMGR,
165         "Bundle:%{public}s verify permission:%{public}s successed.", bundleName.c_str(), permission.c_str());
166     return true;
167 }
168 
LoadAppLabelInfo(Want & want,AppExecFwk::AppJumpControlRule & controlRule,int32_t userId)169 bool AbilityJumpInterceptor::LoadAppLabelInfo(Want &want,
170     AppExecFwk::AppJumpControlRule &controlRule, int32_t userId)
171 {
172     HITRACE_METER_NAME(HITRACE_TAG_ABILITY_MANAGER, __PRETTY_FUNCTION__);
173     AppExecFwk::ApplicationInfo callerAppInfo;
174     StartAbilityUtils::GetApplicationInfo(controlRule.callerPkg, userId, callerAppInfo);
175     AppExecFwk::ApplicationInfo targetAppInfo;
176     StartAbilityUtils::GetApplicationInfo(controlRule.targetPkg, userId, callerAppInfo);
177     want.SetParam(JUMP_DIALOG_CALLER_BUNDLE_NAME, controlRule.callerPkg);
178     want.SetParam(JUMP_DIALOG_CALLER_MODULE_NAME, callerAppInfo.labelResource.moduleName);
179     want.SetParam(JUMP_DIALOG_CALLER_LABEL_ID, static_cast<long long>(callerAppInfo.labelId));
180     want.SetParam(JUMP_DIALOG_TARGET_MODULE_NAME, targetAppInfo.labelResource.moduleName);
181     want.SetParam(JUMP_DIALOG_TARGET_LABEL_ID, static_cast<long long>(targetAppInfo.labelId));
182     return true;
183 }
184 } // namespace AAFwk
185 } // namespace OHOS