1 /* <lambda>null2 * 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 com.android.server.permission.test 18 19 import android.Manifest 20 import android.content.pm.PackageManager 21 import android.content.pm.PermissionGroupInfo 22 import android.content.pm.PermissionInfo 23 import android.content.pm.SigningDetails 24 import android.os.Build 25 import android.os.Bundle 26 import android.util.ArrayMap 27 import android.util.SparseArray 28 import androidx.test.ext.junit.runners.AndroidJUnit4 29 import com.android.internal.pm.pkg.component.ParsedPermission 30 import com.android.internal.pm.pkg.component.ParsedPermissionGroup 31 import com.android.modules.utils.testing.ExtendedMockitoRule 32 import com.android.server.extendedtestutils.wheneverStatic 33 import com.android.server.permission.access.MutableAccessState 34 import com.android.server.permission.access.MutableUserState 35 import com.android.server.permission.access.MutateStateScope 36 import com.android.server.permission.access.immutable.* // ktlint-disable no-wildcard-imports 37 import com.android.server.permission.access.permission.AppIdPermissionPolicy 38 import com.android.server.permission.access.permission.Permission 39 import com.android.server.permission.access.util.hasBits 40 import com.android.server.pm.parsing.PackageInfoUtils 41 import com.android.server.pm.pkg.AndroidPackage 42 import com.android.server.pm.pkg.PackageState 43 import com.android.server.pm.pkg.PackageUserState 44 import com.android.server.testutils.any 45 import com.android.server.testutils.mock 46 import com.android.server.testutils.whenever 47 import org.junit.Before 48 import org.junit.Rule 49 import org.junit.runner.RunWith 50 import org.mockito.ArgumentMatchers.anyLong 51 52 /** 53 * Mocking unit test for AppIdPermissionPolicy. 54 */ 55 @RunWith(AndroidJUnit4::class) 56 abstract class BasePermissionPolicyTest { 57 protected lateinit var oldState: MutableAccessState 58 protected lateinit var newState: MutableAccessState 59 60 protected val defaultPermissionGroup = mockParsedPermissionGroup( 61 PERMISSION_GROUP_NAME_0, 62 PACKAGE_NAME_0 63 ) 64 protected val defaultPermissionTree = mockParsedPermission( 65 PERMISSION_TREE_NAME, 66 PACKAGE_NAME_0, 67 isTree = true 68 ) 69 protected val defaultPermission = mockParsedPermission(PERMISSION_NAME_0, PACKAGE_NAME_0) 70 71 protected val appIdPermissionPolicy = AppIdPermissionPolicy() 72 73 @Rule 74 @JvmField 75 val extendedMockitoRule = ExtendedMockitoRule.Builder(this) 76 .spyStatic(PackageInfoUtils::class.java) 77 .build() 78 79 @Before 80 fun baseSetUp() { 81 oldState = MutableAccessState() 82 createUserState(USER_ID_0) 83 oldState.mutateExternalState().setPackageStates(ArrayMap()) 84 oldState.mutateExternalState().setDisabledSystemPackageStates(ArrayMap()) 85 mockPackageInfoUtilsGeneratePermissionInfo() 86 mockPackageInfoUtilsGeneratePermissionGroupInfo() 87 } 88 89 protected fun createUserState(userId: Int) { 90 oldState.mutateExternalState().mutateUserIds().add(userId) 91 oldState.mutateUserStatesNoWrite().put(userId, MutableUserState()) 92 } 93 94 private fun mockPackageInfoUtilsGeneratePermissionInfo() { 95 wheneverStatic { 96 PackageInfoUtils.generatePermissionInfo(any(ParsedPermission::class.java), anyLong()) 97 }.thenAnswer { invocation -> 98 val parsedPermission = invocation.getArgument<ParsedPermission>(0) 99 val generateFlags = invocation.getArgument<Long>(1) 100 PermissionInfo(parsedPermission.backgroundPermission).apply { 101 name = parsedPermission.name 102 packageName = parsedPermission.packageName 103 metaData = if (generateFlags.toInt().hasBits(PackageManager.GET_META_DATA)) { 104 parsedPermission.metaData 105 } else { 106 null 107 } 108 @Suppress("DEPRECATION") 109 protectionLevel = parsedPermission.protectionLevel 110 group = parsedPermission.group 111 flags = parsedPermission.flags 112 } 113 } 114 } 115 116 private fun mockPackageInfoUtilsGeneratePermissionGroupInfo() { 117 wheneverStatic { 118 PackageInfoUtils.generatePermissionGroupInfo( 119 any(ParsedPermissionGroup::class.java), 120 anyLong() 121 ) 122 }.thenAnswer { invocation -> 123 val parsedPermissionGroup = invocation.getArgument<ParsedPermissionGroup>(0) 124 val generateFlags = invocation.getArgument<Long>(1) 125 @Suppress("DEPRECATION") 126 PermissionGroupInfo().apply { 127 name = parsedPermissionGroup.name 128 packageName = parsedPermissionGroup.packageName 129 metaData = if (generateFlags.toInt().hasBits(PackageManager.GET_META_DATA)) { 130 parsedPermissionGroup.metaData 131 } else { 132 null 133 } 134 flags = parsedPermissionGroup.flags 135 } 136 } 137 } 138 139 /** 140 * Mock an AndroidPackage with PACKAGE_NAME_0, PERMISSION_NAME_0 and PERMISSION_GROUP_NAME_0 141 */ 142 protected fun mockSimpleAndroidPackage(): AndroidPackage = 143 mockAndroidPackage( 144 PACKAGE_NAME_0, 145 permissionGroups = listOf(defaultPermissionGroup), 146 permissions = listOf(defaultPermissionTree, defaultPermission) 147 ) 148 149 protected fun createSimplePermission(isTree: Boolean = false): Permission { 150 val parsedPermission = if (isTree) { defaultPermissionTree } else { defaultPermission } 151 val permissionInfo = PackageInfoUtils.generatePermissionInfo( 152 parsedPermission, 153 PackageManager.GET_META_DATA.toLong() 154 )!! 155 return Permission(permissionInfo, true, Permission.TYPE_MANIFEST, APP_ID_0) 156 } 157 158 protected inline fun mutateState(action: MutateStateScope.() -> Unit) { 159 newState = oldState.toMutable() 160 MutateStateScope(oldState, newState).action() 161 } 162 163 protected fun mockPackageState( 164 appId: Int, 165 packageName: String, 166 isSystem: Boolean = false, 167 ): PackageState = 168 mock { 169 whenever(this.appId).thenReturn(appId) 170 whenever(this.packageName).thenReturn(packageName) 171 whenever(androidPackage).thenReturn(null) 172 whenever(this.isSystem).thenReturn(isSystem) 173 } 174 175 protected fun mockPackageState( 176 appId: Int, 177 androidPackage: AndroidPackage, 178 isSystem: Boolean = false, 179 isPrivileged: Boolean = false, 180 isProduct: Boolean = false, 181 isInstantApp: Boolean = false, 182 isVendor: Boolean = false 183 ): PackageState = 184 mock { 185 whenever(this.appId).thenReturn(appId) 186 whenever(this.androidPackage).thenReturn(androidPackage) 187 val packageName = androidPackage.packageName 188 whenever(this.packageName).thenReturn(packageName) 189 whenever(this.isSystem).thenReturn(isSystem) 190 whenever(this.isPrivileged).thenReturn(isPrivileged) 191 whenever(this.isProduct).thenReturn(isProduct) 192 whenever(this.isVendor).thenReturn(isVendor) 193 val userStates = SparseArray<PackageUserState>().apply { 194 put(USER_ID_0, mock { whenever(this.isInstantApp).thenReturn(isInstantApp) }) 195 } 196 whenever(this.userStates).thenReturn(userStates) 197 } 198 199 protected fun mockAndroidPackage( 200 packageName: String, 201 targetSdkVersion: Int = Build.VERSION_CODES.UPSIDE_DOWN_CAKE, 202 isRequestLegacyExternalStorage: Boolean = false, 203 adoptPermissions: List<String> = emptyList(), 204 implicitPermissions: Set<String> = emptySet(), 205 requestedPermissions: Set<String> = emptySet(), 206 permissionGroups: List<ParsedPermissionGroup> = emptyList(), 207 permissions: List<ParsedPermission> = emptyList(), 208 isSignatureMatching: Boolean = false 209 ): AndroidPackage = 210 mock { 211 whenever(this.packageName).thenReturn(packageName) 212 whenever(this.targetSdkVersion).thenReturn(targetSdkVersion) 213 whenever(this.isRequestLegacyExternalStorage).thenReturn(isRequestLegacyExternalStorage) 214 whenever(this.adoptPermissions).thenReturn(adoptPermissions) 215 whenever(this.implicitPermissions).thenReturn(implicitPermissions) 216 whenever(this.requestedPermissions).thenReturn(requestedPermissions) 217 whenever(this.permissionGroups).thenReturn(permissionGroups) 218 whenever(this.permissions).thenReturn(permissions) 219 val signingDetails = mock<SigningDetails> { 220 whenever( 221 hasCommonSignerWithCapability(any(), any()) 222 ).thenReturn(isSignatureMatching) 223 whenever(hasAncestorOrSelf(any())).thenReturn(isSignatureMatching) 224 whenever( 225 checkCapability(any<SigningDetails>(), any()) 226 ).thenReturn(isSignatureMatching) 227 } 228 whenever(this.signingDetails).thenReturn(signingDetails) 229 } 230 231 protected fun mockParsedPermission( 232 permissionName: String, 233 packageName: String, 234 backgroundPermission: String? = null, 235 group: String? = null, 236 protectionLevel: Int = PermissionInfo.PROTECTION_NORMAL, 237 flags: Int = 0, 238 isTree: Boolean = false 239 ): ParsedPermission = 240 mock { 241 whenever(name).thenReturn(permissionName) 242 whenever(this.packageName).thenReturn(packageName) 243 whenever(metaData).thenReturn(Bundle()) 244 whenever(this.backgroundPermission).thenReturn(backgroundPermission) 245 whenever(this.group).thenReturn(group) 246 whenever(this.protectionLevel).thenReturn(protectionLevel) 247 whenever(this.flags).thenReturn(flags) 248 whenever(this.isTree).thenReturn(isTree) 249 } 250 251 protected fun mockParsedPermissionGroup( 252 permissionGroupName: String, 253 packageName: String, 254 ): ParsedPermissionGroup = 255 mock { 256 whenever(name).thenReturn(permissionGroupName) 257 whenever(this.packageName).thenReturn(packageName) 258 whenever(metaData).thenReturn(Bundle()) 259 } 260 261 protected fun addPackageState( 262 packageState: PackageState, 263 state: MutableAccessState = oldState 264 ) { 265 state.mutateExternalState().apply { 266 setPackageStates( 267 packageStates.toMutableMap().apply { put(packageState.packageName, packageState) } 268 ) 269 mutateAppIdPackageNames().mutateOrPut(packageState.appId) { MutableIndexedListSet() } 270 .add(packageState.packageName) 271 } 272 } 273 274 protected fun removePackageState( 275 packageState: PackageState, 276 state: MutableAccessState = oldState 277 ) { 278 state.mutateExternalState().apply { 279 setPackageStates( 280 packageStates.toMutableMap().apply { remove(packageState.packageName) } 281 ) 282 mutateAppIdPackageNames().mutateOrPut(packageState.appId) { MutableIndexedListSet() } 283 .remove(packageState.packageName) 284 } 285 } 286 287 protected fun addDisabledSystemPackageState( 288 packageState: PackageState, 289 state: MutableAccessState = oldState 290 ) = state.mutateExternalState().apply { 291 (disabledSystemPackageStates as ArrayMap)[packageState.packageName] = packageState 292 } 293 294 protected fun addPermission( 295 parsedPermission: ParsedPermission, 296 type: Int = Permission.TYPE_MANIFEST, 297 isReconciled: Boolean = true, 298 state: MutableAccessState = oldState 299 ) { 300 val permissionInfo = PackageInfoUtils.generatePermissionInfo( 301 parsedPermission, 302 PackageManager.GET_META_DATA.toLong() 303 )!! 304 val appId = state.externalState.packageStates[permissionInfo.packageName]!!.appId 305 val permission = Permission(permissionInfo, isReconciled, type, appId) 306 if (parsedPermission.isTree) { 307 state.mutateSystemState().mutatePermissionTrees()[permission.name] = permission 308 } else { 309 state.mutateSystemState().mutatePermissions()[permission.name] = permission 310 } 311 } 312 313 protected fun addPermissionGroup( 314 parsedPermissionGroup: ParsedPermissionGroup, 315 state: MutableAccessState = oldState 316 ) { 317 state.mutateSystemState().mutatePermissionGroups()[parsedPermissionGroup.name] = 318 PackageInfoUtils.generatePermissionGroupInfo( 319 parsedPermissionGroup, 320 PackageManager.GET_META_DATA.toLong() 321 )!! 322 } 323 324 protected fun getPermission( 325 permissionName: String, 326 state: MutableAccessState = newState 327 ): Permission? = state.systemState.permissions[permissionName] 328 329 protected fun getPermissionTree( 330 permissionTreeName: String, 331 state: MutableAccessState = newState 332 ): Permission? = state.systemState.permissionTrees[permissionTreeName] 333 334 protected fun getPermissionGroup( 335 permissionGroupName: String, 336 state: MutableAccessState = newState 337 ): PermissionGroupInfo? = state.systemState.permissionGroups[permissionGroupName] 338 339 protected fun getPermissionFlags( 340 appId: Int, 341 userId: Int, 342 permissionName: String, 343 state: MutableAccessState = newState 344 ): Int = 345 state.userStates[userId]?.appIdPermissionFlags?.get(appId).getWithDefault(permissionName, 0) 346 347 protected fun setPermissionFlags( 348 appId: Int, 349 userId: Int, 350 permissionName: String, 351 flags: Int, 352 state: MutableAccessState = oldState 353 ) = 354 state.mutateUserState(userId)!!.mutateAppIdPermissionFlags().mutateOrPut(appId) { 355 MutableIndexedMap() 356 }.put(permissionName, flags) 357 358 companion object { 359 @JvmStatic protected val PACKAGE_NAME_0 = "packageName0" 360 @JvmStatic protected val PACKAGE_NAME_1 = "packageName1" 361 @JvmStatic protected val PACKAGE_NAME_2 = "packageName2" 362 @JvmStatic protected val MISSING_ANDROID_PACKAGE = "missingAndroidPackage" 363 @JvmStatic protected val PLATFORM_PACKAGE_NAME = "android" 364 365 @JvmStatic protected val APP_ID_0 = 0 366 @JvmStatic protected val APP_ID_1 = 1 367 @JvmStatic protected val PLATFORM_APP_ID = 2 368 369 @JvmStatic protected val PERMISSION_GROUP_NAME_0 = "permissionGroupName0" 370 @JvmStatic protected val PERMISSION_GROUP_NAME_1 = "permissionGroupName1" 371 372 @JvmStatic protected val PERMISSION_TREE_NAME = "permissionTree" 373 374 @JvmStatic protected val PERMISSION_NAME_0 = "permissionName0" 375 @JvmStatic protected val PERMISSION_NAME_1 = "permissionName1" 376 @JvmStatic protected val PERMISSION_NAME_2 = "permissionName2" 377 @JvmStatic protected val PERMISSION_BELONGS_TO_A_TREE = "permissionTree.permission" 378 @JvmStatic protected val PERMISSION_READ_EXTERNAL_STORAGE = 379 Manifest.permission.READ_EXTERNAL_STORAGE 380 @JvmStatic protected val PERMISSION_POST_NOTIFICATIONS = 381 Manifest.permission.POST_NOTIFICATIONS 382 @JvmStatic protected val PERMISSION_BLUETOOTH_CONNECT = 383 Manifest.permission.BLUETOOTH_CONNECT 384 @JvmStatic protected val PERMISSION_ACCESS_BACKGROUND_LOCATION = 385 Manifest.permission.ACCESS_BACKGROUND_LOCATION 386 @JvmStatic protected val PERMISSION_ACCESS_MEDIA_LOCATION = 387 Manifest.permission.ACCESS_MEDIA_LOCATION 388 389 @JvmStatic protected val USER_ID_0 = 0 390 @JvmStatic protected val USER_ID_NEW = 1 391 } 392 } 393