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

Commit 63c6d8ec authored by Julia Reynolds's avatar Julia Reynolds Committed by Android (Google) Code Review
Browse files

Merge "Modify to ensure that ManagedServices supports concurrent multi-user environments" into main

parents ef2d8101 10c3ac0d
Loading
Loading
Loading
Loading
+252 −38
Original line number Original line Diff line number Diff line
@@ -25,6 +25,8 @@ import static android.os.UserHandle.USER_ALL;
import static android.os.UserHandle.USER_SYSTEM;
import static android.os.UserHandle.USER_SYSTEM;
import static android.service.notification.NotificationListenerService.META_DATA_DEFAULT_AUTOBIND;
import static android.service.notification.NotificationListenerService.META_DATA_DEFAULT_AUTOBIND;


import static com.android.server.notification.Flags.FLAG_MANAGED_SERVICES_CONCURRENT_MULTIUSER;
import static com.android.server.notification.Flags.managedServicesConcurrentMultiuser;
import static com.android.server.notification.NotificationManagerService.privateSpaceFlagsEnabled;
import static com.android.server.notification.NotificationManagerService.privateSpaceFlagsEnabled;


import android.annotation.FlaggedApi;
import android.annotation.FlaggedApi;
@@ -75,7 +77,9 @@ import com.android.internal.util.XmlUtils;
import com.android.internal.util.function.TriPredicate;
import com.android.internal.util.function.TriPredicate;
import com.android.modules.utils.TypedXmlPullParser;
import com.android.modules.utils.TypedXmlPullParser;
import com.android.modules.utils.TypedXmlSerializer;
import com.android.modules.utils.TypedXmlSerializer;
import com.android.server.LocalServices;
import com.android.server.notification.NotificationManagerService.DumpFilter;
import com.android.server.notification.NotificationManagerService.DumpFilter;
import com.android.server.pm.UserManagerInternal;
import com.android.server.utils.TimingsTraceAndSlog;
import com.android.server.utils.TimingsTraceAndSlog;


