From a77f0597df40b7c61b0bc3053754e18e663216cd Mon Sep 17 00:00:00 2001 From: Julia Reynolds Date: Fri, 5 Feb 2021 11:39:35 -0500 Subject: [PATCH] Store uids in listener filters Since listeners can see notifications in managed users, we need to differentiate between pakgs in hte primary and managed profiles. Test: atest Bug: 173052211 Change-Id: I3dca45adab7f1330f7f1523547ddc556cb41184c --- .../NotificationListenerFilter.java | 22 +++++++--- .../NotificationListenerFilterTest.java | 42 +++++++++++-------- .../NotificationManagerService.java | 41 +++++++++++++----- .../NotificationListenersTest.java | 41 ++++++++++++++---- .../NotificationManagerServiceTest.java | 4 +- 5 files changed, 106 insertions(+), 44 deletions(-) diff --git a/core/java/android/service/notification/NotificationListenerFilter.java b/core/java/android/service/notification/NotificationListenerFilter.java index 6fdfaabb009b2..053fb2b1b4eb6 100644 --- a/core/java/android/service/notification/NotificationListenerFilter.java +++ b/core/java/android/service/notification/NotificationListenerFilter.java @@ -20,6 +20,7 @@ import static android.service.notification.NotificationListenerService.FLAG_FILT import static android.service.notification.NotificationListenerService.FLAG_FILTER_TYPE_ONGOING; import static android.service.notification.NotificationListenerService.FLAG_FILTER_TYPE_SILENT; +import android.content.pm.VersionedPackage; import android.os.Parcel; import android.os.Parcelable; import android.util.ArraySet; @@ -31,7 +32,7 @@ import android.util.ArraySet; */ public class NotificationListenerFilter implements Parcelable { private int mAllowedNotificationTypes; - private ArraySet mDisallowedPackages; + private ArraySet mDisallowedPackages; public NotificationListenerFilter() { mAllowedNotificationTypes = FLAG_FILTER_TYPE_CONVERSATIONS @@ -41,7 +42,7 @@ public class NotificationListenerFilter implements Parcelable { mDisallowedPackages = new ArraySet<>(); } - public NotificationListenerFilter(int types, ArraySet pkgs) { + public NotificationListenerFilter(int types, ArraySet pkgs) { mAllowedNotificationTypes = types; mDisallowedPackages = pkgs; } @@ -51,7 +52,8 @@ public class NotificationListenerFilter implements Parcelable { */ protected NotificationListenerFilter(Parcel in) { mAllowedNotificationTypes = in.readInt(); - mDisallowedPackages = (ArraySet) in.readArraySet(String.class.getClassLoader()); + mDisallowedPackages = (ArraySet) in.readArraySet( + VersionedPackage.class.getClassLoader()); } @Override @@ -77,7 +79,7 @@ public class NotificationListenerFilter implements Parcelable { return (mAllowedNotificationTypes & type) != 0; } - public boolean isPackageAllowed(String pkg) { + public boolean isPackageAllowed(VersionedPackage pkg) { return !mDisallowedPackages.contains(pkg); } @@ -85,7 +87,7 @@ public class NotificationListenerFilter implements Parcelable { return mAllowedNotificationTypes; } - public ArraySet getDisallowedPackages() { + public ArraySet getDisallowedPackages() { return mDisallowedPackages; } @@ -93,10 +95,18 @@ public class NotificationListenerFilter implements Parcelable { mAllowedNotificationTypes = types; } - public void setDisallowedPackages(ArraySet pkgs) { + public void setDisallowedPackages(ArraySet pkgs) { mDisallowedPackages = pkgs; } + public void removePackage(VersionedPackage pkg) { + mDisallowedPackages.remove(pkg); + } + + public void addPackage(VersionedPackage pkg) { + mDisallowedPackages.add(pkg); + } + @Override public int describeContents() { return 0; diff --git a/core/tests/coretests/src/android/service/notification/NotificationListenerFilterTest.java b/core/tests/coretests/src/android/service/notification/NotificationListenerFilterTest.java index a43b238405d10..a121941e7b73c 100644 --- a/core/tests/coretests/src/android/service/notification/NotificationListenerFilterTest.java +++ b/core/tests/coretests/src/android/service/notification/NotificationListenerFilterTest.java @@ -16,14 +16,14 @@ package android.service.notification; -import static android.app.NotificationManager.IMPORTANCE_DEFAULT; import static android.service.notification.NotificationListenerService.FLAG_FILTER_TYPE_ALERTING; import static android.service.notification.NotificationListenerService.FLAG_FILTER_TYPE_CONVERSATIONS; +import static android.service.notification.NotificationListenerService.FLAG_FILTER_TYPE_ONGOING; import static android.service.notification.NotificationListenerService.FLAG_FILTER_TYPE_SILENT; import static com.google.common.truth.Truth.assertThat; -import android.app.NotificationChannel; +import android.content.pm.VersionedPackage; import android.os.Parcel; import android.util.ArraySet; @@ -45,16 +45,19 @@ public class NotificationListenerFilterTest { assertThat(nlf.isTypeAllowed(FLAG_FILTER_TYPE_SILENT)).isTrue(); assertThat(nlf.getTypes()).isEqualTo(FLAG_FILTER_TYPE_CONVERSATIONS | FLAG_FILTER_TYPE_ALERTING - | FLAG_FILTER_TYPE_SILENT); + | FLAG_FILTER_TYPE_SILENT + | FLAG_FILTER_TYPE_ONGOING); assertThat(nlf.getDisallowedPackages()).isEmpty(); - assertThat(nlf.isPackageAllowed("pkg1")).isTrue(); + assertThat(nlf.isPackageAllowed(new VersionedPackage("any", 0))).isTrue(); } @Test public void testConstructor() { - ArraySet pkgs = new ArraySet<>(new String[] {"pkg1", "pkg2"}); + VersionedPackage a1 = new VersionedPackage("pkg1", 243); + VersionedPackage a2= new VersionedPackage("pkg2", 2142534); + ArraySet pkgs = new ArraySet<>(new VersionedPackage[] {a1, a2}); NotificationListenerFilter nlf = new NotificationListenerFilter(FLAG_FILTER_TYPE_ALERTING, pkgs); assertThat(nlf.isTypeAllowed(FLAG_FILTER_TYPE_CONVERSATIONS)).isFalse(); @@ -62,20 +65,21 @@ public class NotificationListenerFilterTest { assertThat(nlf.isTypeAllowed(FLAG_FILTER_TYPE_SILENT)).isFalse(); assertThat(nlf.getTypes()).isEqualTo(FLAG_FILTER_TYPE_ALERTING); - assertThat(nlf.getDisallowedPackages()).contains("pkg1"); - assertThat(nlf.getDisallowedPackages()).contains("pkg2"); - assertThat(nlf.isPackageAllowed("pkg1")).isFalse(); - assertThat(nlf.isPackageAllowed("pkg2")).isFalse(); + assertThat(nlf.getDisallowedPackages()).contains(a1); + assertThat(nlf.getDisallowedPackages()).contains(a2); + assertThat(nlf.isPackageAllowed(a1)).isFalse(); + assertThat(nlf.isPackageAllowed(a2)).isFalse(); } @Test public void testSetDisallowedPackages() { NotificationListenerFilter nlf = new NotificationListenerFilter(); - ArraySet pkgs = new ArraySet<>(new String[] {"pkg1"}); + ArraySet pkgs = new ArraySet<>( + new VersionedPackage[] {new VersionedPackage("pkg1", 0)}); nlf.setDisallowedPackages(pkgs); - assertThat(nlf.isPackageAllowed("pkg1")).isFalse(); + assertThat(nlf.isPackageAllowed(new VersionedPackage("pkg1", 0))).isFalse(); } @Test @@ -94,7 +98,9 @@ public class NotificationListenerFilterTest { @Test public void testDescribeContents() { final int expected = 0; - ArraySet pkgs = new ArraySet<>(new String[] {"pkg1", "pkg2"}); + VersionedPackage a1 = new VersionedPackage("pkg1", 243); + VersionedPackage a2= new VersionedPackage("pkg2", 2142534); + ArraySet pkgs = new ArraySet<>(new VersionedPackage[] {a1, a2}); NotificationListenerFilter nlf = new NotificationListenerFilter(FLAG_FILTER_TYPE_ALERTING, pkgs); assertThat(nlf.describeContents()).isEqualTo(expected); @@ -102,7 +108,9 @@ public class NotificationListenerFilterTest { @Test public void testParceling() { - ArraySet pkgs = new ArraySet<>(new String[] {"pkg1", "pkg2"}); + VersionedPackage a1 = new VersionedPackage("pkg1", 243); + VersionedPackage a2= new VersionedPackage("pkg2", 2142534); + ArraySet pkgs = new ArraySet<>(new VersionedPackage[] {a1, a2}); NotificationListenerFilter nlf = new NotificationListenerFilter(FLAG_FILTER_TYPE_ALERTING, pkgs); @@ -116,9 +124,9 @@ public class NotificationListenerFilterTest { assertThat(nlf1.isTypeAllowed(FLAG_FILTER_TYPE_SILENT)).isFalse(); assertThat(nlf1.getTypes()).isEqualTo(FLAG_FILTER_TYPE_ALERTING); - assertThat(nlf1.getDisallowedPackages()).contains("pkg1"); - assertThat(nlf1.getDisallowedPackages()).contains("pkg2"); - assertThat(nlf1.isPackageAllowed("pkg1")).isFalse(); - assertThat(nlf1.isPackageAllowed("pkg2")).isFalse(); + assertThat(nlf1.getDisallowedPackages()).contains(a1); + assertThat(nlf1.getDisallowedPackages()).contains(a2); + assertThat(nlf1.isPackageAllowed(a1)).isFalse(); + assertThat(nlf1.isPackageAllowed(a2)).isFalse(); } } diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index 571b6934e4257..9f2089e39353b 100755 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -175,6 +175,7 @@ import android.content.pm.ServiceInfo; import android.content.pm.ShortcutInfo; import android.content.pm.ShortcutServiceInternal; import android.content.pm.UserInfo; +import android.content.pm.VersionedPackage; import android.content.res.Resources; import android.database.ContentObserver; import android.media.AudioAttributes; @@ -8958,7 +8959,8 @@ public class NotificationManagerService extends SystemService { NotificationListenerFilter nls = mListeners.getNotificationListenerFilter(listener.mKey); if (nls != null && (!nls.isTypeAllowed(notificationType) - || !nls.isPackageAllowed(sbn.getPackageName()))) { + || !nls.isPackageAllowed( + new VersionedPackage(sbn.getPackageName(), sbn.getUid())))) { return false; } return true; @@ -9562,7 +9564,8 @@ public class NotificationManagerService extends SystemService { static final String TAG_REQUESTED_LISTENER = "listener"; static final String ATT_COMPONENT = "component"; static final String ATT_TYPES = "types"; - static final String ATT_PKGS = "pkgs"; + static final String ATT_PKG = "pkg"; + static final String ATT_UID = "uid"; static final String TAG_APPROVED = "allowed"; static final String TAG_DISALLOWED= "disallowed"; static final String XML_SEPARATOR = ","; @@ -9720,6 +9723,18 @@ public class NotificationManagerService extends SystemService { } } } + + // clean up anything in the disallowed pkgs list + for (int i = 0; i < pkgList.length; i++) { + String pkg = pkgList[i]; + int userId = UserHandle.getUserId(uidList[i]); + for (int j = mRequestedNotificationListeners.size() - 1; j >= 0; j--) { + NotificationListenerFilter nlf = mRequestedNotificationListeners.valueAt(j); + + VersionedPackage ai = new VersionedPackage(pkg, uidList[i]); + nlf.removePackage(ai); + } + } } @Override @@ -9749,15 +9764,17 @@ public class NotificationManagerService extends SystemService { int approved = FLAG_FILTER_TYPE_CONVERSATIONS | FLAG_FILTER_TYPE_ALERTING | FLAG_FILTER_TYPE_SILENT | FLAG_FILTER_TYPE_ONGOING; - ArraySet disallowedPkgs = new ArraySet<>(); + ArraySet disallowedPkgs = new ArraySet<>(); final int listenerOuterDepth = parser.getDepth(); while (XmlUtils.nextElementWithin(parser, listenerOuterDepth)) { if (TAG_APPROVED.equals(parser.getName())) { approved = XmlUtils.readIntAttribute(parser, ATT_TYPES); } else if (TAG_DISALLOWED.equals(parser.getName())) { - String pkgs = XmlUtils.readStringAttribute(parser, ATT_PKGS); - if (!TextUtils.isEmpty(pkgs)) { - disallowedPkgs = new ArraySet<>(pkgs.split(XML_SEPARATOR)); + String pkg = XmlUtils.readStringAttribute(parser, ATT_PKG); + int uid = XmlUtils.readIntAttribute(parser, ATT_UID); + if (!TextUtils.isEmpty(pkg)) { + VersionedPackage ai = new VersionedPackage(pkg, uid); + disallowedPkgs.add(ai); } } } @@ -9782,10 +9799,14 @@ public class NotificationManagerService extends SystemService { XmlUtils.writeIntAttribute(out, ATT_TYPES, nlf.getTypes()); out.endTag(null, TAG_APPROVED); - out.startTag(null, TAG_DISALLOWED); - XmlUtils.writeStringAttribute( - out, ATT_PKGS, String.join(XML_SEPARATOR, nlf.getDisallowedPackages())); - out.endTag(null, TAG_DISALLOWED); + for (VersionedPackage ai : nlf.getDisallowedPackages()) { + if (!TextUtils.isEmpty(ai.getPackageName())) { + out.startTag(null, TAG_DISALLOWED); + XmlUtils.writeStringAttribute(out, ATT_PKG, ai.getPackageName()); + XmlUtils.writeIntAttribute(out, ATT_UID, ai.getVersionCode()); + out.endTag(null, TAG_DISALLOWED); + } + } out.endTag(null, TAG_REQUESTED_LISTENER); } diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenersTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenersTest.java index afcf08ef1562b..b13f80b6f4904 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenersTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenersTest.java @@ -25,6 +25,7 @@ import static org.mockito.Mockito.when; import android.app.INotificationManager; import android.content.ComponentName; +import android.content.pm.VersionedPackage; import android.content.pm.IPackageManager; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; @@ -83,11 +84,10 @@ public class NotificationListenersTest extends UiServiceTestCase { String xml = "" + "" + "" - + "" + "" + "" + "" - + "" + + "" + "" + ""; @@ -103,8 +103,9 @@ public class NotificationListenersTest extends UiServiceTestCase { @Test public void testWriteExtraTag() throws Exception { NotificationListenerFilter nlf = new NotificationListenerFilter(7, new ArraySet<>()); + VersionedPackage a1 = new VersionedPackage("pkg1", 243); NotificationListenerFilter nlf2 = - new NotificationListenerFilter(4, new ArraySet<>(new String[] {"something"})); + new NotificationListenerFilter(4, new ArraySet<>(new VersionedPackage[] {a1})); mListeners.setNotificationListenerFilter(Pair.create(mCn1, 0), nlf); mListeners.setNotificationListenerFilter(Pair.create(mCn2, 10), nlf2); @@ -134,16 +135,18 @@ public class NotificationListenersTest extends UiServiceTestCase { assertThat(mListeners.getNotificationListenerFilter(Pair.create(mCn2, 10)).getTypes()) .isEqualTo(4); + VersionedPackage a1 = new VersionedPackage("pkg1", 243); assertThat(mListeners.getNotificationListenerFilter(Pair.create(mCn2, 10)) .getDisallowedPackages()) - .contains("something"); + .contains(a1); } @Test public void testOnUserRemoved() { NotificationListenerFilter nlf = new NotificationListenerFilter(7, new ArraySet<>()); + VersionedPackage a1 = new VersionedPackage("pkg1", 243); NotificationListenerFilter nlf2 = - new NotificationListenerFilter(4, new ArraySet<>(new String[] {"something"})); + new NotificationListenerFilter(4, new ArraySet<>(new VersionedPackage[] {a1})); mListeners.setNotificationListenerFilter(Pair.create(mCn1, 0), nlf); mListeners.setNotificationListenerFilter(Pair.create(mCn2, 10), nlf2); @@ -157,8 +160,9 @@ public class NotificationListenersTest extends UiServiceTestCase { @Test public void testOnUserUnlocked() { // one exists already, say from xml + VersionedPackage a1 = new VersionedPackage("pkg1", 243); NotificationListenerFilter nlf = - new NotificationListenerFilter(4, new ArraySet<>(new String[] {"something"})); + new NotificationListenerFilter(4, new ArraySet<>(new VersionedPackage[] {a1})); mListeners.setNotificationListenerFilter(Pair.create(mCn2, 0), nlf); // new service exists or backfilling on upgrade to S @@ -188,7 +192,7 @@ public class NotificationListenersTest extends UiServiceTestCase { .isEqualTo(4); assertThat(mListeners.getNotificationListenerFilter(Pair.create(mCn2, 0)) .getDisallowedPackages()) - .contains("something"); + .contains(a1); assertThat(mListeners.getNotificationListenerFilter( Pair.create(si.getComponentName(), 0)).getTypes()) @@ -205,8 +209,9 @@ public class NotificationListenersTest extends UiServiceTestCase { @Test public void testOnPackageChanged() { NotificationListenerFilter nlf = new NotificationListenerFilter(7, new ArraySet<>()); + VersionedPackage a1 = new VersionedPackage("pkg1", 243); NotificationListenerFilter nlf2 = - new NotificationListenerFilter(4, new ArraySet<>(new String[] {"something"})); + new NotificationListenerFilter(4, new ArraySet<>(new VersionedPackage[] {a1})); mListeners.setNotificationListenerFilter(Pair.create(mCn1, 0), nlf); mListeners.setNotificationListenerFilter(Pair.create(mCn2, 10), nlf2); @@ -224,8 +229,9 @@ public class NotificationListenersTest extends UiServiceTestCase { @Test public void testOnPackageChanged_removing() { NotificationListenerFilter nlf = new NotificationListenerFilter(7, new ArraySet<>()); + VersionedPackage a1 = new VersionedPackage("pkg1", 243); NotificationListenerFilter nlf2 = - new NotificationListenerFilter(4, new ArraySet<>(new String[] {"something"})); + new NotificationListenerFilter(4, new ArraySet<>(new VersionedPackage[] {a1})); mListeners.setNotificationListenerFilter(Pair.create(mCn1, 0), nlf); mListeners.setNotificationListenerFilter(Pair.create(mCn2, 0), nlf2); @@ -239,4 +245,21 @@ public class NotificationListenersTest extends UiServiceTestCase { .isEqualTo(4); } + @Test + public void testOnPackageChanged_removingDisallowedPackage() { + NotificationListenerFilter nlf = new NotificationListenerFilter(7, new ArraySet<>()); + VersionedPackage a1 = new VersionedPackage("pkg1", 243); + NotificationListenerFilter nlf2 = + new NotificationListenerFilter(4, new ArraySet<>(new VersionedPackage[] {a1})); + mListeners.setNotificationListenerFilter(Pair.create(mCn1, 0), nlf); + mListeners.setNotificationListenerFilter(Pair.create(mCn2, 0), nlf2); + + String[] pkgs = new String[] {"pkg1"}; + int[] uids = new int[] {243}; + mListeners.onPackagesChanged(true, pkgs, uids); + + assertThat(mListeners.getNotificationListenerFilter(Pair.create(mCn1, 0)) + .getDisallowedPackages()).isEmpty(); + } + } diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java index e8888f496a011..a64050996d420 100755 --- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java @@ -464,7 +464,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { // Setup managed services when(mNlf.isTypeAllowed(anyInt())).thenReturn(true); - when(mNlf.isPackageAllowed(anyString())).thenReturn(true); + when(mNlf.isPackageAllowed(any())).thenReturn(true); when(mNlf.isPackageAllowed(null)).thenReturn(true); when(mListeners.getNotificationListenerFilter(any())).thenReturn(mNlf); mListener = mListeners.new ManagedServiceInfo( @@ -7307,7 +7307,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { @Test public void testIsVisibleToListener_disallowedPackage() { - when(mNlf.isPackageAllowed(null)).thenReturn(false); + when(mNlf.isPackageAllowed(any())).thenReturn(false); StatusBarNotification sbn = mock(StatusBarNotification.class); when(sbn.getUserId()).thenReturn(10);