1 /* 2 * Copyright (C) 2022 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.server.pm; 18 19 import android.Manifest; 20 import android.content.Context; 21 import android.content.Intent; 22 import android.content.pm.PackageManager; 23 import android.content.pm.ResolveInfo; 24 import android.os.Binder; 25 26 import com.android.internal.R; 27 import com.android.internal.config.appcloning.AppCloningDeviceConfigHelper; 28 import com.android.server.pm.pkg.PackageStateInternal; 29 import com.android.server.pm.resolution.ComponentResolverApi; 30 import com.android.server.pm.verify.domain.DomainVerificationManagerInternal; 31 32 import java.util.ArrayList; 33 import java.util.List; 34 import java.util.function.Function; 35 36 /** 37 * Intent resolution strategy used when no filtering is required. As of now, the known use-case is 38 * clone profile. 39 */ 40 public class NoFilteringResolver extends CrossProfileResolver { 41 42 /** 43 * Feature flag to allow/restrict intent redirection from/to clone profile. 44 * Default value is false,this is to ensure that framework is not impacted by intent redirection 45 * till we are ready to launch. 46 * From Android U onwards, this would be set to true and eventually removed. 47 * @hide 48 */ 49 private static final String FLAG_ALLOW_INTENT_REDIRECTION_FOR_CLONE_PROFILE = 50 "allow_intent_redirection_for_clone_profile"; 51 52 /** 53 * Returns true if intent redirection for clone profile feature flag 54 * (enable_app_cloning_building_blocks) is set and if its query, 55 * then check if calling user have necessary permission 56 * (android.permission.QUERY_CLONED_APPS) as well as required flag 57 * (PackageManager.MATCH_CLONE_PROFILE) bit set. 58 * @return true if resolver would be used for cross profile resolution. 59 */ isIntentRedirectionAllowed(Context context, AppCloningDeviceConfigHelper appCloningDeviceConfigHelper, boolean resolveForStart, long flags)60 public static boolean isIntentRedirectionAllowed(Context context, 61 AppCloningDeviceConfigHelper appCloningDeviceConfigHelper, boolean resolveForStart, 62 long flags) { 63 boolean canMatchCloneProfile = (flags & PackageManager.MATCH_CLONE_PROFILE) != 0 64 || (flags & PackageManager.MATCH_CLONE_PROFILE_LONG) != 0; 65 return isAppCloningBuildingBlocksEnabled(context, appCloningDeviceConfigHelper) 66 && (resolveForStart 67 || (canMatchCloneProfile 68 && hasPermission(context, Manifest.permission.QUERY_CLONED_APPS))); 69 } 70 NoFilteringResolver(ComponentResolverApi componentResolver, UserManagerService userManagerService)71 public NoFilteringResolver(ComponentResolverApi componentResolver, 72 UserManagerService userManagerService) { 73 super(componentResolver, userManagerService); 74 } 75 76 /** 77 * This is resolution strategy for when no filtering is required. 78 * In case of clone profile, the profile is supposed to be transparent to end user. To end user 79 * clone and owner profile should be part of same user space. Hence, the resolution strategy 80 * would resolve intent in both profile and return combined result without any filtering of the 81 * results. 82 * 83 * @param computer ComputerEngine instance that would be needed by ComponentResolverApi 84 * @param intent request 85 * @param resolvedType the MIME data type of intent request 86 * @param userId source/initiating user 87 * @param targetUserId target user id 88 * @param flags of intent request 89 * @param pkgName the application package name this Intent is limited to 90 * @param matchingFilters {@link CrossProfileIntentFilter}s configured for source user, 91 * targeting the targetUserId 92 * @param hasNonNegativePriorityResult if source have any non-negative(active and valid) 93 * resolveInfo in their profile. 94 * @param pkgSettingFunction function to find PackageStateInternal for given package 95 * @return list of {@link CrossProfileDomainInfo} 96 */ 97 @Override resolveIntent(Computer computer, Intent intent, String resolvedType, int userId, int targetUserId, long flags, String pkgName, List<CrossProfileIntentFilter> matchingFilters, boolean hasNonNegativePriorityResult, Function<String, PackageStateInternal> pkgSettingFunction)98 public List<CrossProfileDomainInfo> resolveIntent(Computer computer, Intent intent, 99 String resolvedType, int userId, int targetUserId, long flags, 100 String pkgName, List<CrossProfileIntentFilter> matchingFilters, 101 boolean hasNonNegativePriorityResult, 102 Function<String, PackageStateInternal> pkgSettingFunction) { 103 List<ResolveInfo> resolveInfos = mComponentResolver.queryActivities(computer, 104 intent, resolvedType, flags, targetUserId); 105 List<CrossProfileDomainInfo> crossProfileDomainInfos = new ArrayList<>(); 106 if (resolveInfos != null) { 107 108 for (int index = 0; index < resolveInfos.size(); index++) { 109 crossProfileDomainInfos.add(new CrossProfileDomainInfo(resolveInfos.get(index), 110 DomainVerificationManagerInternal.APPROVAL_LEVEL_NONE, 111 targetUserId)); 112 } 113 } 114 return filterIfNotSystemUser(crossProfileDomainInfos, userId); 115 } 116 117 /** 118 * In case of Clone profile, the clone and owner profile are going to be part of the same 119 * userspace, we need no filtering out of any clone profile's result. 120 * @param intent request 121 * @param crossProfileDomainInfos resolved in target user 122 * @param flags for intent resolution 123 * @param sourceUserId source user 124 * @param targetUserId target user 125 * @param highestApprovalLevel highest level of domain approval 126 * @return list of CrossProfileDomainInfo 127 */ 128 @Override filterResolveInfoWithDomainPreferredActivity(Intent intent, List<CrossProfileDomainInfo> crossProfileDomainInfos, long flags, int sourceUserId, int targetUserId, int highestApprovalLevel)129 public List<CrossProfileDomainInfo> filterResolveInfoWithDomainPreferredActivity(Intent intent, 130 List<CrossProfileDomainInfo> crossProfileDomainInfos, long flags, int sourceUserId, 131 int targetUserId, int highestApprovalLevel) { 132 // no filtering 133 return crossProfileDomainInfos; 134 } 135 136 /** 137 * Checks if calling uid have the mentioned permission 138 * @param context calling context 139 * @param permission permission name 140 * @return true if uid have the permission 141 */ hasPermission(Context context, String permission)142 private static boolean hasPermission(Context context, String permission) { 143 return context.checkCallingOrSelfPermission(permission) 144 == PackageManager.PERMISSION_GRANTED; 145 } 146 147 /** 148 * Checks if the AppCloningBuildingBlocks flag is enabled. 149 */ isAppCloningBuildingBlocksEnabled(Context context, AppCloningDeviceConfigHelper appCloningDeviceConfigHelper)150 private static boolean isAppCloningBuildingBlocksEnabled(Context context, 151 AppCloningDeviceConfigHelper appCloningDeviceConfigHelper) { 152 final long token = Binder.clearCallingIdentity(); 153 try { 154 return context.getResources().getBoolean(R.bool.config_enableAppCloningBuildingBlocks) 155 && appCloningDeviceConfigHelper.getEnableAppCloningBuildingBlocks(); 156 } finally { 157 Binder.restoreCallingIdentity(token); 158 } 159 } 160 } 161