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
This commit is contained in:
@@ -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;
|
||||
@@ -10693,10 +10694,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
|
||||
@@ -10721,10 +10730,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());
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user