1 /* <lambda>null2 * Copyright (C) 2021 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.access 18 19 import android.util.Slog 20 import com.android.modules.utils.BinaryXmlPullParser 21 import com.android.modules.utils.BinaryXmlSerializer 22 import com.android.server.SystemConfig 23 import com.android.server.permission.access.appop.AppIdAppOpPolicy 24 import com.android.server.permission.access.appop.PackageAppOpPolicy 25 import com.android.server.permission.access.collection.* // ktlint-disable no-wildcard-imports 26 import com.android.server.permission.access.immutable.* // ktlint-disable no-wildcard-imports 27 import com.android.server.permission.access.immutable.IndexedMap 28 import com.android.server.permission.access.permission.AppIdPermissionPolicy 29 import com.android.server.permission.access.permission.DevicePermissionPolicy 30 import com.android.server.permission.access.util.attributeInt 31 import com.android.server.permission.access.util.attributeInterned 32 import com.android.server.permission.access.util.forEachTag 33 import com.android.server.permission.access.util.getAttributeIntOrThrow 34 import com.android.server.permission.access.util.getAttributeValueOrThrow 35 import com.android.server.permission.access.util.tag 36 import com.android.server.permission.access.util.tagName 37 import com.android.server.pm.permission.PermissionAllowlist 38 import com.android.server.pm.pkg.PackageState 39 40 class AccessPolicy 41 private constructor( 42 private val schemePolicies: IndexedMap<String, IndexedMap<String, SchemePolicy>> 43 ) { 44 @Suppress("UNCHECKED_CAST") 45 constructor() : 46 this( 47 MutableIndexedMap<String, MutableIndexedMap<String, SchemePolicy>>().apply { 48 fun addPolicy(policy: SchemePolicy) { 49 getOrPut(policy.subjectScheme) { MutableIndexedMap() }[policy.objectScheme] = 50 policy 51 } 52 addPolicy(AppIdPermissionPolicy()) 53 addPolicy(DevicePermissionPolicy()) 54 addPolicy(AppIdAppOpPolicy()) 55 addPolicy(PackageAppOpPolicy()) 56 } as IndexedMap<String, IndexedMap<String, SchemePolicy>> 57 ) 58 59 fun getSchemePolicy(subjectScheme: String, objectScheme: String): SchemePolicy = 60 checkNotNull(schemePolicies[subjectScheme]?.get(objectScheme)) { 61 "Scheme policy for $subjectScheme and $objectScheme does not exist" 62 } 63 64 fun initialize( 65 state: MutableAccessState, 66 userIds: IntSet, 67 packageStates: Map<String, PackageState>, 68 disabledSystemPackageStates: Map<String, PackageState>, 69 knownPackages: IntMap<Array<String>>, 70 isLeanback: Boolean, 71 configPermissions: Map<String, SystemConfig.PermissionEntry>, 72 privilegedPermissionAllowlistPackages: IndexedListSet<String>, 73 permissionAllowlist: PermissionAllowlist, 74 implicitToSourcePermissions: IndexedMap<String, IndexedListSet<String>> 75 ) { 76 state.mutateExternalState().apply { 77 mutateUserIds() += userIds 78 setPackageStates(packageStates) 79 setDisabledSystemPackageStates(disabledSystemPackageStates) 80 packageStates.forEach { (_, packageState) -> 81 if (packageState.isApex) { 82 return@forEach 83 } 84 mutateAppIdPackageNames() 85 .mutateOrPut(packageState.appId) { MutableIndexedListSet() } 86 .add(packageState.packageName) 87 } 88 setKnownPackages(knownPackages) 89 setLeanback(isLeanback) 90 setConfigPermissions(configPermissions) 91 setPrivilegedPermissionAllowlistPackages(privilegedPermissionAllowlistPackages) 92 setPermissionAllowlist(permissionAllowlist) 93 setImplicitToSourcePermissions(implicitToSourcePermissions) 94 } 95 state.mutateUserStatesNoWrite().apply { 96 userIds.forEachIndexed { _, userId -> this[userId] = MutableUserState() } 97 } 98 } 99 100 fun GetStateScope.onStateMutated() { 101 forEachSchemePolicy { with(it) { onStateMutated() } } 102 } 103 104 fun MutateStateScope.onUserAdded(userId: Int) { 105 newState.mutateExternalState().mutateUserIds() += userId 106 newState.mutateUserStatesNoWrite()[userId] = MutableUserState() 107 forEachSchemePolicy { with(it) { onUserAdded(userId) } } 108 newState.externalState.packageStates.forEach { (_, packageState) -> 109 if (packageState.isApex) { 110 return@forEach 111 } 112 upgradePackageVersion(packageState, userId) 113 } 114 } 115 116 fun MutateStateScope.onUserRemoved(userId: Int) { 117 newState.mutateExternalState().mutateUserIds() -= userId 118 newState.mutateUserStatesNoWrite() -= userId 119 forEachSchemePolicy { with(it) { onUserRemoved(userId) } } 120 } 121 122 fun MutateStateScope.onStorageVolumeMounted( 123 packageStates: Map<String, PackageState>, 124 disabledSystemPackageStates: Map<String, PackageState>, 125 knownPackages: IntMap<Array<String>>, 126 volumeUuid: String?, 127 packageNames: List<String>, 128 isSystemUpdated: Boolean 129 ) { 130 val addedAppIds = MutableIntSet() 131 newState.mutateExternalState().apply { 132 setPackageStates(packageStates) 133 setDisabledSystemPackageStates(disabledSystemPackageStates) 134 packageStates.forEach { (packageName, packageState) -> 135 if (packageState.isApex) { 136 return@forEach 137 } 138 if (packageState.volumeUuid == volumeUuid) { 139 // The APK for a package on a mounted storage volume may still be unavailable 140 // due to APK being deleted, e.g. after an OTA. 141 check( 142 packageState.androidPackage == null || packageNames.contains(packageName) 143 ) { 144 "Package $packageName on storage volume $volumeUuid didn't receive" + 145 " onPackageAdded() before onStorageVolumeMounted()" 146 } 147 val appId = packageState.appId 148 mutateAppIdPackageNames().mutateOrPut(appId) { 149 addedAppIds += appId 150 MutableIndexedListSet() 151 } += packageName 152 } 153 } 154 setKnownPackages(knownPackages) 155 } 156 addedAppIds.forEachIndexed { _, appId -> 157 forEachSchemePolicy { with(it) { onAppIdAdded(appId) } } 158 } 159 forEachSchemePolicy { 160 with(it) { onStorageVolumeMounted(volumeUuid, packageNames, isSystemUpdated) } 161 } 162 packageStates.forEach { (_, packageState) -> 163 if (packageState.isApex) { 164 return@forEach 165 } 166 if (packageState.volumeUuid == volumeUuid) { 167 newState.userStates.forEachIndexed { _, userId, _ -> 168 upgradePackageVersion(packageState, userId) 169 } 170 } 171 } 172 } 173 174 fun MutateStateScope.onPackageAdded( 175 packageStates: Map<String, PackageState>, 176 disabledSystemPackageStates: Map<String, PackageState>, 177 knownPackages: IntMap<Array<String>>, 178 packageName: String 179 ) { 180 val packageState = packageStates[packageName] 181 checkNotNull(packageState) { 182 "Added package $packageName isn't found in packageStates in onPackageAdded()" 183 } 184 val appId = packageState.appId 185 var isAppIdAdded = false 186 newState.mutateExternalState().apply { 187 setPackageStates(packageStates) 188 setDisabledSystemPackageStates(disabledSystemPackageStates) 189 mutateAppIdPackageNames().mutateOrPut(appId) { 190 isAppIdAdded = true 191 MutableIndexedListSet() 192 } += packageName 193 setKnownPackages(knownPackages) 194 } 195 if (isAppIdAdded) { 196 forEachSchemePolicy { with(it) { onAppIdAdded(appId) } } 197 } 198 forEachSchemePolicy { with(it) { onPackageAdded(packageState) } } 199 newState.userStates.forEachIndexed { _, userId, _ -> 200 upgradePackageVersion(packageState, userId) 201 } 202 } 203 204 fun MutateStateScope.onPackageRemoved( 205 packageStates: Map<String, PackageState>, 206 disabledSystemPackageStates: Map<String, PackageState>, 207 knownPackages: IntMap<Array<String>>, 208 packageName: String, 209 appId: Int 210 ) { 211 check(packageName !in packageStates) { 212 "Removed package $packageName is still in packageStates in onPackageRemoved()" 213 } 214 var isAppIdRemoved = false 215 newState.mutateExternalState().apply { 216 setPackageStates(packageStates) 217 setDisabledSystemPackageStates(disabledSystemPackageStates) 218 mutateAppIdPackageNames().mutate(appId)?.apply { 219 this -= packageName 220 if (isEmpty()) { 221 mutateAppIdPackageNames() -= appId 222 isAppIdRemoved = true 223 } 224 } 225 setKnownPackages(knownPackages) 226 } 227 forEachSchemePolicy { with(it) { onPackageRemoved(packageName, appId) } } 228 if (isAppIdRemoved) { 229 forEachSchemePolicy { with(it) { onAppIdRemoved(appId) } } 230 } 231 newState.userStates.forEachIndexed { userStateIndex, _, userState -> 232 if (packageName in userState.packageVersions) { 233 newState.mutateUserStateAt(userStateIndex).mutatePackageVersions() -= packageName 234 } 235 } 236 } 237 238 fun MutateStateScope.onPackageInstalled( 239 packageStates: Map<String, PackageState>, 240 disabledSystemPackageStates: Map<String, PackageState>, 241 knownPackages: IntMap<Array<String>>, 242 packageName: String, 243 userId: Int 244 ) { 245 newState.mutateExternalState().apply { 246 setPackageStates(packageStates) 247 setDisabledSystemPackageStates(disabledSystemPackageStates) 248 setKnownPackages(knownPackages) 249 } 250 val packageState = packageStates[packageName] 251 checkNotNull(packageState) { 252 "Installed package $packageName isn't found in packageStates in onPackageInstalled()" 253 } 254 forEachSchemePolicy { with(it) { onPackageInstalled(packageState, userId) } } 255 } 256 257 fun MutateStateScope.onPackageUninstalled( 258 packageStates: Map<String, PackageState>, 259 disabledSystemPackageStates: Map<String, PackageState>, 260 knownPackages: IntMap<Array<String>>, 261 packageName: String, 262 appId: Int, 263 userId: Int 264 ) { 265 newState.mutateExternalState().apply { 266 setPackageStates(packageStates) 267 setDisabledSystemPackageStates(disabledSystemPackageStates) 268 setKnownPackages(knownPackages) 269 } 270 forEachSchemePolicy { with(it) { onPackageUninstalled(packageName, appId, userId) } } 271 } 272 273 fun MutateStateScope.onSystemReady() { 274 newState.mutateExternalState().setSystemReady(true) 275 forEachSchemePolicy { with(it) { onSystemReady() } } 276 } 277 278 fun migrateSystemState(state: MutableAccessState) { 279 forEachSchemePolicy { with(it) { migrateSystemState(state) } } 280 } 281 282 fun migrateUserState(state: MutableAccessState, userId: Int) { 283 forEachSchemePolicy { with(it) { migrateUserState(state, userId) } } 284 } 285 286 private fun MutateStateScope.upgradePackageVersion(packageState: PackageState, userId: Int) { 287 if (packageState.androidPackage == null) { 288 return 289 } 290 291 val packageName = packageState.packageName 292 // The version would be latest when the package is new to the system, e.g. newly 293 // installed, first boot, or system apps added via OTA. 294 val version = newState.userStates[userId]!!.packageVersions[packageName] 295 when { 296 version == null -> 297 newState.mutateUserState(userId)!!.mutatePackageVersions()[packageName] = 298 VERSION_LATEST 299 version < VERSION_LATEST -> { 300 forEachSchemePolicy { 301 with(it) { upgradePackageState(packageState, userId, version) } 302 } 303 newState.mutateUserState(userId)!!.mutatePackageVersions()[packageName] = 304 VERSION_LATEST 305 } 306 version == VERSION_LATEST -> {} 307 else -> 308 Slog.w( 309 LOG_TAG, 310 "Unexpected version $version for package $packageName," + 311 "latest version is $VERSION_LATEST" 312 ) 313 } 314 } 315 316 fun BinaryXmlPullParser.parseSystemState(state: MutableAccessState) { 317 forEachTag { 318 when (tagName) { 319 TAG_ACCESS -> { 320 forEachTag { forEachSchemePolicy { with(it) { parseSystemState(state) } } } 321 } 322 else -> Slog.w(LOG_TAG, "Ignoring unknown tag $tagName when parsing system state") 323 } 324 } 325 } 326 327 fun BinaryXmlSerializer.serializeSystemState(state: AccessState) { 328 tag(TAG_ACCESS) { forEachSchemePolicy { with(it) { serializeSystemState(state) } } } 329 } 330 331 fun BinaryXmlPullParser.parseUserState(state: MutableAccessState, userId: Int) { 332 forEachTag { 333 when (tagName) { 334 TAG_ACCESS -> { 335 forEachTag { 336 when (tagName) { 337 TAG_PACKAGE_VERSIONS -> parsePackageVersions(state, userId) 338 TAG_DEFAULT_PERMISSION_GRANT -> 339 parseDefaultPermissionGrant(state, userId) 340 else -> { 341 forEachSchemePolicy { with(it) { parseUserState(state, userId) } } 342 } 343 } 344 } 345 } 346 else -> { 347 Slog.w( 348 LOG_TAG, 349 "Ignoring unknown tag $tagName when parsing user state for user $userId" 350 ) 351 } 352 } 353 } 354 } 355 356 private fun BinaryXmlPullParser.parsePackageVersions(state: MutableAccessState, userId: Int) { 357 val userState = state.mutateUserState(userId, WriteMode.NONE)!! 358 val packageVersions = userState.mutatePackageVersions() 359 forEachTag { 360 when (tagName) { 361 TAG_PACKAGE -> parsePackageVersion(packageVersions) 362 else -> Slog.w(LOG_TAG, "Ignoring unknown tag $name when parsing package versions") 363 } 364 } 365 packageVersions.forEachReversedIndexed { packageVersionIndex, packageName, _ -> 366 if (packageName !in state.externalState.packageStates) { 367 Slog.w(LOG_TAG, "Dropping unknown $packageName when parsing package versions") 368 packageVersions.removeAt(packageVersionIndex) 369 userState.requestWriteMode(WriteMode.ASYNCHRONOUS) 370 } 371 } 372 } 373 374 private fun BinaryXmlPullParser.parsePackageVersion( 375 packageVersions: MutableIndexedMap<String, Int> 376 ) { 377 val packageName = getAttributeValueOrThrow(ATTR_NAME).intern() 378 val version = getAttributeIntOrThrow(ATTR_VERSION) 379 packageVersions[packageName] = version 380 } 381 382 private fun BinaryXmlPullParser.parseDefaultPermissionGrant( 383 state: MutableAccessState, 384 userId: Int 385 ) { 386 val userState = state.mutateUserState(userId, WriteMode.NONE)!! 387 val fingerprint = getAttributeValueOrThrow(ATTR_FINGERPRINT).intern() 388 userState.setDefaultPermissionGrantFingerprint(fingerprint) 389 } 390 391 fun BinaryXmlSerializer.serializeUserState(state: AccessState, userId: Int) { 392 tag(TAG_ACCESS) { 393 serializePackageVersions(state.userStates[userId]!!.packageVersions) 394 serializeDefaultPermissionGrantFingerprint( 395 state.userStates[userId]!!.defaultPermissionGrantFingerprint 396 ) 397 forEachSchemePolicy { with(it) { serializeUserState(state, userId) } } 398 } 399 } 400 401 private fun BinaryXmlSerializer.serializePackageVersions( 402 packageVersions: IndexedMap<String, Int> 403 ) { 404 tag(TAG_PACKAGE_VERSIONS) { 405 packageVersions.forEachIndexed { _, packageName, version -> 406 tag(TAG_PACKAGE) { 407 attributeInterned(ATTR_NAME, packageName) 408 attributeInt(ATTR_VERSION, version) 409 } 410 } 411 } 412 } 413 414 private fun BinaryXmlSerializer.serializeDefaultPermissionGrantFingerprint( 415 fingerprint: String? 416 ) { 417 if (fingerprint != null) { 418 tag(TAG_DEFAULT_PERMISSION_GRANT) { attributeInterned(ATTR_FINGERPRINT, fingerprint) } 419 } 420 } 421 422 private fun getSchemePolicy(subject: AccessUri, `object`: AccessUri): SchemePolicy = 423 getSchemePolicy(subject.scheme, `object`.scheme) 424 425 private inline fun forEachSchemePolicy(action: (SchemePolicy) -> Unit) { 426 schemePolicies.forEachIndexed { _, _, objectSchemePolicies -> 427 objectSchemePolicies.forEachIndexed { _, _, schemePolicy -> action(schemePolicy) } 428 } 429 } 430 431 companion object { 432 private val LOG_TAG = AccessPolicy::class.java.simpleName 433 434 internal const val VERSION_LATEST = 15 435 436 private const val TAG_ACCESS = "access" 437 private const val TAG_DEFAULT_PERMISSION_GRANT = "default-permission-grant" 438 private const val TAG_PACKAGE_VERSIONS = "package-versions" 439 private const val TAG_PACKAGE = "package" 440 441 private const val ATTR_FINGERPRINT = "fingerprint" 442 private const val ATTR_NAME = "name" 443 private const val ATTR_VERSION = "version" 444 } 445 } 446 447 abstract class SchemePolicy { 448 abstract val subjectScheme: String 449 450 abstract val objectScheme: String 451 onStateMutatednull452 open fun GetStateScope.onStateMutated() {} 453 onUserAddednull454 open fun MutateStateScope.onUserAdded(userId: Int) {} 455 onUserRemovednull456 open fun MutateStateScope.onUserRemoved(userId: Int) {} 457 onAppIdAddednull458 open fun MutateStateScope.onAppIdAdded(appId: Int) {} 459 onAppIdRemovednull460 open fun MutateStateScope.onAppIdRemoved(appId: Int) {} 461 onStorageVolumeMountednull462 open fun MutateStateScope.onStorageVolumeMounted( 463 volumeUuid: String?, 464 packageNames: List<String>, 465 isSystemUpdated: Boolean, 466 ) {} 467 onPackageAddednull468 open fun MutateStateScope.onPackageAdded(packageState: PackageState) {} 469 onPackageRemovednull470 open fun MutateStateScope.onPackageRemoved(packageName: String, appId: Int) {} 471 onPackageInstallednull472 open fun MutateStateScope.onPackageInstalled(packageState: PackageState, userId: Int) {} 473 onPackageUninstallednull474 open fun MutateStateScope.onPackageUninstalled(packageName: String, appId: Int, userId: Int) {} 475 onSystemReadynull476 open fun MutateStateScope.onSystemReady() {} 477 migrateSystemStatenull478 open fun migrateSystemState(state: MutableAccessState) {} 479 migrateUserStatenull480 open fun migrateUserState(state: MutableAccessState, userId: Int) {} 481 upgradePackageStatenull482 open fun MutateStateScope.upgradePackageState( 483 packageState: PackageState, 484 userId: Int, 485 version: Int 486 ) {} 487 parseSystemStatenull488 open fun BinaryXmlPullParser.parseSystemState(state: MutableAccessState) {} 489 serializeSystemStatenull490 open fun BinaryXmlSerializer.serializeSystemState(state: AccessState) {} 491 parseUserStatenull492 open fun BinaryXmlPullParser.parseUserState(state: MutableAccessState, userId: Int) {} 493 serializeUserStatenull494 open fun BinaryXmlSerializer.serializeUserState(state: AccessState, userId: Int) {} 495 } 496