Match any user pkgs for headless sys user mode

In headless system user mode a package might not be installed in the
system user. Since the config list is only loaded and matched against
packages for the system user, we need to handle the case where a package
might exist on the system but not be installed for the system user.

Bug: 241469882
Test: atest NotificationListenersTest
Change-Id: I3e225047846658479d00d4089b8864860ef0c274
Merged-In: I3e225047846658479d00d4089b8864860ef0c274
(cherry picked from commit 19eb2d59a6)
This commit is contained in:
Jordan Jozwiak
2022-10-10 19:06:15 -07:00
parent 8a046e904e
commit 8228a8a201
2 changed files with 74 additions and 6 deletions

View File

@@ -61,6 +61,7 @@ import static android.content.pm.PackageManager.FEATURE_LEANBACK;
import static android.content.pm.PackageManager.FEATURE_TELECOM;
import static android.content.pm.PackageManager.FEATURE_TELEVISION;
import static android.content.pm.PackageManager.MATCH_ALL;
import static android.content.pm.PackageManager.MATCH_ANY_USER;
import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AWARE;
import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_UNAWARE;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
@@ -10633,10 +10634,18 @@ public class NotificationManagerService extends SystemService {
private final ArraySet<ManagedServiceInfo> mLightTrimListeners = new ArraySet<>();
ArrayMap<Pair<ComponentName, Integer>, NotificationListenerFilter>
mRequestedNotificationListeners = new ArrayMap<>();
private final boolean mIsHeadlessSystemUserMode;
public NotificationListeners(Context context, Object lock, UserProfiles userProfiles,
IPackageManager pm) {
this(context, lock, userProfiles, pm, UserManager.isHeadlessSystemUserMode());
}
@VisibleForTesting
public NotificationListeners(Context context, Object lock, UserProfiles userProfiles,
IPackageManager pm, boolean isHeadlessSystemUserMode) {
super(context, lock, userProfiles, pm);
this.mIsHeadlessSystemUserMode = isHeadlessSystemUserMode;
}
@Override
@@ -10661,10 +10670,16 @@ public class NotificationManagerService extends SystemService {
if (TextUtils.isEmpty(listeners[i])) {
continue;
}
int packageQueryFlags = MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE;
// In the headless system user mode, packages might not be installed for the
// system user. Match packages for any user since apps can be installed only for
// non-system users and would be considering uninstalled for the system user.
if (mIsHeadlessSystemUserMode) {
packageQueryFlags += MATCH_ANY_USER;
}
ArraySet<ComponentName> approvedListeners =
this.queryPackageForServices(listeners[i],
MATCH_DIRECT_BOOT_AWARE
| MATCH_DIRECT_BOOT_UNAWARE, USER_SYSTEM);
this.queryPackageForServices(listeners[i], packageQueryFlags,
USER_SYSTEM);
for (int k = 0; k < approvedListeners.size(); k++) {
ComponentName cn = approvedListeners.valueAt(k);
addDefaultComponentOrPackage(cn.flattenToString());

View File

@@ -15,6 +15,7 @@
*/
package com.android.server.notification;
import static android.content.pm.PackageManager.MATCH_ANY_USER;
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;
@@ -30,9 +31,11 @@ import static junit.framework.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.intThat;
import static org.mockito.ArgumentMatchers.nullable;
import static org.mockito.Mockito.atLeast;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
@@ -49,6 +52,7 @@ import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
import android.content.pm.ServiceInfo;
import android.content.pm.VersionedPackage;
import android.content.res.Resources;
import android.os.Bundle;
import android.os.UserHandle;
import android.service.notification.NotificationListenerFilter;
@@ -69,6 +73,7 @@ import com.google.common.collect.ImmutableList;
import org.junit.Before;
import org.junit.Test;
import org.mockito.ArgumentMatcher;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.mockito.internal.util.reflection.FieldSetter;
@@ -77,6 +82,7 @@ import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.util.Arrays;
import java.util.List;
public class NotificationListenersTest extends UiServiceTestCase {
@@ -85,6 +91,8 @@ public class NotificationListenersTest extends UiServiceTestCase {
private PackageManager mPm;
@Mock
private IPackageManager miPm;
@Mock
private Resources mResources;
@Mock
NotificationManagerService mNm;
@@ -96,7 +104,8 @@ public class NotificationListenersTest extends UiServiceTestCase {
private ComponentName mCn1 = new ComponentName("pkg", "pkg.cmp");
private ComponentName mCn2 = new ComponentName("pkg2", "pkg2.cmp2");
private ComponentName mUninstalledComponent = new ComponentName("pkg3",
"pkg3.NotificationListenerService");
@Before
public void setUp() throws Exception {
@@ -111,7 +120,7 @@ public class NotificationListenersTest extends UiServiceTestCase {
@Test
public void testReadExtraTag() throws Exception {
String xml = "<" + TAG_REQUESTED_LISTENERS+ ">"
String xml = "<" + TAG_REQUESTED_LISTENERS + ">"
+ "<listener component=\"" + mCn1.flattenToString() + "\" user=\"0\">"
+ "<allowed types=\"7\" />"
+ "</listener>"
@@ -130,12 +139,56 @@ public class NotificationListenersTest extends UiServiceTestCase {
validateListenersFromXml();
}
@Test
public void loadDefaultsFromConfig_forHeadlessSystemUser_loadUninstalled() throws Exception {
// setup with headless system user mode
mListeners = spy(mNm.new NotificationListeners(
mContext, new Object(), mock(ManagedServices.UserProfiles.class), miPm,
/* isHeadlessSystemUserMode= */ true));
mockDefaultListenerConfigForUninstalledComponent(mUninstalledComponent);
mListeners.loadDefaultsFromConfig();
assertThat(mListeners.getDefaultComponents()).contains(mUninstalledComponent);
}
@Test
public void loadDefaultsFromConfig_forNonHeadlessSystemUser_ignoreUninstalled()
throws Exception {
// setup without headless system user mode
mListeners = spy(mNm.new NotificationListeners(
mContext, new Object(), mock(ManagedServices.UserProfiles.class), miPm,
/* isHeadlessSystemUserMode= */ false));
mockDefaultListenerConfigForUninstalledComponent(mUninstalledComponent);
mListeners.loadDefaultsFromConfig();
assertThat(mListeners.getDefaultComponents()).doesNotContain(mUninstalledComponent);
}
private void mockDefaultListenerConfigForUninstalledComponent(ComponentName componentName) {
ArraySet<ComponentName> components = new ArraySet<>(Arrays.asList(componentName));
when(mResources
.getString(
com.android.internal.R.string.config_defaultListenerAccessPackages))
.thenReturn(componentName.getPackageName());
when(mContext.getResources()).thenReturn(mResources);
doReturn(components).when(mListeners).queryPackageForServices(
eq(componentName.getPackageName()),
intThat(hasIntBitFlag(MATCH_ANY_USER)),
anyInt());
}
public static ArgumentMatcher<Integer> hasIntBitFlag(int flag) {
return arg -> arg != null && ((arg & flag) == flag);
}
@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 VersionedPackage[] {a1}));
new NotificationListenerFilter(4, new ArraySet<>(new VersionedPackage[]{a1}));
mListeners.setNotificationListenerFilter(Pair.create(mCn1, 0), nlf);
mListeners.setNotificationListenerFilter(Pair.create(mCn2, 10), nlf2);