diff --git a/services/core/java/com/android/server/pm/CloneProfileResolver.java b/services/core/java/com/android/server/pm/CloneProfileResolver.java new file mode 100644 index 0000000000000..d3113e12abe3d --- /dev/null +++ b/services/core/java/com/android/server/pm/CloneProfileResolver.java @@ -0,0 +1,99 @@ +/* + * 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.content.Intent; +import android.content.pm.ResolveInfo; + +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; + +/** + * Cross Profile intent resolution strategy used for and to clone profile. + */ +public class CloneProfileResolver extends CrossProfileResolver { + + public CloneProfileResolver(ComponentResolverApi componentResolver, + UserManagerService userManagerService) { + super(componentResolver, userManagerService); + } + + /** + * This is resolution strategy for Clone Profile. + * 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 resolveIntent(Computer computer, Intent intent, + String resolvedType, int userId, int targetUserId, long flags, + String pkgName, List matchingFilters, + boolean hasNonNegativePriorityResult, + Function pkgSettingFunction) { + List resolveInfos = mComponentResolver.queryActivities(computer, + intent, resolvedType, flags, targetUserId); + List 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); + } + + /** + * As 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 filterResolveInfoWithDomainPreferredActivity(Intent intent, + List crossProfileDomainInfos, long flags, int sourceUserId, + int targetUserId, int highestApprovalLevel) { + // no filtering for clone profile + return crossProfileDomainInfos; + } +} diff --git a/services/core/java/com/android/server/pm/ComputerEngine.java b/services/core/java/com/android/server/pm/ComputerEngine.java index d381e32ed5da4..b2851369b56e8 100644 --- a/services/core/java/com/android/server/pm/ComputerEngine.java +++ b/services/core/java/com/android/server/pm/ComputerEngine.java @@ -460,7 +460,7 @@ public class ComputerEngine implements Computer { mBackgroundDexOptService = args.service.mBackgroundDexOptService; mExternalSourcesPolicy = args.service.mExternalSourcesPolicy; mCrossProfileIntentResolverEngine = new CrossProfileIntentResolverEngine( - mUserManager, mDomainVerificationManager, mDefaultAppProvider); + mUserManager, mDomainVerificationManager, mDefaultAppProvider, mContext); // Used to reference PMS attributes that are primitives and which are not // updated under control of the PMS lock. diff --git a/services/core/java/com/android/server/pm/CrossProfileIntentFilter.java b/services/core/java/com/android/server/pm/CrossProfileIntentFilter.java index 0cd698a5eb0a5..798217f226cf8 100644 --- a/services/core/java/com/android/server/pm/CrossProfileIntentFilter.java +++ b/services/core/java/com/android/server/pm/CrossProfileIntentFilter.java @@ -46,6 +46,9 @@ class CrossProfileIntentFilter extends WatchedIntentFilter { private static final String ATTR_FILTER = "filter"; private static final String ATTR_ACCESS_CONTROL = "accessControl"; + //flag to decide if intent needs to be resolved cross profile if pkgName is already defined + public static final int FLAG_IS_PACKAGE_FOR_FILTER = 0x00000008; + private static final String TAG = "CrossProfileIntentFilter"; /** diff --git a/services/core/java/com/android/server/pm/CrossProfileIntentResolver.java b/services/core/java/com/android/server/pm/CrossProfileIntentResolver.java index 9ea16d322c3c0..2581878055427 100644 --- a/services/core/java/com/android/server/pm/CrossProfileIntentResolver.java +++ b/services/core/java/com/android/server/pm/CrossProfileIntentResolver.java @@ -16,6 +16,8 @@ package com.android.server.pm; +import static com.android.server.pm.CrossProfileIntentFilter.FLAG_IS_PACKAGE_FOR_FILTER; + import android.annotation.NonNull; import android.content.IntentFilter; @@ -37,7 +39,7 @@ class CrossProfileIntentResolver @Override protected boolean isPackageForFilter(String packageName, CrossProfileIntentFilter filter) { - return false; + return (FLAG_IS_PACKAGE_FOR_FILTER & filter.mFlags) != 0; } @Override diff --git a/services/core/java/com/android/server/pm/CrossProfileIntentResolverEngine.java b/services/core/java/com/android/server/pm/CrossProfileIntentResolverEngine.java index 7752fdffb1d78..5ae4cab8e7a6d 100644 --- a/services/core/java/com/android/server/pm/CrossProfileIntentResolverEngine.java +++ b/services/core/java/com/android/server/pm/CrossProfileIntentResolverEngine.java @@ -25,12 +25,14 @@ import static com.android.server.pm.PackageManagerService.TAG; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.UserIdInt; +import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.content.pm.UserInfo; import android.os.Process; import android.text.TextUtils; +import android.util.FeatureFlagUtils; import android.util.Pair; import android.util.Slog; import android.util.SparseArray; @@ -54,13 +56,15 @@ public class CrossProfileIntentResolverEngine { private final UserManagerService mUserManager; private final DomainVerificationManagerInternal mDomainVerificationManager; private final DefaultAppProvider mDefaultAppProvider; + private final Context mContext; public CrossProfileIntentResolverEngine(UserManagerService userManager, DomainVerificationManagerInternal domainVerificationManager, - DefaultAppProvider defaultAppProvider) { + DefaultAppProvider defaultAppProvider, Context context) { mUserManager = userManager; mDomainVerificationManager = domainVerificationManager; mDefaultAppProvider = defaultAppProvider; + mContext = context; } /** @@ -196,6 +200,21 @@ public class CrossProfileIntentResolverEngine { @SuppressWarnings("unused") private CrossProfileResolver chooseCrossProfileResolver(@NonNull Computer computer, UserInfo sourceUserInfo, UserInfo targetUserInfo) { + //todo change isCloneProfile to user properties b/241532322 + /** + * If source or target user is clone profile, using {@link CloneProfileResolver} + * We would allow CloneProfileResolver only if flag + * SETTINGS_ALLOW_INTENT_REDIRECTION_FOR_CLONE_PROFILE is enabled + */ + if (sourceUserInfo.isCloneProfile() || targetUserInfo.isCloneProfile()) { + if (FeatureFlagUtils.isEnabled(mContext, + FeatureFlagUtils.SETTINGS_ALLOW_INTENT_REDIRECTION_FOR_CLONE_PROFILE)) { + return new CloneProfileResolver(computer.getComponentResolver(), + mUserManager); + } else { + return null; + } + } return new DefaultCrossProfileResolver(computer.getComponentResolver(), mUserManager, mDomainVerificationManager); } @@ -313,8 +332,6 @@ public class CrossProfileIntentResolverEngine { } if (pkgName == null && intent.hasWebURI()) { - // If instant apps are not allowed and there is result only from current or cross - // profile return it if (!addInstant && ((candidates.size() <= 1 && crossProfileCandidates.isEmpty()) || (candidates.isEmpty() && !crossProfileCandidates.isEmpty()))) { candidates.addAll(resolveInfoFromCrossProfileDomainInfo(crossProfileCandidates));