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