diff options
4 files changed, 363 insertions, 21 deletions
diff --git a/services/core/java/com/android/server/notification/ManagedServices.java b/services/core/java/com/android/server/notification/ManagedServices.java index 93482e769a2b..122836e19d58 100644 --- a/services/core/java/com/android/server/notification/ManagedServices.java +++ b/services/core/java/com/android/server/notification/ManagedServices.java @@ -21,6 +21,9 @@ 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.content.pm.PackageManager.MATCH_DIRECT_BOOT_AWARE; +import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_UNAWARE; +import static android.content.pm.PackageManager.MATCH_INSTANT; import static android.os.UserHandle.USER_ALL; import static android.os.UserHandle.USER_SYSTEM; import static android.service.notification.NotificationListenerService.META_DATA_DEFAULT_AUTOBIND; @@ -106,7 +109,8 @@ abstract public class ManagedServices { protected final String TAG = getClass().getSimpleName().replace('$', '.'); protected final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); - private static final int ON_BINDING_DIED_REBIND_DELAY_MS = 10000; + protected static final int ON_BINDING_DIED_REBIND_DELAY_MS = 10000; + protected static final int ON_BINDING_DIED_REBIND_MSG = 1234; protected static final String ENABLED_SERVICES_SEPARATOR = ":"; private static final String DB_VERSION_1 = "1"; private static final String DB_VERSION_2 = "2"; @@ -875,7 +879,21 @@ abstract public class ManagedServices { String approvedItem = getApprovedValue(pkgOrComponent); if (approvedItem != null) { + final ComponentName component = ComponentName.unflattenFromString(approvedItem); if (enabled) { + if (Flags.notificationNlsRebind()) { + if (component != null && !isValidService(component, userId)) { + // Only fail if package is available + // If not, it will be validated again in onPackagesChanged + final PackageManager pm = mContext.getPackageManager(); + if (pm.isPackageAvailable(component.getPackageName())) { + Slog.w(TAG, "Skip allowing " + mConfig.caption + + " " + pkgOrComponent + " (userSet: " + userSet + + ") for invalid service"); + return; + } + } + } approved.add(approvedItem); } else { approved.remove(approvedItem); @@ -973,7 +991,7 @@ abstract public class ManagedServices { || isPackageOrComponentAllowed(component.getPackageName(), userId))) { return false; } - return componentHasBindPermission(component, userId); + return isValidService(component, userId); } private boolean componentHasBindPermission(ComponentName component, int userId) { @@ -1220,12 +1238,21 @@ abstract public class ManagedServices { if (!TextUtils.isEmpty(packageName)) { queryIntent.setPackage(packageName); } + + if (Flags.notificationNlsRebind()) { + // Expand the package query + extraFlags |= MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE; + extraFlags |= MATCH_INSTANT; + } + List<ResolveInfo> installedServices = pm.queryIntentServicesAsUser( queryIntent, PackageManager.GET_SERVICES | PackageManager.GET_META_DATA | extraFlags, userId); - if (DEBUG) - Slog.v(TAG, mConfig.serviceInterface + " services: " + installedServices); + if (DEBUG) { + Slog.v(TAG, mConfig.serviceInterface + " pkg: " + packageName + " services: " + + installedServices); + } if (installedServices != null) { for (int i = 0, count = installedServices.size(); i < count; i++) { ResolveInfo resolveInfo = installedServices.get(i); @@ -1325,11 +1352,12 @@ abstract public class ManagedServices { if (TextUtils.equals(getPackageName(approvedPackageOrComponent), packageName)) { final ComponentName component = ComponentName.unflattenFromString( approvedPackageOrComponent); - if (component != null && !componentHasBindPermission(component, userId)) { + if (component != null && !isValidService(component, userId)) { approved.removeAt(j); if (DEBUG) { Slog.v(TAG, "Removing " + approvedPackageOrComponent - + " from approved list; no bind permission found " + + " from approved list; no bind permission or " + + "service interface filter found " + mConfig.bindPermission); } } @@ -1348,6 +1376,15 @@ abstract public class ManagedServices { } } + protected boolean isValidService(ComponentName component, int userId) { + if (Flags.notificationNlsRebind()) { + return componentHasBindPermission(component, userId) && queryPackageForServices( + component.getPackageName(), userId).contains(component); + } else { + return componentHasBindPermission(component, userId); + } + } + protected boolean isValidEntry(String packageOrComponent, int userId) { return hasMatchingServices(packageOrComponent, userId); } @@ -1505,23 +1542,27 @@ abstract public class ManagedServices { * Called when user switched to unbind all services from other users. */ @VisibleForTesting - void unbindOtherUserServices(int currentUser) { + void unbindOtherUserServices(int switchedToUser) { TimingsTraceAndSlog t = new TimingsTraceAndSlog(); - t.traceBegin("ManagedServices.unbindOtherUserServices_current" + currentUser); - unbindServicesImpl(currentUser, true /* allExceptUser */); + t.traceBegin("ManagedServices.unbindOtherUserServices_current" + switchedToUser); + unbindServicesImpl(switchedToUser, true /* allExceptUser */); t.traceEnd(); } - void unbindUserServices(int user) { + void unbindUserServices(int removedUser) { TimingsTraceAndSlog t = new TimingsTraceAndSlog(); - t.traceBegin("ManagedServices.unbindUserServices" + user); - unbindServicesImpl(user, false /* allExceptUser */); + t.traceBegin("ManagedServices.unbindUserServices" + removedUser); + unbindServicesImpl(removedUser, false /* allExceptUser */); t.traceEnd(); } void unbindServicesImpl(int user, boolean allExceptUser) { final SparseArray<Set<ComponentName>> componentsToUnbind = new SparseArray<>(); synchronized (mMutex) { + if (Flags.notificationNlsRebind()) { + // Remove enqueued rebinds to avoid rebinding services for a switched user + mHandler.removeMessages(ON_BINDING_DIED_REBIND_MSG); + } final Set<ManagedServiceInfo> removableBoundServices = getRemovableConnectedServices(); for (ManagedServiceInfo info : removableBoundServices) { if ((allExceptUser && (info.userid != user)) @@ -1716,6 +1757,7 @@ abstract public class ManagedServices { mServicesRebinding.add(servicesBindingTag); mHandler.postDelayed(() -> reregisterService(name, userid), + ON_BINDING_DIED_REBIND_MSG, ON_BINDING_DIED_REBIND_DELAY_MS); } else { Slog.v(TAG, getCaption() + " not rebinding in user " + userid diff --git a/services/core/java/com/android/server/notification/flags.aconfig b/services/core/java/com/android/server/notification/flags.aconfig index f79d9ef174ea..c479acfd6228 100644 --- a/services/core/java/com/android/server/notification/flags.aconfig +++ b/services/core/java/com/android/server/notification/flags.aconfig @@ -194,3 +194,13 @@ flag { description: "Enables sound uri with vibration source in notification channel" bug: "351975435" } + +flag { + name: "notification_nls_rebind" + namespace: "systemui" + description: "Check for NLS service intent filter when rebinding services" + bug: "347674739" + metadata { + purpose: PURPOSE_BUGFIX + } +} 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 48bc9d7c51a1..b5724b5c0cc8 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java @@ -21,8 +21,10 @@ import static android.os.UserManager.USER_TYPE_FULL_SECONDARY; import static android.os.UserManager.USER_TYPE_PROFILE_CLONE; import static android.os.UserManager.USER_TYPE_PROFILE_MANAGED; import static android.os.UserManager.USER_TYPE_PROFILE_PRIVATE; +import static android.platform.test.flag.junit.SetFlagsRule.DefaultInitValueType.DEVICE_DEFAULT; import static android.service.notification.NotificationListenerService.META_DATA_DEFAULT_AUTOBIND; +import static com.android.server.notification.Flags.FLAG_NOTIFICATION_NLS_REBIND; import static com.android.server.notification.ManagedServices.APPROVAL_BY_COMPONENT; import static com.android.server.notification.ManagedServices.APPROVAL_BY_PACKAGE; import static com.android.server.notification.NotificationManagerService.privateSpaceFlagsEnabled; @@ -63,11 +65,14 @@ import android.os.Build; import android.os.Bundle; import android.os.IBinder; import android.os.IInterface; +import android.os.Looper; import android.os.RemoteException; import android.os.UserHandle; import android.os.UserManager; import android.platform.test.annotations.EnableFlags; +import android.platform.test.flag.junit.SetFlagsRule; import android.provider.Settings; +import android.testing.TestableLooper; import android.text.TextUtils; import android.util.ArrayMap; import android.util.ArraySet; @@ -82,7 +87,9 @@ import com.android.server.UiServiceTestCase; import com.google.android.collect.Lists; +import org.junit.After; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; import org.mockito.ArgumentCaptor; import org.mockito.Mock; @@ -103,7 +110,10 @@ import java.util.List; import java.util.Set; import java.util.concurrent.CountDownLatch; + public class ManagedServicesTest extends UiServiceTestCase { + @Rule + public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(DEVICE_DEFAULT); @Mock private IPackageManager mIpm; @@ -115,6 +125,7 @@ public class ManagedServicesTest extends UiServiceTestCase { private ManagedServices.UserProfiles mUserProfiles; @Mock private DevicePolicyManager mDpm; Object mLock = new Object(); + private TestableLooper mTestableLooper; UserInfo mZero = new UserInfo(0, "zero", 0); UserInfo mTen = new UserInfo(10, "ten", 0); @@ -142,6 +153,7 @@ public class ManagedServicesTest extends UiServiceTestCase { @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); + mTestableLooper = new TestableLooper(Looper.getMainLooper()); mContext.setMockPackageManager(mPm); mContext.addMockSystemService(Context.USER_SERVICE, mUm); @@ -199,6 +211,11 @@ public class ManagedServicesTest extends UiServiceTestCase { mIpm, APPROVAL_BY_COMPONENT); } + @After + public void tearDown() throws Exception { + mTestableLooper.destroy(); + } + @Test public void testBackupAndRestore_migration() throws Exception { for (int approvalLevel : new int[] {APPROVAL_BY_COMPONENT, APPROVAL_BY_PACKAGE}) { @@ -888,7 +905,7 @@ public class ManagedServicesTest extends UiServiceTestCase { return true; }); - mockServiceInfoWithMetaData(List.of(cn), service, new ArrayMap<>()); + mockServiceInfoWithMetaData(List.of(cn), service, pm, new ArrayMap<>()); service.addApprovedList("a", 0, true); service.reregisterService(cn, 0); @@ -919,7 +936,7 @@ public class ManagedServicesTest extends UiServiceTestCase { return true; }); - mockServiceInfoWithMetaData(List.of(cn), service, new ArrayMap<>()); + mockServiceInfoWithMetaData(List.of(cn), service, pm, new ArrayMap<>()); service.addApprovedList("a", 0, false); service.reregisterService(cn, 0); @@ -950,7 +967,7 @@ public class ManagedServicesTest extends UiServiceTestCase { return true; }); - mockServiceInfoWithMetaData(List.of(cn), service, new ArrayMap<>()); + mockServiceInfoWithMetaData(List.of(cn), service, pm, new ArrayMap<>()); service.addApprovedList("a/a", 0, true); service.reregisterService(cn, 0); @@ -981,7 +998,7 @@ public class ManagedServicesTest extends UiServiceTestCase { return true; }); - mockServiceInfoWithMetaData(List.of(cn), service, new ArrayMap<>()); + mockServiceInfoWithMetaData(List.of(cn), service, pm, new ArrayMap<>()); service.addApprovedList("a/a", 0, false); service.reregisterService(cn, 0); @@ -1053,6 +1070,78 @@ public class ManagedServicesTest extends UiServiceTestCase { } @Test + @EnableFlags(FLAG_NOTIFICATION_NLS_REBIND) + public void registerService_bindingDied_rebindIsClearedOnUserSwitch() throws Exception { + Context context = mock(Context.class); + PackageManager pm = mock(PackageManager.class); + ApplicationInfo ai = new ApplicationInfo(); + ai.targetSdkVersion = Build.VERSION_CODES.CUR_DEVELOPMENT; + + when(context.getPackageName()).thenReturn(mPkg); + when(context.getUserId()).thenReturn(mUser.getIdentifier()); + when(context.getPackageManager()).thenReturn(pm); + when(pm.getApplicationInfo(anyString(), anyInt())).thenReturn(ai); + + ManagedServices service = new TestManagedServices(context, mLock, mUserProfiles, mIpm, + APPROVAL_BY_PACKAGE); + service = spy(service); + ComponentName cn = ComponentName.unflattenFromString("a/a"); + + // Trigger onBindingDied for component when registering + // => will schedule a rebind in 10 seconds + when(context.bindServiceAsUser(any(), any(), anyInt(), any())).thenAnswer(invocation -> { + Object[] args = invocation.getArguments(); + ServiceConnection sc = (ServiceConnection) args[1]; + sc.onBindingDied(cn); + return true; + }); + service.registerService(cn, 0); + assertThat(service.isBound(cn, 0)).isFalse(); + + // Switch to user 10 + service.onUserSwitched(10); + + // Check that the scheduled rebind for user 0 was cleared + mTestableLooper.moveTimeForward(ManagedServices.ON_BINDING_DIED_REBIND_DELAY_MS); + mTestableLooper.processAllMessages(); + verify(service, never()).reregisterService(any(), anyInt()); + } + + @Test + public void registerService_bindingDied_rebindIsExecutedAfterTimeout() throws Exception { + Context context = mock(Context.class); + PackageManager pm = mock(PackageManager.class); + ApplicationInfo ai = new ApplicationInfo(); + ai.targetSdkVersion = Build.VERSION_CODES.CUR_DEVELOPMENT; + + when(context.getPackageName()).thenReturn(mPkg); + when(context.getUserId()).thenReturn(mUser.getIdentifier()); + when(context.getPackageManager()).thenReturn(pm); + when(pm.getApplicationInfo(anyString(), anyInt())).thenReturn(ai); + + ManagedServices service = new TestManagedServices(context, mLock, mUserProfiles, mIpm, + APPROVAL_BY_PACKAGE); + service = spy(service); + ComponentName cn = ComponentName.unflattenFromString("a/a"); + + // Trigger onBindingDied for component when registering + // => will schedule a rebind in 10 seconds + when(context.bindServiceAsUser(any(), any(), anyInt(), any())).thenAnswer(invocation -> { + Object[] args = invocation.getArguments(); + ServiceConnection sc = (ServiceConnection) args[1]; + sc.onBindingDied(cn); + return true; + }); + service.registerService(cn, 0); + assertThat(service.isBound(cn, 0)).isFalse(); + + // Check that the scheduled rebind is run + mTestableLooper.moveTimeForward(ManagedServices.ON_BINDING_DIED_REBIND_DELAY_MS); + mTestableLooper.processAllMessages(); + verify(service, times(1)).reregisterService(eq(cn), eq(0)); + } + + @Test public void testPackageUninstall_packageNoLongerInApprovedList() throws Exception { for (int approvalLevel : new int[] {APPROVAL_BY_COMPONENT, APPROVAL_BY_PACKAGE}) { ManagedServices service = new TestManagedServices(getContext(), mLock, mUserProfiles, @@ -1211,6 +1300,65 @@ public class ManagedServicesTest extends UiServiceTestCase { } @Test + @EnableFlags(FLAG_NOTIFICATION_NLS_REBIND) + public void testUpgradeAppNoIntentFilterNoRebind() throws Exception { + Context context = spy(getContext()); + doReturn(true).when(context).bindServiceAsUser(any(), any(), anyInt(), any()); + + ManagedServices service = new TestManagedServices(context, mLock, mUserProfiles, + mIpm, APPROVAL_BY_COMPONENT); + + List<String> packages = new ArrayList<>(); + packages.add("package"); + addExpectedServices(service, packages, 0); + + final ComponentName unapprovedComponent = ComponentName.unflattenFromString("package/C1"); + final ComponentName approvedComponent = ComponentName.unflattenFromString("package/C2"); + + // Both components are approved initially + mExpectedPrimaryComponentNames.clear(); + mExpectedPrimaryPackages.clear(); + mExpectedPrimaryComponentNames.put(0, "package/C1:package/C2"); + mExpectedSecondaryComponentNames.clear(); + mExpectedSecondaryPackages.clear(); + + loadXml(service); + + //Component package/C1 loses serviceInterface intent filter + ManagedServices.Config config = service.getConfig(); + when(mPm.queryIntentServicesAsUser(any(), anyInt(), anyInt())) + .thenAnswer(new Answer<List<ResolveInfo>>() { + @Override + public List<ResolveInfo> answer(InvocationOnMock invocationOnMock) + throws Throwable { + Object[] args = invocationOnMock.getArguments(); + Intent invocationIntent = (Intent) args[0]; + if (invocationIntent != null) { + if (invocationIntent.getAction().equals(config.serviceInterface) + && packages.contains(invocationIntent.getPackage())) { + List<ResolveInfo> dummyServices = new ArrayList<>(); + ResolveInfo resolveInfo = new ResolveInfo(); + ServiceInfo serviceInfo = new ServiceInfo(); + serviceInfo.packageName = invocationIntent.getPackage(); + serviceInfo.name = approvedComponent.getClassName(); + serviceInfo.permission = service.getConfig().bindPermission; + resolveInfo.serviceInfo = serviceInfo; + dummyServices.add(resolveInfo); + return dummyServices; + } + } + return new ArrayList<>(); + } + }); + + // Trigger package update + service.onPackagesChanged(false, new String[]{"package"}, new int[]{0}); + + assertFalse(service.isComponentEnabledForCurrentProfiles(unapprovedComponent)); + assertTrue(service.isComponentEnabledForCurrentProfiles(approvedComponent)); + } + + @Test public void testSetPackageOrComponentEnabled() throws Exception { for (int approvalLevel : new int[] {APPROVAL_BY_COMPONENT, APPROVAL_BY_PACKAGE}) { ManagedServices service = new TestManagedServices(getContext(), mLock, mUserProfiles, @@ -1223,6 +1371,21 @@ public class ManagedServicesTest extends UiServiceTestCase { "user10package1/K", "user10.3/Component", "user10package2/L", "user10.4/Component"})); + // mock permissions for services + PackageManager pm = mock(PackageManager.class); + when(getContext().getPackageManager()).thenReturn(pm); + List<ComponentName> enabledComponents = List.of( + ComponentName.unflattenFromString("package/Comp"), + ComponentName.unflattenFromString("package/C2"), + ComponentName.unflattenFromString("again/M4"), + ComponentName.unflattenFromString("user10package/B"), + ComponentName.unflattenFromString("user10/Component"), + ComponentName.unflattenFromString("user10package1/K"), + ComponentName.unflattenFromString("user10.3/Component"), + ComponentName.unflattenFromString("user10package2/L"), + ComponentName.unflattenFromString("user10.4/Component")); + mockServiceInfoWithMetaData(enabledComponents, service, pm, new ArrayMap<>()); + for (int userId : expectedEnabled.keySet()) { ArrayList<String> expectedForUser = expectedEnabled.get(userId); for (int i = 0; i < expectedForUser.size(); i++) { @@ -1284,6 +1447,90 @@ public class ManagedServicesTest extends UiServiceTestCase { } @Test + @EnableFlags(FLAG_NOTIFICATION_NLS_REBIND) + public void testSetPackageOrComponentEnabled_pkgInstalledAfterEnabling() throws Exception { + ManagedServices service = new TestManagedServices(getContext(), mLock, mUserProfiles, + mIpm, APPROVAL_BY_COMPONENT); + + final int userId = 0; + final String validComponent = "again/M4"; + ArrayList<String> expectedEnabled = Lists.newArrayList("package/Comp", "package/C2", + validComponent); + + PackageManager pm = mock(PackageManager.class); + when(getContext().getPackageManager()).thenReturn(pm); + service = spy(service); + + // Component again/M4 is a valid service and the package is available + doReturn(true).when(service) + .isValidService(ComponentName.unflattenFromString(validComponent), userId); + when(pm.isPackageAvailable("again")).thenReturn(true); + + // "package" is not available and its services are not valid + doReturn(false).when(service) + .isValidService(ComponentName.unflattenFromString("package/Comp"), userId); + doReturn(false).when(service) + .isValidService(ComponentName.unflattenFromString("package/C2"), userId); + when(pm.isPackageAvailable("package")).thenReturn(false); + + // Enable all components + for (String component: expectedEnabled) { + service.setPackageOrComponentEnabled(component, userId, true, true); + } + + // Verify everything added is approved + for (String component: expectedEnabled) { + assertTrue("Not allowed: user: " + userId + " entry: " + component + + " for approval level " + APPROVAL_BY_COMPONENT, + service.isPackageOrComponentAllowed(component, userId)); + } + + // Add missing package "package" + service.onPackagesChanged(false, new String[]{"package"}, new int[]{0}); + + // Check that component of "package" are not enabled + assertFalse(service.isComponentEnabledForCurrentProfiles( + ComponentName.unflattenFromString("package/Comp"))); + assertFalse(service.isPackageOrComponentAllowed("package/Comp", userId)); + + assertFalse(service.isComponentEnabledForCurrentProfiles( + ComponentName.unflattenFromString("package/C2"))); + assertFalse(service.isPackageOrComponentAllowed("package/C2", userId)); + + // Check that the valid components are still enabled + assertTrue(service.isComponentEnabledForCurrentProfiles( + ComponentName.unflattenFromString(validComponent))); + assertTrue(service.isPackageOrComponentAllowed(validComponent, userId)); + } + + @Test + @EnableFlags(FLAG_NOTIFICATION_NLS_REBIND) + public void testSetPackageOrComponentEnabled_invalidComponent() throws Exception { + ManagedServices service = new TestManagedServices(getContext(), mLock, mUserProfiles, + mIpm, APPROVAL_BY_COMPONENT); + + final int userId = 0; + final String invalidComponent = "package/Comp"; + + PackageManager pm = mock(PackageManager.class); + when(getContext().getPackageManager()).thenReturn(pm); + service = spy(service); + + // Component is an invalid service and the package is available + doReturn(false).when(service) + .isValidService(ComponentName.unflattenFromString(invalidComponent), userId); + when(pm.isPackageAvailable("package")).thenReturn(true); + service.setPackageOrComponentEnabled(invalidComponent, userId, true, true); + + // Verify that the component was not enabled + assertFalse("Not allowed: user: " + userId + " entry: " + invalidComponent + + " for approval level " + APPROVAL_BY_COMPONENT, + service.isPackageOrComponentAllowed(invalidComponent, userId)); + assertFalse(service.isComponentEnabledForCurrentProfiles( + ComponentName.unflattenFromString(invalidComponent))); + } + + @Test public void testGetAllowedPackages_byUser() throws Exception { for (int approvalLevel : new int[] {APPROVAL_BY_COMPONENT, APPROVAL_BY_PACKAGE}) { ManagedServices service = new TestManagedServices(getContext(), mLock, mUserProfiles, @@ -1944,7 +2191,7 @@ public class ManagedServicesTest extends UiServiceTestCase { metaDataAutobindAllow.putBoolean(META_DATA_DEFAULT_AUTOBIND, true); metaDatas.put(cn_allowed, metaDataAutobindAllow); - mockServiceInfoWithMetaData(componentNames, service, metaDatas); + mockServiceInfoWithMetaData(componentNames, service, pm, metaDatas); service.addApprovedList(cn_allowed.flattenToString(), 0, true); service.addApprovedList(cn_disallowed.flattenToString(), 0, true); @@ -1989,7 +2236,7 @@ public class ManagedServicesTest extends UiServiceTestCase { metaDataAutobindDisallow.putBoolean(META_DATA_DEFAULT_AUTOBIND, false); metaDatas.put(cn_disallowed, metaDataAutobindDisallow); - mockServiceInfoWithMetaData(componentNames, service, metaDatas); + mockServiceInfoWithMetaData(componentNames, service, pm, metaDatas); service.addApprovedList(cn_disallowed.flattenToString(), 0, true); @@ -2028,7 +2275,7 @@ public class ManagedServicesTest extends UiServiceTestCase { metaDataAutobindDisallow.putBoolean(META_DATA_DEFAULT_AUTOBIND, false); metaDatas.put(cn_disallowed, metaDataAutobindDisallow); - mockServiceInfoWithMetaData(componentNames, service, metaDatas); + mockServiceInfoWithMetaData(componentNames, service, pm, metaDatas); service.addApprovedList(cn_disallowed.flattenToString(), 0, true); @@ -2099,8 +2346,8 @@ public class ManagedServicesTest extends UiServiceTestCase { } private void mockServiceInfoWithMetaData(List<ComponentName> componentNames, - ManagedServices service, ArrayMap<ComponentName, Bundle> metaDatas) - throws RemoteException { + ManagedServices service, PackageManager packageManager, + ArrayMap<ComponentName, Bundle> metaDatas) throws RemoteException { when(mIpm.getServiceInfo(any(), anyLong(), anyInt())).thenAnswer( (Answer<ServiceInfo>) invocation -> { ComponentName invocationCn = invocation.getArgument(0); @@ -2115,6 +2362,39 @@ public class ManagedServicesTest extends UiServiceTestCase { return null; } ); + + // add components to queryIntentServicesAsUser response + final List<String> packages = new ArrayList<>(); + for (ComponentName cn: componentNames) { + packages.add(cn.getPackageName()); + } + ManagedServices.Config config = service.getConfig(); + when(packageManager.queryIntentServicesAsUser(any(), anyInt(), anyInt())). + thenAnswer(new Answer<List<ResolveInfo>>() { + @Override + public List<ResolveInfo> answer(InvocationOnMock invocationOnMock) + throws Throwable { + Object[] args = invocationOnMock.getArguments(); + Intent invocationIntent = (Intent) args[0]; + if (invocationIntent != null) { + if (invocationIntent.getAction().equals(config.serviceInterface) + && packages.contains(invocationIntent.getPackage())) { + List<ResolveInfo> dummyServices = new ArrayList<>(); + for (ComponentName cn: componentNames) { + ResolveInfo resolveInfo = new ResolveInfo(); + ServiceInfo serviceInfo = new ServiceInfo(); + serviceInfo.packageName = invocationIntent.getPackage(); + serviceInfo.name = cn.getClassName(); + serviceInfo.permission = service.getConfig().bindPermission; + resolveInfo.serviceInfo = serviceInfo; + dummyServices.add(resolveInfo); + } + return dummyServices; + } + } + return new ArrayList<>(); + } + }); } private void resetComponentsAndPackages() { 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 0f7de7d78ccf..2c645e0ca353 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationAssistantsTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationAssistantsTest.java @@ -28,6 +28,7 @@ import static junit.framework.Assert.assertNotNull; import static junit.framework.Assert.assertTrue; import static org.junit.Assert.assertNull; + import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Matchers.any; @@ -197,6 +198,8 @@ public class NotificationAssistantsTest extends UiServiceTestCase { public void testWriteXml_userTurnedOffNAS() throws Exception { int userId = ActivityManager.getCurrentUser(); + doReturn(true).when(mAssistants).isValidService(eq(mCn), eq(userId)); + mAssistants.loadDefaultsFromConfig(true); mAssistants.setPackageOrComponentEnabled(mCn.flattenToString(), userId, true, @@ -432,6 +435,10 @@ public class NotificationAssistantsTest extends UiServiceTestCase { public void testSetPackageOrComponentEnabled_onlyOnePackage() throws Exception { ComponentName component1 = ComponentName.unflattenFromString("package/Component1"); ComponentName component2 = ComponentName.unflattenFromString("package/Component2"); + + doReturn(true).when(mAssistants).isValidService(eq(component1), eq(mZero.id)); + doReturn(true).when(mAssistants).isValidService(eq(component2), eq(mZero.id)); + mAssistants.setPackageOrComponentEnabled(component1.flattenToString(), mZero.id, true, true, true); verify(mNm, never()).setNotificationAssistantAccessGrantedForUserInternal( @@ -577,6 +584,7 @@ public class NotificationAssistantsTest extends UiServiceTestCase { public void testSetAdjustmentTypeSupportedState() throws Exception { int userId = ActivityManager.getCurrentUser(); + doReturn(true).when(mAssistants).isValidService(eq(mCn), eq(userId)); mAssistants.loadDefaultsFromConfig(true); mAssistants.setPackageOrComponentEnabled(mCn.flattenToString(), userId, true, true, true); @@ -600,6 +608,7 @@ public class NotificationAssistantsTest extends UiServiceTestCase { public void testSetAdjustmentTypeSupportedState_readWriteXml_entries() throws Exception { int userId = ActivityManager.getCurrentUser(); + doReturn(true).when(mAssistants).isValidService(eq(mCn), eq(userId)); mAssistants.loadDefaultsFromConfig(true); mAssistants.setPackageOrComponentEnabled(mCn.flattenToString(), userId, true, true, true); @@ -623,6 +632,7 @@ public class NotificationAssistantsTest extends UiServiceTestCase { public void testSetAdjustmentTypeSupportedState_readWriteXml_empty() throws Exception { int userId = ActivityManager.getCurrentUser(); + doReturn(true).when(mAssistants).isValidService(eq(mCn), eq(userId)); mAssistants.loadDefaultsFromConfig(true); mAssistants.setPackageOrComponentEnabled(mCn.flattenToString(), userId, true, true, true); |