Loading services/core/java/com/android/server/pm/CrossProfileIntentFilter.java +9 −0 Original line number Diff line number Diff line Loading @@ -49,6 +49,15 @@ class CrossProfileIntentFilter extends WatchedIntentFilter { //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; /* This flag, denotes if further cross profile resolution is allowed, e.g. if profile#0 is linked to profile#1 and profile#2 . When intent resolution from profile#1 is started we resolve it in profile#1 and profile#0. The profile#0 is also linked to profile#2, we will only resolve in profile#2 if CrossProfileIntentFilter between profile#1 and profile#0 have set flag FLAG_ALLOW_CHAINED_RESOLUTION. */ public static final int FLAG_ALLOW_CHAINED_RESOLUTION = 0x00000010; private static final String TAG = "CrossProfileIntentFilter"; /** Loading services/core/java/com/android/server/pm/CrossProfileIntentResolverEngine.java +136 −58 Original line number Diff line number Diff line Loading @@ -36,14 +36,19 @@ import android.util.FeatureFlagUtils; import android.util.Pair; import android.util.Slog; import android.util.SparseArray; import android.util.SparseBooleanArray; import com.android.server.LocalServices; import com.android.server.pm.pkg.PackageStateInternal; import com.android.server.pm.verify.domain.DomainVerificationManagerInternal; import com.android.server.pm.verify.domain.DomainVerificationUtils; import java.util.ArrayDeque; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Queue; import java.util.Set; import java.util.function.Function; /** Loading Loading @@ -115,32 +120,39 @@ public class CrossProfileIntentResolverEngine { Intent intent, String resolvedType, int userId, long flags, String pkgName, boolean hasNonNegativePriorityResult, Function<String, PackageStateInternal> pkgSettingFunction) { Queue<Integer> pendingUsers = new ArrayDeque<>(); Set<Integer> visitedUserIds = new HashSet<>(); SparseBooleanArray hasNonNegativePriorityResultFromParent = new SparseBooleanArray(); visitedUserIds.add(userId); pendingUsers.add(userId); hasNonNegativePriorityResultFromParent.put(userId, hasNonNegativePriorityResult); UserManagerInternal umInternal = LocalServices.getService(UserManagerInternal.class); List<CrossProfileDomainInfo> crossProfileDomainInfos = new ArrayList<>(); while (!pendingUsers.isEmpty()) { int currentUserId = pendingUsers.poll(); List<CrossProfileIntentFilter> matchingFilters = computer.getMatchingCrossProfileIntentFilters(intent, resolvedType, userId); computer.getMatchingCrossProfileIntentFilters(intent, resolvedType, currentUserId); if (matchingFilters == null || matchingFilters.isEmpty()) { /** if intent is web intent, checking if parent profile should handle the intent even if there is no matching filter. The configuration is based on user profile restriction android.os.UserManager#ALLOW_PARENT_PROFILE_APP_LINKING **/ if (intent.hasWebURI()) { UserInfo parent = computer.getProfileParent(userId); /** if intent is web intent, checking if parent profile should handle the intent * even if there is no matching filter. The configuration is based on user profile * restriction android.os.UserManager#ALLOW_PARENT_PROFILE_APP_LINKING **/ if (currentUserId == userId && intent.hasWebURI()) { UserInfo parent = computer.getProfileParent(currentUserId); if (parent != null) { CrossProfileDomainInfo generalizedCrossProfileDomainInfo = computer .getCrossProfileDomainPreferredLpr(intent, resolvedType, flags, userId, parent.id); .getCrossProfileDomainPreferredLpr(intent, resolvedType, flags, currentUserId, parent.id); if (generalizedCrossProfileDomainInfo != null) { crossProfileDomainInfos.add(generalizedCrossProfileDomainInfo); } } } return crossProfileDomainInfos; continue; } UserManagerInternal umInternal = LocalServices.getService(UserManagerInternal.class); UserInfo sourceUserInfo = umInternal.getUserInfo(userId); UserInfo sourceUserInfo = umInternal.getUserInfo(currentUserId); // Grouping the CrossProfileIntentFilters based on targerId SparseArray<List<CrossProfileIntentFilter>> crossProfileIntentFiltersByUser = Loading @@ -164,8 +176,14 @@ public class CrossProfileIntentResolverEngine { */ for (int index = 0; index < crossProfileIntentFiltersByUser.size(); index++) { UserInfo targetUserInfo = umInternal.getUserInfo(crossProfileIntentFiltersByUser .keyAt(index)); int targetUserId = crossProfileIntentFiltersByUser.keyAt(index); //if user is already visited then skip resolution for particular user. if (visitedUserIds.contains(targetUserId)) { continue; } UserInfo targetUserInfo = umInternal.getUserInfo(targetUserId); // Choosing strategy based on source and target user CrossProfileResolver crossProfileResolver = Loading @@ -177,11 +195,36 @@ public class CrossProfileIntentResolverEngine { */ if (crossProfileResolver != null) { List<CrossProfileDomainInfo> crossProfileInfos = crossProfileResolver .resolveIntent(computer, intent, resolvedType, userId, crossProfileIntentFiltersByUser.keyAt(index), flags, pkgName, .resolveIntent(computer, intent, resolvedType, currentUserId, targetUserId, flags, pkgName, crossProfileIntentFiltersByUser.valueAt(index), hasNonNegativePriorityResult, pkgSettingFunction); hasNonNegativePriorityResultFromParent.get(currentUserId), pkgSettingFunction); crossProfileDomainInfos.addAll(crossProfileInfos); hasNonNegativePriorityResultFromParent.put(targetUserId, hasNonNegativePriority(crossProfileInfos)); /* Adding target user to queue if flag {@link CrossProfileIntentFilter#FLAG_ALLOW_CHAINED_RESOLUTION} is set for any {@link CrossProfileIntentFilter} */ boolean allowChainedResolution = false; for (int filterIndex = 0; filterIndex < crossProfileIntentFiltersByUser .valueAt(index).size(); filterIndex++) { if ((CrossProfileIntentFilter .FLAG_ALLOW_CHAINED_RESOLUTION & crossProfileIntentFiltersByUser .valueAt(index).get(filterIndex).mFlags) != 0) { allowChainedResolution = true; break; } } if (allowChainedResolution) { pendingUsers.add(targetUserId); } visitedUserIds.add(targetUserId); } } } Loading Loading @@ -237,7 +280,7 @@ public class CrossProfileIntentResolverEngine { /** * Returns true if we source user can reach target user for given intent. The source can * directly or indirectly reach to target. This will perform depth first search to check if * directly or indirectly reach to target. This will perform breadth first search to check if * source can reach target. * @param computer {@link Computer} instance used for resolution by {@link ComponentResolverApi} * @param intent request Loading @@ -251,14 +294,39 @@ public class CrossProfileIntentResolverEngine { @UserIdInt int targetUserId) { if (sourceUserId == targetUserId) return true; Queue<Integer> pendingUsers = new ArrayDeque<>(); Set<Integer> visitedUserIds = new HashSet<>(); visitedUserIds.add(sourceUserId); pendingUsers.add(sourceUserId); while (!pendingUsers.isEmpty()) { int currentUserId = pendingUsers.poll(); List<CrossProfileIntentFilter> matches = computer.getMatchingCrossProfileIntentFilters(intent, resolvedType, sourceUserId); computer.getMatchingCrossProfileIntentFilters(intent, resolvedType, currentUserId); if (matches != null) { for (int index = 0; index < matches.size(); index++) { CrossProfileIntentFilter crossProfileIntentFilter = matches.get(index); if (crossProfileIntentFilter.mTargetUserId == targetUserId) { return true; } if (visitedUserIds.contains(crossProfileIntentFilter.mTargetUserId)) { continue; } /* If source cannot directly reach to target, we will add CrossProfileIntentFilter.mTargetUserId user to queue to check if target user can be reached via CrossProfileIntentFilter.mTargetUserId i.e. it can be indirectly reached through chained/linked profiles. */ if ((CrossProfileIntentFilter.FLAG_ALLOW_CHAINED_RESOLUTION & crossProfileIntentFilter.mFlags) != 0) { pendingUsers.add(crossProfileIntentFilter.mTargetUserId); visitedUserIds.add(crossProfileIntentFilter.mTargetUserId); } } } } return false; Loading Loading @@ -605,4 +673,14 @@ public class CrossProfileIntentResolverEngine { return resolveInfoList; } /** * @param crossProfileDomainInfos list of cross profile domain info in descending priority order * @return if the list contains a resolve info with non-negative priority */ private boolean hasNonNegativePriority(List<CrossProfileDomainInfo> crossProfileDomainInfos) { return crossProfileDomainInfos.size() > 0 && crossProfileDomainInfos.get(0).mResolveInfo != null && crossProfileDomainInfos.get(0).mResolveInfo.priority >= 0; } } Loading
services/core/java/com/android/server/pm/CrossProfileIntentFilter.java +9 −0 Original line number Diff line number Diff line Loading @@ -49,6 +49,15 @@ class CrossProfileIntentFilter extends WatchedIntentFilter { //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; /* This flag, denotes if further cross profile resolution is allowed, e.g. if profile#0 is linked to profile#1 and profile#2 . When intent resolution from profile#1 is started we resolve it in profile#1 and profile#0. The profile#0 is also linked to profile#2, we will only resolve in profile#2 if CrossProfileIntentFilter between profile#1 and profile#0 have set flag FLAG_ALLOW_CHAINED_RESOLUTION. */ public static final int FLAG_ALLOW_CHAINED_RESOLUTION = 0x00000010; private static final String TAG = "CrossProfileIntentFilter"; /** Loading
services/core/java/com/android/server/pm/CrossProfileIntentResolverEngine.java +136 −58 Original line number Diff line number Diff line Loading @@ -36,14 +36,19 @@ import android.util.FeatureFlagUtils; import android.util.Pair; import android.util.Slog; import android.util.SparseArray; import android.util.SparseBooleanArray; import com.android.server.LocalServices; import com.android.server.pm.pkg.PackageStateInternal; import com.android.server.pm.verify.domain.DomainVerificationManagerInternal; import com.android.server.pm.verify.domain.DomainVerificationUtils; import java.util.ArrayDeque; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Queue; import java.util.Set; import java.util.function.Function; /** Loading Loading @@ -115,32 +120,39 @@ public class CrossProfileIntentResolverEngine { Intent intent, String resolvedType, int userId, long flags, String pkgName, boolean hasNonNegativePriorityResult, Function<String, PackageStateInternal> pkgSettingFunction) { Queue<Integer> pendingUsers = new ArrayDeque<>(); Set<Integer> visitedUserIds = new HashSet<>(); SparseBooleanArray hasNonNegativePriorityResultFromParent = new SparseBooleanArray(); visitedUserIds.add(userId); pendingUsers.add(userId); hasNonNegativePriorityResultFromParent.put(userId, hasNonNegativePriorityResult); UserManagerInternal umInternal = LocalServices.getService(UserManagerInternal.class); List<CrossProfileDomainInfo> crossProfileDomainInfos = new ArrayList<>(); while (!pendingUsers.isEmpty()) { int currentUserId = pendingUsers.poll(); List<CrossProfileIntentFilter> matchingFilters = computer.getMatchingCrossProfileIntentFilters(intent, resolvedType, userId); computer.getMatchingCrossProfileIntentFilters(intent, resolvedType, currentUserId); if (matchingFilters == null || matchingFilters.isEmpty()) { /** if intent is web intent, checking if parent profile should handle the intent even if there is no matching filter. The configuration is based on user profile restriction android.os.UserManager#ALLOW_PARENT_PROFILE_APP_LINKING **/ if (intent.hasWebURI()) { UserInfo parent = computer.getProfileParent(userId); /** if intent is web intent, checking if parent profile should handle the intent * even if there is no matching filter. The configuration is based on user profile * restriction android.os.UserManager#ALLOW_PARENT_PROFILE_APP_LINKING **/ if (currentUserId == userId && intent.hasWebURI()) { UserInfo parent = computer.getProfileParent(currentUserId); if (parent != null) { CrossProfileDomainInfo generalizedCrossProfileDomainInfo = computer .getCrossProfileDomainPreferredLpr(intent, resolvedType, flags, userId, parent.id); .getCrossProfileDomainPreferredLpr(intent, resolvedType, flags, currentUserId, parent.id); if (generalizedCrossProfileDomainInfo != null) { crossProfileDomainInfos.add(generalizedCrossProfileDomainInfo); } } } return crossProfileDomainInfos; continue; } UserManagerInternal umInternal = LocalServices.getService(UserManagerInternal.class); UserInfo sourceUserInfo = umInternal.getUserInfo(userId); UserInfo sourceUserInfo = umInternal.getUserInfo(currentUserId); // Grouping the CrossProfileIntentFilters based on targerId SparseArray<List<CrossProfileIntentFilter>> crossProfileIntentFiltersByUser = Loading @@ -164,8 +176,14 @@ public class CrossProfileIntentResolverEngine { */ for (int index = 0; index < crossProfileIntentFiltersByUser.size(); index++) { UserInfo targetUserInfo = umInternal.getUserInfo(crossProfileIntentFiltersByUser .keyAt(index)); int targetUserId = crossProfileIntentFiltersByUser.keyAt(index); //if user is already visited then skip resolution for particular user. if (visitedUserIds.contains(targetUserId)) { continue; } UserInfo targetUserInfo = umInternal.getUserInfo(targetUserId); // Choosing strategy based on source and target user CrossProfileResolver crossProfileResolver = Loading @@ -177,11 +195,36 @@ public class CrossProfileIntentResolverEngine { */ if (crossProfileResolver != null) { List<CrossProfileDomainInfo> crossProfileInfos = crossProfileResolver .resolveIntent(computer, intent, resolvedType, userId, crossProfileIntentFiltersByUser.keyAt(index), flags, pkgName, .resolveIntent(computer, intent, resolvedType, currentUserId, targetUserId, flags, pkgName, crossProfileIntentFiltersByUser.valueAt(index), hasNonNegativePriorityResult, pkgSettingFunction); hasNonNegativePriorityResultFromParent.get(currentUserId), pkgSettingFunction); crossProfileDomainInfos.addAll(crossProfileInfos); hasNonNegativePriorityResultFromParent.put(targetUserId, hasNonNegativePriority(crossProfileInfos)); /* Adding target user to queue if flag {@link CrossProfileIntentFilter#FLAG_ALLOW_CHAINED_RESOLUTION} is set for any {@link CrossProfileIntentFilter} */ boolean allowChainedResolution = false; for (int filterIndex = 0; filterIndex < crossProfileIntentFiltersByUser .valueAt(index).size(); filterIndex++) { if ((CrossProfileIntentFilter .FLAG_ALLOW_CHAINED_RESOLUTION & crossProfileIntentFiltersByUser .valueAt(index).get(filterIndex).mFlags) != 0) { allowChainedResolution = true; break; } } if (allowChainedResolution) { pendingUsers.add(targetUserId); } visitedUserIds.add(targetUserId); } } } Loading Loading @@ -237,7 +280,7 @@ public class CrossProfileIntentResolverEngine { /** * Returns true if we source user can reach target user for given intent. The source can * directly or indirectly reach to target. This will perform depth first search to check if * directly or indirectly reach to target. This will perform breadth first search to check if * source can reach target. * @param computer {@link Computer} instance used for resolution by {@link ComponentResolverApi} * @param intent request Loading @@ -251,14 +294,39 @@ public class CrossProfileIntentResolverEngine { @UserIdInt int targetUserId) { if (sourceUserId == targetUserId) return true; Queue<Integer> pendingUsers = new ArrayDeque<>(); Set<Integer> visitedUserIds = new HashSet<>(); visitedUserIds.add(sourceUserId); pendingUsers.add(sourceUserId); while (!pendingUsers.isEmpty()) { int currentUserId = pendingUsers.poll(); List<CrossProfileIntentFilter> matches = computer.getMatchingCrossProfileIntentFilters(intent, resolvedType, sourceUserId); computer.getMatchingCrossProfileIntentFilters(intent, resolvedType, currentUserId); if (matches != null) { for (int index = 0; index < matches.size(); index++) { CrossProfileIntentFilter crossProfileIntentFilter = matches.get(index); if (crossProfileIntentFilter.mTargetUserId == targetUserId) { return true; } if (visitedUserIds.contains(crossProfileIntentFilter.mTargetUserId)) { continue; } /* If source cannot directly reach to target, we will add CrossProfileIntentFilter.mTargetUserId user to queue to check if target user can be reached via CrossProfileIntentFilter.mTargetUserId i.e. it can be indirectly reached through chained/linked profiles. */ if ((CrossProfileIntentFilter.FLAG_ALLOW_CHAINED_RESOLUTION & crossProfileIntentFilter.mFlags) != 0) { pendingUsers.add(crossProfileIntentFilter.mTargetUserId); visitedUserIds.add(crossProfileIntentFilter.mTargetUserId); } } } } return false; Loading Loading @@ -605,4 +673,14 @@ public class CrossProfileIntentResolverEngine { return resolveInfoList; } /** * @param crossProfileDomainInfos list of cross profile domain info in descending priority order * @return if the list contains a resolve info with non-negative priority */ private boolean hasNonNegativePriority(List<CrossProfileDomainInfo> crossProfileDomainInfos) { return crossProfileDomainInfos.size() > 0 && crossProfileDomainInfos.get(0).mResolveInfo != null && crossProfileDomainInfos.get(0).mResolveInfo.priority >= 0; } }