Loading services/core/java/com/android/server/notification/ManagedServices.java +252 −38 Original line number Original line Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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()); Loading @@ -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<>(); Loading Loading @@ -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(); Loading Loading @@ -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) { Loading Loading @@ -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); Loading Loading @@ -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); } } } } Loading Loading @@ -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)); } } } } Loading @@ -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)); Loading @@ -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); Loading Loading @@ -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); Loading @@ -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); } } } } Loading Loading @@ -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<>(); Loading @@ -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. */ */ Loading @@ -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<>()); Loading Loading @@ -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. Loading @@ -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, Loading @@ -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); } } Loading Loading @@ -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); Loading @@ -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); } } } } Loading Loading @@ -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); } } } } Loading services/core/java/com/android/server/notification/NotificationManagerService.java +30 −16 File changed.Preview size limit exceeded, changes collapsed. Show changes services/core/java/com/android/server/notification/flags.aconfig +7 −0 Original line number Original line Diff line number Diff line Loading @@ -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" } services/tests/uiservicestests/Android.bp +1 −0 Original line number Original line Diff line number Diff line Loading @@ -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", Loading services/tests/uiservicestests/src/com/android/server/UiServiceTestCase.java +4 −0 Original line number Original line Diff line number Diff line Loading @@ -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; Loading @@ -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"; Loading Loading @@ -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 Loading
services/core/java/com/android/server/notification/ManagedServices.java +252 −38 Original line number Original line Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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()); Loading @@ -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<>(); Loading Loading @@ -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(); Loading Loading @@ -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) { Loading Loading @@ -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); Loading Loading @@ -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); } } } } Loading Loading @@ -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)); } } } } Loading @@ -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)); Loading @@ -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); Loading Loading @@ -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); Loading @@ -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); } } } } Loading Loading @@ -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<>(); Loading @@ -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. */ */ Loading @@ -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<>()); Loading Loading @@ -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. Loading @@ -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, Loading @@ -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); } } Loading Loading @@ -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); Loading @@ -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); } } } } Loading Loading @@ -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); } } } } Loading
services/core/java/com/android/server/notification/NotificationManagerService.java +30 −16 File changed.Preview size limit exceeded, changes collapsed. Show changes
services/core/java/com/android/server/notification/flags.aconfig +7 −0 Original line number Original line Diff line number Diff line Loading @@ -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" }
services/tests/uiservicestests/Android.bp +1 −0 Original line number Original line Diff line number Diff line Loading @@ -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", Loading
services/tests/uiservicestests/src/com/android/server/UiServiceTestCase.java +4 −0 Original line number Original line Diff line number Diff line Loading @@ -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; Loading @@ -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"; Loading Loading @@ -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