From 0668238d5063ceab5886a548dbe263086334ed69 Mon Sep 17 00:00:00 2001 From: Nagendra Prasad Nagarle Basavaraju Date: Wed, 13 Mar 2024 15:46:39 +0000 Subject: [PATCH] SatelliteAccessController enhancements to handle delete user scenario - Handle onRoleHoldersChanged is not triggered even if the user has a default app setup and gets deleted scenario. - Adding ACTION_USER_REMOVED intent filter, to monitor for User removal. This to used to update satellite fallback uid list and to keep allowed uid range updated at multi layer request of track default and satellite transport with Internet restricted capability Bug: 326373613 Test: atest FrameworksNetTests Change-Id: I1f30cd129309486bccbc61802ed600c142077411 --- .../SatelliteAccessController.java | 61 +++-- .../SatelliteAccessControllerTest.kt | 250 +++++++++++++----- 2 files changed, 223 insertions(+), 88 deletions(-) diff --git a/service/src/com/android/server/connectivity/SatelliteAccessController.java b/service/src/com/android/server/connectivity/SatelliteAccessController.java index b53abce8fe..2cdc932a12 100644 --- a/service/src/com/android/server/connectivity/SatelliteAccessController.java +++ b/service/src/com/android/server/connectivity/SatelliteAccessController.java @@ -20,7 +20,10 @@ import android.Manifest; import android.annotation.NonNull; import android.app.role.OnRoleHoldersChangedListener; import android.app.role.RoleManager; +import android.content.BroadcastReceiver; import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.os.Handler; @@ -49,7 +52,6 @@ public class SatelliteAccessController { private final Context mContext; private final Dependencies mDeps; private final DefaultMessageRoleListener mDefaultMessageRoleListener; - private final UserManager mUserManager; private final Consumer> mCallback; private final Handler mConnectivityServiceHandler; @@ -114,7 +116,6 @@ public class SatelliteAccessController { @NonNull final Handler connectivityServiceInternalHandler) { mContext = c; mDeps = deps; - mUserManager = mContext.getSystemService(UserManager.class); mDefaultMessageRoleListener = new DefaultMessageRoleListener(); mCallback = callback; mConnectivityServiceHandler = connectivityServiceInternalHandler; @@ -165,9 +166,6 @@ public class SatelliteAccessController { } // on Role sms change triggered by OnRoleHoldersChangedListener() - // TODO(b/326373613): using UserLifecycleListener, callback to be received when user removed for - // user delete scenario. This to be used to update uid list and ML Layer request can also be - // updated. private void onRoleSmsChanged(@NonNull UserHandle userHandle) { int userId = userHandle.getIdentifier(); if (userId == Process.INVALID_UID) { @@ -184,9 +182,8 @@ public class SatelliteAccessController { mAllUsersSatelliteNetworkFallbackUidCache.get(userId, new ArraySet<>()); Log.i(TAG, "currentUser : role_sms_packages: " + userId + " : " + packageNames); - final Set newUidsForUser = !packageNames.isEmpty() - ? updateSatelliteNetworkFallbackUidListCache(packageNames, userHandle) - : new ArraySet<>(); + final Set newUidsForUser = + updateSatelliteNetworkFallbackUidListCache(packageNames, userHandle); Log.i(TAG, "satellite_fallback_uid: " + newUidsForUser); // on Role change, update the multilayer request at ConnectivityService with updated @@ -197,6 +194,11 @@ public class SatelliteAccessController { mAllUsersSatelliteNetworkFallbackUidCache.put(userId, newUidsForUser); + // Update all users fallback cache for user, send cs fallback to update ML request + reportSatelliteNetworkFallbackUids(); + } + + private void reportSatelliteNetworkFallbackUids() { // Merge all uids of multiple users available Set mergedSatelliteNetworkFallbackUidCache = new ArraySet<>(); for (int i = 0; i < mAllUsersSatelliteNetworkFallbackUidCache.size(); i++) { @@ -210,27 +212,48 @@ public class SatelliteAccessController { mCallback.accept(mergedSatelliteNetworkFallbackUidCache); } - private List getRoleSmsChangedPackageName(UserHandle userHandle) { - try { - return mDeps.getRoleHoldersAsUser(RoleManager.ROLE_SMS, userHandle); - } catch (RuntimeException e) { - Log.wtf(TAG, "Could not get package name at role sms change update due to: " + e); - return null; - } - } - - /** Register OnRoleHoldersChangedListener */ public void start() { mConnectivityServiceHandler.post(this::updateAllUserRoleSmsUids); + + // register sms OnRoleHoldersChangedListener mDefaultMessageRoleListener.register(); + + // Monitor for User removal intent, to update satellite fallback uids. + IntentFilter userRemovedFilter = new IntentFilter(Intent.ACTION_USER_REMOVED); + mContext.registerReceiver(new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + final String action = intent.getAction(); + if (Intent.ACTION_USER_REMOVED.equals(action)) { + final UserHandle userHandle = intent.getParcelableExtra(Intent.EXTRA_USER); + if (userHandle == null) return; + updateSatelliteFallbackUidListOnUserRemoval(userHandle.getIdentifier()); + } else { + Log.wtf(TAG, "received unexpected intent: " + action); + } + } + }, userRemovedFilter, null, mConnectivityServiceHandler); + } private void updateAllUserRoleSmsUids() { - List existingUsers = mUserManager.getUserHandles(true /* excludeDying */); + UserManager userManager = mContext.getSystemService(UserManager.class); + // get existing user handles of available users + List existingUsers = userManager.getUserHandles(true /*excludeDying*/); + // Iterate through the user handles and obtain their uids with role sms and satellite // communication permission + Log.i(TAG, "existing users: " + existingUsers); for (UserHandle userHandle : existingUsers) { onRoleSmsChanged(userHandle); } } + + private void updateSatelliteFallbackUidListOnUserRemoval(int userIdRemoved) { + Log.i(TAG, "user id removed:" + userIdRemoved); + if (mAllUsersSatelliteNetworkFallbackUidCache.contains(userIdRemoved)) { + mAllUsersSatelliteNetworkFallbackUidCache.remove(userIdRemoved); + reportSatelliteNetworkFallbackUids(); + } + } } diff --git a/tests/unit/java/com/android/server/connectivity/SatelliteAccessControllerTest.kt b/tests/unit/java/com/android/server/connectivity/SatelliteAccessControllerTest.kt index 193078b57d..788532565f 100644 --- a/tests/unit/java/com/android/server/connectivity/SatelliteAccessControllerTest.kt +++ b/tests/unit/java/com/android/server/connectivity/SatelliteAccessControllerTest.kt @@ -18,17 +18,22 @@ package com.android.server.connectivity import android.Manifest import android.app.role.OnRoleHoldersChangedListener import android.app.role.RoleManager +import android.content.BroadcastReceiver import android.content.Context +import android.content.Intent +import android.content.IntentFilter import android.content.pm.ApplicationInfo import android.content.pm.PackageManager -import android.content.pm.UserInfo import android.os.Build import android.os.Handler +import android.os.Looper import android.os.UserHandle +import android.os.UserManager import android.util.ArraySet -import com.android.server.makeMockUserManager import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo import com.android.testutils.DevSdkIgnoreRunner +import java.util.concurrent.Executor +import java.util.function.Consumer import org.junit.Before import org.junit.Test import org.junit.runner.RunWith @@ -36,30 +41,32 @@ import org.mockito.ArgumentCaptor import org.mockito.ArgumentMatchers.any import org.mockito.ArgumentMatchers.anyInt import org.mockito.ArgumentMatchers.eq +import org.mockito.ArgumentMatchers.isNull import org.mockito.Mockito.doReturn import org.mockito.Mockito.mock import org.mockito.Mockito.never +import org.mockito.Mockito.timeout +import org.mockito.Mockito.times import org.mockito.Mockito.verify -import java.util.concurrent.Executor -import java.util.function.Consumer -private const val USER = 0 -val USER_INFO = UserInfo(USER, "" /* name */, UserInfo.FLAG_PRIMARY) -val USER_HANDLE = UserHandle(USER) private const val PRIMARY_USER = 0 private const val SECONDARY_USER = 10 private val PRIMARY_USER_HANDLE = UserHandle.of(PRIMARY_USER) private val SECONDARY_USER_HANDLE = UserHandle.of(SECONDARY_USER) + // sms app names private const val SMS_APP1 = "sms_app_1" private const val SMS_APP2 = "sms_app_2" + // sms app ids private const val SMS_APP_ID1 = 100 private const val SMS_APP_ID2 = 101 + // UID for app1 and app2 on primary user // These app could become default sms app for user1 private val PRIMARY_USER_SMS_APP_UID1 = UserHandle.getUid(PRIMARY_USER, SMS_APP_ID1) private val PRIMARY_USER_SMS_APP_UID2 = UserHandle.getUid(PRIMARY_USER, SMS_APP_ID2) + // UID for app1 and app2 on secondary user // These app could become default sms app for user2 private val SECONDARY_USER_SMS_APP_UID1 = UserHandle.getUid(SECONDARY_USER, SMS_APP_ID1) @@ -69,154 +76,259 @@ private val SECONDARY_USER_SMS_APP_UID2 = UserHandle.getUid(SECONDARY_USER, SMS_ @IgnoreUpTo(Build.VERSION_CODES.TIRAMISU) class SatelliteAccessControllerTest { private val context = mock(Context::class.java) - private val mPackageManager = mock(PackageManager::class.java) - private val mHandler = mock(Handler::class.java) - private val mRoleManager = - mock(SatelliteAccessController.Dependencies::class.java) + private val primaryUserContext = mock(Context::class.java) + private val secondaryUserContext = mock(Context::class.java) + private val mPackageManagerPrimaryUser = mock(PackageManager::class.java) + private val mPackageManagerSecondaryUser = mock(PackageManager::class.java) + private val mDeps = mock(SatelliteAccessController.Dependencies::class.java) private val mCallback = mock(Consumer::class.java) as Consumer> - private val mSatelliteAccessController = - SatelliteAccessController(context, mRoleManager, mCallback, mHandler) + private val userManager = mock(UserManager::class.java) + private val mHandler = Handler(Looper.getMainLooper()) + private var mSatelliteAccessController = + SatelliteAccessController(context, mDeps, mCallback, mHandler) private lateinit var mRoleHolderChangedListener: OnRoleHoldersChangedListener + private lateinit var mUserRemovedReceiver: BroadcastReceiver + + private fun mockService(name: String, clazz: Class, service: T) { + doReturn(name).`when`(context).getSystemServiceName(clazz) + doReturn(service).`when`(context).getSystemService(name) + if (context.getSystemService(clazz) == null) { + // Test is using mockito-extended + doReturn(service).`when`(context).getSystemService(clazz) + } + } + @Before @Throws(PackageManager.NameNotFoundException::class) fun setup() { - makeMockUserManager(USER_INFO, USER_HANDLE) - doReturn(context).`when`(context).createContextAsUser(any(), anyInt()) - doReturn(mPackageManager).`when`(context).packageManager + doReturn(emptyList()).`when`(userManager).getUserHandles(true) + mockService(Context.USER_SERVICE, UserManager::class.java, userManager) - doReturn(PackageManager.PERMISSION_GRANTED) - .`when`(mPackageManager) - .checkPermission(Manifest.permission.SATELLITE_COMMUNICATION, SMS_APP1) - doReturn(PackageManager.PERMISSION_GRANTED) - .`when`(mPackageManager) - .checkPermission(Manifest.permission.SATELLITE_COMMUNICATION, SMS_APP2) + doReturn(primaryUserContext).`when`(context).createContextAsUser(PRIMARY_USER_HANDLE, 0) + doReturn(mPackageManagerPrimaryUser).`when`(primaryUserContext).packageManager - // Initialise default message application primary user package1 + doReturn(secondaryUserContext).`when`(context).createContextAsUser(SECONDARY_USER_HANDLE, 0) + doReturn(mPackageManagerSecondaryUser).`when`(secondaryUserContext).packageManager + + for (app in listOf(SMS_APP1, SMS_APP2)) { + doReturn(PackageManager.PERMISSION_GRANTED) + .`when`(mPackageManagerPrimaryUser) + .checkPermission(Manifest.permission.SATELLITE_COMMUNICATION, app) + doReturn(PackageManager.PERMISSION_GRANTED) + .`when`(mPackageManagerSecondaryUser) + .checkPermission(Manifest.permission.SATELLITE_COMMUNICATION, app) + } + + // Initialise message application primary user package1 val applicationInfo1 = ApplicationInfo() applicationInfo1.uid = PRIMARY_USER_SMS_APP_UID1 doReturn(applicationInfo1) - .`when`(mPackageManager) + .`when`(mPackageManagerPrimaryUser) .getApplicationInfo(eq(SMS_APP1), anyInt()) - // Initialise default message application primary user package2 + // Initialise message application primary user package2 val applicationInfo2 = ApplicationInfo() applicationInfo2.uid = PRIMARY_USER_SMS_APP_UID2 doReturn(applicationInfo2) - .`when`(mPackageManager) + .`when`(mPackageManagerPrimaryUser) .getApplicationInfo(eq(SMS_APP2), anyInt()) - // Get registered listener using captor - val listenerCaptor = ArgumentCaptor.forClass( - OnRoleHoldersChangedListener::class.java - ) - mSatelliteAccessController.start() - verify(mRoleManager).addOnRoleHoldersChangedListenerAsUser( - any(Executor::class.java), listenerCaptor.capture(), any(UserHandle::class.java)) - mRoleHolderChangedListener = listenerCaptor.value + // Initialise message application secondary user package1 + val applicationInfo3 = ApplicationInfo() + applicationInfo3.uid = SECONDARY_USER_SMS_APP_UID1 + doReturn(applicationInfo3) + .`when`(mPackageManagerSecondaryUser) + .getApplicationInfo(eq(SMS_APP1), anyInt()) + + // Initialise message application secondary user package2 + val applicationInfo4 = ApplicationInfo() + applicationInfo4.uid = SECONDARY_USER_SMS_APP_UID2 + doReturn(applicationInfo4) + .`when`(mPackageManagerSecondaryUser) + .getApplicationInfo(eq(SMS_APP2), anyInt()) } @Test fun test_onRoleHoldersChanged_SatelliteFallbackUid_Changed_SingleUser() { - doReturn(listOf()).`when`(mRoleManager).getRoleHoldersAsUser(RoleManager.ROLE_SMS, - PRIMARY_USER_HANDLE) + startSatelliteAccessController() + doReturn(listOf()).`when`(mDeps).getRoleHoldersAsUser( + RoleManager.ROLE_SMS, + PRIMARY_USER_HANDLE + ) mRoleHolderChangedListener.onRoleHoldersChanged(RoleManager.ROLE_SMS, PRIMARY_USER_HANDLE) verify(mCallback, never()).accept(any()) // check DEFAULT_MESSAGING_APP1 is available as satellite network fallback uid doReturn(listOf(SMS_APP1)) - .`when`(mRoleManager).getRoleHoldersAsUser(RoleManager.ROLE_SMS, PRIMARY_USER_HANDLE) + .`when`(mDeps).getRoleHoldersAsUser(RoleManager.ROLE_SMS, PRIMARY_USER_HANDLE) mRoleHolderChangedListener.onRoleHoldersChanged(RoleManager.ROLE_SMS, PRIMARY_USER_HANDLE) verify(mCallback).accept(setOf(PRIMARY_USER_SMS_APP_UID1)) // check SMS_APP2 is available as satellite network Fallback uid - doReturn(listOf(SMS_APP2)).`when`(mRoleManager).getRoleHoldersAsUser(RoleManager.ROLE_SMS, - PRIMARY_USER_HANDLE) + doReturn(listOf(SMS_APP2)).`when`(mDeps).getRoleHoldersAsUser( + RoleManager.ROLE_SMS, + PRIMARY_USER_HANDLE + ) mRoleHolderChangedListener.onRoleHoldersChanged(RoleManager.ROLE_SMS, PRIMARY_USER_HANDLE) verify(mCallback).accept(setOf(PRIMARY_USER_SMS_APP_UID2)) // check no uid is available as satellite network fallback uid - doReturn(listOf()).`when`(mRoleManager).getRoleHoldersAsUser(RoleManager.ROLE_SMS, - PRIMARY_USER_HANDLE) + doReturn(listOf()).`when`(mDeps).getRoleHoldersAsUser( + RoleManager.ROLE_SMS, + PRIMARY_USER_HANDLE + ) mRoleHolderChangedListener.onRoleHoldersChanged(RoleManager.ROLE_SMS, PRIMARY_USER_HANDLE) verify(mCallback).accept(ArraySet()) } @Test fun test_onRoleHoldersChanged_NoSatelliteCommunicationPermission() { - doReturn(listOf()).`when`(mRoleManager).getRoleHoldersAsUser(RoleManager.ROLE_SMS, - PRIMARY_USER_HANDLE) + startSatelliteAccessController() + doReturn(listOf()).`when`(mDeps).getRoleHoldersAsUser( + RoleManager.ROLE_SMS, + PRIMARY_USER_HANDLE + ) mRoleHolderChangedListener.onRoleHoldersChanged(RoleManager.ROLE_SMS, PRIMARY_USER_HANDLE) verify(mCallback, never()).accept(any()) // check DEFAULT_MESSAGING_APP1 is not available as satellite network fallback uid // since satellite communication permission not available. doReturn(PackageManager.PERMISSION_DENIED) - .`when`(mPackageManager) + .`when`(mPackageManagerPrimaryUser) .checkPermission(Manifest.permission.SATELLITE_COMMUNICATION, SMS_APP1) doReturn(listOf(SMS_APP1)) - .`when`(mRoleManager).getRoleHoldersAsUser(RoleManager.ROLE_SMS, PRIMARY_USER_HANDLE) + .`when`(mDeps).getRoleHoldersAsUser(RoleManager.ROLE_SMS, PRIMARY_USER_HANDLE) mRoleHolderChangedListener.onRoleHoldersChanged(RoleManager.ROLE_SMS, PRIMARY_USER_HANDLE) verify(mCallback, never()).accept(any()) } @Test fun test_onRoleHoldersChanged_RoleSms_NotAvailable() { + startSatelliteAccessController() doReturn(listOf(SMS_APP1)) - .`when`(mRoleManager).getRoleHoldersAsUser(RoleManager.ROLE_SMS, PRIMARY_USER_HANDLE) - mRoleHolderChangedListener.onRoleHoldersChanged(RoleManager.ROLE_BROWSER, - PRIMARY_USER_HANDLE) + .`when`(mDeps).getRoleHoldersAsUser(RoleManager.ROLE_SMS, PRIMARY_USER_HANDLE) + mRoleHolderChangedListener.onRoleHoldersChanged( + RoleManager.ROLE_BROWSER, + PRIMARY_USER_HANDLE + ) verify(mCallback, never()).accept(any()) } @Test fun test_onRoleHoldersChanged_SatelliteNetworkFallbackUid_Changed_multiUser() { - doReturn(listOf()).`when`(mRoleManager).getRoleHoldersAsUser(RoleManager.ROLE_SMS, - PRIMARY_USER_HANDLE) + startSatelliteAccessController() + doReturn(listOf()).`when`(mDeps).getRoleHoldersAsUser( + RoleManager.ROLE_SMS, + PRIMARY_USER_HANDLE + ) mRoleHolderChangedListener.onRoleHoldersChanged(RoleManager.ROLE_SMS, PRIMARY_USER_HANDLE) verify(mCallback, never()).accept(any()) // check SMS_APP1 is available as satellite network fallback uid at primary user doReturn(listOf(SMS_APP1)) - .`when`(mRoleManager).getRoleHoldersAsUser(RoleManager.ROLE_SMS, PRIMARY_USER_HANDLE) + .`when`(mDeps).getRoleHoldersAsUser(RoleManager.ROLE_SMS, PRIMARY_USER_HANDLE) mRoleHolderChangedListener.onRoleHoldersChanged(RoleManager.ROLE_SMS, PRIMARY_USER_HANDLE) verify(mCallback).accept(setOf(PRIMARY_USER_SMS_APP_UID1)) // check SMS_APP2 is available as satellite network fallback uid at primary user - doReturn(listOf(SMS_APP2)).`when`(mRoleManager).getRoleHoldersAsUser(RoleManager.ROLE_SMS, - PRIMARY_USER_HANDLE) + doReturn(listOf(SMS_APP2)).`when`(mDeps).getRoleHoldersAsUser( + RoleManager.ROLE_SMS, + PRIMARY_USER_HANDLE + ) mRoleHolderChangedListener.onRoleHoldersChanged(RoleManager.ROLE_SMS, PRIMARY_USER_HANDLE) verify(mCallback).accept(setOf(PRIMARY_USER_SMS_APP_UID2)) // check SMS_APP1 is available as satellite network fallback uid at secondary user - val applicationInfo1 = ApplicationInfo() - applicationInfo1.uid = SECONDARY_USER_SMS_APP_UID1 - doReturn(applicationInfo1).`when`(mPackageManager) - .getApplicationInfo(eq(SMS_APP1), anyInt()) - doReturn(listOf(SMS_APP1)).`when`(mRoleManager).getRoleHoldersAsUser(RoleManager.ROLE_SMS, - SECONDARY_USER_HANDLE) + doReturn(listOf(SMS_APP1)).`when`(mDeps).getRoleHoldersAsUser( + RoleManager.ROLE_SMS, + SECONDARY_USER_HANDLE + ) mRoleHolderChangedListener.onRoleHoldersChanged(RoleManager.ROLE_SMS, SECONDARY_USER_HANDLE) verify(mCallback).accept(setOf(PRIMARY_USER_SMS_APP_UID2, SECONDARY_USER_SMS_APP_UID1)) // check no uid is available as satellite network fallback uid at primary user - doReturn(listOf()).`when`(mRoleManager).getRoleHoldersAsUser(RoleManager.ROLE_SMS, - PRIMARY_USER_HANDLE) - mRoleHolderChangedListener.onRoleHoldersChanged(RoleManager.ROLE_SMS, - PRIMARY_USER_HANDLE) + doReturn(listOf()).`when`(mDeps).getRoleHoldersAsUser( + RoleManager.ROLE_SMS, + PRIMARY_USER_HANDLE + ) + mRoleHolderChangedListener.onRoleHoldersChanged( + RoleManager.ROLE_SMS, + PRIMARY_USER_HANDLE + ) verify(mCallback).accept(setOf(SECONDARY_USER_SMS_APP_UID1)) // check SMS_APP2 is available as satellite network fallback uid at secondary user - applicationInfo1.uid = SECONDARY_USER_SMS_APP_UID2 - doReturn(applicationInfo1).`when`(mPackageManager) - .getApplicationInfo(eq(SMS_APP2), anyInt()) doReturn(listOf(SMS_APP2)) - .`when`(mRoleManager).getRoleHoldersAsUser(RoleManager.ROLE_SMS, SECONDARY_USER_HANDLE) + .`when`(mDeps).getRoleHoldersAsUser(RoleManager.ROLE_SMS, SECONDARY_USER_HANDLE) mRoleHolderChangedListener.onRoleHoldersChanged(RoleManager.ROLE_SMS, SECONDARY_USER_HANDLE) verify(mCallback).accept(setOf(SECONDARY_USER_SMS_APP_UID2)) // check no uid is available as satellite network fallback uid at secondary user - doReturn(listOf()).`when`(mRoleManager).getRoleHoldersAsUser(RoleManager.ROLE_SMS, - SECONDARY_USER_HANDLE) + doReturn(listOf()).`when`(mDeps).getRoleHoldersAsUser( + RoleManager.ROLE_SMS, + SECONDARY_USER_HANDLE + ) mRoleHolderChangedListener.onRoleHoldersChanged(RoleManager.ROLE_SMS, SECONDARY_USER_HANDLE) verify(mCallback).accept(ArraySet()) } + + @Test + fun test_SatelliteFallbackUidCallback_OnUserRemoval() { + startSatelliteAccessController() + // check SMS_APP2 is available as satellite network fallback uid at primary user + doReturn(listOf(SMS_APP2)).`when`(mDeps).getRoleHoldersAsUser( + RoleManager.ROLE_SMS, + PRIMARY_USER_HANDLE + ) + mRoleHolderChangedListener.onRoleHoldersChanged(RoleManager.ROLE_SMS, PRIMARY_USER_HANDLE) + verify(mCallback).accept(setOf(PRIMARY_USER_SMS_APP_UID2)) + + // check SMS_APP1 is available as satellite network fallback uid at secondary user + doReturn(listOf(SMS_APP1)).`when`(mDeps).getRoleHoldersAsUser( + RoleManager.ROLE_SMS, + SECONDARY_USER_HANDLE + ) + mRoleHolderChangedListener.onRoleHoldersChanged(RoleManager.ROLE_SMS, SECONDARY_USER_HANDLE) + verify(mCallback).accept(setOf(PRIMARY_USER_SMS_APP_UID2, SECONDARY_USER_SMS_APP_UID1)) + + val userRemovalIntent = Intent(Intent.ACTION_USER_REMOVED) + userRemovalIntent.putExtra(Intent.EXTRA_USER, SECONDARY_USER_HANDLE) + mUserRemovedReceiver.onReceive(context, userRemovalIntent) + verify(mCallback, times(2)).accept(setOf(PRIMARY_USER_SMS_APP_UID2)) + } + + @Test + fun testOnStartUpCallbackSatelliteFallbackUidWithExistingUsers() { + doReturn( + listOf(PRIMARY_USER_HANDLE) + ).`when`(userManager).getUserHandles(true) + doReturn(listOf(SMS_APP1)) + .`when`(mDeps).getRoleHoldersAsUser(RoleManager.ROLE_SMS, PRIMARY_USER_HANDLE) + // At start up, SatelliteAccessController must call CS callback with existing users' + // default messaging apps uids. + startSatelliteAccessController() + verify(mCallback, timeout(500)).accept(setOf(PRIMARY_USER_SMS_APP_UID1)) + } + + private fun startSatelliteAccessController() { + mSatelliteAccessController.start() + // Get registered listener using captor + val listenerCaptor = ArgumentCaptor.forClass(OnRoleHoldersChangedListener::class.java) + verify(mDeps).addOnRoleHoldersChangedListenerAsUser( + any(Executor::class.java), + listenerCaptor.capture(), + any(UserHandle::class.java) + ) + mRoleHolderChangedListener = listenerCaptor.value + + // Get registered receiver using captor + val userRemovedReceiverCaptor = ArgumentCaptor.forClass(BroadcastReceiver::class.java) + verify(context).registerReceiver( + userRemovedReceiverCaptor.capture(), + any(IntentFilter::class.java), + isNull(), + any(Handler::class.java) + ) + mUserRemovedReceiver = userRemovedReceiverCaptor.value + } }