diff options
7 files changed, 374 insertions, 119 deletions
diff --git a/core/java/android/service/notification/NotificationAssistantService.java b/core/java/android/service/notification/NotificationAssistantService.java index 26240c572898..c1a3c2b5f150 100644 --- a/core/java/android/service/notification/NotificationAssistantService.java +++ b/core/java/android/service/notification/NotificationAssistantService.java @@ -283,6 +283,9 @@ public abstract class NotificationAssistantService extends NotificationListenerS } catch (android.os.RemoteException ex) { Log.v(TAG, "Unable to contact notification manager", ex); throw ex.rethrowFromSystemServer(); + } catch (SecurityException e) { + // app cannot catch and recover from this, so do on their behalf + Log.w(TAG, "Enqueue adjustment failed; no longer connected", e); } } break; diff --git a/services/core/java/com/android/server/notification/ManagedServices.java b/services/core/java/com/android/server/notification/ManagedServices.java index 7751f5f9bcb8..8d9c66cdb803 100644 --- a/services/core/java/com/android/server/notification/ManagedServices.java +++ b/services/core/java/com/android/server/notification/ManagedServices.java @@ -20,6 +20,7 @@ import static android.content.Context.BIND_ALLOW_WHITELIST_MANAGEMENT; import static android.content.Context.BIND_AUTO_CREATE; import static android.content.Context.BIND_FOREGROUND_SERVICE; import static android.content.Context.DEVICE_POLICY_SERVICE; +import static android.os.UserHandle.USER_ALL; import android.annotation.NonNull; import android.app.ActivityManager; @@ -53,12 +54,15 @@ import android.service.notification.ManagedServicesProto.ServiceProto; import android.text.TextUtils; import android.util.ArrayMap; import android.util.ArraySet; +import android.util.IntArray; import android.util.Log; import android.util.Pair; import android.util.Slog; import android.util.SparseArray; import android.util.proto.ProtoOutputStream; +import com.android.internal.annotations.GuardedBy; +import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.XmlUtils; import com.android.server.notification.NotificationManagerService.DumpFilter; @@ -72,6 +76,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.HashSet; import java.util.List; +import java.util.Objects; import java.util.Set; import java.util.function.Predicate; @@ -138,10 +143,6 @@ abstract public class ManagedServices { // not mean that we are currently bound to said package/component. private ArrayMap<Integer, ArrayMap<Boolean, ArraySet<String>>> mApproved = new ArrayMap<>(); - // Kept to de-dupe user change events (experienced after boot, when we receive a settings and a - // user change). - private int[] mLastSeenProfileIds; - // True if approved services are stored in xml, not settings. private boolean mUseXml; @@ -296,7 +297,7 @@ abstract public class ManagedServices { Settings.Secure.putStringForUser( mContext.getContentResolver(), element, value, userId); loadAllowedComponentsFromSettings(); - rebindServices(false); + rebindServices(false, userId); } } } @@ -381,7 +382,7 @@ abstract public class ManagedServices { } } } - rebindServices(false); + rebindServices(false, USER_ALL); } protected void upgradeXml(final int xmlVersion, final int userId) {} @@ -456,7 +457,7 @@ abstract public class ManagedServices { } } - rebindServices(false); + rebindServices(false, userId); } private String getApprovedValue(String pkgOrComponent) { @@ -574,7 +575,7 @@ abstract public class ManagedServices { if (anyServicesInvolved) { // make sure we're still bound to any of our services who may have just upgraded - rebindServices(false); + rebindServices(false, USER_ALL); } } } @@ -582,21 +583,17 @@ abstract public class ManagedServices { public void onUserRemoved(int user) { Slog.i(TAG, "Removing approved services for removed user " + user); mApproved.remove(user); - rebindServices(true); + rebindServices(true, user); } public void onUserSwitched(int user) { if (DEBUG) Slog.d(TAG, "onUserSwitched u=" + user); - if (Arrays.equals(mLastSeenProfileIds, mUserProfiles.getCurrentProfileIds())) { - if (DEBUG) Slog.d(TAG, "Current profile IDs didn't change, skipping rebindServices()."); - return; - } - rebindServices(true); + rebindServices(true, user); } public void onUserUnlocked(int user) { if (DEBUG) Slog.d(TAG, "onUserUnlocked u=" + user); - rebindServices(false); + rebindServices(false, user); } private ManagedServiceInfo getServiceFromTokenLocked(IInterface service) { @@ -690,9 +687,10 @@ abstract public class ManagedServices { component.flattenToShortString()); synchronized (mMutex) { - final int[] userIds = mUserProfiles.getCurrentProfileIds(); + final IntArray userIds = mUserProfiles.getCurrentProfileIds(); - for (int userId : userIds) { + for (int i = 0; i < userIds.size(); i++) { + final int userId = userIds.get(i); if (enabled) { if (isPackageOrComponentAllowed(component.toString(), userId) || isPackageOrComponentAllowed(component.getPackageName(), userId)) { @@ -834,20 +832,14 @@ abstract public class ManagedServices { return false; } - /** - * Called whenever packages change, the user switches, or the secure setting - * is altered. (For example in response to USER_SWITCHED in our broadcast receiver) - */ - protected void rebindServices(boolean forceRebind) { - if (DEBUG) Slog.d(TAG, "rebindServices"); - final int[] userIds = mUserProfiles.getCurrentProfileIds(); - final int nUserIds = userIds.length; - + @VisibleForTesting + protected SparseArray<ArraySet<ComponentName>> getAllowedComponents(IntArray userIds) { + final int nUserIds = userIds.size(); final SparseArray<ArraySet<ComponentName>> componentsByUser = new SparseArray<>(); for (int i = 0; i < nUserIds; ++i) { - final int userId = userIds[i]; - final ArrayMap<Boolean, ArraySet<String>> approvedLists = mApproved.get(userIds[i]); + final int userId = userIds.get(i); + final ArrayMap<Boolean, ArraySet<String>> approvedLists = mApproved.get(userId); if (approvedLists != null) { final int N = approvedLists.size(); for (int j = 0; j < N; j++) { @@ -861,67 +853,125 @@ abstract public class ManagedServices { } } } + return componentsByUser; + } - final ArrayList<ManagedServiceInfo> removableBoundServices = new ArrayList<>(); - final SparseArray<Set<ComponentName>> toAdd = new SparseArray<>(); + @GuardedBy("mMutex") + protected void populateComponentsToBind(SparseArray<Set<ComponentName>> componentsToBind, + final IntArray activeUsers, + SparseArray<ArraySet<ComponentName>> approvedComponentsByUser) { + mEnabledServicesForCurrentProfiles.clear(); + mEnabledServicesPackageNames.clear(); + final int nUserIds = activeUsers.size(); - synchronized (mMutex) { - // Rebind to non-system services if user switched - for (ManagedServiceInfo service : mServices) { - if (!service.isSystem && !service.isGuest(this)) { - removableBoundServices.add(service); - } + for (int i = 0; i < nUserIds; ++i) { + // decode the list of components + final int userId = activeUsers.get(i); + final ArraySet<ComponentName> userComponents = approvedComponentsByUser.get(userId); + if (null == userComponents) { + componentsToBind.put(userId, new ArraySet<>()); + continue; } - mEnabledServicesForCurrentProfiles.clear(); - mEnabledServicesPackageNames.clear(); + final Set<ComponentName> add = new HashSet<>(userComponents); + add.removeAll(mSnoozingForCurrentProfiles); - for (int i = 0; i < nUserIds; ++i) { - // decode the list of components - final ArraySet<ComponentName> userComponents = componentsByUser.get(userIds[i]); - if (null == userComponents) { - toAdd.put(userIds[i], new ArraySet<>()); - continue; - } - - final Set<ComponentName> add = new HashSet<>(userComponents); - add.removeAll(mSnoozingForCurrentProfiles); + componentsToBind.put(userId, add); - toAdd.put(userIds[i], add); + mEnabledServicesForCurrentProfiles.addAll(userComponents); - mEnabledServicesForCurrentProfiles.addAll(userComponents); + for (int j = 0; j < userComponents.size(); j++) { + final ComponentName component = userComponents.valueAt(j); + mEnabledServicesPackageNames.add(component.getPackageName()); + } + } + } - for (int j = 0; j < userComponents.size(); j++) { - final ComponentName component = userComponents.valueAt(j); - mEnabledServicesPackageNames.add(component.getPackageName()); - } + @GuardedBy("mMutex") + protected Set<ManagedServiceInfo> getRemovableConnectedServices() { + final Set<ManagedServiceInfo> removableBoundServices = new ArraySet<>(); + for (ManagedServiceInfo service : mServices) { + if (!service.isSystem && !service.isGuest(this)) { + removableBoundServices.add(service); } } + return removableBoundServices; + } + protected void populateComponentsToUnbind( + boolean forceRebind, + Set<ManagedServiceInfo> removableBoundServices, + SparseArray<Set<ComponentName>> allowedComponentsToBind, + SparseArray<Set<ComponentName>> componentsToUnbind) { for (ManagedServiceInfo info : removableBoundServices) { - final ComponentName component = info.component; - final int oldUser = info.userid; - final Set<ComponentName> allowedComponents = toAdd.get(info.userid); + final Set<ComponentName> allowedComponents = allowedComponentsToBind.get(info.userid); if (allowedComponents != null) { - if (allowedComponents.contains(component) && !forceRebind) { - // Already bound, don't need to bind again. - allowedComponents.remove(component); - } else { - // No longer allowed to be bound, or must rebind. - Slog.v(TAG, "disabling " + getCaption() + " for user " - + oldUser + ": " + component); - unregisterService(component, oldUser); + if (forceRebind || !allowedComponents.contains(info.component)) { + Set<ComponentName> toUnbind = + componentsToUnbind.get(info.userid, new ArraySet<>()); + toUnbind.add(info.component); + componentsToUnbind.put(info.userid, toUnbind); } } } + } - for (int i = 0; i < nUserIds; ++i) { - final Set<ComponentName> add = toAdd.get(userIds[i]); + /** + * Called whenever packages change, the user switches, or the secure setting + * is altered. (For example in response to USER_SWITCHED in our broadcast receiver) + */ + protected void rebindServices(boolean forceRebind, int userToRebind) { + if (DEBUG) Slog.d(TAG, "rebindServices " + forceRebind + " " + userToRebind); + IntArray userIds = mUserProfiles.getCurrentProfileIds(); + if (userToRebind != USER_ALL) { + userIds = new IntArray(1); + userIds.add(userToRebind); + } + + final SparseArray<Set<ComponentName>> componentsToBind = new SparseArray<>(); + final SparseArray<Set<ComponentName>> componentsToUnbind = new SparseArray<>(); + + synchronized (mMutex) { + final SparseArray<ArraySet<ComponentName>> approvedComponentsByUser = + getAllowedComponents(userIds); + final Set<ManagedServiceInfo> removableBoundServices = getRemovableConnectedServices(); + + // Filter approvedComponentsByUser to collect all of the components that are allowed + // for the currently active user(s). + populateComponentsToBind(componentsToBind, userIds, approvedComponentsByUser); + + // For every current non-system connection, disconnect services that are no longer + // approved, or ALL services if we are force rebinding + populateComponentsToUnbind( + forceRebind, removableBoundServices, componentsToBind, componentsToUnbind); + } + + unbindFromServices(componentsToUnbind); + bindToServices(componentsToBind); + } + + protected void unbindFromServices(SparseArray<Set<ComponentName>> componentsToUnbind) { + for (int i = 0; i < componentsToUnbind.size(); i++) { + final int userId = componentsToUnbind.keyAt(i); + final Set<ComponentName> removableComponents = componentsToUnbind.get(userId); + for (ComponentName cn : removableComponents) { + // No longer allowed to be bound, or must rebind. + Slog.v(TAG, "disabling " + getCaption() + " for user " + userId + ": " + cn); + unregisterService(cn, userId); + } + } + } + + // Attempt to bind to services, skipping those that cannot be found or lack the permission. + private void bindToServices(SparseArray<Set<ComponentName>> componentsToBind) { + for (int i = 0; i < componentsToBind.size(); i++) { + final int userId = componentsToBind.keyAt(i); + final Set<ComponentName> add = componentsToBind.get(userId); for (ComponentName component : add) { try { ServiceInfo info = mPm.getServiceInfo(component, PackageManager.MATCH_DIRECT_BOOT_AWARE - | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, userIds[i]); + | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, userId); if (info == null) { Slog.w(TAG, "Not binding " + getCaption() + " service " + component + ": service not found"); @@ -933,15 +983,13 @@ abstract public class ManagedServices { continue; } Slog.v(TAG, - "enabling " + getCaption() + " for " + userIds[i] + ": " + component); - registerService(component, userIds[i]); + "enabling " + getCaption() + " for " + userId + ": " + component); + registerService(component, userId); } catch (RemoteException e) { e.rethrowFromSystemServer(); } } } - - mLastSeenProfileIds = userIds; } /** @@ -1018,7 +1066,7 @@ abstract public class ManagedServices { @Override public void onServiceConnected(ComponentName name, IBinder binder) { - Slog.v(TAG, getCaption() + " service connected: " + name); + Slog.v(TAG, userid + " " + getCaption() + " service connected: " + name); boolean added = false; ManagedServiceInfo info = null; synchronized (mMutex) { @@ -1040,12 +1088,12 @@ abstract public class ManagedServices { @Override public void onServiceDisconnected(ComponentName name) { - Slog.v(TAG, getCaption() + " connection lost: " + name); + Slog.v(TAG, userid + " " + getCaption() + " connection lost: " + name); } @Override public void onBindingDied(ComponentName name) { - Slog.w(TAG, getCaption() + " binding died: " + name); + Slog.w(TAG, userid + " " + getCaption() + " binding died: " + name); synchronized (mMutex) { unbindService(this, name, userid); if (!mServicesRebinding.contains(servicesBindingTag)) { @@ -1057,8 +1105,8 @@ abstract public class ManagedServices { } }, ON_BINDING_DIED_REBIND_DELAY_MS); } else { - Slog.v(TAG, getCaption() + " not rebinding as " - + "a previous rebind attempt was made: " + name); + Slog.v(TAG, getCaption() + " not rebinding in user " + userid + + " as a previous rebind attempt was made: " + name); } } } @@ -1068,7 +1116,8 @@ abstract public class ManagedServices { BIND_AUTO_CREATE | BIND_FOREGROUND_SERVICE | BIND_ALLOW_WHITELIST_MANAGEMENT, new UserHandle(userid))) { mServicesBound.remove(servicesBindingTag); - Slog.w(TAG, "Unable to bind " + getCaption() + " service: " + intent); + Slog.w(TAG, "Unable to bind " + getCaption() + " service: " + intent + + " in user " + userid); return; } } catch (SecurityException ex) { @@ -1232,9 +1281,9 @@ abstract public class ManagedServices { if (!isEnabledForCurrentProfiles()) { return false; } - if (this.userid == UserHandle.USER_ALL) return true; + if (this.userid == USER_ALL) return true; if (this.isSystem) return true; - if (nid == UserHandle.USER_ALL || nid == this.userid) return true; + if (nid == USER_ALL || nid == this.userid) return true; return supportsProfiles() && mUserProfiles.isCurrentProfile(nid) && isPermittedForProfile(nid); @@ -1280,6 +1329,24 @@ abstract public class ManagedServices { Binder.restoreCallingIdentity(identity); } } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + ManagedServiceInfo that = (ManagedServiceInfo) o; + return userid == that.userid + && isSystem == that.isSystem + && targetSdkVersion == that.targetSdkVersion + && Objects.equals(service, that.service) + && Objects.equals(component, that.component) + && Objects.equals(connection, that.connection); + } + + @Override + public int hashCode() { + return Objects.hash(service, component, userid, isSystem, connection, targetSdkVersion); + } } /** convenience method for looking in mEnabledServicesForCurrentProfiles */ @@ -1305,12 +1372,15 @@ abstract public class ManagedServices { } } - public int[] getCurrentProfileIds() { + /** + * Returns the currently active users (generally one user and its work profile). + */ + public IntArray getCurrentProfileIds() { synchronized (mCurrentProfiles) { - int[] users = new int[mCurrentProfiles.size()]; + IntArray users = new IntArray(mCurrentProfiles.size()); final int N = mCurrentProfiles.size(); for (int i = 0; i < N; ++i) { - users[i] = mCurrentProfiles.keyAt(i); + users.add(mCurrentProfiles.keyAt(i)); } return users; } diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index 60597b58ec52..d522dbae29de 100644 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -174,6 +174,7 @@ import android.text.TextUtils; import android.util.ArrayMap; import android.util.ArraySet; import android.util.AtomicFile; +import android.util.IntArray; import android.util.Log; import android.util.Slog; import android.util.SparseArray; @@ -1562,7 +1563,7 @@ public class NotificationManagerService extends SystemService { filter.addAction(Intent.ACTION_USER_REMOVED); filter.addAction(Intent.ACTION_USER_UNLOCKED); filter.addAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE); - getContext().registerReceiver(mIntentReceiver, filter); + getContext().registerReceiverAsUser(mIntentReceiver, UserHandle.ALL, filter, null, null); IntentFilter pkgFilter = new IntentFilter(); pkgFilter.addAction(Intent.ACTION_PACKAGE_ADDED); @@ -1694,10 +1695,10 @@ public class NotificationManagerService extends SystemService { UserHandle.getUserId(uid), REASON_CHANNEL_BANNED, null); if (isUidSystemOrPhone(uid)) { - int[] profileIds = mUserProfiles.getCurrentProfileIds(); - int N = profileIds.length; + IntArray profileIds = mUserProfiles.getCurrentProfileIds(); + int N = profileIds.size(); for (int i = 0; i < N; i++) { - int profileId = profileIds[i]; + int profileId = profileIds.get(i); cancelAllNotificationsInt(MY_UID, MY_PID, pkg, channel.getId(), 0, 0, true, profileId, REASON_CHANNEL_BANNED, null); @@ -6693,7 +6694,9 @@ public class NotificationManagerService extends SystemService { @Override public void onUserUnlocked(int user) { if (DEBUG) Slog.d(TAG, "onUserUnlocked u=" + user); - rebindServices(true); + // force rebind the assistant, as it might be keeping its own state in user locked + // storage + rebindServices(true, user); } protected void onNotificationsSeenLocked(ArrayList<NotificationRecord> records) { diff --git a/services/core/java/com/android/server/notification/SnoozeHelper.java b/services/core/java/com/android/server/notification/SnoozeHelper.java index a178a525cede..2b581d601ad5 100644 --- a/services/core/java/com/android/server/notification/SnoozeHelper.java +++ b/services/core/java/com/android/server/notification/SnoozeHelper.java @@ -15,17 +15,8 @@ */ package com.android.server.notification; -import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.logging.MetricsLogger; -import com.android.internal.logging.nano.MetricsProto; - -import org.xmlpull.v1.XmlPullParser; -import org.xmlpull.v1.XmlPullParserException; -import org.xmlpull.v1.XmlSerializer; - import android.annotation.NonNull; import android.app.AlarmManager; -import android.app.Notification; import android.app.PendingIntent; import android.content.BroadcastReceiver; import android.content.Context; @@ -37,9 +28,18 @@ import android.os.SystemClock; import android.os.UserHandle; import android.service.notification.StatusBarNotification; import android.util.ArrayMap; +import android.util.IntArray; import android.util.Log; import android.util.Slog; +import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.logging.MetricsLogger; +import com.android.internal.logging.nano.MetricsProto; + +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; +import org.xmlpull.v1.XmlSerializer; + import java.io.IOException; import java.io.PrintWriter; import java.util.ArrayList; @@ -105,12 +105,12 @@ public class SnoozeHelper { protected @NonNull List<NotificationRecord> getSnoozed() { List<NotificationRecord> snoozedForUser = new ArrayList<>(); - int[] userIds = mUserProfiles.getCurrentProfileIds(); + IntArray userIds = mUserProfiles.getCurrentProfileIds(); if (userIds != null) { - final int N = userIds.length; + final int N = userIds.size(); for (int i = 0; i < N; i++) { final ArrayMap<String, ArrayMap<String, NotificationRecord>> snoozedPkgs = - mSnoozedNotifications.get(userIds[i]); + mSnoozedNotifications.get(userIds.get(i)); if (snoozedPkgs != null) { final int M = snoozedPkgs.size(); for (int j = 0; j < M; j++) { @@ -179,7 +179,7 @@ public class SnoozeHelper { protected boolean cancel(int userId, boolean includeCurrentProfiles) { int[] userIds = {userId}; if (includeCurrentProfiles) { - userIds = mUserProfiles.getCurrentProfileIds(); + userIds = mUserProfiles.getCurrentProfileIds().toArray(); } final int N = userIds.length; for (int i = 0; i < N; i++) { diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java index 95d4a15b5fdb..659c6e7aeed3 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java @@ -20,6 +20,7 @@ import static com.android.server.notification.ManagedServices.APPROVAL_BY_PACKAG import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertFalse; +import static junit.framework.Assert.assertNotNull; import static junit.framework.Assert.assertTrue; import static org.mockito.Matchers.any; @@ -34,6 +35,7 @@ import static org.mockito.Mockito.when; import android.content.ComponentName; import android.content.Context; import android.content.Intent; +import android.content.ServiceConnection; import android.content.pm.IPackageManager; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; @@ -47,6 +49,9 @@ import android.os.UserManager; import android.provider.Settings; import android.text.TextUtils; import android.util.ArrayMap; +import android.util.ArraySet; +import android.util.IntArray; +import android.util.SparseArray; import android.util.Xml; import com.android.internal.util.FastXmlSerializer; @@ -68,7 +73,9 @@ import java.io.BufferedOutputStream; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.util.ArrayList; +import java.util.Collection; import java.util.List; +import java.util.Set; public class ManagedServicesTest extends UiServiceTestCase { @@ -113,7 +120,12 @@ public class ManagedServicesTest extends UiServiceTestCase { when(mUm.getUserInfo(eq(user.id))).thenReturn(user); } when(mUm.getUsers()).thenReturn(users); - when(mUserProfiles.getCurrentProfileIds()).thenReturn(new int[] {0, 10, 11, 12}); + IntArray profileIds = new IntArray(); + profileIds.add(0); + profileIds.add(11); + profileIds.add(10); + profileIds.add(12); + when(mUserProfiles.getCurrentProfileIds()).thenReturn(profileIds); mExpectedPrimaryPackages = new ArrayMap<>(); mExpectedPrimaryPackages.put(0, "this.is.a.package.name:another.package"); @@ -165,12 +177,12 @@ public class ManagedServicesTest extends UiServiceTestCase { @Test public void testBackupAndRestore_migration_preO() throws Exception { - ArrayMap backupPrimaryPackages = new ArrayMap<>(); + ArrayMap<Integer, String> backupPrimaryPackages = new ArrayMap<>(); backupPrimaryPackages.put(0, "backup.0:backup:0a"); backupPrimaryPackages.put(10, "10.backup"); backupPrimaryPackages.put(11, "eleven"); backupPrimaryPackages.put(12, ""); - ArrayMap backupPrimaryComponentNames = new ArrayMap<>(); + ArrayMap<Integer, String> backupPrimaryComponentNames = new ArrayMap<>(); backupPrimaryComponentNames.put(0, "backup.first/whatever:a/b"); backupPrimaryComponentNames.put(10, "again/M1"); backupPrimaryComponentNames.put(11, "orange/youglad:itisnot/banana"); @@ -179,11 +191,11 @@ public class ManagedServicesTest extends UiServiceTestCase { backupPrimary.put(APPROVAL_BY_PACKAGE, backupPrimaryPackages); backupPrimary.put(APPROVAL_BY_COMPONENT, backupPrimaryComponentNames); - ArrayMap backupSecondaryComponentNames = new ArrayMap<>(); + ArrayMap<Integer, String> backupSecondaryComponentNames = new ArrayMap<>(); backupSecondaryComponentNames.put(0, "secondary.1/component.Name"); backupSecondaryComponentNames.put(10, "this.is.another.package.backup/with.Component:component.backup/2"); - ArrayMap backupSecondaryPackages = new ArrayMap<>(); + ArrayMap<Integer, String> backupSecondaryPackages = new ArrayMap<>(); backupSecondaryPackages.put(0, ""); backupSecondaryPackages.put(10, "this.is.another.package.backup:package.backup"); @@ -368,7 +380,7 @@ public class ManagedServicesTest extends UiServiceTestCase { serializer.endDocument(); serializer.flush(); - for (int userId : mUserProfiles.getCurrentProfileIds()) { + for (int userId : mUserProfiles.getCurrentProfileIds().toArray()) { List<String> expected = stringToList(mExpectedPrimary.get(approvalLevel).get(userId)); List<String> actual = stringToList(Settings.Secure.getStringForUser( @@ -633,7 +645,7 @@ public class ManagedServicesTest extends UiServiceTestCase { } @Test - public void testGetAllowedComponents() throws Exception { + public void testGetAllowedComponentsByUser() throws Exception { ManagedServices service = new TestManagedServices(getContext(), mLock, mUserProfiles, mIpm, APPROVAL_BY_COMPONENT); loadXml(service); @@ -708,6 +720,145 @@ public class ManagedServicesTest extends UiServiceTestCase { assertTrue(services.isSameUser(service, 10)); } + @Test + public void testGetAllowedComponents() throws Exception { + ManagedServices service = new TestManagedServices(getContext(), mLock, mUserProfiles, mIpm, + APPROVAL_BY_COMPONENT); + loadXml(service); + + SparseArray<ArraySet<ComponentName>> expected = new SparseArray<>(); + + ArraySet<ComponentName> expected10 = new ArraySet<>(); + expected10.add(ComponentName.unflattenFromString("this.is.another.package/M1")); + expected10.add(ComponentName.unflattenFromString("this.is.another.package/with.Component")); + expected10.add(ComponentName.unflattenFromString("component/2")); + expected10.add(ComponentName.unflattenFromString("package/component2")); + expected.put(10, expected10); + ArraySet<ComponentName> expected0 = new ArraySet<>(); + expected0.add(ComponentName.unflattenFromString("secondary/component.Name")); + expected0.add(ComponentName.unflattenFromString("this.is.a.package.name/Ba")); + expected0.add(ComponentName.unflattenFromString("another.package/B1")); + expected.put(0, expected0); + ArraySet<ComponentName> expected12 = new ArraySet<>(); + expected12.add(ComponentName.unflattenFromString("bananas!/Bananas!")); + expected.put(12, expected12); + expected.put(11, new ArraySet<>()); + + SparseArray<ArraySet<ComponentName>> actual = + service.getAllowedComponents(mUserProfiles.getCurrentProfileIds()); + + assertContentsInAnyOrder(expected, actual); + } + + @Test + public void testPopulateComponentsToUnbind_forceRebind() { + ManagedServices service = new TestManagedServices(getContext(), mLock, mUserProfiles, mIpm, + APPROVAL_BY_COMPONENT); + + IInterface iInterface = mock(IInterface.class); + when(iInterface.asBinder()).thenReturn(mock(IBinder.class)); + + ManagedServices.ManagedServiceInfo service0 = service.new ManagedServiceInfo( + iInterface, ComponentName.unflattenFromString("a/a"), 0, false, + mock(ServiceConnection.class), 26); + ManagedServices.ManagedServiceInfo service10 = service.new ManagedServiceInfo( + iInterface, ComponentName.unflattenFromString("b/b"), 10, false, + mock(ServiceConnection.class), 26); + Set<ManagedServices.ManagedServiceInfo> removableBoundServices = new ArraySet<>(); + removableBoundServices.add(service0); + removableBoundServices.add(service10); + + SparseArray<Set<ComponentName>> allowedComponentsToBind = new SparseArray<>(); + Set<ComponentName> allowed0 = new ArraySet<>(); + allowed0.add(ComponentName.unflattenFromString("a/a")); + allowedComponentsToBind.put(0, allowed0); + Set<ComponentName> allowed10 = new ArraySet<>(); + allowed10.add(ComponentName.unflattenFromString("b/b")); + allowedComponentsToBind.put(10, allowed10); + + SparseArray<Set<ComponentName>> componentsToUnbind = new SparseArray<>(); + + service.populateComponentsToUnbind(true, removableBoundServices, allowedComponentsToBind, + componentsToUnbind); + + assertEquals(2, componentsToUnbind.size()); + assertTrue(componentsToUnbind.get(0).contains(ComponentName.unflattenFromString("a/a"))); + assertTrue(componentsToUnbind.get(10).contains(ComponentName.unflattenFromString("b/b"))); + } + + @Test + public void testPopulateComponentsToUnbind() { + ManagedServices service = new TestManagedServices(getContext(), mLock, mUserProfiles, mIpm, + APPROVAL_BY_COMPONENT); + + IInterface iInterface = mock(IInterface.class); + when(iInterface.asBinder()).thenReturn(mock(IBinder.class)); + + ManagedServices.ManagedServiceInfo service0 = service.new ManagedServiceInfo( + iInterface, ComponentName.unflattenFromString("a/a"), 0, false, + mock(ServiceConnection.class), 26); + ManagedServices.ManagedServiceInfo service0a = service.new ManagedServiceInfo( + iInterface, ComponentName.unflattenFromString("c/c"), 0, false, + mock(ServiceConnection.class), 26); + ManagedServices.ManagedServiceInfo service10 = service.new ManagedServiceInfo( + iInterface, ComponentName.unflattenFromString("b/b"), 10, false, + mock(ServiceConnection.class), 26); + Set<ManagedServices.ManagedServiceInfo> removableBoundServices = new ArraySet<>(); + removableBoundServices.add(service0); + removableBoundServices.add(service0a); + removableBoundServices.add(service10); + + SparseArray<Set<ComponentName>> allowedComponentsToBind = new SparseArray<>(); + Set<ComponentName> allowed0 = new ArraySet<>(); + allowed0.add(ComponentName.unflattenFromString("a/a")); + allowedComponentsToBind.put(0, allowed0); + Set<ComponentName> allowed10 = new ArraySet<>(); + allowed10.add(ComponentName.unflattenFromString("b/b")); + allowedComponentsToBind.put(10, allowed10); + + SparseArray<Set<ComponentName>> componentsToUnbind = new SparseArray<>(); + + service.populateComponentsToUnbind(false, removableBoundServices, allowedComponentsToBind, + componentsToUnbind); + + assertEquals(1, componentsToUnbind.size()); + assertEquals(1, componentsToUnbind.get(0).size()); + assertTrue(componentsToUnbind.get(0).contains(ComponentName.unflattenFromString("c/c"))); + } + + @Test + public void populateComponentsToBind() { + ManagedServices service = new TestManagedServices(getContext(), mLock, mUserProfiles, mIpm, + APPROVAL_BY_COMPONENT); + + SparseArray<ArraySet<ComponentName>> approvedComponentsByUser = new SparseArray<>(); + ArraySet<ComponentName> allowed0 = new ArraySet<>(); + allowed0.add(ComponentName.unflattenFromString("a/a")); + approvedComponentsByUser.put(0, allowed0); + ArraySet<ComponentName> allowed10 = new ArraySet<>(); + allowed10.add(ComponentName.unflattenFromString("b/b")); + allowed10.add(ComponentName.unflattenFromString("c/c")); + approvedComponentsByUser.put(10, allowed10); + ArraySet<ComponentName> allowed15 = new ArraySet<>(); + allowed15.add(ComponentName.unflattenFromString("d/d")); + approvedComponentsByUser.put(15, allowed15); + + IntArray users = new IntArray(); + users.add(10); + users.add(0); + + SparseArray<Set<ComponentName>> componentsToBind = new SparseArray<>(); + + service.populateComponentsToBind(componentsToBind, users, approvedComponentsByUser); + + assertEquals(2, componentsToBind.size()); + assertEquals(1, componentsToBind.get(0).size()); + assertTrue(componentsToBind.get(0).contains(ComponentName.unflattenFromString("a/a"))); + assertEquals(2, componentsToBind.get(10).size()); + assertTrue(componentsToBind.get(10).contains(ComponentName.unflattenFromString("b/b"))); + assertTrue(componentsToBind.get(10).contains(ComponentName.unflattenFromString("c/c"))); + } + private void loadXml(ManagedServices service) throws Exception { final StringBuffer xml = new StringBuffer(); xml.append("<" + service.getConfig().xmlTag + ">\n"); @@ -775,7 +926,8 @@ public class ManagedServicesTest extends UiServiceTestCase { ManagedServices.ENABLED_SERVICES_SEPARATOR))); } - private void assertContentsInAnyOrder(List<?> expected, List<?> actual) { + private void assertContentsInAnyOrder(Collection<?> expected, Collection<?> actual) { + assertNotNull(actual); assertEquals(expected.size(), actual.size()); for (Object o : expected) { @@ -787,6 +939,21 @@ public class ManagedServicesTest extends UiServiceTestCase { } } + private void assertContentsInAnyOrder(SparseArray<ArraySet<ComponentName>> expected, + SparseArray<ArraySet<ComponentName>> actual) throws Exception { + assertEquals(expected.size(), actual.size()); + + for (int i = 0; i < expected.size(); i++) { + int key = expected.keyAt(i); + assertTrue(actual.indexOfKey(key) >= 0); + try { + assertContentsInAnyOrder(expected.valueAt(i), actual.get(key)); + } catch (Throwable t) { + throw new Exception("Error validating " + key, t); + } + } + } + private void verifyExpectedBoundEntries(ManagedServices service, boolean primary) throws Exception { ArrayMap<Integer, String> verifyMap = primary ? mExpectedPrimary.get(service.mApprovalLevel) @@ -920,7 +1087,7 @@ public class ManagedServicesTest extends UiServiceTestCase { @Override protected boolean checkType(IInterface service) { - return false; + return true; } @Override diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationAssistantsTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationAssistantsTest.java index f9a4f784bf4f..1de1e4ef8b9f 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationAssistantsTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationAssistantsTest.java @@ -33,6 +33,7 @@ import android.content.pm.ResolveInfo; import android.content.pm.ServiceInfo; import android.content.pm.UserInfo; import android.os.UserManager; +import android.util.IntArray; import android.util.Xml; import com.android.internal.util.FastXmlSerializer; @@ -103,7 +104,12 @@ public class NotificationAssistantsTest extends UiServiceTestCase { } when(mUm.getUsers()).thenReturn(users); when(mUm.getUsers(anyBoolean())).thenReturn(users); - when(mUserProfiles.getCurrentProfileIds()).thenReturn(new int[] {0, 10, 11, 12}); + IntArray profileIds = new IntArray(); + profileIds.add(0); + profileIds.add(11); + profileIds.add(10); + profileIds.add(12); + when(mUserProfiles.getCurrentProfileIds()).thenReturn(profileIds); } @Test diff --git a/services/tests/uiservicestests/src/com/android/server/notification/SnoozeHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/SnoozeHelperTest.java index 88c6fcf138cf..b955e56c80a8 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/SnoozeHelperTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/SnoozeHelperTest.java @@ -32,6 +32,7 @@ import android.os.UserHandle; import android.service.notification.StatusBarNotification; import android.support.test.runner.AndroidJUnit4; import android.test.suitebuilder.annotation.SmallTest; +import android.util.IntArray; import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertFalse; @@ -235,18 +236,22 @@ public class SnoozeHelperTest extends UiServiceTestCase { mSnoozeHelper.snooze(r2, 1000); mSnoozeHelper.snooze(r3, 1000); mSnoozeHelper.snooze(r4, 1000); - when(mUserProfiles.getCurrentProfileIds()).thenReturn( - new int[] {UserHandle.USER_SYSTEM}); + IntArray profileIds = new IntArray(); + profileIds.add(UserHandle.USER_SYSTEM); + when(mUserProfiles.getCurrentProfileIds()).thenReturn(profileIds); assertEquals(3, mSnoozeHelper.getSnoozed().size()); - when(mUserProfiles.getCurrentProfileIds()).thenReturn( - new int[] {UserHandle.USER_CURRENT}); + profileIds = new IntArray(); + profileIds.add(UserHandle.USER_CURRENT); + when(mUserProfiles.getCurrentProfileIds()).thenReturn(profileIds); assertEquals(1, mSnoozeHelper.getSnoozed().size()); } @Test public void testGetSnoozedByUser_managedProfiles() throws Exception { - when(mUserProfiles.getCurrentProfileIds()).thenReturn( - new int[] {UserHandle.USER_SYSTEM, UserHandle.USER_CURRENT}); + IntArray profileIds = new IntArray(); + profileIds.add(UserHandle.USER_CURRENT); + profileIds.add(UserHandle.USER_SYSTEM); + when(mUserProfiles.getCurrentProfileIds()).thenReturn(profileIds); NotificationRecord r = getNotificationRecord("pkg", 1, "one", UserHandle.SYSTEM); NotificationRecord r2 = getNotificationRecord("pkg", 2, "two", UserHandle.SYSTEM); NotificationRecord r3 = getNotificationRecord("pkg2", 3, "three", UserHandle.SYSTEM); @@ -273,8 +278,9 @@ public class SnoozeHelperTest extends UiServiceTestCase { @Test public void repostGroupSummary_repostsSummary() throws Exception { - when(mUserProfiles.getCurrentProfileIds()).thenReturn( - new int[] {UserHandle.USER_SYSTEM}); + IntArray profileIds = new IntArray(); + profileIds.add(UserHandle.USER_SYSTEM); + when(mUserProfiles.getCurrentProfileIds()).thenReturn(profileIds); NotificationRecord r = getNotificationRecord( "pkg", 1, "one", UserHandle.SYSTEM, "group1", true); NotificationRecord r2 = getNotificationRecord( |