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 "ability_interceptor.h"
17
18 #include <chrono>
19
20 #include "ability_info.h"
21 #include "ability_manager_errors.h"
22 #include "accesstoken_kit.h"
23 #include "app_jump_control_rule.h"
24 #include "app_running_control_rule_result.h"
25 #include "bundlemgr/bundle_mgr_interface.h"
26 #include "bundle_constants.h"
27 #ifndef SUPPORT_ERMS
28 #include "erms_mgr_interface.h"
29 #include "erms_mgr_param.h"
30 #endif
31 #include "hilog_wrapper.h"
32 #include "in_process_call_wrapper.h"
33 #include "ipc_skeleton.h"
34 #include "permission_constants.h"
35 #include "permission_verification.h"
36 #include "system_dialog_scheduler.h"
37 #include "want.h"
38 namespace OHOS {
39 namespace AAFwk {
40 #ifdef SUPPORT_ERMS
41 using namespace OHOS::EcologicalRuleMgrService;
42
43 constexpr int32_t TYPE_HARMONY_INVALID = 0;
44 constexpr int32_t TYPE_HARMONY_APP = 1;
45 constexpr int32_t TYPE_HARMONY_SERVICE = 2;
46 #else
47 using ErmsCallerInfo = OHOS::AppExecFwk::ErmsParams::CallerInfo;
48 using ExperienceRule = OHOS::AppExecFwk::ErmsParams::ExperienceRule;
49 #endif
50
51 const std::string ACTION_MARKET_CROWDTEST = "ohos.want.action.marketCrowdTest";
52 const std::string ACTION_MARKET_DISPOSED = "ohos.want.action.marketDisposed";
53 const std::string PERMISSION_MANAGE_DISPOSED_APP_STATUS = "ohos.permission.MANAGE_DISPOSED_APP_STATUS";
54 const std::string JUMP_DIALOG_CALLER_BUNDLE_NAME = "interceptor_callerBundleName";
55 const std::string JUMP_DIALOG_CALLER_MODULE_NAME = "interceptor_callerModuleName";
56 const std::string JUMP_DIALOG_CALLER_LABEL_ID = "interceptor_callerLabelId";
57 const std::string JUMP_DIALOG_TARGET_MODULE_NAME = "interceptor_targetModuleName";
58 const std::string JUMP_DIALOG_TARGET_LABEL_ID = "interceptor_targetLabelId";
59
~AbilityInterceptor()60 AbilityInterceptor::~AbilityInterceptor()
61 {}
62
CrowdTestInterceptor()63 CrowdTestInterceptor::CrowdTestInterceptor()
64 {}
65
~CrowdTestInterceptor()66 CrowdTestInterceptor::~CrowdTestInterceptor()
67 {}
68
DoProcess(const Want & want,int requestCode,int32_t userId,bool isForeground)69 ErrCode CrowdTestInterceptor::DoProcess(const Want &want, int requestCode, int32_t userId, bool isForeground)
70 {
71 if (CheckCrowdtest(want, userId)) {
72 HILOG_ERROR("Crowdtest expired.");
73 #ifdef SUPPORT_GRAPHICS
74 if (isForeground) {
75 int ret = IN_PROCESS_CALL(AbilityUtil::StartAppgallery(requestCode, userId, ACTION_MARKET_CROWDTEST));
76 if (ret != ERR_OK) {
77 HILOG_ERROR("Crowdtest implicit start appgallery failed.");
78 return ret;
79 }
80 }
81 #endif
82 return ERR_CROWDTEST_EXPIRED;
83 }
84 return ERR_OK;
85 }
86
CheckCrowdtest(const Want & want,int32_t userId)87 bool CrowdTestInterceptor::CheckCrowdtest(const Want &want, int32_t userId)
88 {
89 // get bms
90 auto bms = AbilityUtil::GetBundleManager();
91 if (!bms) {
92 HILOG_ERROR("GetBundleManager failed");
93 return false;
94 }
95
96 // get crowdtest status and time
97 std::string bundleName = want.GetBundle();
98 AppExecFwk::ApplicationInfo callerAppInfo;
99 bool result = IN_PROCESS_CALL(
100 bms->GetApplicationInfo(bundleName, AppExecFwk::ApplicationFlag::GET_BASIC_APPLICATION_INFO,
101 userId, callerAppInfo)
102 );
103 if (!result) {
104 HILOG_ERROR("GetApplicaionInfo from bms failed.");
105 return false;
106 }
107
108 auto appDistributionType = callerAppInfo.appDistributionType;
109 auto appCrowdtestDeadline = callerAppInfo.crowdtestDeadline;
110 int64_t now = std::chrono::duration_cast<std::chrono::seconds>(std::chrono::
111 system_clock::now().time_since_epoch()).count();
112 if (appDistributionType == AppExecFwk::Constants::APP_DISTRIBUTION_TYPE_CROWDTESTING &&
113 appCrowdtestDeadline < now) {
114 HILOG_INFO("The application is expired, expired time is %{public}s",
115 std::to_string(appCrowdtestDeadline).c_str());
116 return true;
117 }
118 return false;
119 }
120
ControlInterceptor()121 ControlInterceptor::ControlInterceptor()
122 {}
123
~ControlInterceptor()124 ControlInterceptor::~ControlInterceptor()
125 {}
126
DoProcess(const Want & want,int requestCode,int32_t userId,bool isForeground)127 ErrCode ControlInterceptor::DoProcess(const Want &want, int requestCode, int32_t userId, bool isForeground)
128 {
129 AppExecFwk::AppRunningControlRuleResult controlRule;
130 if (CheckControl(want, userId, controlRule)) {
131 HILOG_INFO("The target application is intercpted. %{public}s", controlRule.controlMessage.c_str());
132 #ifdef SUPPORT_GRAPHICS
133 if (isForeground && controlRule.controlWant != nullptr) {
134 int ret = IN_PROCESS_CALL(AbilityManagerClient::GetInstance()->StartAbility(*controlRule.controlWant,
135 userId, requestCode));
136 if (ret != ERR_OK) {
137 HILOG_ERROR("Control implicit start appgallery failed.");
138 return ret;
139 }
140 }
141 #endif
142 if (controlRule.isEdm) {
143 return ERR_EDM_APP_CONTROLLED;
144 }
145 return ERR_APP_CONTROLLED;
146 }
147 return ERR_OK;
148 }
149
CheckControl(const Want & want,int32_t userId,AppExecFwk::AppRunningControlRuleResult & controlRule)150 bool ControlInterceptor::CheckControl(const Want &want, int32_t userId,
151 AppExecFwk::AppRunningControlRuleResult &controlRule)
152 {
153 // get bms
154 auto bms = AbilityUtil::GetBundleManager();
155 if (!bms) {
156 HILOG_ERROR("GetBundleManager failed");
157 return false;
158 }
159
160 // get disposed status
161 std::string bundleName = want.GetBundle();
162 auto appControlMgr = bms->GetAppControlProxy();
163 if (appControlMgr == nullptr) {
164 HILOG_ERROR("Get appControlMgr failed");
165 return false;
166 }
167
168 auto ret = IN_PROCESS_CALL(appControlMgr->GetAppRunningControlRule(bundleName, userId, controlRule));
169 if (ret != ERR_OK) {
170 HILOG_DEBUG("Get No AppRunningControlRule");
171 return false;
172 }
173 return true;
174 }
175
EcologicalRuleInterceptor()176 EcologicalRuleInterceptor::EcologicalRuleInterceptor()
177 {}
178
~EcologicalRuleInterceptor()179 EcologicalRuleInterceptor::~EcologicalRuleInterceptor()
180 {}
181
DoProcess(const Want & want,int requestCode,int32_t userId,bool isForeground)182 ErrCode EcologicalRuleInterceptor::DoProcess(const Want &want, int requestCode, int32_t userId, bool isForeground)
183 {
184 bool isStartIncludeAtomicService = AbilityUtil::IsStartIncludeAtomicService(want, userId);
185 if (!isStartIncludeAtomicService) {
186 HILOG_DEBUG("This startup does not contain atomic service, keep going.");
187 return ERR_OK;
188 }
189
190 ErmsCallerInfo callerInfo;
191 ExperienceRule rule;
192 #ifdef SUPPORT_ERMS
193 GetEcologicalCallerInfo(want, callerInfo, userId);
194 int ret = IN_PROCESS_CALL(EcologicalRuleMgrServiceClient::GetInstance()->QueryStartExperience(want,
195 callerInfo, rule));
196 #else
197 int ret = CheckRule(want, callerInfo, rule);
198 #endif
199 if (!ret) {
200 HILOG_ERROR("check ecological rule failed, keep going.");
201 return ERR_OK;
202 }
203
204 HILOG_DEBUG("check ecological rule success");
205 if (rule.isAllow) {
206 HILOG_ERROR("ecological rule is allow, keep going.");
207 return ERR_OK;
208 }
209 #ifdef SUPPORT_GRAPHICS
210 if (isForeground && (rule.replaceWant != nullptr)) {
211 int ret = IN_PROCESS_CALL(AbilityManagerClient::GetInstance()->StartAbility(*rule.replaceWant,
212 userId, requestCode));
213 if (ret != ERR_OK) {
214 HILOG_ERROR("ecological start replace want failed.");
215 return ret;
216 }
217 }
218 #endif
219 return ERR_ECOLOGICAL_CONTROL_STATUS;
220 }
221
222 #ifdef SUPPORT_ERMS
GetEcologicalCallerInfo(const Want & want,ErmsCallerInfo & callerInfo,int32_t userId)223 void EcologicalRuleInterceptor::GetEcologicalCallerInfo(const Want &want, ErmsCallerInfo &callerInfo, int32_t userId)
224 {
225 callerInfo.packageName = want.GetStringParam(Want::PARAM_RESV_CALLER_BUNDLE_NAME);
226 callerInfo.uid = want.GetIntParam(Want::PARAM_RESV_CALLER_UID, IPCSkeleton::GetCallingUid());
227 callerInfo.pid = want.GetIntParam(Want::PARAM_RESV_CALLER_PID, IPCSkeleton::GetCallingPid());
228 callerInfo.targetAppType = TYPE_HARMONY_INVALID;
229 callerInfo.callerAppType = TYPE_HARMONY_INVALID;
230
231 auto bms = AbilityUtil::GetBundleManager();
232 if (!bms) {
233 HILOG_ERROR("GetBundleManager failed");
234 return;
235 }
236
237 std::string targetBundleName = want.GetBundle();
238 AppExecFwk::ApplicationInfo targetAppInfo;
239 bool getTargetResult = IN_PROCESS_CALL(bms->GetApplicationInfo(targetBundleName,
240 AppExecFwk::ApplicationFlag::GET_BASIC_APPLICATION_INFO, userId, targetAppInfo));
241 if (!getTargetResult) {
242 HILOG_ERROR("Get targetAppInfo failed.");
243 } else if (targetAppInfo.bundleType == AppExecFwk::BundleType::ATOMIC_SERVICE) {
244 HILOG_DEBUG("the target type is atomic service");
245 callerInfo.targetAppType = TYPE_HARMONY_SERVICE;
246 } else if (targetAppInfo.bundleType == AppExecFwk::BundleType::APP) {
247 HILOG_DEBUG("the target type is app");
248 callerInfo.targetAppType = TYPE_HARMONY_APP;
249 } else {
250 HILOG_DEBUG("the target type is invalid type");
251 }
252
253 std::string callerBundleName;
254 ErrCode err = IN_PROCESS_CALL(bms->GetNameForUid(callerInfo.uid, callerBundleName));
255 if (err != ERR_OK) {
256 HILOG_ERROR("Get callerBundleName failed.");
257 return;
258 }
259 AppExecFwk::ApplicationInfo callerAppInfo;
260 bool getCallerResult = IN_PROCESS_CALL(bms->GetApplicationInfo(callerBundleName,
261 AppExecFwk::ApplicationFlag::GET_BASIC_APPLICATION_INFO, userId, callerAppInfo));
262 if (!getCallerResult) {
263 HILOG_DEBUG("Get callerAppInfo failed.");
264 } else if (callerAppInfo.bundleType == AppExecFwk::BundleType::ATOMIC_SERVICE) {
265 HILOG_DEBUG("the caller type is atomic service");
266 callerInfo.callerAppType = TYPE_HARMONY_SERVICE;
267 } else if (callerAppInfo.bundleType == AppExecFwk::BundleType::APP) {
268 HILOG_DEBUG("the caller type is app");
269 callerInfo.callerAppType = TYPE_HARMONY_APP;
270 } else {
271 HILOG_DEBUG("the caller type is invalid type");
272 }
273 }
274 #else
CheckRule(const Want & want,ErmsCallerInfo & callerInfo,ExperienceRule & rule)275 bool EcologicalRuleInterceptor::CheckRule(const Want &want, ErmsCallerInfo &callerInfo, ExperienceRule &rule)
276 {
277 HILOG_DEBUG("Enter Erms CheckRule.");
278 auto erms = AbilityUtil::CheckEcologicalRuleMgr();
279 if (!erms) {
280 HILOG_ERROR("CheckEcologicalRuleMgr failed.");
281 return false;
282 }
283 int ret = IN_PROCESS_CALL(erms->QueryStartExperience(want, callerInfo, rule));
284 if (ret != ERR_OK) {
285 HILOG_ERROR("Failed to query start experience from erms.");
286 return false;
287 }
288
289 return true;
290 }
291 #endif
292
AbilityJumpInterceptor()293 AbilityJumpInterceptor::AbilityJumpInterceptor()
294 {}
295
~AbilityJumpInterceptor()296 AbilityJumpInterceptor::~AbilityJumpInterceptor()
297 {}
298
DoProcess(const Want & want,int requestCode,int32_t userId,bool isForeground)299 ErrCode AbilityJumpInterceptor::DoProcess(const Want &want, int requestCode, int32_t userId, bool isForeground)
300 {
301 if (!isForeground) {
302 HILOG_INFO("This startup is not foreground, keep going.");
303 return ERR_OK;
304 }
305 bool isStartIncludeAtomicService = AbilityUtil::IsStartIncludeAtomicService(want, userId);
306 if (isStartIncludeAtomicService) {
307 HILOG_INFO("This startup contain atomic service, keep going.");
308 return ERR_OK;
309 }
310 // get bms
311 auto bms = AbilityUtil::GetBundleManager();
312 if (!bms) {
313 HILOG_ERROR("GetBundleManager failed");
314 return ERR_OK;
315 }
316 AppExecFwk::AbilityInfo targetAbilityInfo;
317 IN_PROCESS_CALL_WITHOUT_RET(bms->QueryAbilityInfo(want,
318 AppExecFwk::AbilityInfoFlag::GET_ABILITY_INFO_WITH_APPLICATION, userId, targetAbilityInfo));
319 if (targetAbilityInfo.type != AppExecFwk::AbilityType::PAGE) {
320 HILOG_INFO("Target is not page Ability, keep going, abilityType:%{public}d", targetAbilityInfo.type);
321 return ERR_OK;
322 }
323 AppExecFwk::AppJumpControlRule controlRule;
324 if (CheckControl(bms, want, userId, controlRule)) {
325 #ifdef SUPPORT_GRAPHICS
326 HILOG_INFO("app jump need to be intercepted, caller:%{public}s, target:%{public}s",
327 controlRule.callerPkg.c_str(), controlRule.targetPkg.c_str());
328 auto sysDialogScheduler = DelayedSingleton<SystemDialogScheduler>::GetInstance();
329 Want targetWant = want;
330 Want dialogWant = sysDialogScheduler->GetJumpInterceptorDialogWant(targetWant);
331 AbilityUtil::ParseJumpInterceptorWant(dialogWant, controlRule.callerPkg);
332 LoadAppLabelInfo(bms, dialogWant, controlRule, userId);
333 int ret = IN_PROCESS_CALL(AbilityManagerClient::GetInstance()->StartAbility(dialogWant,
334 userId, requestCode));
335 if (ret != ERR_OK) {
336 HILOG_INFO("AppInterceptor Dialog StartAbility error, ret:%{public}d", ret);
337 return ret;
338 }
339 #endif
340 return ERR_APP_JUMP_INTERCEPTOR_STATUS;
341 }
342 return ERR_OK;
343 }
344
CheckControl(sptr<AppExecFwk::IBundleMgr> & bms,const Want & want,int32_t userId,AppExecFwk::AppJumpControlRule & controlRule)345 bool AbilityJumpInterceptor::CheckControl(sptr<AppExecFwk::IBundleMgr> &bms, const Want &want, int32_t userId,
346 AppExecFwk::AppJumpControlRule &controlRule)
347 {
348 int callerUid = IPCSkeleton::GetCallingUid();
349 std::string callerBundleName;
350 auto result = IN_PROCESS_CALL(bms->GetNameForUid(callerUid, callerBundleName));
351 std::string targetBundleName = want.GetBundle();
352 controlRule.callerPkg = callerBundleName;
353 controlRule.targetPkg = targetBundleName;
354 if (result != ERR_OK) {
355 HILOG_ERROR("GetBundleName from bms fail.");
356 return false;
357 }
358 if (controlRule.callerPkg.empty() || controlRule.targetPkg.empty()) {
359 HILOG_INFO("This startup is not explicitly, keep going.");
360 return false;
361 }
362 if (controlRule.callerPkg == controlRule.targetPkg) {
363 HILOG_INFO("jump within the same app.");
364 return false;
365 }
366 if (CheckIfJumpExempt(bms, controlRule, userId)) {
367 HILOG_INFO("jump from or to system or exempt apps");
368 return false;
369 }
370 // get disposed status
371 auto appControlMgr = bms->GetAppControlProxy();
372 if (appControlMgr == nullptr) {
373 HILOG_ERROR("Get appControlMgr failed");
374 return false;
375 }
376
377 if (IN_PROCESS_CALL(appControlMgr->GetAppJumpControlRule(callerBundleName, targetBundleName,
378 userId, controlRule)) != ERR_OK) {
379 HILOG_INFO("no jump control rule found");
380 return true;
381 }
382 HILOG_INFO("get appJumpControlRule, jumpMode:%d", controlRule.jumpMode);
383 return controlRule.jumpMode != AppExecFwk::AbilityJumpMode::DIRECT;
384 }
385
CheckIfJumpExempt(sptr<AppExecFwk::IBundleMgr> & bms,AppExecFwk::AppJumpControlRule & controlRule,int32_t userId)386 bool AbilityJumpInterceptor::CheckIfJumpExempt(sptr<AppExecFwk::IBundleMgr> &bms,
387 AppExecFwk::AppJumpControlRule &controlRule, int32_t userId)
388 {
389 if (CheckIfExemptByBundleName(bms, controlRule.callerPkg,
390 PermissionConstants::PERMISSION_EXEMPT_AS_CALLER, userId)) {
391 HILOG_INFO("Jump from exempt caller app, No need to intercept");
392 return true;
393 }
394 if (CheckIfExemptByBundleName(bms, controlRule.targetPkg,
395 PermissionConstants::PERMISSION_EXEMPT_AS_TARGET, userId)) {
396 HILOG_INFO("Jump to exempt target app, No need to intercept");
397 return true;
398 }
399 HILOG_INFO("Third-party apps jump to third-party apps");
400 return false;
401 }
402
CheckIfExemptByBundleName(sptr<AppExecFwk::IBundleMgr> & bms,const std::string & bundleName,const std::string & permission,int32_t userId)403 bool AbilityJumpInterceptor::CheckIfExemptByBundleName(sptr<AppExecFwk::IBundleMgr> &bms,
404 const std::string &bundleName, const std::string &permission, int32_t userId)
405 {
406 AppExecFwk::ApplicationInfo appInfo;
407 if (!IN_PROCESS_CALL(bms->GetApplicationInfo(bundleName, AppExecFwk::BundleFlag::GET_BUNDLE_DEFAULT,
408 userId, appInfo))) {
409 HILOG_ERROR("VerifyPermission failed to get application info");
410 return false;
411 }
412 if (appInfo.isSystemApp) {
413 HILOG_INFO("bundle:%{public}s is system app", bundleName.c_str());
414 return true;
415 }
416 int32_t ret = Security::AccessToken::AccessTokenKit::VerifyAccessToken(appInfo.accessTokenId, permission);
417 if (ret == Security::AccessToken::PermissionState::PERMISSION_DENIED) {
418 HILOG_DEBUG("VerifyPermission %{public}d: PERMISSION_DENIED", appInfo.accessTokenId);
419 return false;
420 }
421 HILOG_INFO("bundle:%{public}s verify permission:%{public}s successed", bundleName.c_str(), permission.c_str());
422 return true;
423 }
424
LoadAppLabelInfo(sptr<AppExecFwk::IBundleMgr> & bms,Want & want,AppExecFwk::AppJumpControlRule & controlRule,int32_t userId)425 bool AbilityJumpInterceptor::LoadAppLabelInfo(sptr<AppExecFwk::IBundleMgr> &bms, Want &want,
426 AppExecFwk::AppJumpControlRule &controlRule, int32_t userId)
427 {
428 AppExecFwk::ApplicationInfo callerAppInfo;
429 IN_PROCESS_CALL(bms->GetApplicationInfo(controlRule.callerPkg,
430 AppExecFwk::ApplicationFlag::GET_BASIC_APPLICATION_INFO, userId, callerAppInfo));
431 AppExecFwk::ApplicationInfo targetAppInfo;
432 IN_PROCESS_CALL(bms->GetApplicationInfo(controlRule.targetPkg,
433 AppExecFwk::ApplicationFlag::GET_BASIC_APPLICATION_INFO, userId, targetAppInfo));
434 want.SetParam(JUMP_DIALOG_CALLER_BUNDLE_NAME, controlRule.callerPkg);
435 want.SetParam(JUMP_DIALOG_CALLER_MODULE_NAME, callerAppInfo.labelResource.moduleName);
436 want.SetParam(JUMP_DIALOG_CALLER_LABEL_ID, callerAppInfo.labelId);
437 want.SetParam(JUMP_DIALOG_TARGET_MODULE_NAME, targetAppInfo.labelResource.moduleName);
438 want.SetParam(JUMP_DIALOG_TARGET_LABEL_ID, targetAppInfo.labelId);
439 return true;
440 }
441 } // namespace AAFwk
442 } // namespace OHOS
443