Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 63798c59 authored by Nicolas Prevot's avatar Nicolas Prevot
Browse files

Introducing crossProfileIntentFilters that skip the current profile.

For these crossProfileIntentFilters, the activities in the current profile cannot
respond to the intent.
Only activities in the target profile can respond to the intent.

BUG: 14936725

Change-Id: I5e2704c2b56ff50a8339dd49284956391d7fad7e
parent a062a933
Loading
Loading
Loading
Loading
+3 −20
Original line number Diff line number Diff line
@@ -1457,24 +1457,15 @@ final class ApplicationPackageManager extends PackageManager {
     * @hide
     */
    @Override
    public void addCrossProfileIntentFilter(IntentFilter filter, boolean removable,
            int sourceUserId, int targetUserId) {
    public void addCrossProfileIntentFilter(IntentFilter filter, int sourceUserId, int targetUserId,
            int flags) {
        try {
            mPM.addCrossProfileIntentFilter(filter, removable, sourceUserId, targetUserId);
            mPM.addCrossProfileIntentFilter(filter, sourceUserId, targetUserId, flags);
        } catch (RemoteException e) {
            // Should never happen!
        }
    }

    /**
     * @hide
     */
    @Override
    public void addForwardingIntentFilter(IntentFilter filter, boolean removable, int sourceUserId,
            int targetUserId) {
        addCrossProfileIntentFilter(filter, removable, sourceUserId, targetUserId);
    }

    /**
     * @hide
     */
@@ -1487,14 +1478,6 @@ final class ApplicationPackageManager extends PackageManager {
        }
    }

    /**
     * @hide
     */
    @Override
    public void clearForwardingIntentFilters(int sourceUserId) {
        clearCrossProfileIntentFilters(sourceUserId);
    }

    private final ContextImpl mContext;
    private final IPackageManager mPM;

+2 −2
Original line number Diff line number Diff line
@@ -248,8 +248,8 @@ interface IPackageManager {

    void clearPackagePersistentPreferredActivities(String packageName, int userId);

    void addCrossProfileIntentFilter(in IntentFilter filter, boolean removable, int sourceUserId,
            int targetUserId);
    void addCrossProfileIntentFilter(in IntentFilter intentFilter, int sourceUserId, int targetUserId,
            int flags);

    void clearCrossProfileIntentFilters(int sourceUserId);

+20 −20
Original line number Diff line number Diff line
@@ -196,6 +196,22 @@ public abstract class PackageManager {
     */
    public static final int MATCH_DEFAULT_ONLY   = 0x00010000;

    /**
     * Flag for {@link addCrossProfileIntentFilter}: if the cross-profile intent has been set by the
     * profile owner.
     * @hide
     */
    public static final int SET_BY_PROFILE_OWNER= 0x00000001;

    /**
     * Flag for {@link addCrossProfileIntentFilter}: if this flag is set:
     * when resolving an intent that matches the {@link CrossProfileIntentFilter}, the current
     * profile will be skipped.
     * Only activities in the target user can respond to the intent.
     * @hide
     */
    public static final int SKIP_CURRENT_PROFILE = 0x00000002;

    /** @hide */
    @IntDef({PERMISSION_GRANTED, PERMISSION_DENIED})
    @Retention(RetentionPolicy.SOURCE)
@@ -3586,30 +3602,14 @@ public abstract class PackageManager {
     * {@link CrossProfileIntentFilter}
     * @hide
     */
    public abstract void addCrossProfileIntentFilter(IntentFilter filter, boolean removable,
            int sourceUserId, int targetUserId);

    /**
     * @hide
     * @deprecated
     * TODO: remove it as soon as the code of ManagedProvisionning is updated
    */
    public abstract void addForwardingIntentFilter(IntentFilter filter, boolean removable,
            int sourceUserId, int targetUserId);
    public abstract void addCrossProfileIntentFilter(IntentFilter filter, int sourceUserId,
            int targetUserId, int flags);

    /**
     * Clearing removable {@link CrossProfileIntentFilter}s which have the specified user as their
     * source
     * Clearing {@link CrossProfileIntentFilter}s which have the specified user as their
     * source, and have been set by the profile owner
     * @param sourceUserId
     * be cleared.
     * @hide
     */
    public abstract void clearCrossProfileIntentFilters(int sourceUserId);

    /**
     * @hide
     * @deprecated
     * TODO: remove it as soon as the code of ManagedProvisionning is updated
    */
    public abstract void clearForwardingIntentFilters(int sourceUserId);
}
+15 −14
Original line number Diff line number Diff line
@@ -32,35 +32,31 @@ import android.os.UserHandle;
 */
class CrossProfileIntentFilter extends IntentFilter {
    private static final String ATTR_TARGET_USER_ID = "targetUserId";
    private static final String ATTR_USER_ID_DEST = "userIdDest";//Old name. Kept for compatibility.
    private static final String ATTR_REMOVABLE = "removable";
    private static final String ATTR_FLAGS = "flags";
    private static final String ATTR_FILTER = "filter";

    private static final String TAG = "CrossProfileIntentFilter";

    // If the intent matches the IntentFilter, then it can be forwarded to this userId.
    final int mTargetUserId;
    boolean mRemovable;
    final int mFlags;

    CrossProfileIntentFilter(IntentFilter filter, boolean removable, int targetUserId) {
    CrossProfileIntentFilter(IntentFilter filter, int targetUserId, int flags) {
        super(filter);
        mTargetUserId = targetUserId;
        mRemovable = removable;
        mFlags = flags;
    }

    public int getTargetUserId() {
        return mTargetUserId;
    }

    public boolean isRemovable() {
        return mRemovable;
    public int getFlags() {
        return mFlags;
    }

    CrossProfileIntentFilter(XmlPullParser parser) throws XmlPullParserException, IOException {
        String targetUserIdString = parser.getAttributeValue(null, ATTR_TARGET_USER_ID);
        if (targetUserIdString == null) {
            targetUserIdString = parser.getAttributeValue(null, ATTR_USER_ID_DEST);
        }
        if (targetUserIdString == null) {
            String msg = "Missing element under " + TAG +": " + ATTR_TARGET_USER_ID + " at " +
                    parser.getPositionDescription();
@@ -69,9 +65,14 @@ class CrossProfileIntentFilter extends IntentFilter {
        } else {
            mTargetUserId = Integer.parseInt(targetUserIdString);
        }
        String removableString = parser.getAttributeValue(null, ATTR_REMOVABLE);
        if (removableString != null) {
            mRemovable = Boolean.parseBoolean(removableString);
        String flagsString = parser.getAttributeValue(null, ATTR_FLAGS);
        if (flagsString == null) {
            String msg = "Missing element under " + TAG +": " + ATTR_FLAGS + " at " +
                    parser.getPositionDescription();
            PackageManagerService.reportSettingsProblem(Log.WARN, msg);
            mFlags = 0;
        } else {
            mFlags = Integer.parseInt(flagsString);
        }
        int outerDepth = parser.getDepth();
        String tagName = parser.getName();
@@ -104,7 +105,7 @@ class CrossProfileIntentFilter extends IntentFilter {

    public void writeToXml(XmlSerializer serializer) throws IOException {
        serializer.attribute(null, ATTR_TARGET_USER_ID, Integer.toString(mTargetUserId));
        serializer.attribute(null, ATTR_REMOVABLE, Boolean.toString(mRemovable));
        serializer.attribute(null, ATTR_FLAGS, Integer.toString(mFlags));
        serializer.startTag(null, ATTR_FILTER);
            super.writeToXml(serializer);
        serializer.endTag(null, ATTR_FILTER);
+95 −45
Original line number Diff line number Diff line
@@ -147,6 +147,7 @@ import android.util.LogPrinter;
import android.util.PrintStreamPrinter;
import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseBooleanArray;
import android.util.Xml;
import android.view.Display;
@@ -3347,7 +3348,7 @@ public class PackageManagerService extends IPackageManager.Stub {
    }
    /*
     * Returns if intent can be forwarded from the userId from to dest
     * Returns if intent can be forwarded from the sourceUserId to the targetUserId
     */
    @Override
    public boolean canForwardTo(Intent intent, String resolvedType, int sourceUserId,
@@ -3367,9 +3368,9 @@ public class PackageManagerService extends IPackageManager.Stub {
    private List<CrossProfileIntentFilter> getMatchingCrossProfileIntentFilters(Intent intent,
            String resolvedType, int userId) {
        CrossProfileIntentResolver cpir = mSettings.mCrossProfileIntentResolvers.get(userId);
        if (cpir != null) {
            return cpir.queryIntent(intent, resolvedType, false, userId);
        CrossProfileIntentResolver resolver = mSettings.mCrossProfileIntentResolvers.get(userId);
        if (resolver != null) {
            return resolver.queryIntent(intent, resolvedType, false, userId);
        }
        return null;
    }
@@ -3402,36 +3403,24 @@ public class PackageManagerService extends IPackageManager.Stub {
        synchronized (mPackages) {
            final String pkgName = intent.getPackage();
            if (pkgName == null) {
                List<ResolveInfo> result =
                        mActivities.queryIntent(intent, resolvedType, flags, userId);
                // Checking if we can forward the intent to another user
                List<CrossProfileIntentFilter> cpifs =
                List<ResolveInfo> result;
                List<CrossProfileIntentFilter> matchingFilters =
                        getMatchingCrossProfileIntentFilters(intent, resolvedType, userId);
                if (cpifs != null) {
                    CrossProfileIntentFilter crossProfileIntentFilterWithResult = null;
                    HashSet<Integer> alreadyTriedUserIds = new HashSet<Integer>();
                    for (CrossProfileIntentFilter cpif : cpifs) {
                        int targetUserId = cpif.getTargetUserId();
                        // Two {@link CrossProfileIntentFilter}s can have the same targetUserId and
                        // match the same an intent. For performance reasons, it is better not to
                        // run queryIntent twice for the same userId
                        if (!alreadyTriedUserIds.contains(targetUserId)) {
                            List<ResolveInfo> resultUser = mActivities.queryIntent(intent,
                                    resolvedType, flags, targetUserId);
                            if (resultUser != null) {
                                crossProfileIntentFilterWithResult = cpif;
                                // As soon as there is a match in another user, we add the
                                // intentForwarderActivity to the list of ResolveInfo.
                                break;
                            }
                            alreadyTriedUserIds.add(targetUserId);
                        }
                    }
                    if (crossProfileIntentFilterWithResult != null) {
                        ResolveInfo forwardingResolveInfo = createForwardingResolveInfo(
                                crossProfileIntentFilterWithResult, userId);
                        result.add(forwardingResolveInfo);
                // Check for results that need to skip the current profile.
                ResolveInfo resolveInfo = querySkipCurrentProfileIntents(matchingFilters, intent,
                        resolvedType, flags, userId);
                if (resolveInfo != null) {
                    result = new ArrayList<ResolveInfo>(1);
                    result.add(resolveInfo);
                    return result;
                }
                // Check for results in the current profile.
                result = mActivities.queryIntent(intent, resolvedType, flags, userId);
                // Check for cross profile results.
                resolveInfo = queryCrossProfileIntents(
                        matchingFilters, intent, resolvedType, flags, userId);
                if (resolveInfo != null) {
                    result.add(resolveInfo);
                }
                return result;
            }
@@ -3444,10 +3433,68 @@ public class PackageManagerService extends IPackageManager.Stub {
        }
    }
    private ResolveInfo createForwardingResolveInfo(CrossProfileIntentFilter cpif,
    private ResolveInfo querySkipCurrentProfileIntents(
            List<CrossProfileIntentFilter> matchingFilters, Intent intent, String resolvedType,
            int flags, int sourceUserId) {
        if (matchingFilters != null) {
            int size = matchingFilters.size();
            for (int i = 0; i < size; i ++) {
                CrossProfileIntentFilter filter = matchingFilters.get(i);
                if ((filter.getFlags() & PackageManager.SKIP_CURRENT_PROFILE) != 0) {
                    // Checking if there are activities in the target user that can handle the
                    // intent.
                    ResolveInfo resolveInfo = checkTargetCanHandle(filter, intent, resolvedType,
                            flags, sourceUserId);
                    if (resolveInfo != null) {
                        return createForwardingResolveInfo(filter, sourceUserId);
                    }
                }
            }
        }
        return null;
    }
    // Return matching ResolveInfo if any for skip current profile intent filters.
    private ResolveInfo queryCrossProfileIntents(
            List<CrossProfileIntentFilter> matchingFilters, Intent intent, String resolvedType,
            int flags, int sourceUserId) {
        if (matchingFilters != null) {
            // Two {@link CrossProfileIntentFilter}s can have the same targetUserId and
            // match the same intent. For performance reasons, it is better not to
            // run queryIntent twice for the same userId
            SparseBooleanArray alreadyTriedUserIds = new SparseBooleanArray();
            int size = matchingFilters.size();
            for (int i = 0; i < size; i++) {
                CrossProfileIntentFilter filter = matchingFilters.get(i);
                int targetUserId = filter.getTargetUserId();
                if ((filter.getFlags() & PackageManager.SKIP_CURRENT_PROFILE) == 0
                        && !alreadyTriedUserIds.get(targetUserId)) {
                    // Checking if there are activities in the target user that can handle the
                    // intent.
                    ResolveInfo resolveInfo = checkTargetCanHandle(filter, intent, resolvedType,
                            flags, sourceUserId);
                    if (resolveInfo != null) return resolveInfo;
                    alreadyTriedUserIds.put(targetUserId, true);
                }
            }
        }
        return null;
    }
    private ResolveInfo checkTargetCanHandle(CrossProfileIntentFilter filter, Intent intent,
            String resolvedType, int flags, int sourceUserId) {
        List<ResolveInfo> resultTargetUser = mActivities.queryIntent(intent,
                resolvedType, flags, filter.getTargetUserId());
        if (resultTargetUser != null) {
            return createForwardingResolveInfo(filter, sourceUserId);
        }
        return null;
    }
    private ResolveInfo createForwardingResolveInfo(CrossProfileIntentFilter filter,
            int sourceUserId) {
        String className;
        int targetUserId = cpif.getTargetUserId();
        int targetUserId = filter.getTargetUserId();
        if (targetUserId == UserHandle.USER_OWNER) {
            className = FORWARD_INTENT_TO_USER_OWNER;
        } else {
@@ -3463,7 +3510,7 @@ public class PackageManagerService extends IPackageManager.Stub {
        forwardingResolveInfo.preferredOrder = 0;
        forwardingResolveInfo.match = 0;
        forwardingResolveInfo.isDefault = true;
        forwardingResolveInfo.filter = cpif;
        forwardingResolveInfo.filter = filter;
        return forwardingResolveInfo;
    }
@@ -11542,17 +11589,18 @@ public class PackageManagerService extends IPackageManager.Stub {
    }
    @Override
    public void addCrossProfileIntentFilter(IntentFilter filter, boolean removable,
            int sourceUserId, int targetUserId) {
    public void addCrossProfileIntentFilter(IntentFilter intentFilter, int sourceUserId,
            int targetUserId, int flags) {
        mContext.enforceCallingOrSelfPermission(
                        android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, null);
        if (filter.countActions() == 0) {
        if (intentFilter.countActions() == 0) {
            Slog.w(TAG, "Cannot set a crossProfile intent filter with no filter actions");
            return;
        }
        synchronized (mPackages) {
            mSettings.editCrossProfileIntentResolverLPw(sourceUserId).addFilter(
                    new CrossProfileIntentFilter(filter, removable, targetUserId));
            CrossProfileIntentFilter filter = new CrossProfileIntentFilter(intentFilter,
                    targetUserId, flags);
            mSettings.editCrossProfileIntentResolverLPw(sourceUserId).addFilter(filter);
            mSettings.writePackageRestrictionsLPr(sourceUserId);
        }
    }
@@ -11562,12 +11610,14 @@ public class PackageManagerService extends IPackageManager.Stub {
        mContext.enforceCallingOrSelfPermission(
                        android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, null);
        synchronized (mPackages) {
            CrossProfileIntentResolver cpir =
            CrossProfileIntentResolver resolver =
                    mSettings.editCrossProfileIntentResolverLPw(sourceUserId);
            HashSet<CrossProfileIntentFilter> set =
                    new HashSet<CrossProfileIntentFilter>(cpir.filterSet());
            for (CrossProfileIntentFilter cpif : set) {
                if (cpif.isRemovable()) cpir.removeFilter(cpif);
                    new HashSet<CrossProfileIntentFilter>(resolver.filterSet());
            for (CrossProfileIntentFilter filter : set) {
                if ((filter.getFlags() & PackageManager.SET_BY_PROFILE_OWNER) != 0) {
                    resolver.removeFilter(filter);
                }
            }
            mSettings.writePackageRestrictionsLPr(sourceUserId);
        }
Loading