Merge changes I3aa177e5,I2d678ef2,I9c4ec4b7

* changes:
  Various refactors to UidPermissionPolicy code.
  Start AccessCheckingService in SystemServer.
  Make AccessCheckingService a SystemService.
This commit is contained in:
Hai Zhang
2022-12-12 21:02:29 +00:00
committed by Android (Google) Code Review
27 changed files with 529 additions and 517 deletions

View File

@@ -154,6 +154,7 @@ import com.android.server.os.DeviceIdentifiersPolicyService;
import com.android.server.os.NativeTombstoneManagerService;
import com.android.server.os.SchedulingPolicyService;
import com.android.server.people.PeopleService;
import com.android.server.permission.access.AccessCheckingService;
import com.android.server.pm.ApexManager;
import com.android.server.pm.ApexSystemServiceInfo;
import com.android.server.pm.BackgroundInstallControlService;
@@ -1110,6 +1111,11 @@ public final class SystemServer implements Dumpable {
startMemtrackProxyService();
t.traceEnd();
// Start AccessCheckingService which provides new implementation for permission and app op.
t.traceBegin("StartAccessCheckingService");
mSystemServiceManager.startService(AccessCheckingService.class);
t.traceEnd();
// Activity manager runs the show.
t.traceBegin("StartActivityManager");
// TODO: Might need to move after migration to WM.

View File

@@ -16,11 +16,23 @@
package com.android.server.permission.access
import android.content.Context
import com.android.internal.annotations.Keep
import com.android.server.permission.access.external.PackageState
import com.android.server.LocalManagerRegistry
import com.android.server.LocalServices
import com.android.server.SystemService
import com.android.server.appop.AppOpsCheckingServiceInterface
import com.android.server.permission.access.appop.AppOpService
import com.android.server.permission.access.collection.* // ktlint-disable no-wildcard-imports
import com.android.server.permission.access.permission.PermissionService
import com.android.server.pm.PackageManagerLocal
import com.android.server.pm.UserManagerService
import com.android.server.pm.permission.PermissionManagerServiceInterface
import com.android.server.pm.permission.PermissionManagerServiceInternal
import com.android.server.pm.pkg.PackageState
@Keep
class AccessCheckingService {
class AccessCheckingService(context: Context) : SystemService(context) {
@Volatile
private lateinit var state: AccessState
private val stateLock = Any()
@@ -29,14 +41,35 @@ class AccessCheckingService {
private val persistence = AccessPersistence(policy)
fun init() {
private lateinit var appOpService: AppOpService
private lateinit var permissionService: PermissionService
private lateinit var packageManagerLocal: PackageManagerLocal
private lateinit var userManagerService: UserManagerService
override fun onStart() {
appOpService = AppOpService(this)
permissionService = PermissionService(this)
LocalServices.addService(AppOpsCheckingServiceInterface::class.java, appOpService)
LocalServices.addService(PermissionManagerServiceInterface::class.java, permissionService)
}
fun initialize() {
packageManagerLocal =
LocalManagerRegistry.getManagerOrThrow(PackageManagerLocal::class.java)
userManagerService = UserManagerService.getInstance()
val userIds = IntSet(userManagerService.userIdsIncludingPreCreated)
val packageStates = packageManagerLocal.packageStates
val state = AccessState()
state.systemState.userIds.apply {
// TODO: Get and add all user IDs.
// TODO: Maybe get and add all packages?
}
policy.initialize(state, userIds, packageStates)
persistence.read(state)
this.state = state
appOpService.initialize()
permissionService.initialize()
}
fun getDecision(subject: AccessUri, `object`: AccessUri): Int =
@@ -50,30 +83,60 @@ class AccessCheckingService {
}
}
fun onUserAdded(userId: Int) {
internal fun onUserAdded(userId: Int) {
mutateState {
with(policy) { onUserAdded(userId) }
}
}
fun onUserRemoved(userId: Int) {
internal fun onUserRemoved(userId: Int) {
mutateState {
with(policy) { onUserRemoved(userId) }
}
}
fun onPackageAdded(packageState: PackageState) {
internal fun onStorageVolumeMounted(volumeUuid: String?, isSystemUpdated: Boolean) {
val packageStates = packageManagerLocal.packageStates
mutateState {
with(policy) { onPackageAdded(packageState) }
with(policy) { onStorageVolumeMounted(packageStates, volumeUuid, isSystemUpdated) }
}
}
fun onPackageRemoved(packageState: PackageState) {
internal fun onPackageAdded(packageName: String) {
val packageStates = packageManagerLocal.packageStates
mutateState {
with(policy) { onPackageRemoved(packageState) }
with(policy) { onPackageAdded(packageStates, packageName) }
}
}
internal fun onPackageRemoved(packageName: String, appId: Int) {
val packageStates = packageManagerLocal.packageStates
mutateState {
with(policy) { onPackageRemoved(packageStates, packageName, appId) }
}
}
internal fun onPackageInstalled(
packageName: String,
params: PermissionManagerServiceInternal.PackageInstalledParams,
userId: Int
) {
val packageStates = packageManagerLocal.packageStates
mutateState {
with(policy) { onPackageInstalled(packageStates, packageName, params, userId) }
}
}
internal fun onPackageUninstalled(packageName: String, appId: Int, userId: Int) {
val packageStates = packageManagerLocal.packageStates
mutateState {
with(policy) { onPackageUninstalled(packageStates, packageName, appId, userId) }
}
}
private val PackageManagerLocal.packageStates: Map<String, PackageState>
get() = withUnfilteredSnapshot().use { it.packageStates }
internal inline fun <T> getState(action: GetStateScope.() -> T): T =
GetStateScope(state).action()

View File

@@ -22,11 +22,12 @@ import com.android.modules.utils.BinaryXmlSerializer
import com.android.server.permission.access.appop.PackageAppOpPolicy
import com.android.server.permission.access.appop.UidAppOpPolicy
import com.android.server.permission.access.collection.* // ktlint-disable no-wildcard-imports
import com.android.server.permission.access.external.PackageState
import com.android.server.permission.access.permission.UidPermissionPolicy
import com.android.server.permission.access.util.forEachTag
import com.android.server.permission.access.util.tag
import com.android.server.permission.access.util.tagName
import com.android.server.pm.permission.PermissionManagerServiceInternal
import com.android.server.pm.pkg.PackageState
class AccessPolicy private constructor(
private val schemePolicies: IndexedMap<String, IndexedMap<String, SchemePolicy>>
@@ -53,6 +54,17 @@ class AccessPolicy private constructor(
with(getSchemePolicy(subject, `object`)) { setDecision(subject, `object`, decision) }
}
fun initialize(state: AccessState, userIds: IntSet, packageStates: Map<String, PackageState>) {
state.systemState.apply {
this.userIds += userIds
this.packageStates = packageStates
packageStates.forEach { (_, packageState) ->
appIds.getOrPut(packageState.appId) { IndexedListSet() }
.add(packageState.packageName)
}
}
}
fun MutateStateScope.onUserAdded(userId: Int) {
newState.systemState.userIds += userId
newState.userStates[userId] = UserState()
@@ -69,18 +81,34 @@ class AccessPolicy private constructor(
}
}
fun MutateStateScope.onPackageAdded(packageState: PackageState) {
var isAppIdAdded = false
newState.systemState.apply {
packageStates[packageState.packageName] = packageState
appIds.getOrPut(packageState.appId) {
isAppIdAdded = true
IndexedListSet()
}.add(packageState.packageName)
fun MutateStateScope.onStorageVolumeMounted(
packageStates: Map<String, PackageState>,
volumeUuid: String?,
isSystemUpdated: Boolean
) {
newState.systemState.packageStates = packageStates
forEachSchemePolicy {
with(it) { onStorageVolumeMounted(volumeUuid, isSystemUpdated) }
}
}
fun MutateStateScope.onPackageAdded(
packageStates: Map<String, PackageState>,
packageName: String
) {
newState.systemState.packageStates = packageStates
var isAppIdAdded = false
val packageState = packageStates[packageName]
// TODO(zhanghai): Remove check before submission.
checkNotNull(packageState)
val appId = packageState.appId
newState.systemState.appIds.getOrPut(appId) {
isAppIdAdded = true
IndexedListSet()
}.add(packageName)
if (isAppIdAdded) {
forEachSchemePolicy {
with(it) { onAppIdAdded(packageState.appId) }
with(it) { onAppIdAdded(appId) }
}
}
forEachSchemePolicy {
@@ -88,30 +116,61 @@ class AccessPolicy private constructor(
}
}
fun MutateStateScope.onPackageRemoved(packageState: PackageState) {
fun MutateStateScope.onPackageRemoved(
packageStates: Map<String, PackageState>,
packageName: String,
appId: Int
) {
newState.systemState.packageStates = packageStates
var isAppIdRemoved = false
newState.systemState.apply {
packageStates -= packageState.packageName
appIds.apply appIds@{
this[packageState.appId]?.apply {
this -= packageState.packageName
if (isEmpty()) {
this@appIds -= packageState.appId
isAppIdRemoved = true
}
// TODO(zhanghai): Remove check before submission.
check(packageName !in packageStates)
newState.systemState.appIds.apply appIds@{
this[appId]?.apply {
this -= packageName
if (isEmpty()) {
this@appIds -= appId
isAppIdRemoved = true
}
}
}
forEachSchemePolicy {
with(it) { onPackageRemoved(packageState) }
with(it) { onPackageRemoved(packageName, appId) }
}
if (isAppIdRemoved) {
forEachSchemePolicy {
with(it) { onAppIdRemoved(packageState.appId) }
with(it) { onAppIdRemoved(appId) }
}
}
}
fun MutateStateScope.onPackageInstalled(
packageStates: Map<String, PackageState>,
packageName: String,
params: PermissionManagerServiceInternal.PackageInstalledParams,
userId: Int
) {
newState.systemState.packageStates = packageStates
val packageState = packageStates[packageName]
// TODO(zhanghai): Remove check before submission.
checkNotNull(packageState)
forEachSchemePolicy {
with(it) { onPackageInstalled(packageState, params, userId) }
}
}
fun MutateStateScope.onPackageUninstalled(
packageStates: Map<String, PackageState>,
packageName: String,
appId: Int,
userId: Int
) {
newState.systemState.packageStates = packageStates
forEachSchemePolicy {
with(it) { onPackageUninstalled(packageName, appId, userId) }
}
}
fun BinaryXmlPullParser.parseSystemState(systemState: SystemState) {
forEachTag {
when (tagName) {
@@ -230,9 +289,22 @@ abstract class SchemePolicy {
open fun MutateStateScope.onAppIdRemoved(appId: Int) {}
open fun MutateStateScope.onStorageVolumeMounted(
volumeUuid: String?,
isSystemUpdated: Boolean
) {}
open fun MutateStateScope.onPackageAdded(packageState: PackageState) {}
open fun MutateStateScope.onPackageRemoved(packageState: PackageState) {}
open fun MutateStateScope.onPackageRemoved(packageName: String, appId: Int) {}
open fun MutateStateScope.onPackageInstalled(
packageState: PackageState,
params: PermissionManagerServiceInternal.PackageInstalledParams,
userId: Int
) {}
open fun MutateStateScope.onPackageUninstalled(packageName: String, appId: Int, userId: Int) {}
open fun BinaryXmlPullParser.parseSystemState(systemState: SystemState) {}

View File

@@ -18,8 +18,8 @@ package com.android.server.permission.access
import android.content.pm.PermissionGroupInfo
import com.android.server.permission.access.collection.* // ktlint-disable no-wildcard-imports
import com.android.server.permission.access.data.Permission
import com.android.server.permission.access.external.PackageState
import com.android.server.permission.access.permission.Permission
import com.android.server.pm.pkg.PackageState
class AccessState private constructor(
val systemState: SystemState,
@@ -32,8 +32,8 @@ class AccessState private constructor(
class SystemState private constructor(
val userIds: IntSet,
val packageStates: IndexedMap<String, PackageState>,
val disabledSystemPackageStates: IndexedMap<String, PackageState>,
var packageStates: Map<String, PackageState>,
var disabledSystemPackageStates: Map<String, PackageState>,
val appIds: IntMap<IndexedListSet<String>>,
// A map of KnownPackagesInt to a set of known package names
val knownPackages: IntMap<IndexedListSet<String>>,
@@ -59,7 +59,7 @@ class SystemState private constructor(
val permissions: IndexedMap<String, Permission>
) : WritableState() {
constructor() : this(
IntSet(), IndexedMap(), IndexedMap(), IntMap(), IntMap(), IntMap(), IndexedMap(),
IntSet(), emptyMap(), emptyMap(), IntMap(), IntMap(), IntMap(), IndexedMap(),
IndexedListSet(), IndexedMap(), IndexedMap(), IndexedMap(), IndexedMap(), IndexedMap(),
IndexedMap(), IndexedMap(), IndexedMap(), IndexedMap(), IndexedMap(), IndexedMap(),
IndexedMap(), IndexedMap(), IndexedMap()
@@ -68,8 +68,8 @@ class SystemState private constructor(
fun copy(): SystemState =
SystemState(
userIds.copy(),
packageStates.copy { it },
disabledSystemPackageStates.copy { it },
packageStates,
disabledSystemPackageStates,
appIds.copy { it.copy() },
knownPackages.copy { it.copy() },
deviceAndProfileOwners.copy { it },
@@ -94,14 +94,17 @@ class SystemState private constructor(
class UserState private constructor(
// A map of (appId to a map of (permissionName to permissionFlags))
val permissionFlags: IntMap<IndexedMap<String, Int>>,
val uidPermissionFlags: IntMap<IndexedMap<String, Int>>,
val uidAppOpModes: IntMap<IndexedMap<String, Int>>,
val packageAppOpModes: IndexedMap<String, IndexedMap<String, Int>>
) : WritableState() {
constructor() : this(IntMap(), IntMap(), IndexedMap())
fun copy(): UserState = UserState(permissionFlags.copy { it.copy { it } },
uidAppOpModes.copy { it.copy { it } }, packageAppOpModes.copy { it.copy { it } })
fun copy(): UserState = UserState(
uidPermissionFlags.copy { it.copy { it } },
uidAppOpModes.copy { it.copy { it } },
packageAppOpModes.copy { it.copy { it } }
)
}
object WriteMode {

View File

@@ -16,8 +16,7 @@
package com.android.server.permission.access
import com.android.server.permission.access.external.UserHandle
import com.android.server.permission.access.external.UserHandleCompat
import android.os.UserHandle
sealed class AccessUri(
val scheme: String
@@ -70,7 +69,7 @@ data class UidUri(
val uid: Int
) : AccessUri(SCHEME) {
val userId: Int
get() = UserHandleCompat.getUserId(uid)
get() = UserHandle.getUserId(uid)
val appId: Int
get() = UserHandle.getAppId(uid)

View File

@@ -24,9 +24,13 @@ import com.android.server.appop.OnOpModeChangedListener
import com.android.server.permission.access.AccessCheckingService
import java.io.PrintWriter
class AppOpsCheckingServiceCompatImpl(
private val accessCheckingService: AccessCheckingService
class AppOpService(
private val service: AccessCheckingService
) : AppOpsCheckingServiceInterface {
fun initialize() {
TODO("Not yet implemented")
}
override fun getNonDefaultUidModes(uid: Int): SparseIntArray {
TODO("Not yet implemented")
}
@@ -139,6 +143,6 @@ class AppOpsCheckingServiceCompatImpl(
}
companion object {
private val LOG_TAG = AppOpsCheckingServiceCompatImpl::class.java.simpleName
private val LOG_TAG = AppOpService::class.java.simpleName
}
}

View File

@@ -23,7 +23,6 @@ import com.android.server.permission.access.MutateStateScope
import com.android.server.permission.access.PackageUri
import com.android.server.permission.access.UserState
import com.android.server.permission.access.collection.* // ktlint-disable no-wildcard-imports
import com.android.server.permission.access.external.PackageState
class PackageAppOpPolicy : BaseAppOpPolicy(PackageAppOpPersistence()) {
override val subjectScheme: String
@@ -48,9 +47,9 @@ class PackageAppOpPolicy : BaseAppOpPolicy(PackageAppOpPersistence()) {
newState.userStates[subject.userId]?.packageAppOpModes?.remove(subject.packageName)
}
override fun MutateStateScope.onPackageRemoved(packageState: PackageState) {
override fun MutateStateScope.onPackageRemoved(packageName: String, appId: Int) {
newState.userStates.forEachIndexed { _, _, userState ->
userState.packageAppOpModes -= packageState.packageName
userState.packageAppOpModes -= packageName
}
}
}

View File

@@ -72,18 +72,24 @@ inline operator fun <T> IndexedList<T>.plusAssign(element: T) {
add(element)
}
inline fun <T> IndexedList<T>.removeAllIndexed(predicate: (Int, T) -> Boolean) {
inline fun <T> IndexedList<T>.removeAllIndexed(predicate: (Int, T) -> Boolean): Boolean {
var isChanged = false
for (index in lastIndex downTo 0) {
if (predicate(index, this[index])) {
removeAt(index)
isChanged = true
}
}
return isChanged
}
inline fun <T> IndexedList<T>.retainAllIndexed(predicate: (Int, T) -> Boolean) {
inline fun <T> IndexedList<T>.retainAllIndexed(predicate: (Int, T) -> Boolean): Boolean {
var isChanged = false
for (index in lastIndex downTo 0) {
if (!predicate(index, this[index])) {
removeAt(index)
isChanged = true
}
}
return isChanged
}

View File

@@ -123,18 +123,24 @@ inline operator fun <T> IndexedListSet<T>.plusAssign(element: T) {
add(element)
}
inline fun <T> IndexedListSet<T>.removeAllIndexed(predicate: (Int, T) -> Boolean) {
inline fun <T> IndexedListSet<T>.removeAllIndexed(predicate: (Int, T) -> Boolean): Boolean {
var isChanged = false
for (index in lastIndex downTo 0) {
if (predicate(index, elementAt(index))) {
removeAt(index)
isChanged = true
}
}
return isChanged
}
inline fun <T> IndexedListSet<T>.retainAllIndexed(predicate: (Int, T) -> Boolean) {
inline fun <T> IndexedListSet<T>.retainAllIndexed(predicate: (Int, T) -> Boolean): Boolean {
var isChanged = false
for (index in lastIndex downTo 0) {
if (!predicate(index, elementAt(index))) {
removeAt(index)
isChanged = true
}
}
return isChanged
}

View File

@@ -111,20 +111,26 @@ inline fun <K, V> IndexedMap<K, V>.putWithDefault(key: K, value: V, defaultValue
}
}
inline fun <K, V> IndexedMap<K, V>.removeAllIndexed(predicate: (Int, K, V) -> Boolean) {
inline fun <K, V> IndexedMap<K, V>.removeAllIndexed(predicate: (Int, K, V) -> Boolean): Boolean {
var isChanged = false
for (index in lastIndex downTo 0) {
if (predicate(index, keyAt(index), valueAt(index))) {
removeAt(index)
isChanged = true
}
}
return isChanged
}
inline fun <K, V> IndexedMap<K, V>.retainAllIndexed(predicate: (Int, K, V) -> Boolean) {
inline fun <K, V> IndexedMap<K, V>.retainAllIndexed(predicate: (Int, K, V) -> Boolean): Boolean {
var isChanged = false
for (index in lastIndex downTo 0) {
if (!predicate(index, keyAt(index), valueAt(index))) {
removeAt(index)
isChanged = true
}
}
return isChanged
}
@Suppress("NOTHING_TO_INLINE")

View File

@@ -80,20 +80,26 @@ inline operator fun <T> IndexedSet<T>.plusAssign(element: T) {
add(element)
}
inline fun <T> IndexedSet<T>.removeAllIndexed(predicate: (Int, T) -> Boolean) {
inline fun <T> IndexedSet<T>.removeAllIndexed(predicate: (Int, T) -> Boolean): Boolean {
var isChanged = false
for (index in lastIndex downTo 0) {
if (predicate(index, elementAt(index))) {
removeAt(index)
isChanged = true
}
}
return isChanged
}
inline fun <T> IndexedSet<T>.retainAllIndexed(predicate: (Int, T) -> Boolean) {
inline fun <T> IndexedSet<T>.retainAllIndexed(predicate: (Int, T) -> Boolean): Boolean {
var isChanged = false
for (index in lastIndex downTo 0) {
if (!predicate(index, elementAt(index))) {
removeAt(index)
isChanged = true
}
}
return isChanged
}
@Suppress("NOTHING_TO_INLINE")

View File

@@ -120,20 +120,26 @@ inline fun <T> IntMap<T>.putWithDefault(key: Int, value: T, defaultValue: T): T
}
}
inline fun <T> IntMap<T>.removeAllIndexed(predicate: (Int, Int, T) -> Boolean) {
inline fun <T> IntMap<T>.removeAllIndexed(predicate: (Int, Int, T) -> Boolean): Boolean {
var isChanged = false
for (index in lastIndex downTo 0) {
if (predicate(index, keyAt(index), valueAt(index))) {
removeAt(index)
isChanged = true
}
}
return isChanged
}
inline fun <T> IntMap<T>.retainAllIndexed(predicate: (Int, Int, T) -> Boolean) {
inline fun <T> IntMap<T>.retainAllIndexed(predicate: (Int, Int, T) -> Boolean): Boolean {
var isChanged = false
for (index in lastIndex downTo 0) {
if (!predicate(index, keyAt(index), valueAt(index))) {
removeAt(index)
isChanged = true
}
}
return isChanged
}
inline val <T> IntMap<T>.size: Int

View File

@@ -51,6 +51,8 @@ class IntSet private constructor(
fun copy(): IntSet = IntSet(array.clone())
}
fun IntSet(values: IntArray): IntSet = IntSet().apply{ this += values }
inline fun IntSet.allIndexed(predicate: (Int, Int) -> Boolean): Boolean {
for (index in 0 until size) {
if (!predicate(index, elementAt(index))) {
@@ -103,18 +105,32 @@ inline operator fun IntSet.plusAssign(element: Int) {
add(element)
}
inline fun IntSet.removeAllIndexed(predicate: (Int, Int) -> Boolean) {
operator fun IntSet.plusAssign(set: IntSet) {
set.forEachIndexed { _, it -> this += it }
}
operator fun IntSet.plusAssign(array: IntArray) {
array.forEach { this += it }
}
inline fun IntSet.removeAllIndexed(predicate: (Int, Int) -> Boolean): Boolean {
var isChanged = false
for (index in lastIndex downTo 0) {
if (predicate(index, elementAt(index))) {
removeAt(index)
isChanged = true
}
}
return isChanged
}
inline fun IntSet.retainAllIndexed(predicate: (Int, Int) -> Boolean) {
inline fun IntSet.retainAllIndexed(predicate: (Int, Int) -> Boolean): Boolean {
var isChanged = false
for (index in lastIndex downTo 0) {
if (!predicate(index, elementAt(index))) {
removeAt(index)
isChanged = true
}
}
return isChanged
}

View File

@@ -49,18 +49,24 @@ inline fun <T> List<T>.noneIndexed(predicate: (Int, T) -> Boolean): Boolean {
return true
}
inline fun <T> MutableList<T>.removeAllIndexed(predicate: (Int, T) -> Boolean) {
inline fun <T> MutableList<T>.removeAllIndexed(predicate: (Int, T) -> Boolean): Boolean {
var isChanged = false
for (index in lastIndex downTo 0) {
if (predicate(index, this[index])) {
removeAt(index)
isChanged = true
}
}
return isChanged
}
inline fun <T> MutableList<T>.retainAllIndexed(predicate: (Int, T) -> Boolean) {
inline fun <T> MutableList<T>.retainAllIndexed(predicate: (Int, T) -> Boolean): Boolean {
var isChanged = false
for (index in lastIndex downTo 0) {
if (!predicate(index, this[index])) {
removeAt(index)
isChanged = true
}
}
return isChanged
}

View File

@@ -1,43 +0,0 @@
/*
* Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.server.permission.access.data
import com.android.server.permission.access.external.AndroidPackage
class Package(
private val androidPackage: AndroidPackage
) {
val name: String
get() = androidPackage.packageName
val adoptPermissions: List<String>
get() = androidPackage.adoptPermissions
val appId: Int
get() = androidPackage.appId
val requestedPermissions: List<String>
get() = androidPackage.requestedPermissions
override fun equals(other: Any?): Boolean {
throw NotImplementedError()
}
override fun hashCode(): Int {
throw NotImplementedError()
}
}

View File

@@ -1,29 +0,0 @@
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.server.permission.access.external
class CompatibilityPermissionInfo {
companion object {
val COMPAT_PERMS = arrayOf(CompatibilityPermissionInfo())
}
val name: String
get() = throw NotImplementedError()
val sdkVersion: Int
get() = throw NotImplementedError()
}

View File

@@ -1,34 +0,0 @@
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.server.permission.access.external
class KnownPackages {
companion object {
const val PACKAGE_SYSTEM = 0
const val PACKAGE_SETUP_WIZARD = 1
const val PACKAGE_INSTALLER = 2
const val PACKAGE_VERIFIER = 4
const val PACKAGE_SYSTEM_TEXT_CLASSIFIER = 6
const val PACKAGE_PERMISSION_CONTROLLER = 7
const val PACKAGE_CONFIGURATOR = 10
const val PACKAGE_INCIDENT_REPORT_APPROVER = 11
const val PACKAGE_APP_PREDICTOR = 12
const val PACKAGE_COMPANION = 15
const val PACKAGE_RETAIL_DEMO = 16
const val PACKAGE_RECENTS = 17
}
}

View File

@@ -1,33 +0,0 @@
/*
* Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.server.permission.access.external
import android.content.pm.PermissionGroupInfo
import android.content.pm.PermissionInfo
object PackageInfoUtils {
fun generatePermissionInfo(parsedPermission: ParsedPermission, flags: Long): PermissionInfo {
throw NotImplementedError()
}
fun generatePermissionGroupInfo(
parsedPermissionGroup: ParsedPermissionGroup,
flags: Long
): PermissionGroupInfo {
throw NotImplementedError()
}
}

View File

@@ -1,65 +0,0 @@
/*
* Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.server.permission.access.external
import android.util.SparseArray
interface PackageState {
val androidPackage: AndroidPackage?
val appId: Int
val isSystem: Boolean
val isUpdatedSystemApp: Boolean
val packageName: String
val userStates: SparseArray<PackageUserState>
val hasSharedUser: Boolean
val sharedUserAppId: Int
val signingDetails: SigningDetails
}
interface AndroidPackage {
val packageName: String
val apexModuleName: String?
val appId: Int
val isPrivileged: Boolean
val isOem: Boolean
val isVendor: Boolean
val isProduct: Boolean
val isSystemExt: Boolean
val targetSdkVersion: Int
val adoptPermissions: List<String>
val permissions: List<ParsedPermission>
val permissionGroups: List<ParsedPermissionGroup>
val requestedPermissions: List<String>
val implicitPermissions: List<String>
}
interface ParsedPermission {
val name: String
val isTree: Boolean
val packageName: String
val isSignature: Boolean
val protectionLevel: Int
}
interface ParsedPermissionGroup {
val name: String
val packageName: String
}
interface PackageUserState {
val isInstantApp: Boolean
}

View File

@@ -1,24 +0,0 @@
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.server.permission.access.external
class RoSystemProperties {
companion object {
const val CONTROL_PRIVAPP_PERMISSIONS_DISABLE = false
const val CONTROL_PRIVAPP_PERMISSIONS_ENFORCE = false
}
}

View File

@@ -1,42 +0,0 @@
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.server.permission.access.external
object SigningDetails {
fun hasCommonSignerWithCapability(otherDetails: SigningDetails, flags: Int): Boolean {
throw NotImplementedError()
}
fun hasAncestorOrSelf(oldDetails: SigningDetails): Boolean {
throw NotImplementedError()
}
fun checkCapability(oldDetails: SigningDetails, flags: Int): Boolean {
throw NotImplementedError()
}
fun hasAncestorOrSelfWithDigest(certDigests: Set<String>): Boolean {
throw NotImplementedError()
}
class CertCapabilities {
companion object {
/** grant SIGNATURE permissions to pkgs with this cert */
var PERMISSION = 4
}
}
}

View File

@@ -1,31 +0,0 @@
/*
* Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.server.permission.access.external
interface UserHandle {
companion object {
fun getAppId(uid: Int): Int {
throw NotImplementedError()
}
}
}
object UserHandleCompat {
fun getUserId(uid: Int): Int {
throw NotImplementedError()
}
}

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package com.android.server.permission.access.data
package com.android.server.permission.access.permission
import android.content.pm.PermissionInfo
import com.android.server.permission.access.util.hasBits

View File

@@ -27,6 +27,7 @@ object PermissionFlags {
// For the permissions that are implicit for the package
const val IMPLICIT = 1 shl 5
const val MASK_ALL = 0.inv()
const val MASK_GRANTED = INSTALL_GRANTED or PROTECTION_GRANTED or OTHER_GRANTED or ROLE_GRANTED
const val MASK_RUNTIME = OTHER_GRANTED or IMPLICIT
}

View File

@@ -33,8 +33,9 @@ import com.android.server.pm.permission.PermissionManagerServiceInterface
import com.android.server.permission.access.AccessCheckingService
import com.android.server.permission.access.PermissionUri
import com.android.server.permission.access.UidUri
import com.android.server.permission.access.data.Permission
import com.android.server.permission.access.collection.* // ktlint-disable no-wildcard-imports
import com.android.server.permission.access.util.hasBits
import com.android.server.pm.UserManagerService
import com.android.server.pm.permission.LegacyPermission
import com.android.server.pm.permission.LegacyPermissionSettings
import com.android.server.pm.permission.LegacyPermissionState
@@ -46,17 +47,24 @@ import java.io.PrintWriter
/**
* Modern implementation of [PermissionManagerServiceInterface].
*/
class ModernPermissionManagerServiceImpl(
class PermissionService(
private val service: AccessCheckingService
) : PermissionManagerServiceInterface {
private val policy =
service.getSchemePolicy(UidUri.SCHEME, PermissionUri.SCHEME) as UidPermissionPolicy
private val packageManagerInternal =
LocalServices.getService(PackageManagerInternal::class.java)
private lateinit var packageManagerInternal: PackageManagerInternal
private lateinit var packageManagerLocal: PackageManagerLocal
private lateinit var userManagerService: UserManagerService
private val packageManagerLocal =
LocalManagerRegistry.getManagerOrThrow(PackageManagerLocal::class.java)
private val mountedStorageVolumes = IndexedSet<String?>()
fun initialize() {
packageManagerInternal = LocalServices.getService(PackageManagerInternal::class.java)
packageManagerLocal =
LocalManagerRegistry.getManagerOrThrow(PackageManagerLocal::class.java)
userManagerService = UserManagerService.getInstance()
}
override fun getAllPermissionGroups(flags: Int): List<PermissionGroupInfo> {
TODO("Not yet implemented")
@@ -351,6 +359,8 @@ class ModernPermissionManagerServiceImpl(
}
override fun readLegacyPermissionsTEMP(legacyPermissionSettings: LegacyPermissionSettings) {
// Package settings has been read when this method is called.
service.initialize()
TODO("Not yet implemented")
}
@@ -375,15 +385,18 @@ class ModernPermissionManagerServiceImpl(
}
override fun onUserCreated(userId: Int) {
TODO("Not yet implemented")
service.onUserAdded(userId)
}
override fun onUserRemoved(userId: Int) {
TODO("Not yet implemented")
service.onUserRemoved(userId)
}
override fun onStorageVolumeMounted(volumeUuid: String, fingerprintChanged: Boolean) {
TODO("Not yet implemented")
service.onStorageVolumeMounted(volumeUuid, fingerprintChanged)
synchronized(mountedStorageVolumes) {
mountedStorageVolumes += volumeUuid
}
}
override fun onPackageAdded(
@@ -391,7 +404,18 @@ class ModernPermissionManagerServiceImpl(
isInstantApp: Boolean,
oldPackage: AndroidPackage?
) {
TODO("Not yet implemented")
synchronized(mountedStorageVolumes) {
if (androidPackage.volumeUuid !in mountedStorageVolumes) {
// Wait for the storage volume to be mounted and batch the state mutation there.
return
}
}
service.onPackageAdded(androidPackage.packageName)
}
override fun onPackageRemoved(androidPackage: AndroidPackage) {
// This may not be a full removal so ignored - we'll figure out full removal in
// onPackageUninstalled().
}
override fun onPackageInstalled(
@@ -400,21 +424,37 @@ class ModernPermissionManagerServiceImpl(
params: PermissionManagerServiceInternal.PackageInstalledParams,
userId: Int
) {
TODO("Not yet implemented")
synchronized(mountedStorageVolumes) {
if (androidPackage.volumeUuid !in mountedStorageVolumes) {
// Wait for the storage volume to be mounted and batch the state mutation there.
return
}
}
val userIds = if (userId == UserHandle.USER_ALL) {
userManagerService.userIdsIncludingPreCreated
} else {
intArrayOf(userId)
}
userIds.forEach { service.onPackageInstalled(androidPackage.packageName, params, it) }
}
override fun onPackageUninstalled(
packageName: String,
appId: Int,
androidPackage: AndroidPackage?,
sharedUserPkgs: MutableList<AndroidPackage>,
sharedUserPkgs: List<AndroidPackage>,
userId: Int
) {
TODO("Not yet implemented")
}
override fun onPackageRemoved(androidPackage: AndroidPackage) {
TODO("Not yet implemented")
val userIds = if (userId == UserHandle.USER_ALL) {
userManagerService.userIdsIncludingPreCreated
} else {
intArrayOf(userId)
}
userIds.forEach { service.onPackageUninstalled(packageName, appId, it) }
val packageState = packageManagerInternal.packageStates[packageName]
if (packageState == null) {
service.onPackageRemoved(packageName, appId)
}
}
/**

View File

@@ -22,7 +22,6 @@ import com.android.modules.utils.BinaryXmlPullParser
import com.android.modules.utils.BinaryXmlSerializer
import com.android.server.permission.access.SystemState
import com.android.server.permission.access.collection.* // ktlint-disable no-wildcard-imports
import com.android.server.permission.access.data.Permission
import com.android.server.permission.access.util.attribute
import com.android.server.permission.access.util.attributeInt
import com.android.server.permission.access.util.attributeIntHex

View File

@@ -20,9 +20,11 @@ import android.Manifest
import android.content.pm.PackageManager
import android.content.pm.PermissionGroupInfo
import android.content.pm.PermissionInfo
import android.content.pm.SigningDetails
import android.os.Build
import android.os.UserHandle
import android.util.Log
import com.android.internal.os.RoSystemProperties
import com.android.modules.utils.BinaryXmlPullParser
import com.android.modules.utils.BinaryXmlSerializer
import com.android.server.permission.access.AccessState
@@ -33,22 +35,24 @@ import com.android.server.permission.access.PermissionUri
import com.android.server.permission.access.SchemePolicy
import com.android.server.permission.access.SystemState
import com.android.server.permission.access.UidUri
import com.android.server.permission.access.UserState
import com.android.server.permission.access.collection.* // ktlint-disable no-wildcard-imports
import com.android.server.permission.access.data.Permission
import com.android.server.permission.access.external.AndroidPackage
import com.android.server.permission.access.external.CompatibilityPermissionInfo
import com.android.server.permission.access.external.KnownPackages
import com.android.server.permission.access.external.PackageInfoUtils
import com.android.server.permission.access.external.PackageState
import com.android.server.permission.access.external.RoSystemProperties
import com.android.server.permission.access.external.SigningDetails
import com.android.server.permission.access.util.andInv
import com.android.server.permission.access.util.hasAnyBit
import com.android.server.permission.access.util.hasBits
import com.android.server.pm.KnownPackages
import com.android.server.pm.parsing.PackageInfoUtils
import com.android.server.pm.permission.CompatibilityPermissionInfo
import com.android.server.pm.pkg.AndroidPackage
import com.android.server.pm.pkg.PackageState
class UidPermissionPolicy : SchemePolicy() {
private val persistence = UidPermissionPersistence()
@Volatile
private var onPermissionFlagsChangedListeners =
IndexedListSet<OnPermissionFlagsChangedListener>()
private val onPermissionFlagsChangedListenersLock = Any()
override val subjectScheme: String
get() = UidUri.SCHEME
@@ -58,8 +62,7 @@ class UidPermissionPolicy : SchemePolicy() {
override fun GetStateScope.getDecision(subject: AccessUri, `object`: AccessUri): Int {
subject as UidUri
`object` as PermissionUri
return state.userStates[subject.userId]?.permissionFlags?.get(subject.appId)
?.get(`object`.permissionName) ?: 0
return getPermissionFlags(subject.appId, subject.userId, `object`.permissionName)
}
override fun MutateStateScope.setDecision(
@@ -69,26 +72,22 @@ class UidPermissionPolicy : SchemePolicy() {
) {
subject as UidUri
`object` as PermissionUri
val uidFlags = newState.userStates.getOrPut(subject.userId) { UserState() }
.permissionFlags.getOrPut(subject.appId) { IndexedMap() }
uidFlags[`object`.permissionName] = decision
setPermissionFlags(subject.appId, subject.userId, `object`.permissionName, decision)
}
override fun MutateStateScope.onUserAdded(userId: Int) {
newState.systemState.packageStates.forEachValueIndexed { _, packageState ->
evaluateAllPermissionStatesForPackageAndUser(packageState, null, userId)
newState.systemState.packageStates.forEach { (_, packageState) ->
evaluateAllPermissionStatesForPackageAndUser(packageState, userId, null)
grantImplicitPermissions(packageState, userId)
}
}
override fun MutateStateScope.onAppIdAdded(appId: Int) {
newState.userStates.forEachIndexed { _, _, userState ->
userState.permissionFlags.getOrPut(appId) { IndexedMap() }
}
}
override fun MutateStateScope.onAppIdRemoved(appId: Int) {
newState.userStates.forEachIndexed { _, _, userState -> userState.permissionFlags -= appId }
newState.userStates.forEachValueIndexed { _, userState ->
userState.uidPermissionFlags -= appId
userState.requestWrite()
// Skip notifying the change listeners since the app ID no longer exists.
}
}
override fun MutateStateScope.onPackageAdded(packageState: PackageState) {
@@ -97,7 +96,7 @@ class UidPermissionPolicy : SchemePolicy() {
addPermissionGroups(packageState)
addPermissions(packageState, changedPermissionNames)
// TODO: revokeStoragePermissionsIfScopeExpandedInternal()
trimPermissions(packageState.packageName)
trimPermissions(packageState.packageName, changedPermissionNames)
changedPermissionNames.forEachIndexed { _, permissionName ->
evaluatePermissionStateForAllPackages(permissionName, packageState)
}
@@ -121,22 +120,23 @@ class UidPermissionPolicy : SchemePolicy() {
if (!canAdoptPermissions(packageName, originalPackageName)) {
return@forEachIndexed
}
newState.systemState.permissions.let { permissions ->
permissions.forEachIndexed permissions@ {
permissionIndex, permissionName, oldPermission ->
if (oldPermission.packageName != originalPackageName) {
return@permissions
}
@Suppress("DEPRECATION")
val newPermissionInfo = PermissionInfo().apply {
name = oldPermission.permissionInfo.name
this.packageName = packageName
protectionLevel = oldPermission.permissionInfo.protectionLevel
}
val newPermission = Permission(newPermissionInfo, false, oldPermission.type, 0)
changedPermissionNames += permissionName
permissions.setValueAt(permissionIndex, newPermission)
val systemState = newState.systemState
val permissions = systemState.permissions
permissions.forEachIndexed permissions@ {
permissionIndex, permissionName, oldPermission ->
if (oldPermission.packageName != originalPackageName) {
return@permissions
}
@Suppress("DEPRECATION")
val newPermissionInfo = PermissionInfo().apply {
name = oldPermission.permissionInfo.name
this.packageName = packageName
protectionLevel = oldPermission.permissionInfo.protectionLevel
}
val newPermission = Permission(newPermissionInfo, false, oldPermission.type, 0)
permissions.setValueAt(permissionIndex, newPermission)
systemState.requestWrite()
changedPermissionNames += permissionName
}
}
}
@@ -179,7 +179,7 @@ class UidPermissionPolicy : SchemePolicy() {
packageState.androidPackage!!.permissionGroups.forEachIndexed { _, parsedPermissionGroup ->
val newPermissionGroup = PackageInfoUtils.generatePermissionGroupInfo(
parsedPermissionGroup, PackageManager.GET_META_DATA.toLong()
)
)!!
// TODO: Clear permission state on group take-over?
val permissionGroupName = newPermissionGroup.name
val oldPermissionGroup = newState.systemState.permissionGroups[permissionGroupName]
@@ -211,13 +211,14 @@ class UidPermissionPolicy : SchemePolicy() {
// }
val newPermissionInfo = PackageInfoUtils.generatePermissionInfo(
parsedPermission, PackageManager.GET_META_DATA.toLong()
)
)!!
// TODO: newPermissionInfo.flags |= PermissionInfo.FLAG_INSTALLED
val systemState = newState.systemState
val permissionName = newPermissionInfo.name
val oldPermission = if (parsedPermission.isTree) {
newState.systemState.permissionTrees[permissionName]
systemState.permissionTrees[permissionName]
} else {
newState.systemState.permissions[permissionName]
systemState.permissions[permissionName]
}
// Different from the old implementation, which may add an (incomplete) signature
// permission inside another package's permission tree, we now consistently ignore such
@@ -247,19 +248,18 @@ class UidPermissionPolicy : SchemePolicy() {
if (oldPermission.type == Permission.TYPE_CONFIG && !oldPermission.isReconciled) {
// It's a config permission and has no owner, take ownership now.
Permission(newPermissionInfo, true, Permission.TYPE_CONFIG, packageState.appId)
} else if (newState.systemState.packageStates[oldPackageName]?.isSystem != true) {
} else if (systemState.packageStates[oldPackageName]?.isSystem != true) {
Log.w(
LOG_TAG, "Overriding permission $permissionName with new declaration in" +
" system package $newPackageName: originally declared in another" +
" package $oldPackageName"
)
// Remove permission state on owner change.
newState.userStates.forEachValueIndexed { _, userState ->
userState.permissionFlags.forEachValueIndexed { _, permissionFlags ->
permissionFlags -= newPermissionInfo.name
systemState.userIds.forEachIndexed { _, userId ->
systemState.appIds.forEachKeyIndexed { _, appId ->
setPermissionFlags(appId, userId, permissionName, 0)
}
}
// TODO: Notify re-evaluation of this permission.
Permission(
newPermissionInfo, true, Permission.TYPE_MANIFEST, packageState.appId
)
@@ -278,23 +278,28 @@ class UidPermissionPolicy : SchemePolicy() {
Permission(newPermissionInfo, true, Permission.TYPE_MANIFEST, packageState.appId)
}
changedPermissionNames += permissionName
if (parsedPermission.isTree) {
newState.systemState.permissionTrees[permissionName] = newPermission
systemState.permissionTrees[permissionName] = newPermission
} else {
newState.systemState.permissions[permissionName] = newPermission
systemState.permissions[permissionName] = newPermission
}
systemState.requestWrite()
changedPermissionNames += permissionName
}
}
private fun MutateStateScope.trimPermissions(packageName: String) {
val packageState = newState.systemState.packageStates[packageName]
private fun MutateStateScope.trimPermissions(
packageName: String,
changedPermissionNames: IndexedSet<String>
) {
val systemState = newState.systemState
val packageState = systemState.packageStates[packageName]
val androidPackage = packageState?.androidPackage
if (packageState != null && androidPackage == null) {
return
}
newState.systemState.permissionTrees.removeAllIndexed {
val isPermissionTreeRemoved = systemState.permissionTrees.removeAllIndexed {
_, permissionTreeName, permissionTree ->
permissionTree.packageName == packageName && (
packageState == null || androidPackage!!.permissions.noneIndexed { _, it ->
@@ -302,26 +307,30 @@ class UidPermissionPolicy : SchemePolicy() {
}
)
}
if (isPermissionTreeRemoved) {
systemState.requestWrite()
}
newState.systemState.permissions.removeAllIndexed { i, permissionName, permission ->
systemState.permissions.removeAllIndexed { permissionIndex, permissionName, permission ->
val updatedPermission = updatePermissionIfDynamic(permission)
newState.systemState.permissions.setValueAt(i, updatedPermission)
newState.systemState.permissions.setValueAt(permissionIndex, updatedPermission)
if (updatedPermission.packageName == packageName && (
packageState == null || androidPackage!!.permissions.noneIndexed { _, it ->
!it.isTree && it.name == permissionName
}
)) {
if (!isPermissionDeclaredByDisabledSystemPackage(permission)) {
newState.userStates.forEachIndexed { _, userId, userState ->
userState.permissionFlags.forEachKeyIndexed { _, appId ->
setPermissionFlags(
appId, permissionName, getPermissionFlags(
appId, permissionName, userId
) and PermissionFlags.INSTALL_REVOKED, userId
)
}
// Different from the old implementation where we keep the permission state if the
// permission is declared by a disabled system package (ag/15189282), we now
// shouldn't be notified when the updated system package is removed but the disabled
// system package isn't re-enabled yet, so we don't need to maintain that brittle
// special case either.
systemState.userIds.forEachIndexed { _, userId ->
systemState.appIds.forEachKeyIndexed { _, appId ->
setPermissionFlags(appId, userId, permissionName, 0)
}
}
changedPermissionNames += permissionName
systemState.requestWrite()
true
} else {
false
@@ -329,16 +338,6 @@ class UidPermissionPolicy : SchemePolicy() {
}
}
private fun MutateStateScope.isPermissionDeclaredByDisabledSystemPackage(
permission: Permission
): Boolean {
val disabledSystemPackage = newState.systemState
.disabledSystemPackageStates[permission.packageName]?.androidPackage ?: return false
return disabledSystemPackage.permissions.anyIndexed { _, it ->
it.name == permission.name && it.protectionLevel == permission.protectionLevel
}
}
private fun MutateStateScope.updatePermissionIfDynamic(permission: Permission): Permission {
if (!permission.isDynamic) {
return permission
@@ -368,11 +367,14 @@ class UidPermissionPolicy : SchemePolicy() {
permissionName: String,
installedPackageState: PackageState?
) {
newState.systemState.userIds.forEachIndexed { _, userId ->
oldState.userStates[userId]?.permissionFlags?.forEachIndexed {
_, appId, permissionFlags ->
if (permissionName in permissionFlags) {
evaluatePermissionState(appId, permissionName, installedPackageState, userId)
val systemState = newState.systemState
systemState.userIds.forEachIndexed { _, userId ->
systemState.appIds.forEachKeyIndexed { _, appId ->
val isPermissionRequested = anyPackageInAppId(appId) { packageState ->
permissionName in packageState.androidPackage!!.requestedPermissions
}
if (isPermissionRequested) {
evaluatePermissionState(appId, userId, permissionName, installedPackageState)
}
}
}
@@ -384,28 +386,28 @@ class UidPermissionPolicy : SchemePolicy() {
) {
newState.systemState.userIds.forEachIndexed { _, userId ->
evaluateAllPermissionStatesForPackageAndUser(
packageState, installedPackageState, userId
packageState, userId, installedPackageState
)
}
}
private fun MutateStateScope.evaluateAllPermissionStatesForPackageAndUser(
packageState: PackageState,
installedPackageState: PackageState?,
userId: Int
userId: Int,
installedPackageState: PackageState?
) {
packageState.androidPackage?.requestedPermissions?.forEachIndexed { _, permissionName ->
evaluatePermissionState(
packageState.appId, permissionName, installedPackageState, userId
packageState.appId, userId, permissionName, installedPackageState
)
}
}
private fun MutateStateScope.evaluatePermissionState(
appId: Int,
userId: Int,
permissionName: String,
installedPackageState: PackageState?,
userId: Int
installedPackageState: PackageState?
) {
val packageNames = newState.systemState.appIds[appId]
val hasMissingPackage = packageNames.anyIndexed { _, packageName ->
@@ -416,7 +418,7 @@ class UidPermissionPolicy : SchemePolicy() {
return
}
val permission = newState.systemState.permissions[permissionName] ?: return
val oldFlags = getPermissionFlags(appId, permissionName, userId)
val oldFlags = getPermissionFlags(appId, userId, permissionName)
if (permission.isNormal) {
val wasGranted = oldFlags.hasBits(PermissionFlags.INSTALL_GRANTED)
if (!wasGranted) {
@@ -438,7 +440,7 @@ class UidPermissionPolicy : SchemePolicy() {
} else {
PermissionFlags.INSTALL_REVOKED
}
setPermissionFlags(appId, permissionName, newFlags, userId)
setPermissionFlags(appId, userId, permissionName, newFlags)
}
} else if (permission.isSignature || permission.isInternal) {
val wasProtectionGranted = oldFlags.hasBits(PermissionFlags.PROTECTION_GRANTED)
@@ -477,7 +479,7 @@ class UidPermissionPolicy : SchemePolicy() {
if (permission.isRole) {
newFlags = newFlags or (oldFlags and PermissionFlags.ROLE_GRANTED)
}
setPermissionFlags(appId, permissionName, newFlags, userId)
setPermissionFlags(appId, userId, permissionName, newFlags)
} else if (permission.isRuntime) {
// TODO: add runtime permissions
} else {
@@ -503,7 +505,7 @@ class UidPermissionPolicy : SchemePolicy() {
}
// Explicitly check against the old state to determine if this permission is new.
val isNewPermission = getPermissionFlags(
appId, implicitPermissionName, userId, oldState
appId, userId, implicitPermissionName, oldState
) == 0
if (!isNewPermission) {
return@implicitPermissions
@@ -516,7 +518,7 @@ class UidPermissionPolicy : SchemePolicy() {
checkNotNull(sourcePermission) {
"Unknown source permission $sourcePermissionName in split permissions"
}
val sourceFlags = getPermissionFlags(appId, sourcePermissionName, userId)
val sourceFlags = getPermissionFlags(appId, userId, sourcePermissionName)
val isSourceGranted = sourceFlags.hasAnyBit(PermissionFlags.MASK_GRANTED)
val isNewGranted = newFlags.hasAnyBit(PermissionFlags.MASK_GRANTED)
val isGrantingNewFromRevoke = isSourceGranted && !isNewGranted
@@ -531,27 +533,10 @@ class UidPermissionPolicy : SchemePolicy() {
}
}
newFlags = newFlags or PermissionFlags.IMPLICIT
setPermissionFlags(appId, implicitPermissionName, newFlags, userId)
setPermissionFlags(appId, userId, implicitPermissionName, newFlags)
}
}
private fun MutateStateScope.getPermissionFlags(
appId: Int,
permissionName: String,
userId: Int,
state: AccessState = newState
): Int = state.userStates[userId].permissionFlags[appId].getWithDefault(permissionName, 0)
private fun MutateStateScope.setPermissionFlags(
appId: Int,
permissionName: String,
flags: Int,
userId: Int
) {
newState.userStates[userId].permissionFlags[appId]!!
.putWithDefault(permissionName, flags, 0)
}
private fun isCompatibilityPermissionForPackage(
androidPackage: AndroidPackage,
permissionName: String
@@ -573,23 +558,24 @@ class UidPermissionPolicy : SchemePolicy() {
packageState: PackageState,
permission: Permission
): Boolean {
// check if the package is allow to use this signature permission. A package is allowed to
// use a signature permission if:
// - it has the same set of signing certificates as the source package
// - or its signing certificate was rotated from the source package's certificate
// - or its signing certificate is a previous signing certificate of the defining
// package, and the defining package still trusts the old certificate for permissions
// - or it shares a common signing certificate in its lineage with the defining package,
// and the defining package still trusts the old certificate for permissions
// - or it shares the above relationships with the system package
// Check if the package is allowed to use this signature permission. A package is allowed
// to use a signature permission if:
// - it has the same set of signing certificates as the source package
// - or its signing certificate was rotated from the source package's certificate
// - or its signing certificate is a previous signing certificate of the defining
// package, and the defining package still trusts the old certificate for permissions
// - or it shares a common signing certificate in its lineage with the defining package,
// and the defining package still trusts the old certificate for permissions
// - or it shares the above relationships with the system package
val packageSigningDetails = packageState.androidPackage!!.signingDetails
val sourceSigningDetails = newState.systemState
.packageStates[permission.packageName]?.signingDetails
.packageStates[permission.packageName]?.androidPackage?.signingDetails
val platformSigningDetails = newState.systemState
.packageStates[PLATFORM_PACKAGE_NAME]!!.signingDetails
return sourceSigningDetails?.hasCommonSignerWithCapability(packageState.signingDetails,
.packageStates[PLATFORM_PACKAGE_NAME]!!.androidPackage!!.signingDetails
return sourceSigningDetails?.hasCommonSignerWithCapability(packageSigningDetails,
SigningDetails.CertCapabilities.PERMISSION) == true ||
packageState.signingDetails.hasAncestorOrSelf(platformSigningDetails) ||
platformSigningDetails.checkCapability(packageState.signingDetails,
packageSigningDetails.hasAncestorOrSelf(platformSigningDetails) ||
platformSigningDetails.checkCapability(packageSigningDetails,
SigningDetails.CertCapabilities.PERMISSION)
}
@@ -629,7 +615,10 @@ class UidPermissionPolicy : SchemePolicy() {
androidPackage: AndroidPackage,
permissionName: String
): Boolean {
val apexModuleName = androidPackage.apexModuleName
// TODO(b/261913353): STOPSHIP: Add AndroidPackage.apexModuleName. The below is only for
// passing compilation but won't actually work.
//val apexModuleName = androidPackage.apexModuleName
val apexModuleName = androidPackage.packageName
val systemState = newState.systemState
val packageName = androidPackage.packageName
val permissionNames = when {
@@ -657,7 +646,10 @@ class UidPermissionPolicy : SchemePolicy() {
): Boolean {
// Different from the previous implementation, which may incorrectly use the APEX package
// name, we now use the APEX module name to be consistent with the allowlist.
val apexModuleName = androidPackage.apexModuleName
// TODO(b/261913353): STOPSHIP: Add AndroidPackage.apexModuleName. The below is only for
// passing compilation but won't actually work.
//val apexModuleName = androidPackage.apexModuleName
val apexModuleName = androidPackage.packageName
val systemState = newState.systemState
val packageName = androidPackage.packageName
val permissionNames = when {
@@ -741,7 +733,7 @@ class UidPermissionPolicy : SchemePolicy() {
return true
}
if (permission.isKnownSigner &&
packageState.signingDetails.hasAncestorOrSelfWithDigest(permission.knownCerts)) {
androidPackage.signingDetails.hasAncestorOrSelfWithDigest(permission.knownCerts)) {
// If the permission is to be granted to a known signer then check if any of this
// app's signing certificates are in the trusted certificate digest Set.
return true
@@ -840,8 +832,11 @@ class UidPermissionPolicy : SchemePolicy() {
return uid == ownerUid
}
override fun MutateStateScope.onPackageRemoved(packageState: PackageState) {
// TODO
override fun MutateStateScope.onPackageRemoved(packageName: String, appId: Int) {
// TODO: STOPSHIP: Remove this check or at least turn into logging.
check(packageName !in newState.systemState.disabledSystemPackageStates) {
"Package $packageName reported as removed before disabled system package is enabled"
}
}
override fun BinaryXmlPullParser.parseSystemState(systemState: SystemState) {
@@ -858,6 +853,76 @@ class UidPermissionPolicy : SchemePolicy() {
fun GetStateScope.getPermission(permissionName: String): Permission? =
state.systemState.permissions[permissionName]
fun GetStateScope.getPermissionFlags(
appId: Int,
userId: Int,
permissionName: String
): Int = getPermissionFlags(state, appId, userId, permissionName)
private fun MutateStateScope.getPermissionFlags(
appId: Int,
userId: Int,
permissionName: String,
state: AccessState = newState
): Int = getPermissionFlags(state, appId, userId, permissionName)
private fun getPermissionFlags(
state: AccessState,
appId: Int,
userId: Int,
permissionName: String
): Int = state.userStates[userId].uidPermissionFlags[appId].getWithDefault(permissionName, 0)
fun MutateStateScope.setPermissionFlags(
appId: Int,
userId: Int,
permissionName: String,
flags: Int
): Boolean =
updatePermissionFlags(appId, userId, permissionName, PermissionFlags.MASK_ALL, flags)
fun MutateStateScope.updatePermissionFlags(
appId: Int,
userId: Int,
permissionName: String,
flagMask: Int,
flagValues: Int
): Boolean {
val userState = newState.userStates[userId]
val uidPermissionFlags = userState.uidPermissionFlags
var permissionFlags = uidPermissionFlags[appId]
val oldFlags = permissionFlags.getWithDefault(permissionName, 0)
val newFlags = (oldFlags andInv flagMask) or flagValues
if (oldFlags == newFlags) {
return false
}
if (permissionFlags == null) {
permissionFlags = IndexedMap()
uidPermissionFlags[appId] = permissionFlags
}
permissionFlags.putWithDefault(permissionName, newFlags, 0)
if (permissionFlags.isEmpty()) {
uidPermissionFlags -= appId
}
userState.requestWrite()
onPermissionFlagsChangedListeners.forEachIndexed { _, it ->
it.onPermissionFlagsChanged(appId, userId, permissionName, oldFlags, newFlags)
}
return true
}
fun addOnPermissionFlagsChangedListener(listener: OnPermissionFlagsChangedListener) {
synchronized(onPermissionFlagsChangedListenersLock) {
onPermissionFlagsChangedListeners = onPermissionFlagsChangedListeners + listener
}
}
fun removeOnPermissionFlagsChangedListener(listener: OnPermissionFlagsChangedListener) {
synchronized(onPermissionFlagsChangedListenersLock) {
onPermissionFlagsChangedListeners = onPermissionFlagsChangedListeners - listener
}
}
companion object {
private val LOG_TAG = UidPermissionPolicy::class.java.simpleName
@@ -872,4 +937,14 @@ class UidPermissionPolicy : SchemePolicy() {
Manifest.permission.READ_MEDIA_VIDEO,
)
}
fun interface OnPermissionFlagsChangedListener {
fun onPermissionFlagsChanged(
appId: Int,
userId: Int,
permissionName: String,
oldFlags: Int,
newFlags: Int
)
}
}