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 return isAppCloningBuildingBlocksEnabled(context, appCloningDeviceConfigHelper) 64 && (resolveForStart || (((flags & PackageManager.MATCH_CLONE_PROFILE) != 0) 65 && hasPermission(context, Manifest.permission.QUERY_CLONED_APPS))); 66 } 67 NoFilteringResolver(ComponentResolverApi componentResolver, UserManagerService userManagerService)68 public NoFilteringResolver(ComponentResolverApi componentResolver, 69 UserManagerService userManagerService) { 70 super(componentResolver, userManagerService); 71 } 72 73 /** 74 * This is resolution strategy for when no filtering is required. 75 * In case of clone profile, the profile is supposed to be transparent to end user. To end user 76 * clone and owner profile should be part of same user space. Hence, the resolution strategy 77 * would resolve intent in both profile and return combined result without any filtering of the 78 * results. 79 * 80 * @param computer ComputerEngine instance that would be needed by ComponentResolverApi 81 * @param intent request 82 * @param resolvedType the MIME data type of intent request 83 * @param userId source/initiating user 84 * @param targetUserId target user id 85 * @param flags of intent request 86 * @param pkgName the application package name this Intent is limited to 87 * @param matchingFilters {@link CrossProfileIntentFilter}s configured for source user, 88 * targeting the targetUserId 89 * @param hasNonNegativePriorityResult if source have any non-negative(active and valid) 90 * resolveInfo in their profile. 91 * @param pkgSettingFunction function to find PackageStateInternal for given package 92 * @return list of {@link CrossProfileDomainInfo} 93 */ 94 @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)95 public List<CrossProfileDomainInfo> resolveIntent(Computer computer, Intent intent, 96 String resolvedType, int userId, int targetUserId, long flags, 97 String pkgName, List<CrossProfileIntentFilter> matchingFilters, 98 boolean hasNonNegativePriorityResult, 99 Function<String, PackageStateInternal> pkgSettingFunction) { 100 List<ResolveInfo> resolveInfos = mComponentResolver.queryActivities(computer, 101 intent, resolvedType, flags, targetUserId); 102 List<CrossProfileDomainInfo> crossProfileDomainInfos = new ArrayList<>(); 103 if (resolveInfos != null) { 104 105 for (int index = 0; index < resolveInfos.size(); index++) { 106 crossProfileDomainInfos.add(new CrossProfileDomainInfo(resolveInfos.get(index), 107 DomainVerificationManagerInternal.APPROVAL_LEVEL_NONE, 108 targetUserId)); 109 } 110 } 111 return filterIfNotSystemUser(crossProfileDomainInfos, userId); 112 } 113 114 /** 115 * In case of Clone profile, the clone and owner profile are going to be part of the same 116 * userspace, we need no filtering out of any clone profile's result. 117 * @param intent request 118 * @param crossProfileDomainInfos resolved in target user 119 * @param flags for intent resolution 120 * @param sourceUserId source user 121 * @param targetUserId target user 122 * @param highestApprovalLevel highest level of domain approval 123 * @return list of CrossProfileDomainInfo 124 */ 125 @Override filterResolveInfoWithDomainPreferredActivity(Intent intent, List<CrossProfileDomainInfo> crossProfileDomainInfos, long flags, int sourceUserId, int targetUserId, int highestApprovalLevel)126 public List<CrossProfileDomainInfo> filterResolveInfoWithDomainPreferredActivity(Intent intent, 127 List<CrossProfileDomainInfo> crossProfileDomainInfos, long flags, int sourceUserId, 128 int targetUserId, int highestApprovalLevel) { 129 // no filtering 130 return crossProfileDomainInfos; 131 } 132 133 /** 134 * Checks if calling uid have the mentioned permission 135 * @param context calling context 136 * @param permission permission name 137 * @return true if uid have the permission 138 */ hasPermission(Context context, String permission)139 private static boolean hasPermission(Context context, String permission) { 140 return context.checkCallingOrSelfPermission(permission) 141 == PackageManager.PERMISSION_GRANTED; 142 } 143 144 /** 145 * Checks if the AppCloningBuildingBlocks flag is enabled. 146 */ isAppCloningBuildingBlocksEnabled(Context context, AppCloningDeviceConfigHelper appCloningDeviceConfigHelper)147 private static boolean isAppCloningBuildingBlocksEnabled(Context context, 148 AppCloningDeviceConfigHelper appCloningDeviceConfigHelper) { 149 final long token = Binder.clearCallingIdentity(); 150 try { 151 return context.getResources().getBoolean(R.bool.config_enableAppCloningBuildingBlocks) 152 && appCloningDeviceConfigHelper.getEnableAppCloningBuildingBlocks(); 153 } finally { 154 Binder.restoreCallingIdentity(token); 155 } 156 } 157 } 158