1 /*
2  * Copyright (C) 2023 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 
17 package android.permission.cts
18 
19 import android.Manifest
20 import android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND
21 import android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND_SERVICE
22 import android.app.Instrumentation
23 import android.companion.virtual.VirtualDeviceManager.PERSISTENT_DEVICE_ID_DEFAULT
24 import android.companion.virtual.VirtualDeviceManager.VirtualDevice
25 import android.content.Context
26 import android.content.Intent
27 import android.content.pm.PackageManager.FLAG_PERMISSION_ONE_TIME
28 import android.content.pm.PackageManager.FLAG_PERMISSION_USER_FIXED
29 import android.content.pm.PackageManager.FLAG_PERMISSION_USER_SENSITIVE_WHEN_GRANTED
30 import android.content.pm.PackageManager.FLAG_PERMISSION_USER_SET
31 import android.content.pm.PackageManager.PERMISSION_DENIED
32 import android.content.pm.PackageManager.PERMISSION_GRANTED
33 import android.os.Build
34 import android.os.UserHandle
35 import android.permission.PermissionManager
36 import android.permission.flags.Flags
37 import android.platform.test.annotations.AppModeFull
38 import android.platform.test.annotations.RequiresFlagsDisabled
39 import android.platform.test.annotations.RequiresFlagsEnabled
40 import android.platform.test.flag.junit.DeviceFlagsValueProvider
41 import android.virtualdevice.cts.common.VirtualDeviceRule
42 import androidx.test.ext.junit.runners.AndroidJUnit4
43 import androidx.test.filters.SdkSuppress
44 import androidx.test.platform.app.InstrumentationRegistry
45 import com.android.compatibility.common.util.SystemUtil.eventually
46 import com.android.compatibility.common.util.SystemUtil.runShellCommandOrThrow
47 import com.android.compatibility.common.util.SystemUtil.waitForBroadcasts
48 import com.google.common.truth.Truth.assertThat
49 import org.junit.After
50 import org.junit.Before
51 import org.junit.Rule
52 import org.junit.Test
53 import org.junit.runner.RunWith
54 
55 @RunWith(AndroidJUnit4::class)
56 @AppModeFull(reason = " cannot be accessed by instant apps")
57 @SdkSuppress(minSdkVersion = Build.VERSION_CODES.VANILLA_ICE_CREAM, codeName = "VanillaIceCream")
58 class DevicePermissionsTest {
59     private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
60     private val defaultDeviceContext = instrumentation.targetContext
61 
62     private lateinit var virtualDevice: VirtualDevice
63     private lateinit var virtualDeviceContext: Context
64     private lateinit var persistentDeviceId: String
65 
66     private lateinit var permissionManager: PermissionManager
67 
68     @get:Rule
69     var mVirtualDeviceRule = VirtualDeviceRule.withAdditionalPermissions(
70             Manifest.permission.GRANT_RUNTIME_PERMISSIONS,
71             Manifest.permission.MANAGE_ONE_TIME_PERMISSION_SESSIONS,
72             Manifest.permission.REVOKE_RUNTIME_PERMISSIONS,
73             Manifest.permission.GET_RUNTIME_PERMISSIONS
74         )
75 
76     @Rule @JvmField val mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule()
77 
78     @Before
setupnull79     fun setup() {
80         virtualDevice = mVirtualDeviceRule.createManagedVirtualDevice()
81         virtualDeviceContext = defaultDeviceContext.createDeviceContext(virtualDevice.deviceId)
82         permissionManager = virtualDeviceContext.getSystemService(PermissionManager::class.java)!!
83         persistentDeviceId = virtualDevice.persistentDeviceId!!
84         runShellCommandOrThrow("pm install -r $TEST_APK")
85     }
86 
87     @After
cleanupnull88     fun cleanup() {
89         runShellCommandOrThrow("pm uninstall $TEST_PACKAGE_NAME")
90     }
91 
92     @RequiresFlagsEnabled(
93         Flags.FLAG_DEVICE_AWARE_PERMISSION_APIS_ENABLED,
94         Flags.FLAG_DEVICE_AWARE_PERMISSIONS_ENABLED
95     )
96     @Test
testDeviceAwareRuntimePermissionIsGrantednull97     fun testDeviceAwareRuntimePermissionIsGranted() {
98         grantPermissionAndAssertGranted(Manifest.permission.CAMERA, virtualDeviceContext)
99     }
100 
101     @RequiresFlagsDisabled(Flags.FLAG_DEVICE_AWARE_PERMISSIONS_ENABLED)
102     @Test
testDeviceAwareRuntimePermissionGrantIsInheritednull103     fun testDeviceAwareRuntimePermissionGrantIsInherited() {
104         grantPermissionAndAssertGranted(Manifest.permission.CAMERA, defaultDeviceContext)
105 
106         assertPermission(Manifest.permission.CAMERA, PERMISSION_GRANTED, virtualDeviceContext)
107     }
108 
109     @Test
testNonDeviceAwareRuntimePermissionGrantIsInheritednull110     fun testNonDeviceAwareRuntimePermissionGrantIsInherited() {
111         grantPermissionAndAssertGranted(NON_DEVICE_AWARE_PERMISSION, defaultDeviceContext)
112 
113         assertPermission(NON_DEVICE_AWARE_PERMISSION, PERMISSION_GRANTED, virtualDeviceContext)
114     }
115 
116     @RequiresFlagsEnabled(
117         Flags.FLAG_DEVICE_AWARE_PERMISSION_APIS_ENABLED,
118         Flags.FLAG_DEVICE_AWARE_PERMISSIONS_ENABLED
119     )
120     @Test
testDeviceAwareRuntimePermissionIsRevokednull121     fun testDeviceAwareRuntimePermissionIsRevoked() {
122         grantPermissionAndAssertGranted(DEVICE_AWARE_PERMISSION, virtualDeviceContext)
123 
124         revokePermissionAndAssertDenied(DEVICE_AWARE_PERMISSION, virtualDeviceContext)
125     }
126 
127     @Test
testNonDeviceAwareRuntimePermissionIsRevokedForDefaultDevicenull128     fun testNonDeviceAwareRuntimePermissionIsRevokedForDefaultDevice() {
129         grantPermissionAndAssertGranted(NON_DEVICE_AWARE_PERMISSION, defaultDeviceContext)
130         assertPermission(NON_DEVICE_AWARE_PERMISSION, PERMISSION_GRANTED, virtualDeviceContext)
131         // Revoke call from virtualDeviceContext should revoke for default device as well.
132         revokePermissionAndAssertDenied(NON_DEVICE_AWARE_PERMISSION, virtualDeviceContext)
133         assertPermission(NON_DEVICE_AWARE_PERMISSION, PERMISSION_DENIED, defaultDeviceContext)
134     }
135 
136     @Test
testNormalPermissionGrantIsInheritednull137     fun testNormalPermissionGrantIsInherited() {
138         assertPermission(Manifest.permission.INTERNET, PERMISSION_GRANTED, virtualDeviceContext)
139     }
140 
141     @Test
testSignaturePermissionGrantIsInheritednull142     fun testSignaturePermissionGrantIsInherited() {
143         assertPermission(CUSTOM_SIGNATURE_PERMISSION, PERMISSION_GRANTED, virtualDeviceContext)
144     }
145 
146     @Test
testOneTimePermissionIsRevokednull147     fun testOneTimePermissionIsRevoked() {
148         grantPermissionAndAssertGranted(DEVICE_AWARE_PERMISSION, virtualDeviceContext)
149         virtualDeviceContext.packageManager.updatePermissionFlags(
150             DEVICE_AWARE_PERMISSION,
151             TEST_PACKAGE_NAME,
152             FLAG_PERMISSION_ONE_TIME,
153             FLAG_PERMISSION_ONE_TIME,
154             UserHandle.of(virtualDeviceContext.userId)
155         )
156 
157         permissionManager.startOneTimePermissionSession(
158             TEST_PACKAGE_NAME,
159             0,
160             0,
161             IMPORTANCE_FOREGROUND,
162             IMPORTANCE_FOREGROUND_SERVICE
163         )
164         eventually {
165             assertPermission(DEVICE_AWARE_PERMISSION, PERMISSION_DENIED, virtualDeviceContext)
166         }
167     }
168 
169     @RequiresFlagsEnabled(
170         Flags.FLAG_DEVICE_AWARE_PERMISSION_APIS_ENABLED,
171         Flags.FLAG_DEVICE_AWARE_PERMISSIONS_ENABLED
172     )
173     @Test
testRevokeSelfPermissionOnKillnull174     fun testRevokeSelfPermissionOnKill() {
175         grantPermissionAndAssertGranted(DEVICE_AWARE_PERMISSION, virtualDeviceContext)
176 
177         revokeSelfPermission(DEVICE_AWARE_PERMISSION, virtualDeviceContext)
178         eventually {
179             assertPermission(DEVICE_AWARE_PERMISSION, PERMISSION_DENIED, virtualDeviceContext)
180         }
181     }
182 
183     @RequiresFlagsEnabled(
184         Flags.FLAG_DEVICE_AWARE_PERMISSION_APIS_ENABLED,
185         Flags.FLAG_DEVICE_AWARE_PERMISSIONS_ENABLED
186     )
187     @Test
testGrantAndRevokeDeviceAwarePermissionByPersistentDeviceIdnull188     fun testGrantAndRevokeDeviceAwarePermissionByPersistentDeviceId() {
189         val deviceAwarePermission = DEVICE_AWARE_PERMISSION
190 
191         permissionManager.grantRuntimePermission(
192             TEST_PACKAGE_NAME,
193             deviceAwarePermission,
194             persistentDeviceId
195         )
196 
197         assertThat(
198                 permissionManager.checkPermission(
199                     deviceAwarePermission,
200                     TEST_PACKAGE_NAME,
201                     virtualDevice.persistentDeviceId!!
202                 )
203             )
204             .isEqualTo(PERMISSION_GRANTED)
205 
206         assertThat(
207                 permissionManager.checkPermission(
208                     deviceAwarePermission,
209                     TEST_PACKAGE_NAME,
210                     PERSISTENT_DEVICE_ID_DEFAULT
211                 )
212             )
213             .isEqualTo(PERMISSION_DENIED)
214 
215         permissionManager.revokeRuntimePermission(
216             TEST_PACKAGE_NAME,
217             deviceAwarePermission,
218             persistentDeviceId,
219             "test"
220         )
221 
222         assertThat(
223                 permissionManager.checkPermission(
224                     deviceAwarePermission,
225                     TEST_PACKAGE_NAME,
226                     virtualDevice.persistentDeviceId!!
227                 )
228             )
229             .isEqualTo(PERMISSION_DENIED)
230     }
231 
232     @RequiresFlagsEnabled(
233         Flags.FLAG_DEVICE_AWARE_PERMISSION_APIS_ENABLED,
234         Flags.FLAG_DEVICE_AWARE_PERMISSIONS_ENABLED
235     )
236     @Test
testUpdateAndGetPermissionFlagsByPersistentDeviceIdnull237     fun testUpdateAndGetPermissionFlagsByPersistentDeviceId() {
238         val deviceAwarePermission = DEVICE_AWARE_PERMISSION
239         val flagMask = FLAG_PERMISSION_USER_SET or FLAG_PERMISSION_USER_FIXED
240         val flag = FLAG_PERMISSION_USER_SET
241 
242         assertThat(
243                 permissionManager.getPermissionFlags(
244                     TEST_PACKAGE_NAME,
245                     deviceAwarePermission,
246                     persistentDeviceId
247                 )
248             )
249             .isEqualTo(0)
250 
251         permissionManager.updatePermissionFlags(
252             TEST_PACKAGE_NAME,
253             deviceAwarePermission,
254             persistentDeviceId,
255             flagMask,
256             flag
257         )
258 
259         assertThat(
260                 permissionManager.getPermissionFlags(
261                     TEST_PACKAGE_NAME,
262                     deviceAwarePermission,
263                     persistentDeviceId
264                 )
265             )
266             .isEqualTo(FLAG_PERMISSION_USER_SET)
267     }
268 
269     @RequiresFlagsEnabled(
270         Flags.FLAG_DEVICE_AWARE_PERMISSION_APIS_ENABLED,
271         Flags.FLAG_DEVICE_AWARE_PERMISSIONS_ENABLED
272     )
273     @Test
testAllPermissionStatesApiGrantForVirtualDevicenull274     fun testAllPermissionStatesApiGrantForVirtualDevice() {
275         // Setting a flag explicitly so that the permission consistently stays in the state
276         permissionManager.updatePermissionFlags(
277             TEST_PACKAGE_NAME,
278             DEVICE_AWARE_PERMISSION,
279             PERSISTENT_DEVICE_ID_DEFAULT,
280             FLAG_PERMISSION_USER_SENSITIVE_WHEN_GRANTED,
281             FLAG_PERMISSION_USER_SENSITIVE_WHEN_GRANTED
282         )
283 
284         assertThat(
285                 permissionManager
286                     .getAllPermissionStates(TEST_PACKAGE_NAME, persistentDeviceId)
287                     .isEmpty()
288             )
289             .isTrue()
290 
291         permissionManager.grantRuntimePermission(
292             TEST_PACKAGE_NAME,
293             DEVICE_AWARE_PERMISSION,
294             persistentDeviceId
295         )
296 
297         val permissionStateMap =
298             permissionManager.getAllPermissionStates(TEST_PACKAGE_NAME, persistentDeviceId)
299         assertThat(permissionStateMap.size).isEqualTo(1)
300         assertThat(permissionStateMap[DEVICE_AWARE_PERMISSION]!!.isGranted).isTrue()
301         assertThat(permissionStateMap[DEVICE_AWARE_PERMISSION]!!.flags).isEqualTo(0)
302 
303         assertThat(
304                 permissionManager
305                     .getAllPermissionStates(TEST_PACKAGE_NAME, PERSISTENT_DEVICE_ID_DEFAULT)[
306                         DEVICE_AWARE_PERMISSION]!!
307                     .isGranted
308             )
309             .isFalse()
310 
311         permissionManager.revokeRuntimePermission(
312             TEST_PACKAGE_NAME,
313             DEVICE_AWARE_PERMISSION,
314             persistentDeviceId,
315             "test"
316         )
317 
318         assertThat(
319                 permissionManager
320                     .getAllPermissionStates(TEST_PACKAGE_NAME, persistentDeviceId)
321                     .contains(DEVICE_AWARE_PERMISSION)
322             )
323             .isFalse()
324     }
325 
326     @RequiresFlagsEnabled(
327         Flags.FLAG_DEVICE_AWARE_PERMISSION_APIS_ENABLED,
328         Flags.FLAG_DEVICE_AWARE_PERMISSIONS_ENABLED
329     )
330     @Test
testAllPermissionStatesApiFlagsForVirtualDevicenull331     fun testAllPermissionStatesApiFlagsForVirtualDevice() {
332         val flagMask = FLAG_PERMISSION_USER_SET or FLAG_PERMISSION_USER_FIXED
333         val flag = FLAG_PERMISSION_USER_SET
334 
335         assertThat(permissionManager.getAllPermissionStates(TEST_PACKAGE_NAME, persistentDeviceId))
336             .isEmpty()
337 
338         permissionManager.updatePermissionFlags(
339             TEST_PACKAGE_NAME,
340             DEVICE_AWARE_PERMISSION,
341             persistentDeviceId,
342             flagMask,
343             flag
344         )
345 
346         assertThat(
347                 hasPermission(
348                     permissionManager
349                         .getAllPermissionStates(TEST_PACKAGE_NAME, persistentDeviceId)[
350                             DEVICE_AWARE_PERMISSION]!!
351                         .flags,
352                     flag
353                 )
354             )
355             .isTrue()
356 
357         assertThat(
358                 hasPermission(
359                     permissionManager
360                         .getAllPermissionStates(TEST_PACKAGE_NAME, persistentDeviceId)[
361                             DEVICE_AWARE_PERMISSION]!!
362                         .flags,
363                     FLAG_PERMISSION_USER_FIXED
364                 )
365             )
366             .isFalse()
367     }
368 
369     @RequiresFlagsEnabled(Flags.FLAG_DEVICE_AWARE_PERMISSION_APIS_ENABLED)
370     @Test
testAllPermissionStatesApiGrantForDefaultDevicenull371     fun testAllPermissionStatesApiGrantForDefaultDevice() {
372         // Setting a flag explicitly so that the permission consistently stays in the state upon
373         // revoke
374         permissionManager.updatePermissionFlags(
375             TEST_PACKAGE_NAME,
376             DEVICE_AWARE_PERMISSION,
377             PERSISTENT_DEVICE_ID_DEFAULT,
378             FLAG_PERMISSION_USER_SENSITIVE_WHEN_GRANTED,
379             FLAG_PERMISSION_USER_SENSITIVE_WHEN_GRANTED
380         )
381 
382         permissionManager.grantRuntimePermission(
383             TEST_PACKAGE_NAME,
384             DEVICE_AWARE_PERMISSION,
385             PERSISTENT_DEVICE_ID_DEFAULT
386         )
387 
388         assertThat(
389                 permissionManager
390                     .getAllPermissionStates(TEST_PACKAGE_NAME, PERSISTENT_DEVICE_ID_DEFAULT)[
391                         DEVICE_AWARE_PERMISSION]!!
392                     .isGranted
393             )
394             .isTrue()
395 
396         assertThat(
397                 permissionManager
398                     .getAllPermissionStates(TEST_PACKAGE_NAME, persistentDeviceId)
399                     .contains(DEVICE_AWARE_PERMISSION)
400             )
401             .isFalse()
402 
403         permissionManager.revokeRuntimePermission(
404             TEST_PACKAGE_NAME,
405             DEVICE_AWARE_PERMISSION,
406             PERSISTENT_DEVICE_ID_DEFAULT,
407             "test"
408         )
409 
410         assertThat(
411                 permissionManager
412                     .getAllPermissionStates(TEST_PACKAGE_NAME, PERSISTENT_DEVICE_ID_DEFAULT)[
413                         DEVICE_AWARE_PERMISSION]!!
414                     .isGranted
415             )
416             .isFalse()
417     }
418 
419     @RequiresFlagsEnabled(Flags.FLAG_DEVICE_AWARE_PERMISSION_APIS_ENABLED)
420     @Test
testAllPermissionStatesApiFlagsForDefaultDevicenull421     fun testAllPermissionStatesApiFlagsForDefaultDevice() {
422         val flagMask = FLAG_PERMISSION_USER_SET or FLAG_PERMISSION_USER_FIXED
423         val flag = FLAG_PERMISSION_USER_SET
424 
425         assertThat(
426                 permissionManager
427                     .getAllPermissionStates(TEST_PACKAGE_NAME, PERSISTENT_DEVICE_ID_DEFAULT)
428                     .contains(DEVICE_AWARE_PERMISSION)
429             )
430             .isFalse()
431 
432         permissionManager.updatePermissionFlags(
433             TEST_PACKAGE_NAME,
434             DEVICE_AWARE_PERMISSION,
435             PERSISTENT_DEVICE_ID_DEFAULT,
436             flagMask,
437             flag
438         )
439 
440         assertThat(
441                 hasPermission(
442                     permissionManager
443                         .getAllPermissionStates(TEST_PACKAGE_NAME, PERSISTENT_DEVICE_ID_DEFAULT)[
444                             DEVICE_AWARE_PERMISSION]!!
445                         .flags,
446                     flag
447                 )
448             )
449             .isTrue()
450 
451         assertThat(
452                 hasPermission(
453                     permissionManager
454                         .getAllPermissionStates(TEST_PACKAGE_NAME, PERSISTENT_DEVICE_ID_DEFAULT)[
455                             DEVICE_AWARE_PERMISSION]!!
456                         .flags,
457                     FLAG_PERMISSION_USER_FIXED
458                 )
459             )
460             .isFalse()
461     }
462 
463     @RequiresFlagsEnabled(Flags.FLAG_DEVICE_AWARE_PERMISSION_APIS_ENABLED)
464     @Test
testAllPermissionStatesApiThatNonDeviceAwareRuntimePermissionGrantIsNotInheritednull465     fun testAllPermissionStatesApiThatNonDeviceAwareRuntimePermissionGrantIsNotInherited() {
466         permissionManager.grantRuntimePermission(
467             TEST_PACKAGE_NAME,
468             NON_DEVICE_AWARE_PERMISSION,
469             PERSISTENT_DEVICE_ID_DEFAULT
470         )
471 
472         assertThat(
473                 permissionManager
474                     .getAllPermissionStates(TEST_PACKAGE_NAME, PERSISTENT_DEVICE_ID_DEFAULT)[
475                         NON_DEVICE_AWARE_PERMISSION]!!
476                     .isGranted
477             )
478             .isTrue()
479 
480         assertThat(
481                 permissionManager
482                     .getAllPermissionStates(TEST_PACKAGE_NAME, persistentDeviceId)
483                     .contains(NON_DEVICE_AWARE_PERMISSION)
484             )
485             .isFalse()
486     }
487 
hasPermissionnull488     private fun hasPermission(permissionFlags: Int, permissionBit: Int): Boolean =
489         permissionFlags and permissionBit != 0
490 
491     private fun revokeSelfPermission(permissionName: String, context: Context) {
492         val intent = Intent(PERMISSION_SELF_REVOKE_INTENT)
493         intent.setClassName(TEST_PACKAGE_NAME, PERMISSION_SELF_REVOKE_RECEIVER)
494         intent.putExtra("permissionName", permissionName)
495         intent.putExtra("deviceID", context.deviceId)
496         context.sendBroadcast(intent)
497         waitForBroadcasts()
498     }
499 
grantPermissionAndAssertGrantednull500     private fun grantPermissionAndAssertGranted(permissionName: String, context: Context) {
501         context.packageManager.grantRuntimePermission(
502             TEST_PACKAGE_NAME,
503             permissionName,
504             UserHandle.of(context.userId)
505         )
506         assertPermission(permissionName, PERMISSION_GRANTED, context)
507     }
508 
revokePermissionAndAssertDeniednull509     private fun revokePermissionAndAssertDenied(permissionName: String, context: Context) {
510         context.packageManager.revokeRuntimePermission(
511             TEST_PACKAGE_NAME,
512             permissionName,
513             UserHandle.of(context.userId)
514         )
515         assertPermission(permissionName, PERMISSION_DENIED, context)
516     }
517 
assertPermissionnull518     private fun assertPermission(
519         permissionName: String,
520         permissionState: Int,
521         context: Context,
522     ) {
523         assertThat(context.packageManager.checkPermission(permissionName, TEST_PACKAGE_NAME))
524             .isEqualTo(permissionState)
525     }
526 
527     companion object {
528         private const val TEST_PACKAGE_NAME = "android.permission.cts.appthatrequestpermission"
529         private const val TEST_APK =
530             "/data/local/tmp/cts-permission/CtsAppThatRequestsDevicePermissions.apk"
531 
532         private const val CUSTOM_SIGNATURE_PERMISSION =
533             "android.permission.cts.CUSTOM_SIGNATURE_PERMISSION"
534 
535         private const val PERMISSION_SELF_REVOKE_INTENT =
536             "android.permission.cts.appthatrequestpermission.REVOKE_SELF_PERMISSION"
537         private const val PERMISSION_SELF_REVOKE_RECEIVER =
538             "android.permission.cts.appthatrequestpermission.RevokeSelfPermissionReceiver"
539 
540         private const val DEVICE_AWARE_PERMISSION = Manifest.permission.RECORD_AUDIO
541         private const val NON_DEVICE_AWARE_PERMISSION = Manifest.permission.READ_CONTACTS
542     }
543 }
544