blob: b87256dbbd9a66082e3b98ac47a5922e7e055d75 [file] [log] [blame]
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.server.pm;
import android.Manifest;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.os.Binder;
import com.android.internal.R;
import com.android.internal.config.appcloning.AppCloningDeviceConfigHelper;
import com.android.server.pm.pkg.PackageStateInternal;
import com.android.server.pm.resolution.ComponentResolverApi;
import com.android.server.pm.verify.domain.DomainVerificationManagerInternal;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Function;
/**
* Intent resolution strategy used when no filtering is required. As of now, the known use-case is
* clone profile.
*/
public class NoFilteringResolver extends CrossProfileResolver {
/**
* Feature flag to allow/restrict intent redirection from/to clone profile.
* Default value is false,this is to ensure that framework is not impacted by intent redirection
* till we are ready to launch.
* From Android U onwards, this would be set to true and eventually removed.
* @hide
*/
private static final String FLAG_ALLOW_INTENT_REDIRECTION_FOR_CLONE_PROFILE =
"allow_intent_redirection_for_clone_profile";
/**
* Returns true if intent redirection for clone profile feature flag
* (enable_app_cloning_building_blocks) is set and if its query,
* then check if calling user have necessary permission
* (android.permission.QUERY_CLONED_APPS) as well as required flag
* (PackageManager.MATCH_CLONE_PROFILE) bit set.
* @return true if resolver would be used for cross profile resolution.
*/
public static boolean isIntentRedirectionAllowed(Context context,
AppCloningDeviceConfigHelper appCloningDeviceConfigHelper, boolean resolveForStart,
long flags) {
return isAppCloningBuildingBlocksEnabled(context, appCloningDeviceConfigHelper)
&& (resolveForStart || (((flags & PackageManager.MATCH_CLONE_PROFILE) != 0)
&& hasPermission(context, Manifest.permission.QUERY_CLONED_APPS)));
}
public NoFilteringResolver(ComponentResolverApi componentResolver,
UserManagerService userManagerService) {
super(componentResolver, userManagerService);
}
/**
* This is resolution strategy for when no filtering is required.
* In case of clone profile, the profile is supposed to be transparent to end user. To end user
* clone and owner profile should be part of same user space. Hence, the resolution strategy
* would resolve intent in both profile and return combined result without any filtering of the
* results.
*
* @param computer ComputerEngine instance that would be needed by ComponentResolverApi
* @param intent request
* @param resolvedType the MIME data type of intent request
* @param userId source/initiating user
* @param targetUserId target user id
* @param flags of intent request
* @param pkgName the application package name this Intent is limited to
* @param matchingFilters {@link CrossProfileIntentFilter}s configured for source user,
* targeting the targetUserId
* @param hasNonNegativePriorityResult if source have any non-negative(active and valid)
* resolveInfo in their profile.
* @param pkgSettingFunction function to find PackageStateInternal for given package
* @return list of {@link CrossProfileDomainInfo}
*/
@Override
public List<CrossProfileDomainInfo> resolveIntent(Computer computer, Intent intent,
String resolvedType, int userId, int targetUserId, long flags,
String pkgName, List<CrossProfileIntentFilter> matchingFilters,
boolean hasNonNegativePriorityResult,
Function<String, PackageStateInternal> pkgSettingFunction) {
List<ResolveInfo> resolveInfos = mComponentResolver.queryActivities(computer,
intent, resolvedType, flags, targetUserId);
List<CrossProfileDomainInfo> crossProfileDomainInfos = new ArrayList<>();
if (resolveInfos != null) {
for (int index = 0; index < resolveInfos.size(); index++) {
crossProfileDomainInfos.add(new CrossProfileDomainInfo(resolveInfos.get(index),
DomainVerificationManagerInternal.APPROVAL_LEVEL_NONE,
targetUserId));
}
}
return filterIfNotSystemUser(crossProfileDomainInfos, userId);
}
/**
* In case of Clone profile, the clone and owner profile are going to be part of the same
* userspace, we need no filtering out of any clone profile's result.
* @param intent request
* @param crossProfileDomainInfos resolved in target user
* @param flags for intent resolution
* @param sourceUserId source user
* @param targetUserId target user
* @param highestApprovalLevel highest level of domain approval
* @return list of CrossProfileDomainInfo
*/
@Override
public List<CrossProfileDomainInfo> filterResolveInfoWithDomainPreferredActivity(Intent intent,
List<CrossProfileDomainInfo> crossProfileDomainInfos, long flags, int sourceUserId,
int targetUserId, int highestApprovalLevel) {
// no filtering
return crossProfileDomainInfos;
}
/**
* Checks if calling uid have the mentioned permission
* @param context calling context
* @param permission permission name
* @return true if uid have the permission
*/
private static boolean hasPermission(Context context, String permission) {
return context.checkCallingOrSelfPermission(permission)
== PackageManager.PERMISSION_GRANTED;
}
/**
* Checks if the AppCloningBuildingBlocks flag is enabled.
*/
private static boolean isAppCloningBuildingBlocksEnabled(Context context,
AppCloningDeviceConfigHelper appCloningDeviceConfigHelper) {
final long token = Binder.clearCallingIdentity();
try {
return context.getResources().getBoolean(R.bool.config_enableAppCloningBuildingBlocks)
&& appCloningDeviceConfigHelper.getEnableAppCloningBuildingBlocks();
} finally {
Binder.restoreCallingIdentity(token);
}
}
}