1 /*
2  * Copyright (C) 2024 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.android.server.connectivity
17 
18 import android.Manifest
19 import android.app.role.OnRoleHoldersChangedListener
20 import android.app.role.RoleManager
21 import android.content.BroadcastReceiver
22 import android.content.Context
23 import android.content.Intent
24 import android.content.IntentFilter
25 import android.content.pm.ApplicationInfo
26 import android.content.pm.PackageManager
27 import android.os.Build
28 import android.os.Handler
29 import android.os.Looper
30 import android.os.UserHandle
31 import android.os.UserManager
32 import android.util.ArraySet
33 import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo
34 import com.android.testutils.DevSdkIgnoreRunner
35 import java.util.concurrent.Executor
36 import java.util.function.Consumer
37 import org.junit.Before
38 import org.junit.Test
39 import org.junit.runner.RunWith
40 import org.mockito.ArgumentCaptor
41 import org.mockito.ArgumentMatchers.any
42 import org.mockito.ArgumentMatchers.anyInt
43 import org.mockito.ArgumentMatchers.eq
44 import org.mockito.ArgumentMatchers.isNull
45 import org.mockito.Mockito.doReturn
46 import org.mockito.Mockito.mock
47 import org.mockito.Mockito.never
48 import org.mockito.Mockito.timeout
49 import org.mockito.Mockito.times
50 import org.mockito.Mockito.verify
51 
52 private const val PRIMARY_USER = 0
53 private const val SECONDARY_USER = 10
54 private val PRIMARY_USER_HANDLE = UserHandle.of(PRIMARY_USER)
55 private val SECONDARY_USER_HANDLE = UserHandle.of(SECONDARY_USER)
56 
57 // sms app names
58 private const val SMS_APP1 = "sms_app_1"
59 private const val SMS_APP2 = "sms_app_2"
60 
61 // sms app ids
62 private const val SMS_APP_ID1 = 100
63 private const val SMS_APP_ID2 = 101
64 
65 // UID for app1 and app2 on primary user
66 // These app could become default sms app for user1
67 private val PRIMARY_USER_SMS_APP_UID1 = UserHandle.getUid(PRIMARY_USER, SMS_APP_ID1)
68 private val PRIMARY_USER_SMS_APP_UID2 = UserHandle.getUid(PRIMARY_USER, SMS_APP_ID2)
69 
70 // UID for app1 and app2 on secondary user
71 // These app could become default sms app for user2
72 private val SECONDARY_USER_SMS_APP_UID1 = UserHandle.getUid(SECONDARY_USER, SMS_APP_ID1)
73 private val SECONDARY_USER_SMS_APP_UID2 = UserHandle.getUid(SECONDARY_USER, SMS_APP_ID2)
74 
75 @RunWith(DevSdkIgnoreRunner::class)
76 @IgnoreUpTo(Build.VERSION_CODES.TIRAMISU)
77 class SatelliteAccessControllerTest {
78     private val context = mock(Context::class.java)
79     private val primaryUserContext = mock(Context::class.java)
80     private val secondaryUserContext = mock(Context::class.java)
81     private val mPackageManagerPrimaryUser = mock(PackageManager::class.java)
82     private val mPackageManagerSecondaryUser = mock(PackageManager::class.java)
83     private val mDeps = mock(SatelliteAccessController.Dependencies::class.java)
84     private val mCallback = mock(Consumer::class.java) as Consumer<Set<Int>>
85     private val userManager = mock(UserManager::class.java)
86     private val mHandler = Handler(Looper.getMainLooper())
87     private var mSatelliteAccessController =
88         SatelliteAccessController(context, mDeps, mCallback, mHandler)
89     private lateinit var mRoleHolderChangedListener: OnRoleHoldersChangedListener
90     private lateinit var mUserRemovedReceiver: BroadcastReceiver
91 
mockServicenull92     private fun <T> mockService(name: String, clazz: Class<T>, service: T) {
93         doReturn(name).`when`(context).getSystemServiceName(clazz)
94         doReturn(service).`when`(context).getSystemService(name)
95         if (context.getSystemService(clazz) == null) {
96             // Test is using mockito-extended
97             doReturn(service).`when`(context).getSystemService(clazz)
98         }
99     }
100 
101     @Before
102     @Throws(PackageManager.NameNotFoundException::class)
setupnull103     fun setup() {
104         doReturn(emptyList<UserHandle>()).`when`(userManager).getUserHandles(true)
105         mockService(Context.USER_SERVICE, UserManager::class.java, userManager)
106 
107         doReturn(primaryUserContext).`when`(context).createContextAsUser(PRIMARY_USER_HANDLE, 0)
108         doReturn(mPackageManagerPrimaryUser).`when`(primaryUserContext).packageManager
109 
110         doReturn(secondaryUserContext).`when`(context).createContextAsUser(SECONDARY_USER_HANDLE, 0)
111         doReturn(mPackageManagerSecondaryUser).`when`(secondaryUserContext).packageManager
112 
113         for (app in listOf(SMS_APP1, SMS_APP2)) {
114             doReturn(PackageManager.PERMISSION_GRANTED)
115                 .`when`(mPackageManagerPrimaryUser)
116                 .checkPermission(Manifest.permission.SATELLITE_COMMUNICATION, app)
117             doReturn(PackageManager.PERMISSION_GRANTED)
118                 .`when`(mPackageManagerSecondaryUser)
119                 .checkPermission(Manifest.permission.SATELLITE_COMMUNICATION, app)
120         }
121 
122         // Initialise message application primary user package1
123         val applicationInfo1 = ApplicationInfo()
124         applicationInfo1.uid = PRIMARY_USER_SMS_APP_UID1
125         doReturn(applicationInfo1)
126             .`when`(mPackageManagerPrimaryUser)
127             .getApplicationInfo(eq(SMS_APP1), anyInt())
128 
129         // Initialise message application primary user package2
130         val applicationInfo2 = ApplicationInfo()
131         applicationInfo2.uid = PRIMARY_USER_SMS_APP_UID2
132         doReturn(applicationInfo2)
133             .`when`(mPackageManagerPrimaryUser)
134             .getApplicationInfo(eq(SMS_APP2), anyInt())
135 
136         // Initialise message application secondary user package1
137         val applicationInfo3 = ApplicationInfo()
138         applicationInfo3.uid = SECONDARY_USER_SMS_APP_UID1
139         doReturn(applicationInfo3)
140             .`when`(mPackageManagerSecondaryUser)
141             .getApplicationInfo(eq(SMS_APP1), anyInt())
142 
143         // Initialise message application secondary user package2
144         val applicationInfo4 = ApplicationInfo()
145         applicationInfo4.uid = SECONDARY_USER_SMS_APP_UID2
146         doReturn(applicationInfo4)
147             .`when`(mPackageManagerSecondaryUser)
148             .getApplicationInfo(eq(SMS_APP2), anyInt())
149     }
150 
151     @Test
test_onRoleHoldersChanged_SatelliteFallbackUid_Changed_SingleUsernull152     fun test_onRoleHoldersChanged_SatelliteFallbackUid_Changed_SingleUser() {
153         startSatelliteAccessController()
154         doReturn(listOf<String>()).`when`(mDeps).getRoleHoldersAsUser(
155             RoleManager.ROLE_SMS,
156             PRIMARY_USER_HANDLE
157         )
158         mRoleHolderChangedListener.onRoleHoldersChanged(RoleManager.ROLE_SMS, PRIMARY_USER_HANDLE)
159         verify(mCallback, never()).accept(any())
160 
161         // check DEFAULT_MESSAGING_APP1 is available as satellite network fallback uid
162         doReturn(listOf(SMS_APP1))
163             .`when`(mDeps).getRoleHoldersAsUser(RoleManager.ROLE_SMS, PRIMARY_USER_HANDLE)
164         mRoleHolderChangedListener.onRoleHoldersChanged(RoleManager.ROLE_SMS, PRIMARY_USER_HANDLE)
165         verify(mCallback).accept(setOf(PRIMARY_USER_SMS_APP_UID1))
166 
167         // check SMS_APP2 is available as satellite network Fallback uid
168         doReturn(listOf(SMS_APP2)).`when`(mDeps).getRoleHoldersAsUser(
169             RoleManager.ROLE_SMS,
170             PRIMARY_USER_HANDLE
171         )
172         mRoleHolderChangedListener.onRoleHoldersChanged(RoleManager.ROLE_SMS, PRIMARY_USER_HANDLE)
173         verify(mCallback).accept(setOf(PRIMARY_USER_SMS_APP_UID2))
174 
175         // check no uid is available as satellite network fallback uid
176         doReturn(listOf<String>()).`when`(mDeps).getRoleHoldersAsUser(
177             RoleManager.ROLE_SMS,
178             PRIMARY_USER_HANDLE
179         )
180         mRoleHolderChangedListener.onRoleHoldersChanged(RoleManager.ROLE_SMS, PRIMARY_USER_HANDLE)
181         verify(mCallback).accept(ArraySet())
182     }
183 
184     @Test
test_onRoleHoldersChanged_NoSatelliteCommunicationPermissionnull185     fun test_onRoleHoldersChanged_NoSatelliteCommunicationPermission() {
186         startSatelliteAccessController()
187         doReturn(listOf<Any>()).`when`(mDeps).getRoleHoldersAsUser(
188             RoleManager.ROLE_SMS,
189             PRIMARY_USER_HANDLE
190         )
191         mRoleHolderChangedListener.onRoleHoldersChanged(RoleManager.ROLE_SMS, PRIMARY_USER_HANDLE)
192         verify(mCallback, never()).accept(any())
193 
194         // check DEFAULT_MESSAGING_APP1 is not available as satellite network fallback uid
195         // since satellite communication permission not available.
196         doReturn(PackageManager.PERMISSION_DENIED)
197             .`when`(mPackageManagerPrimaryUser)
198             .checkPermission(Manifest.permission.SATELLITE_COMMUNICATION, SMS_APP1)
199         doReturn(listOf(SMS_APP1))
200             .`when`(mDeps).getRoleHoldersAsUser(RoleManager.ROLE_SMS, PRIMARY_USER_HANDLE)
201         mRoleHolderChangedListener.onRoleHoldersChanged(RoleManager.ROLE_SMS, PRIMARY_USER_HANDLE)
202         verify(mCallback, never()).accept(any())
203     }
204 
205     @Test
test_onRoleHoldersChanged_RoleSms_NotAvailablenull206     fun test_onRoleHoldersChanged_RoleSms_NotAvailable() {
207         startSatelliteAccessController()
208         doReturn(listOf(SMS_APP1))
209             .`when`(mDeps).getRoleHoldersAsUser(RoleManager.ROLE_SMS, PRIMARY_USER_HANDLE)
210         mRoleHolderChangedListener.onRoleHoldersChanged(
211             RoleManager.ROLE_BROWSER,
212             PRIMARY_USER_HANDLE
213         )
214         verify(mCallback, never()).accept(any())
215     }
216 
217     @Test
test_onRoleHoldersChanged_SatelliteNetworkFallbackUid_Changed_multiUsernull218     fun test_onRoleHoldersChanged_SatelliteNetworkFallbackUid_Changed_multiUser() {
219         startSatelliteAccessController()
220         doReturn(listOf<String>()).`when`(mDeps).getRoleHoldersAsUser(
221             RoleManager.ROLE_SMS,
222             PRIMARY_USER_HANDLE
223         )
224         mRoleHolderChangedListener.onRoleHoldersChanged(RoleManager.ROLE_SMS, PRIMARY_USER_HANDLE)
225         verify(mCallback, never()).accept(any())
226 
227         // check SMS_APP1 is available as satellite network fallback uid at primary user
228         doReturn(listOf(SMS_APP1))
229             .`when`(mDeps).getRoleHoldersAsUser(RoleManager.ROLE_SMS, PRIMARY_USER_HANDLE)
230         mRoleHolderChangedListener.onRoleHoldersChanged(RoleManager.ROLE_SMS, PRIMARY_USER_HANDLE)
231         verify(mCallback).accept(setOf(PRIMARY_USER_SMS_APP_UID1))
232 
233         // check SMS_APP2 is available as satellite network fallback uid at primary user
234         doReturn(listOf(SMS_APP2)).`when`(mDeps).getRoleHoldersAsUser(
235             RoleManager.ROLE_SMS,
236             PRIMARY_USER_HANDLE
237         )
238         mRoleHolderChangedListener.onRoleHoldersChanged(RoleManager.ROLE_SMS, PRIMARY_USER_HANDLE)
239         verify(mCallback).accept(setOf(PRIMARY_USER_SMS_APP_UID2))
240 
241         // check SMS_APP1 is available as satellite network fallback uid at secondary user
242         doReturn(listOf(SMS_APP1)).`when`(mDeps).getRoleHoldersAsUser(
243             RoleManager.ROLE_SMS,
244             SECONDARY_USER_HANDLE
245         )
246         mRoleHolderChangedListener.onRoleHoldersChanged(RoleManager.ROLE_SMS, SECONDARY_USER_HANDLE)
247         verify(mCallback).accept(setOf(PRIMARY_USER_SMS_APP_UID2, SECONDARY_USER_SMS_APP_UID1))
248 
249         // check no uid is available as satellite network fallback uid at primary user
250         doReturn(listOf<String>()).`when`(mDeps).getRoleHoldersAsUser(
251             RoleManager.ROLE_SMS,
252             PRIMARY_USER_HANDLE
253         )
254         mRoleHolderChangedListener.onRoleHoldersChanged(
255             RoleManager.ROLE_SMS,
256             PRIMARY_USER_HANDLE
257         )
258         verify(mCallback).accept(setOf(SECONDARY_USER_SMS_APP_UID1))
259 
260         // check SMS_APP2 is available as satellite network fallback uid at secondary user
261         doReturn(listOf(SMS_APP2))
262             .`when`(mDeps).getRoleHoldersAsUser(RoleManager.ROLE_SMS, SECONDARY_USER_HANDLE)
263         mRoleHolderChangedListener.onRoleHoldersChanged(RoleManager.ROLE_SMS, SECONDARY_USER_HANDLE)
264         verify(mCallback).accept(setOf(SECONDARY_USER_SMS_APP_UID2))
265 
266         // check no uid is available as satellite network fallback uid at secondary user
267         doReturn(listOf<String>()).`when`(mDeps).getRoleHoldersAsUser(
268             RoleManager.ROLE_SMS,
269             SECONDARY_USER_HANDLE
270         )
271         mRoleHolderChangedListener.onRoleHoldersChanged(RoleManager.ROLE_SMS, SECONDARY_USER_HANDLE)
272         verify(mCallback).accept(ArraySet())
273     }
274 
275     @Test
test_SatelliteFallbackUidCallback_OnUserRemovalnull276     fun test_SatelliteFallbackUidCallback_OnUserRemoval() {
277         startSatelliteAccessController()
278         // check SMS_APP2 is available as satellite network fallback uid at primary user
279         doReturn(listOf(SMS_APP2)).`when`(mDeps).getRoleHoldersAsUser(
280             RoleManager.ROLE_SMS,
281             PRIMARY_USER_HANDLE
282         )
283         mRoleHolderChangedListener.onRoleHoldersChanged(RoleManager.ROLE_SMS, PRIMARY_USER_HANDLE)
284         verify(mCallback).accept(setOf(PRIMARY_USER_SMS_APP_UID2))
285 
286         // check SMS_APP1 is available as satellite network fallback uid at secondary user
287         doReturn(listOf(SMS_APP1)).`when`(mDeps).getRoleHoldersAsUser(
288             RoleManager.ROLE_SMS,
289             SECONDARY_USER_HANDLE
290         )
291         mRoleHolderChangedListener.onRoleHoldersChanged(RoleManager.ROLE_SMS, SECONDARY_USER_HANDLE)
292         verify(mCallback).accept(setOf(PRIMARY_USER_SMS_APP_UID2, SECONDARY_USER_SMS_APP_UID1))
293 
294         val userRemovalIntent = Intent(Intent.ACTION_USER_REMOVED)
295         userRemovalIntent.putExtra(Intent.EXTRA_USER, SECONDARY_USER_HANDLE)
296         mUserRemovedReceiver.onReceive(context, userRemovalIntent)
297         verify(mCallback, times(2)).accept(setOf(PRIMARY_USER_SMS_APP_UID2))
298     }
299 
300     @Test
testOnStartUpCallbackSatelliteFallbackUidWithExistingUsersnull301     fun testOnStartUpCallbackSatelliteFallbackUidWithExistingUsers() {
302         doReturn(
303             listOf(PRIMARY_USER_HANDLE)
304         ).`when`(userManager).getUserHandles(true)
305         doReturn(listOf(SMS_APP1))
306             .`when`(mDeps).getRoleHoldersAsUser(RoleManager.ROLE_SMS, PRIMARY_USER_HANDLE)
307         // At start up, SatelliteAccessController must call CS callback with existing users'
308         // default messaging apps uids.
309         startSatelliteAccessController()
310         verify(mCallback, timeout(500)).accept(setOf(PRIMARY_USER_SMS_APP_UID1))
311     }
312 
startSatelliteAccessControllernull313     private fun startSatelliteAccessController() {
314         mSatelliteAccessController.start()
315         // Get registered listener using captor
316         val listenerCaptor = ArgumentCaptor.forClass(OnRoleHoldersChangedListener::class.java)
317         verify(mDeps).addOnRoleHoldersChangedListenerAsUser(
318             any(Executor::class.java),
319             listenerCaptor.capture(),
320             any(UserHandle::class.java)
321         )
322         mRoleHolderChangedListener = listenerCaptor.value
323 
324         // Get registered receiver using captor
325         val userRemovedReceiverCaptor = ArgumentCaptor.forClass(BroadcastReceiver::class.java)
326         verify(context).registerReceiver(
327             userRemovedReceiverCaptor.capture(),
328             any(IntentFilter::class.java),
329             isNull(),
330             any(Handler::class.java)
331         )
332          mUserRemovedReceiver = userRemovedReceiverCaptor.value
333     }
334 }
335