import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParser;
@@ -134,6 +138,7 @@ abstract public class ManagedServices {
    private final UserProfiles mUserProfiles;
    private final UserProfiles mUserProfiles;
    protected final IPackageManager mPm;
    protected final IPackageManager mPm;
    protected final UserManager mUm;
    protected final UserManager mUm;
    protected final UserManagerInternal mUmInternal;
    private final Config mConfig;
    private final Config mConfig;
    private final Handler mHandler = new Handler(Looper.getMainLooper());
    private final Handler mHandler = new Handler(Looper.getMainLooper());


@@ -157,12 +162,17 @@ abstract public class ManagedServices {
    protected final ArraySet<String> mDefaultPackages = new ArraySet<>();
    protected final ArraySet<String> mDefaultPackages = new ArraySet<>();


    // lists the component names of all enabled (and therefore potentially connected)
    // lists the component names of all enabled (and therefore potentially connected)
    // app services for current profiles.
    // app services for each user. This is intended to support a concurrent multi-user environment.
    // key value is the resolved userId.
    @GuardedBy("mMutex")
    @GuardedBy("mMutex")
    private final ArraySet<ComponentName> mEnabledServicesForCurrentProfiles = new ArraySet<>();
    private final SparseArray<ArraySet<ComponentName>> mEnabledServicesByUser =
    // Just the packages from mEnabledServicesForCurrentProfiles
            new SparseArray<>();
    // Just the packages from mEnabledServicesByUser
    // This is intended to support a concurrent multi-user environment.
    // key value is the resolved userId.
    @GuardedBy("mMutex")
    @GuardedBy("mMutex")
    private final ArraySet<String> mEnabledServicesPackageNames = new ArraySet<>();
    private final SparseArray<ArraySet<String>> mEnabledServicesPackageNamesByUser =
            new SparseArray<>();
    // Per user id, list of enabled packages that have nevertheless asked not to be run
    // Per user id, list of enabled packages that have nevertheless asked not to be run
    @GuardedBy("mSnoozing")
    @GuardedBy("mSnoozing")
    private final SparseSetArray<ComponentName> mSnoozing = new SparseSetArray<>();
    private final SparseSetArray<ComponentName> mSnoozing = new SparseSetArray<>();
@@ -195,6 +205,7 @@ abstract public class ManagedServices {
        mConfig = getConfig();
        mConfig = getConfig();
        mApprovalLevel = APPROVAL_BY_COMPONENT;
        mApprovalLevel = APPROVAL_BY_COMPONENT;
        mUm = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
        mUm = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
        mUmInternal = LocalServices.getService(UserManagerInternal.class);
    }
    }


    abstract protected Config getConfig();
    abstract protected Config getConfig();
@@ -383,12 +394,31 @@ abstract public class ManagedServices {
        }
        }


        synchronized (mMutex) {
        synchronized (mMutex) {
            pw.println("    All " + getCaption() + "s (" + mEnabledServicesForCurrentProfiles.size()
            if (managedServicesConcurrentMultiuser()) {
                for (int i = 0; i < mEnabledServicesByUser.size(); i++) {
                    final int userId = mEnabledServicesByUser.keyAt(i);
                    final ArraySet<ComponentName> componentNames =
                            mEnabledServicesByUser.get(userId);
                    String userString = userId == UserHandle.USER_CURRENT
                            ? "current profiles" : "user " + Integer.toString(userId);
                    pw.println("    All " + getCaption() + "s (" + componentNames.size()
                            + ") enabled for " +  userString + ":");
                    for (ComponentName cmpt : componentNames) {
                        if (filter != null && !filter.matches(cmpt)) continue;
                        pw.println("      " + cmpt);
                    }
                }
            } else {
                final ArraySet<ComponentName> enabledServicesForCurrentProfiles =
                        mEnabledServicesByUser.get(UserHandle.USER_CURRENT);
                pw.println("    All " + getCaption() + "s ("
                        + enabledServicesForCurrentProfiles.size()
                        + ") enabled for current profiles:");
                        + ") enabled for current profiles:");
            for (ComponentName cmpt : mEnabledServicesForCurrentProfiles) {
                for (ComponentName cmpt : enabledServicesForCurrentProfiles) {
                    if (filter != null && !filter.matches(cmpt)) continue;
                    if (filter != null && !filter.matches(cmpt)) continue;
                    pw.println("      " + cmpt);
                    pw.println("      " + cmpt);
                }
                }
            }


            pw.println("    Live " + getCaption() + "s (" + mServices.size() + "):");
            pw.println("    Live " + getCaption() + "s (" + mServices.size() + "):");
            for (ManagedServiceInfo info : mServices) {
            for (ManagedServiceInfo info : mServices) {
@@ -442,12 +472,25 @@ abstract public class ManagedServices {
            }
            }
        }
        }



        synchronized (mMutex) {
        synchronized (mMutex) {
            for (ComponentName cmpt : mEnabledServicesForCurrentProfiles) {
            if (managedServicesConcurrentMultiuser()) {
                for (int i = 0; i < mEnabledServicesByUser.size(); i++) {
                    final int userId = mEnabledServicesByUser.keyAt(i);
                    final ArraySet<ComponentName> componentNames =
                            mEnabledServicesByUser.get(userId);
                    for (ComponentName cmpt : componentNames) {
                        if (filter != null && !filter.matches(cmpt)) continue;
                        cmpt.dumpDebug(proto, ManagedServicesProto.ENABLED);
                    }
                }
            } else {
                final ArraySet<ComponentName> enabledServicesForCurrentProfiles =
                        mEnabledServicesByUser.get(UserHandle.USER_CURRENT);
                for (ComponentName cmpt : enabledServicesForCurrentProfiles) {
                    if (filter != null && !filter.matches(cmpt)) continue;
                    if (filter != null && !filter.matches(cmpt)) continue;
                    cmpt.dumpDebug(proto, ManagedServicesProto.ENABLED);
                    cmpt.dumpDebug(proto, ManagedServicesProto.ENABLED);
                }
                }
            }
            for (ManagedServiceInfo info : mServices) {
            for (ManagedServiceInfo info : mServices) {
                if (filter != null && !filter.matches(info.component)) continue;
                if (filter != null && !filter.matches(info.component)) continue;
                info.dumpDebug(proto, ManagedServicesProto.LIVE_SERVICES, this);
                info.dumpDebug(proto, ManagedServicesProto.LIVE_SERVICES, this);
@@ -841,9 +884,31 @@ abstract public class ManagedServices {
        }
        }
    }
    }


    /** convenience method for looking in mEnabledServicesPackageNamesByUser
     * for UserHandle.USER_CURRENT.
     * This is a legacy API. When FLAG_MANAGED_SERVICES_CONCURRENT_MULTIUSER becomes
     * trunk stable,  this API should be deprecated.  Additionally, when this method
     * is deprecated, the unit tests written using this method should also be revised.
     *
     * @param pkg target package name
     * @return boolean value that indicates whether it is enabled for the current profiles
     */
    protected boolean isComponentEnabledForPackage(String pkg) {
    protected boolean isComponentEnabledForPackage(String pkg) {
        return isComponentEnabledForPackage(pkg, UserHandle.USER_CURRENT);
    }

    /** convenience method for looking in mEnabledServicesPackageNamesByUser
     *
     * @param pkg target package name
     * @param userId the id of the target user
     * @return boolean value that indicates whether it is enabled for the target user
     */
    @FlaggedApi(FLAG_MANAGED_SERVICES_CONCURRENT_MULTIUSER)
    protected boolean isComponentEnabledForPackage(String pkg, int userId) {
        synchronized (mMutex) {
        synchronized (mMutex) {
            return mEnabledServicesPackageNames.contains(pkg);
            ArraySet<String> enabledServicesPackageNames =
                    mEnabledServicesPackageNamesByUser.get(resolveUserId(userId));
            return enabledServicesPackageNames != null && enabledServicesPackageNames.contains(pkg);
        }
        }
    }
    }


@@ -1016,9 +1081,14 @@ abstract public class ManagedServices {
    public void onPackagesChanged(boolean removingPackage, String[] pkgList, int[] uidList) {
    public void onPackagesChanged(boolean removingPackage, String[] pkgList, int[] uidList) {
        if (DEBUG) {
        if (DEBUG) {
            synchronized (mMutex) {
            synchronized (mMutex) {
                int resolvedUserId = (managedServicesConcurrentMultiuser()
                        && (uidList != null && uidList.length > 0))
                        ? resolveUserId(UserHandle.getUserId(uidList[0]))
                        : UserHandle.USER_CURRENT;
                Slog.d(TAG, "onPackagesChanged removingPackage=" + removingPackage
                Slog.d(TAG, "onPackagesChanged removingPackage=" + removingPackage
                        + " pkgList=" + (pkgList == null ? null : Arrays.asList(pkgList))
                        + " pkgList=" + (pkgList == null ? null : Arrays.asList(pkgList))
                        + " mEnabledServicesPackageNames=" + mEnabledServicesPackageNames);
                        + " mEnabledServicesPackageNames="
                        + mEnabledServicesPackageNamesByUser.get(resolvedUserId));
            }
            }
        }
        }


@@ -1034,11 +1104,18 @@ abstract public class ManagedServices {
                }
                }
            }
            }
            for (String pkgName : pkgList) {
            for (String pkgName : pkgList) {
                if (!managedServicesConcurrentMultiuser()) {
                    if (isComponentEnabledForPackage(pkgName)) {
                    if (isComponentEnabledForPackage(pkgName)) {
                        anyServicesInvolved = true;
                        anyServicesInvolved = true;
                    }
                    }
                }
                if (uidList != null && uidList.length > 0) {
                if (uidList != null && uidList.length > 0) {
                    for (int uid : uidList) {
                    for (int uid : uidList) {
                        if (managedServicesConcurrentMultiuser()) {
                            if (isComponentEnabledForPackage(pkgName, UserHandle.getUserId(uid))) {
                                anyServicesInvolved = true;
                            }
                        }
                        if (isPackageAllowed(pkgName, UserHandle.getUserId(uid))) {
                        if (isPackageAllowed(pkgName, UserHandle.getUserId(uid))) {
                            anyServicesInvolved = true;
                            anyServicesInvolved = true;
                            trimApprovedListsForInvalidServices(pkgName, UserHandle.getUserId(uid));
                            trimApprovedListsForInvalidServices(pkgName, UserHandle.getUserId(uid));
@@ -1065,6 +1142,36 @@ abstract public class ManagedServices {
        unbindUserServices(user);
        unbindUserServices(user);
    }
    }


    /**
     * Call this method when a user is stopped
     *
     * @param user the id of the stopped user
     */
    public void onUserStopped(int user) {
        if (!managedServicesConcurrentMultiuser()) {
            return;
        }
        boolean hasAny = false;
        synchronized (mMutex) {
            if (mEnabledServicesByUser.contains(user)
                    && mEnabledServicesPackageNamesByUser.contains(user)) {
                // Through the ManagedServices.resolveUserId,
                // we resolve UserHandle.USER_CURRENT as the key for users
                // other than the visible background user.
                // Therefore, the user IDs that exist as keys for each member variable
                // correspond to the visible background user.
                // We need to unbind services of the stopped visible background user.
                mEnabledServicesByUser.remove(user);
                mEnabledServicesPackageNamesByUser.remove(user);
                hasAny = true;
            }
        }
        if (hasAny) {
            Slog.i(TAG, "Removing approved services for stopped user " + user);
            unbindUserServices(user);
        }
    }

    public void onUserSwitched(int user) {
    public void onUserSwitched(int user) {
        if (DEBUG) Slog.d(TAG, "onUserSwitched u=" + user);
        if (DEBUG) Slog.d(TAG, "onUserSwitched u=" + user);
        unbindOtherUserServices(user);
        unbindOtherUserServices(user);
@@ -1386,19 +1493,42 @@ abstract public class ManagedServices {
    protected void populateComponentsToBind(SparseArray<Set<ComponentName>> componentsToBind,
    protected void populateComponentsToBind(SparseArray<Set<ComponentName>> componentsToBind,
            final IntArray activeUsers,
            final IntArray activeUsers,
            SparseArray<ArraySet<ComponentName>> approvedComponentsByUser) {
            SparseArray<ArraySet<ComponentName>> approvedComponentsByUser) {
        mEnabledServicesForCurrentProfiles.clear();
        mEnabledServicesPackageNames.clear();
        final int nUserIds = activeUsers.size();
        final int nUserIds = activeUsers.size();

        if (managedServicesConcurrentMultiuser()) {
            for (int i = 0; i < nUserIds; ++i) {
                final int resolvedUserId = resolveUserId(activeUsers.get(i));
                if (mEnabledServicesByUser.get(resolvedUserId) != null) {
                    mEnabledServicesByUser.get(resolvedUserId).clear();
                }
                if (mEnabledServicesPackageNamesByUser.get(resolvedUserId) != null) {
                    mEnabledServicesPackageNamesByUser.get(resolvedUserId).clear();
                }
            }
        } else {
            mEnabledServicesByUser.clear();
            mEnabledServicesPackageNamesByUser.clear();
        }
        for (int i = 0; i < nUserIds; ++i) {
        for (int i = 0; i < nUserIds; ++i) {
            // decode the list of components
            final int userId = activeUsers.get(i);
            final int userId = activeUsers.get(i);
            // decode the list of components
            final ArraySet<ComponentName> userComponents = approvedComponentsByUser.get(userId);
            final ArraySet<ComponentName> userComponents = approvedComponentsByUser.get(userId);
            if (null == userComponents) {
            if (null == userComponents) {
                componentsToBind.put(userId, new ArraySet<>());
                componentsToBind.put(userId, new ArraySet<>());
                continue;
                continue;
            }
            }


            final int resolvedUserId = managedServicesConcurrentMultiuser()
                    ? resolveUserId(userId)
                    : UserHandle.USER_CURRENT;
            ArraySet<ComponentName> enabledServices =
                    mEnabledServicesByUser.contains(resolvedUserId)
                    ? mEnabledServicesByUser.get(resolvedUserId)
                    : new ArraySet<>();
            ArraySet<String> enabledServicesPackageName =
                    mEnabledServicesPackageNamesByUser.contains(resolvedUserId)
                    ? mEnabledServicesPackageNamesByUser.get(resolvedUserId)
                    : new ArraySet<>();

            final Set<ComponentName> add = new HashSet<>(userComponents);
            final Set<ComponentName> add = new HashSet<>(userComponents);
            synchronized (mSnoozing) {
            synchronized (mSnoozing) {
                ArraySet<ComponentName> snoozed = mSnoozing.get(userId);
                ArraySet<ComponentName> snoozed = mSnoozing.get(userId);
@@ -1409,12 +1539,12 @@ abstract public class ManagedServices {


            componentsToBind.put(userId, add);
            componentsToBind.put(userId, add);


            mEnabledServicesForCurrentProfiles.addAll(userComponents);
            enabledServices.addAll(userComponents);

            for (int j = 0; j < userComponents.size(); j++) {
            for (int j = 0; j < userComponents.size(); j++) {
                final ComponentName component = userComponents.valueAt(j);
                enabledServicesPackageName.add(userComponents.valueAt(j).getPackageName());
                mEnabledServicesPackageNames.add(component.getPackageName());
            }
            }
            mEnabledServicesByUser.put(resolvedUserId, enabledServices);
            mEnabledServicesPackageNamesByUser.put(resolvedUserId, enabledServicesPackageName);
        }
        }
    }
    }


@@ -1453,13 +1583,9 @@ abstract public class ManagedServices {
     */
     */
    protected void rebindServices(boolean forceRebind, int userToRebind) {
    protected void rebindServices(boolean forceRebind, int userToRebind) {
        if (DEBUG) Slog.d(TAG, "rebindServices " + forceRebind + " " + userToRebind);
        if (DEBUG) Slog.d(TAG, "rebindServices " + forceRebind + " " + userToRebind);
        IntArray userIds = mUserProfiles.getCurrentProfileIds();
        boolean rebindAllCurrentUsers = mUserProfiles.isProfileUser(userToRebind, mContext)
        boolean rebindAllCurrentUsers = mUserProfiles.isProfileUser(userToRebind, mContext)
                && allowRebindForParentUser();
                && allowRebindForParentUser();
        if (userToRebind != USER_ALL && !rebindAllCurrentUsers) {
        IntArray userIds = getUserIdsForRebindServices(userToRebind, rebindAllCurrentUsers);
            userIds = new IntArray(1);
            userIds.add(userToRebind);
        }


        final SparseArray<Set<ComponentName>> componentsToBind = new SparseArray<>();
        final SparseArray<Set<ComponentName>> componentsToBind = new SparseArray<>();
        final SparseArray<Set<ComponentName>> componentsToUnbind = new SparseArray<>();
        final SparseArray<Set<ComponentName>> componentsToUnbind = new SparseArray<>();
@@ -1483,6 +1609,23 @@ abstract public class ManagedServices {
        bindToServices(componentsToBind);
        bindToServices(componentsToBind);
    }
    }


    private IntArray getUserIdsForRebindServices(int userToRebind, boolean rebindAllCurrentUsers) {
        IntArray userIds = mUserProfiles.getCurrentProfileIds();
        if (userToRebind != USER_ALL && !rebindAllCurrentUsers) {
            userIds = new IntArray(1);
            userIds.add(userToRebind);
        } else if (managedServicesConcurrentMultiuser()
                && userToRebind == USER_ALL) {
            for (UserInfo user : mUm.getUsers()) {
                if (mUmInternal.isVisibleBackgroundFullUser(user.id)
                        && !userIds.contains(user.id)) {
                    userIds.add(user.id);
                }
            }
        }
        return userIds;
    }

    /**
    /**
     * Called when user switched to unbind all services from other users.
     * Called when user switched to unbind all services from other users.
     */
     */
@@ -1506,7 +1649,11 @@ abstract public class ManagedServices {
        synchronized (mMutex) {
        synchronized (mMutex) {
            final Set<ManagedServiceInfo> removableBoundServices = getRemovableConnectedServices();
            final Set<ManagedServiceInfo> removableBoundServices = getRemovableConnectedServices();
            for (ManagedServiceInfo info : removableBoundServices) {
            for (ManagedServiceInfo info : removableBoundServices) {
                if ((allExceptUser && (info.userid != user))
                // User switching is the event for the forground user.
                // It should not affect the service of the visible background user.
                if ((allExceptUser && (info.userid != user)
                        && !(managedServicesConcurrentMultiuser()
                            && info.isVisibleBackgroundUserService))
                        || (!allExceptUser && (info.userid == user))) {
                        || (!allExceptUser && (info.userid == user))) {
                    Set<ComponentName> toUnbind =
                    Set<ComponentName> toUnbind =
                            componentsToUnbind.get(info.userid, new ArraySet<>());
                            componentsToUnbind.get(info.userid, new ArraySet<>());
@@ -1860,6 +2007,29 @@ abstract public class ManagedServices {
        return true;
        return true;
    }
    }


    /**
     * This method returns the mapped id for the incoming user id
     * If the incoming id was not the id of the visible background user, it returns USER_CURRENT.
     * In the other cases, it returns the same value as the input.
     *
     * @param userId the id of the user
     * @return the user id if it is a visible background user, otherwise
     * {@link UserHandle#USER_CURRENT}
     */
    @FlaggedApi(FLAG_MANAGED_SERVICES_CONCURRENT_MULTIUSER)
    @VisibleForTesting
    public int resolveUserId(int userId) {
        if (managedServicesConcurrentMultiuser()) {
            if (mUmInternal.isVisibleBackgroundFullUser(userId)) {
                // The dataset of the visible background user should be managed independently.
                return userId;
            }
        }
        // The data of current user and its profile users need to  be managed
        // in a dataset as before.
        return UserHandle.USER_CURRENT;
    }

    /**
    /**
     * Returns true if services in the parent user should be rebound
     * Returns true if services in the parent user should be rebound
     *  when rebindServices is called with a profile userId.
     *  when rebindServices is called with a profile userId.
@@ -1878,6 +2048,8 @@ abstract public class ManagedServices {
        public int targetSdkVersion;
        public int targetSdkVersion;
        public Pair<ComponentName, Integer> mKey;
        public Pair<ComponentName, Integer> mKey;
        public int uid;
        public int uid;
        @FlaggedApi(FLAG_MANAGED_SERVICES_CONCURRENT_MULTIUSER)
        public boolean isVisibleBackgroundUserService;


        public ManagedServiceInfo(IInterface service, ComponentName component,
        public ManagedServiceInfo(IInterface service, ComponentName component,
                int userid, boolean isSystem, ServiceConnection connection, int targetSdkVersion,
                int userid, boolean isSystem, ServiceConnection connection, int targetSdkVersion,
@@ -1889,6 +2061,10 @@ abstract public class ManagedServices {
            this.connection = connection;
            this.connection = connection;
            this.targetSdkVersion = targetSdkVersion;
            this.targetSdkVersion = targetSdkVersion;
            this.uid = uid;
            this.uid = uid;
            if (managedServicesConcurrentMultiuser()) {
                this.isVisibleBackgroundUserService = LocalServices
                        .getService(UserManagerInternal.class).isVisibleBackgroundFullUser(userid);
            }
            mKey = Pair.create(component, userid);
            mKey = Pair.create(component, userid);
        }
        }


@@ -1937,19 +2113,28 @@ abstract public class ManagedServices {
        }
        }


        public boolean isSameUser(int userId) {
        public boolean isSameUser(int userId) {
            if (!isEnabledForCurrentProfiles()) {
            if (!isEnabledForUser()) {
                return false;
                return false;
            }
            }
            return userId == USER_ALL || userId == this.userid;
            return userId == USER_ALL || userId == this.userid;
        }
        }


        public boolean enabledAndUserMatches(int nid) {
        public boolean enabledAndUserMatches(int nid) {
            if (!isEnabledForCurrentProfiles()) {
            if (!isEnabledForUser()) {
                return false;
                return false;
            }
            }
            if (this.userid == USER_ALL) return true;
            if (this.userid == USER_ALL) return true;
            if (this.isSystem) return true;
            if (this.isSystem) return true;
            if (nid == USER_ALL || nid == this.userid) return true;
            if (nid == USER_ALL || nid == this.userid) return true;
            if (managedServicesConcurrentMultiuser()
                    && mUmInternal.getProfileParentId(nid)
                        != mUmInternal.getProfileParentId(this.userid)) {
                // If the profile parent IDs do not match each other,
                // it is determined that the users do not match.
                // This situation may occur when comparing the current user's ID
                // with the visible background user's ID.
                return false;
            }
            return supportsProfiles()
            return supportsProfiles()
                    && mUserProfiles.isCurrentProfile(nid)
                    && mUserProfiles.isCurrentProfile(nid)
                    && isPermittedForProfile(nid);
                    && isPermittedForProfile(nid);
@@ -1969,12 +2154,21 @@ abstract public class ManagedServices {
            removeServiceImpl(this.service, this.userid);
            removeServiceImpl(this.service, this.userid);
        }
        }


        /** convenience method for looking in mEnabledServicesForCurrentProfiles */
        /**
        public boolean isEnabledForCurrentProfiles() {
         * convenience method for looking in mEnabledServicesByUser.
         * If FLAG_MANAGED_SERVICES_CONCURRENT_MULTIUSER is disabled, this manages the data using
         * only UserHandle.USER_CURRENT as the key, in order to behave the same as the legacy logic.
        */
        public boolean isEnabledForUser() {
            if (this.isSystem) return true;
            if (this.isSystem) return true;
            if (this.connection == null) return false;
            if (this.connection == null) return false;
            synchronized (mMutex) {
            synchronized (mMutex) {
                return mEnabledServicesForCurrentProfiles.contains(this.component);
                int resolvedUserId = managedServicesConcurrentMultiuser()
                        ? resolveUserId(this.userid)
                        : UserHandle.USER_CURRENT;
                ArraySet<ComponentName> enabledServices =
                        mEnabledServicesByUser.get(resolvedUserId);
                return enabledServices != null && enabledServices.contains(this.component);
            }
            }
        }
        }


@@ -2017,10 +2211,30 @@ abstract public class ManagedServices {
        }
        }
    }
    }


    /** convenience method for looking in mEnabledServicesForCurrentProfiles */
    /** convenience method for looking in mEnabledServicesByUser for UserHandle.USER_CURRENT.
     * This is a legacy API. When FLAG_MANAGED_SERVICES_CONCURRENT_MULTIUSER becomes
     * trunk stable,  this API should be deprecated.  Additionally, when this method
     * is deprecated, the unit tests written using this method should also be revised.
     *
     * @param component target component name
     * @return boolean value that indicates whether it is enabled for the current profiles
     */
    public boolean isComponentEnabledForCurrentProfiles(ComponentName component) {
    public boolean isComponentEnabledForCurrentProfiles(ComponentName component) {
        return isComponentEnabledForUser(component, UserHandle.USER_CURRENT);
    }

    /** convenience method for looking in mEnabledServicesForUser
     *
     * @param component target component name
     * @param userId the id of the target user
     * @return boolean value that indicates whether it is enabled for the target user
    */
    @FlaggedApi(FLAG_MANAGED_SERVICES_CONCURRENT_MULTIUSER)
    public boolean isComponentEnabledForUser(ComponentName component, int userId) {
        synchronized (mMutex) {
        synchronized (mMutex) {
            return mEnabledServicesForCurrentProfiles.contains(component);
            ArraySet<ComponentName> enabledServicesForUser =
                    mEnabledServicesByUser.get(resolveUserId(userId));
            return enabledServicesForUser != null && enabledServicesForUser.contains(component);
        }
        }
    }
    }


+30 −16

File changed.

Preview size limit exceeded, changes collapsed.

+7 −0
Original line number Original line Diff line number Diff line
@@ -210,3 +210,10 @@ flag {
    purpose: PURPOSE_BUGFIX
    purpose: PURPOSE_BUGFIX
  }
  }
}
}

flag {
  name: "managed_services_concurrent_multiuser"
  namespace: "systemui"
  description: "Enables ManagedServices to support Concurrent multi user environment"
  bug: "380297485"
}
+1 −0
Original line number Original line Diff line number Diff line
@@ -32,6 +32,7 @@ android_test {
        "androidx.test.rules",
        "androidx.test.rules",
        "hamcrest-library",
        "hamcrest-library",
        "mockito-target-inline-minus-junit4",
        "mockito-target-inline-minus-junit4",
        "mockito-target-extended",
        "platform-compat-test-rules",
        "platform-compat-test-rules",
        "platform-test-annotations",
        "platform-test-annotations",
        "platformprotosnano",
        "platformprotosnano",
+4 −0
Original line number Original line Diff line number Diff line
@@ -30,6 +30,7 @@ import android.testing.TestableContext;


import androidx.test.InstrumentationRegistry;
import androidx.test.InstrumentationRegistry;


import com.android.server.pm.UserManagerInternal;
import com.android.server.uri.UriGrantsManagerInternal;
import com.android.server.uri.UriGrantsManagerInternal;


import org.junit.After;
import org.junit.After;
@@ -41,6 +42,7 @@ import org.mockito.MockitoAnnotations;


public class UiServiceTestCase {
public class UiServiceTestCase {
    @Mock protected PackageManagerInternal mPmi;
    @Mock protected PackageManagerInternal mPmi;
    @Mock protected UserManagerInternal mUmi;
    @Mock protected UriGrantsManagerInternal mUgmInternal;
    @Mock protected UriGrantsManagerInternal mUgmInternal;


    protected static final String PKG_N_MR1 = "com.example.n_mr1";
    protected static final String PKG_N_MR1 = "com.example.n_mr1";
@@ -92,6 +94,8 @@ public class UiServiceTestCase {
                    }
                    }
                });
                });


        LocalServices.removeServiceForTest(UserManagerInternal.class);
        LocalServices.addService(UserManagerInternal.class, mUmi);
        LocalServices.removeServiceForTest(UriGrantsManagerInternal.class);
        LocalServices.removeServiceForTest(UriGrantsManagerInternal.class);
        LocalServices.addService(UriGrantsManagerInternal.class, mUgmInternal);
        LocalServices.addService(UriGrantsManagerInternal.class, mUgmInternal);
        when(mUgmInternal.checkGrantUriPermission(
        when(mUgmInternal.checkGrantUriPermission(
Loading