Add ModernPermissionManagerServiceImpl skeleton and two methods.

Also allow compatibility layer to talk to policy directly by
introducing scopes for getting and mutating state, because
compatibility layer shouldn't have direct access to states, while
scope also allows getting rid of a lot of boilerplate for passing
states around.

Bug: 182523293
Test: presubmit
Change-Id: I36f53383c261b51372178d8c183c190bdb3c7132
This commit is contained in:
Hai Zhang
2022-12-04 01:47:19 -08:00
parent 3fe1511378
commit 6faa4aaafa
15 changed files with 696 additions and 261 deletions

View File

@@ -467,7 +467,7 @@ public class PermissionManagerService extends IPermissionManager.Stub {
@Override
public PermissionInfo getPermissionInfo(String permissionName, String packageName, int flags) {
return mPermissionManagerServiceImpl.getPermissionInfo(permissionName, packageName, flags);
return mPermissionManagerServiceImpl.getPermissionInfo(permissionName, flags, packageName);
}
@Override
@@ -792,14 +792,14 @@ public class PermissionManagerService extends IPermissionManager.Stub {
@NonNull
@Override
public ArrayList<PermissionInfo> getAllPermissionsWithProtection(
public List<PermissionInfo> getAllPermissionsWithProtection(
@PermissionInfo.Protection int protection) {
return mPermissionManagerServiceImpl.getAllPermissionsWithProtection(protection);
}
@NonNull
@Override
public ArrayList<PermissionInfo> getAllPermissionsWithProtectionFlags(
public List<PermissionInfo> getAllPermissionsWithProtectionFlags(
@PermissionInfo.ProtectionFlags int protectionFlags) {
return mPermissionManagerServiceImpl
.getAllPermissionsWithProtectionFlags(protectionFlags);

View File

@@ -559,8 +559,8 @@ public class PermissionManagerServiceImpl implements PermissionManagerServiceInt
@Override
@Nullable
public PermissionInfo getPermissionInfo(@NonNull String permName, @NonNull String opPackageName,
@PackageManager.PermissionInfoFlags int flags) {
public PermissionInfo getPermissionInfo(@NonNull String permName,
@PackageManager.PermissionInfoFlags int flags, @NonNull String opPackageName) {
final int callingUid = Binder.getCallingUid();
if (mPackageManagerInt.getInstantAppPackageName(callingUid) != null) {
return null;
@@ -2127,7 +2127,7 @@ public class PermissionManagerServiceImpl implements PermissionManagerServiceInt
for (int i = 0; i < numRequestedPermissions; i++) {
PermissionInfo permInfo = getPermissionInfo(
newPackage.getRequestedPermissions().get(i),
newPackage.getPackageName(), 0);
0, newPackage.getPackageName());
if (permInfo == null) {
continue;
}
@@ -5204,9 +5204,9 @@ public class PermissionManagerServiceImpl implements PermissionManagerServiceInt
@NonNull
@Override
public ArrayList<PermissionInfo> getAllPermissionsWithProtection(
public List<PermissionInfo> getAllPermissionsWithProtection(
@PermissionInfo.Protection int protection) {
ArrayList<PermissionInfo> matchingPermissions = new ArrayList<>();
List<PermissionInfo> matchingPermissions = new ArrayList<>();
synchronized (mLock) {
for (final Permission permission : mRegistry.getPermissions()) {
@@ -5221,9 +5221,9 @@ public class PermissionManagerServiceImpl implements PermissionManagerServiceInt
@NonNull
@Override
public ArrayList<PermissionInfo> getAllPermissionsWithProtectionFlags(
public List<PermissionInfo> getAllPermissionsWithProtectionFlags(
@PermissionInfo.ProtectionFlags int protectionFlags) {
ArrayList<PermissionInfo> matchingPermissions = new ArrayList<>();
List<PermissionInfo> matchingPermissions = new ArrayList<>();
synchronized (mLock) {
for (final Permission permission : mRegistry.getPermissions()) {

View File

@@ -32,7 +32,6 @@ import com.android.server.pm.pkg.AndroidPackage;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -77,8 +76,8 @@ public interface PermissionManagerServiceInterface extends PermissionManagerInte
* @return a {@link PermissionInfo} containing information about the permission, or {@code null}
* if not found
*/
PermissionInfo getPermissionInfo(@NonNull String permName, @NonNull String opPackageName,
@PackageManager.PermissionInfoFlags int flags);
PermissionInfo getPermissionInfo(@NonNull String permName,
@PackageManager.PermissionInfoFlags int flags, @NonNull String opPackageName);
/**
* Query for all of the permissions associated with a particular group.
@@ -487,11 +486,11 @@ public interface PermissionManagerServiceInterface extends PermissionManagerInte
/** Get all permissions that have a certain protection */
@NonNull
ArrayList<PermissionInfo> getAllPermissionsWithProtection(
List<PermissionInfo> getAllPermissionsWithProtection(
@PermissionInfo.Protection int protection);
/** Get all permissions that have certain protection flags */
@NonNull ArrayList<PermissionInfo> getAllPermissionsWithProtectionFlags(
@NonNull List<PermissionInfo> getAllPermissionsWithProtectionFlags(
@PermissionInfo.ProtectionFlags int protectionFlags);
/**

View File

@@ -164,11 +164,12 @@ public interface PermissionManagerServiceInternal extends PermissionManagerInter
/** Get all permissions that have a certain protection */
@NonNull
ArrayList<PermissionInfo> getAllPermissionsWithProtection(
List<PermissionInfo> getAllPermissionsWithProtection(
@PermissionInfo.Protection int protection);
/** Get all permissions that have certain protection flags */
@NonNull ArrayList<PermissionInfo> getAllPermissionsWithProtectionFlags(
/** Get all permissions that have certain protection flags
* @return*/
@NonNull List<PermissionInfo> getAllPermissionsWithProtectionFlags(
@PermissionInfo.ProtectionFlags int protectionFlags);
/**

View File

@@ -232,7 +232,7 @@ public final class PermissionPolicyService extends SystemService {
}
};
final ArrayList<PermissionInfo> dangerousPerms =
final List<PermissionInfo> dangerousPerms =
mPermissionManagerInternal.getAllPermissionsWithProtection(
PermissionInfo.PROTECTION_DANGEROUS);
try {

View File

@@ -29,6 +29,8 @@ java_library_static {
],
static_libs: [
"kotlin-stdlib",
// Adds reflection-less suppressed exceptions and AutoCloseable.use().
"kotlin-stdlib-jdk7",
],
jarjar_rules: "jarjar-rules.txt",
kotlincflags: [

View File

@@ -40,46 +40,53 @@ class AccessCheckingService {
}
fun getDecision(subject: AccessUri, `object`: AccessUri): Int =
policy.getDecision(subject, `object`, state)
getState {
with(policy) { getDecision(subject, `object`) }
}
fun setDecision(subject: AccessUri, `object`: AccessUri, decision: Int) {
mutateState { oldState, newState ->
policy.setDecision(subject, `object`, decision, oldState, newState)
mutateState {
with(policy) { setDecision(subject, `object`, decision) }
}
}
fun onUserAdded(userId: Int) {
mutateState { oldState, newState ->
policy.onUserAdded(userId, oldState, newState)
mutateState {
with(policy) { onUserAdded(userId) }
}
}
fun onUserRemoved(userId: Int) {
mutateState { oldState, newState ->
policy.onUserRemoved(userId, oldState, newState)
mutateState {
with(policy) { onUserRemoved(userId) }
}
}
fun onPackageAdded(packageState: PackageState) {
mutateState { oldState, newState ->
policy.onPackageAdded(packageState, oldState, newState)
mutateState {
with(policy) { onPackageAdded(packageState) }
}
}
fun onPackageRemoved(packageState: PackageState) {
mutateState { oldState, newState ->
policy.onPackageRemoved(packageState, oldState, newState)
mutateState {
with(policy) { onPackageRemoved(packageState) }
}
}
// TODO: Replace (oldState, newState) with Kotlin context receiver once it's stabilized.
private inline fun mutateState(action: (oldState: AccessState, newState: AccessState) -> Unit) {
internal inline fun <T> getState(action: GetStateScope.() -> T): T =
GetStateScope(state).action()
internal inline fun mutateState(action: MutateStateScope.() -> Unit) {
synchronized(stateLock) {
val oldState = state
val newState = oldState.copy()
action(oldState, newState)
MutateStateScope(oldState, newState).action()
persistence.write(newState)
state = newState
}
}
internal fun getSchemePolicy(subjectScheme: String, objectScheme: String): SchemePolicy =
policy.getSchemePolicy(subjectScheme, objectScheme)
}

View File

@@ -44,13 +44,13 @@ class AccessPersistence(
systemFile.parse {
// This is the canonical way to call an extension function in a different class.
// TODO(b/259469752): Use context receiver for this when it becomes stable.
with(policy) { this@parse.parseSystemState(systemState) }
with(policy) { parseSystemState(systemState) }
}
}
private fun readUserState(userId: Int, userState: UserState) {
getUserFile(userId).parse {
with(policy) { this@parse.parseUserState(userId, userState) }
with(policy) { parseUserState(userId, userState) }
}
}
@@ -82,13 +82,13 @@ class AccessPersistence(
private fun writeSystemState(systemState: SystemState) {
systemFile.serialize {
with(policy) { this@serialize.serializeSystemState(systemState) }
with(policy) { serializeSystemState(systemState) }
}
}
private fun writeUserState(userId: Int, userState: UserState) {
getUserFile(userId).serialize {
with(policy) { this@serialize.serializeUserState(userId, userState) }
with(policy) { serializeUserState(userId, userState) }
}
}

View File

@@ -41,38 +41,35 @@ class AccessPolicy private constructor(
}
)
fun getDecision(subject: AccessUri, `object`: AccessUri, state: AccessState): Int =
getSchemePolicy(subject, `object`).getDecision(subject, `object`, state)
fun setDecision(
subject: AccessUri,
`object`: AccessUri,
decision: Int,
oldState: AccessState,
newState: AccessState
) {
getSchemePolicy(subject, `object`)
.setDecision(subject, `object`, decision, oldState, newState)
}
private fun getSchemePolicy(subject: AccessUri, `object`: AccessUri): SchemePolicy =
checkNotNull(schemePolicies[subject.scheme]?.get(`object`.scheme)) {
"Scheme policy for subject=$subject object=$`object` does not exist"
fun getSchemePolicy(subjectScheme: String, objectScheme: String): SchemePolicy =
checkNotNull(schemePolicies[subjectScheme]?.get(objectScheme)) {
"Scheme policy for $subjectScheme and $objectScheme does not exist"
}
fun onUserAdded(userId: Int, oldState: AccessState, newState: AccessState) {
fun GetStateScope.getDecision(subject: AccessUri, `object`: AccessUri): Int =
with(getSchemePolicy(subject, `object`)){ getDecision(subject, `object`) }
fun MutateStateScope.setDecision(subject: AccessUri, `object`: AccessUri, decision: Int) {
with(getSchemePolicy(subject, `object`)) { setDecision(subject, `object`, decision) }
}
fun MutateStateScope.onUserAdded(userId: Int) {
newState.systemState.userIds += userId
newState.userStates[userId] = UserState()
forEachSchemePolicy { it.onUserAdded(userId, oldState, newState) }
forEachSchemePolicy {
with(it) { onUserAdded(userId) }
}
}
fun onUserRemoved(userId: Int, oldState: AccessState, newState: AccessState) {
fun MutateStateScope.onUserRemoved(userId: Int) {
newState.systemState.userIds -= userId
newState.userStates -= userId
forEachSchemePolicy { it.onUserRemoved(userId, oldState, newState) }
forEachSchemePolicy {
with(it) { onUserRemoved(userId) }
}
}
fun onPackageAdded(packageState: PackageState, oldState: AccessState, newState: AccessState) {
fun MutateStateScope.onPackageAdded(packageState: PackageState) {
var isAppIdAdded = false
newState.systemState.apply {
packageStates[packageState.packageName] = packageState
@@ -82,12 +79,16 @@ class AccessPolicy private constructor(
}.add(packageState.packageName)
}
if (isAppIdAdded) {
forEachSchemePolicy { it.onAppIdAdded(packageState.appId, oldState, newState) }
forEachSchemePolicy {
with(it) { onAppIdAdded(packageState.appId) }
}
}
forEachSchemePolicy {
with(it) { onPackageAdded(packageState) }
}
forEachSchemePolicy { it.onPackageAdded(packageState, oldState, newState) }
}
fun onPackageRemoved(packageState: PackageState, oldState: AccessState, newState: AccessState) {
fun MutateStateScope.onPackageRemoved(packageState: PackageState) {
var isAppIdRemoved = false
newState.systemState.apply {
packageStates -= packageState.packageName
@@ -101,9 +102,13 @@ class AccessPolicy private constructor(
}
}
}
forEachSchemePolicy { it.onPackageRemoved(packageState, oldState, newState) }
forEachSchemePolicy {
with(it) { onPackageRemoved(packageState) }
}
if (isAppIdRemoved) {
forEachSchemePolicy { it.onAppIdRemoved(packageState.appId, oldState, newState) }
forEachSchemePolicy {
with(it) { onAppIdRemoved(packageState.appId) }
}
}
}
@@ -113,7 +118,7 @@ class AccessPolicy private constructor(
TAG_ACCESS -> {
forEachTag {
forEachSchemePolicy {
with(it) { this@parseSystemState.parseSystemState(systemState) }
with(it) { parseSystemState(systemState) }
}
}
}
@@ -125,7 +130,7 @@ class AccessPolicy private constructor(
fun BinaryXmlSerializer.serializeSystemState(systemState: SystemState) {
tag(TAG_ACCESS) {
forEachSchemePolicy {
with(it) { this@serializeSystemState.serializeSystemState(systemState) }
with(it) { serializeSystemState(systemState) }
}
}
}
@@ -136,7 +141,7 @@ class AccessPolicy private constructor(
TAG_ACCESS -> {
forEachTag {
forEachSchemePolicy {
with(it) { this@parseUserState.parseUserState(userId, userState) }
with(it) { parseUserState(userId, userState) }
}
}
}
@@ -153,11 +158,14 @@ class AccessPolicy private constructor(
fun BinaryXmlSerializer.serializeUserState(userId: Int, userState: UserState) {
tag(TAG_ACCESS) {
forEachSchemePolicy {
with(it) { this@serializeUserState.serializeUserState(userId, userState) }
with(it) { serializeUserState(userId, userState) }
}
}
}
private fun getSchemePolicy(subject: AccessUri, `object`: AccessUri): SchemePolicy =
getSchemePolicy(subject.scheme, `object`.scheme)
private inline fun forEachSchemePolicy(action: (SchemePolicy) -> Unit) {
schemePolicies.forEachValueIndexed { _, objectSchemePolicies ->
objectSchemePolicies.forEachValueIndexed { _, schemePolicy ->
@@ -182,14 +190,12 @@ abstract class SchemePolicy {
abstract val objectScheme: String
abstract fun getDecision(subject: AccessUri, `object`: AccessUri, state: AccessState): Int
abstract fun GetStateScope.getDecision(subject: AccessUri, `object`: AccessUri): Int
abstract fun setDecision(
abstract fun MutateStateScope.setDecision(
subject: AccessUri,
`object`: AccessUri,
decision: Int,
oldState: AccessState,
newState: AccessState
decision: Int
)
fun addOnDecisionChangedListener(listener: OnDecisionChangedListener) {
@@ -216,25 +222,17 @@ abstract class SchemePolicy {
}
}
open fun onUserAdded(userId: Int, oldState: AccessState, newState: AccessState) {}
open fun MutateStateScope.onUserAdded(userId: Int) {}
open fun onUserRemoved(userId: Int, oldState: AccessState, newState: AccessState) {}
open fun MutateStateScope.onUserRemoved(userId: Int) {}
open fun onAppIdAdded(appId: Int, oldState: AccessState, newState: AccessState) {}
open fun MutateStateScope.onAppIdAdded(appId: Int) {}
open fun onAppIdRemoved(appId: Int, oldState: AccessState, newState: AccessState) {}
open fun MutateStateScope.onAppIdRemoved(appId: Int) {}
open fun onPackageAdded(
packageState: PackageState,
oldState: AccessState,
newState: AccessState
) {}
open fun MutateStateScope.onPackageAdded(packageState: PackageState) {}
open fun onPackageRemoved(
packageState: PackageState,
oldState: AccessState,
newState: AccessState
) {}
open fun MutateStateScope.onPackageRemoved(packageState: PackageState) {}
open fun BinaryXmlPullParser.parseSystemState(systemState: SystemState) {}

View File

@@ -124,3 +124,12 @@ abstract class WritableState {
}
}
}
class GetStateScope(
val state: AccessState
)
class MutateStateScope(
val oldState: AccessState,
val newState: AccessState
)

View File

@@ -19,44 +19,43 @@ package com.android.server.permission.access.appop
import android.app.AppOpsManager
import com.android.modules.utils.BinaryXmlPullParser
import com.android.modules.utils.BinaryXmlSerializer
import com.android.server.permission.access.AccessState
import com.android.server.permission.access.AccessUri
import com.android.server.permission.access.AppOpUri
import com.android.server.permission.access.GetStateScope
import com.android.server.permission.access.MutateStateScope
import com.android.server.permission.access.SchemePolicy
import com.android.server.permission.access.UserState
import com.android.server.permission.access.collection.* // ktlint-disable no-wildcard-imports
abstract class BaseAppOpPolicy(private val persistence: BaseAppOpPersistence) : SchemePolicy() {
override fun getDecision(subject: AccessUri, `object`: AccessUri, state: AccessState): Int {
override fun GetStateScope.getDecision(subject: AccessUri, `object`: AccessUri): Int {
`object` as AppOpUri
return getModes(subject, state)
return getModes(subject)
.getWithDefault(`object`.appOpName, opToDefaultMode(`object`.appOpName))
}
override fun setDecision(
override fun MutateStateScope.setDecision(
subject: AccessUri,
`object`: AccessUri,
decision: Int,
oldState: AccessState,
newState: AccessState
decision: Int
) {
`object` as AppOpUri
val modes = getOrCreateModes(subject, newState)
val modes = getOrCreateModes(subject)
val oldMode = modes.putWithDefault(`object`.appOpName, decision,
opToDefaultMode(`object`.appOpName))
if (modes.isEmpty()) {
removeModes(subject, newState)
removeModes(subject)
}
if (oldMode != decision) {
notifyOnDecisionChangedListeners(subject, `object`, oldMode, decision)
}
}
abstract fun getModes(subject: AccessUri, state: AccessState): IndexedMap<String, Int>?
abstract fun GetStateScope.getModes(subject: AccessUri): IndexedMap<String, Int>?
abstract fun getOrCreateModes(subject: AccessUri, state: AccessState): IndexedMap<String, Int>
abstract fun MutateStateScope.getOrCreateModes(subject: AccessUri): IndexedMap<String, Int>
abstract fun removeModes(subject: AccessUri, state: AccessState)
abstract fun MutateStateScope.removeModes(subject: AccessUri)
// TODO need to check that [AppOpsManager.getSystemAlertWindowDefault] works; likely no issue
// since running in system process.

View File

@@ -16,9 +16,10 @@
package com.android.server.permission.access.appop
import com.android.server.permission.access.AccessState
import com.android.server.permission.access.AccessUri
import com.android.server.permission.access.AppOpUri
import com.android.server.permission.access.GetStateScope
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
@@ -31,27 +32,23 @@ class PackageAppOpPolicy : BaseAppOpPolicy(PackageAppOpPersistence()) {
override val objectScheme: String
get() = AppOpUri.SCHEME
override fun getModes(subject: AccessUri, state: AccessState): IndexedMap<String, Int>? {
override fun GetStateScope.getModes(subject: AccessUri): IndexedMap<String, Int>? {
subject as PackageUri
return state.userStates[subject.userId]?.packageAppOpModes?.get(subject.packageName)
}
override fun getOrCreateModes(subject: AccessUri, state: AccessState): IndexedMap<String, Int> {
override fun MutateStateScope.getOrCreateModes(subject: AccessUri): IndexedMap<String, Int> {
subject as PackageUri
return state.userStates.getOrPut(subject.userId) { UserState() }
return newState.userStates.getOrPut(subject.userId) { UserState() }
.packageAppOpModes.getOrPut(subject.packageName) { IndexedMap() }
}
override fun removeModes(subject: AccessUri, state: AccessState) {
override fun MutateStateScope.removeModes(subject: AccessUri) {
subject as PackageUri
state.userStates[subject.userId]?.packageAppOpModes?.remove(subject.packageName)
newState.userStates[subject.userId]?.packageAppOpModes?.remove(subject.packageName)
}
override fun onPackageRemoved(
packageState: PackageState,
oldState: AccessState,
newState: AccessState
) {
override fun MutateStateScope.onPackageRemoved(packageState: PackageState) {
newState.userStates.forEachIndexed { _, _, userState ->
userState.packageAppOpModes -= packageState.packageName
}

View File

@@ -16,9 +16,10 @@
package com.android.server.permission.access.appop
import com.android.server.permission.access.AccessState
import com.android.server.permission.access.AccessUri
import com.android.server.permission.access.AppOpUri
import com.android.server.permission.access.GetStateScope
import com.android.server.permission.access.MutateStateScope
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
@@ -30,23 +31,23 @@ class UidAppOpPolicy : BaseAppOpPolicy(UidAppOpPersistence()) {
override val objectScheme: String
get() = AppOpUri.SCHEME
override fun getModes(subject: AccessUri, state: AccessState): IndexedMap<String, Int>? {
override fun GetStateScope.getModes(subject: AccessUri): IndexedMap<String, Int>? {
subject as UidUri
return state.userStates[subject.userId]?.uidAppOpModes?.get(subject.appId)
}
override fun getOrCreateModes(subject: AccessUri, state: AccessState): IndexedMap<String, Int> {
override fun MutateStateScope.getOrCreateModes(subject: AccessUri): IndexedMap<String, Int> {
subject as UidUri
return state.userStates.getOrPut(subject.userId) { UserState() }
return newState.userStates.getOrPut(subject.userId) { UserState() }
.uidAppOpModes.getOrPut(subject.appId) { IndexedMap() }
}
override fun removeModes(subject: AccessUri, state: AccessState) {
override fun MutateStateScope.removeModes(subject: AccessUri) {
subject as UidUri
state.userStates[subject.userId]?.uidAppOpModes?.remove(subject.appId)
newState.userStates[subject.userId]?.uidAppOpModes?.remove(subject.appId)
}
override fun onAppIdRemoved(appId: Int, oldState: AccessState, newState: AccessState) {
override fun MutateStateScope.onAppIdRemoved(appId: Int) {
newState.userStates.forEachIndexed { _, _, userState ->
userState.uidAppOpModes -= appId
}

View File

@@ -0,0 +1,456 @@
/*
* 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.permission
import android.content.pm.PackageManager
import android.content.pm.PackageManagerInternal
import android.content.pm.PermissionGroupInfo
import android.content.pm.PermissionInfo
import android.content.pm.permission.SplitPermissionInfoParcelable
import android.os.Binder
import android.os.Build
import android.os.Process
import android.os.UserHandle
import android.permission.IOnPermissionsChangeListener
import com.android.server.LocalManagerRegistry
import com.android.server.LocalServices
import com.android.server.pm.PackageManagerLocal
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.util.hasBits
import com.android.server.pm.permission.LegacyPermission
import com.android.server.pm.permission.LegacyPermissionSettings
import com.android.server.pm.permission.LegacyPermissionState
import com.android.server.pm.permission.PermissionManagerServiceInternal
import com.android.server.pm.pkg.AndroidPackage
import java.io.FileDescriptor
import java.io.PrintWriter
/**
* Modern implementation of [PermissionManagerServiceInterface].
*/
class ModernPermissionManagerServiceImpl(
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 val packageManagerLocal =
LocalManagerRegistry.getManagerOrThrow(PackageManagerLocal::class.java)
override fun getAllPermissionGroups(flags: Int): List<PermissionGroupInfo> {
TODO("Not yet implemented")
}
override fun getPermissionGroupInfo(
permissionGroupName: String,
flags: Int
): PermissionGroupInfo? {
val permissionGroup: PermissionGroupInfo
packageManagerLocal.withUnfilteredSnapshot().use { snapshot ->
val callingUid = Binder.getCallingUid()
if (snapshot.isUidInstantApp(callingUid)) {
return null
}
permissionGroup = service.getState {
with(policy) { getPermissionGroup(permissionGroupName) }
} ?: return null
val isPermissionGroupVisible =
snapshot.isPackageVisibleToUid(permissionGroup.packageName, callingUid)
if (!isPermissionGroupVisible) {
return null
}
}
return permissionGroup.generatePermissionGroupInfo(flags)
}
/**
* Generate a new [PermissionGroupInfo] from [PermissionGroupInfo] and adjust it accordingly.
*/
private fun PermissionGroupInfo.generatePermissionGroupInfo(flags: Int): PermissionGroupInfo =
@Suppress("DEPRECATION")
PermissionGroupInfo(this).apply {
if (!flags.hasBits(PackageManager.GET_META_DATA)) {
metaData = null
}
}
override fun getPermissionInfo(
permissionName: String,
flags: Int,
opPackageName: String
): PermissionInfo? {
val permission: Permission
val targetSdkVersion: Int
packageManagerLocal.withUnfilteredSnapshot().use { snapshot ->
val callingUid = Binder.getCallingUid()
if (snapshot.isUidInstantApp(callingUid)) {
return null
}
permission = service.getState {
with(policy) { getPermission(permissionName) }
} ?: return null
val isPermissionVisible =
snapshot.isPackageVisibleToUid(permission.packageName, callingUid)
if (!isPermissionVisible) {
return null
}
val callingAppId = UserHandle.getAppId(callingUid)
val opPackage = snapshot.packageStates[opPackageName]?.androidPackage
targetSdkVersion = when {
// System sees all flags.
callingAppId == Process.ROOT_UID || callingAppId == Process.SYSTEM_UID ||
callingAppId == Process.SHELL_UID -> Build.VERSION_CODES.CUR_DEVELOPMENT
opPackage != null -> opPackage.targetSdkVersion
else -> Build.VERSION_CODES.CUR_DEVELOPMENT
}
}
return permission.generatePermissionInfo(flags, targetSdkVersion)
}
/**
* Generate a new [PermissionInfo] from [Permission] and adjust it accordingly.
*/
private fun Permission.generatePermissionInfo(
flags: Int,
targetSdkVersion: Int
): PermissionInfo =
@Suppress("DEPRECATION")
PermissionInfo(permissionInfo).apply {
if (!flags.hasBits(PackageManager.GET_META_DATA)) {
metaData = null
}
if (targetSdkVersion < Build.VERSION_CODES.O) {
val protection = protection
// Signature permission's protection flags are always reported.
if (protection != PermissionInfo.PROTECTION_SIGNATURE) {
protectionLevel = protection
}
}
}
override fun queryPermissionsByGroup(
permissionGroupName: String,
flags: Int
): List<PermissionInfo> {
TODO("Not yet implemented")
}
override fun getAllPermissionsWithProtection(protection: Int): List<PermissionInfo> {
TODO("Not yet implemented")
}
override fun getAllPermissionsWithProtectionFlags(protectionFlags: Int): List<PermissionInfo> {
TODO("Not yet implemented")
}
override fun getPermissionGids(permissionName: String, userId: Int): IntArray {
TODO("Not yet implemented")
}
override fun addPermission(permissionInfo: PermissionInfo, async: Boolean): Boolean {
TODO("Not yet implemented")
}
override fun removePermission(permissionName: String) {
TODO("Not yet implemented")
}
override fun checkPermission(packageName: String, permissionName: String, userId: Int): Int {
TODO("Not yet implemented")
}
override fun checkUidPermission(uid: Int, permissionName: String): Int {
TODO("Not yet implemented")
}
override fun getGrantedPermissions(packageName: String, userId: Int): Set<String> {
TODO("Not yet implemented")
}
override fun grantRuntimePermission(packageName: String, permissionName: String, userId: Int) {
TODO("Not yet implemented")
}
override fun revokeRuntimePermission(
packageName: String,
permissionName: String,
userId: Int,
reason: String?
) {
TODO("Not yet implemented")
}
override fun revokePostNotificationPermissionWithoutKillForTest(
packageName: String,
userId: Int
) {
TODO("Not yet implemented")
}
override fun addOnPermissionsChangeListener(listener: IOnPermissionsChangeListener) {
TODO("Not yet implemented")
}
override fun removeOnPermissionsChangeListener(listener: IOnPermissionsChangeListener) {
TODO("Not yet implemented")
}
override fun getPermissionFlags(packageName: String, permissionName: String, userId: Int): Int {
TODO("Not yet implemented")
}
override fun isPermissionRevokedByPolicy(
packageName: String,
permissionName: String,
userId: Int
): Boolean {
TODO("Not yet implemented")
}
override fun isPermissionsReviewRequired(packageName: String, userId: Int): Boolean {
TODO("Not yet implemented")
}
override fun shouldShowRequestPermissionRationale(
packageName: String,
permissionName: String,
userId: Int
): Boolean {
TODO("Not yet implemented")
}
override fun updatePermissionFlags(
packageName: String,
permissionName: String,
flagMask: Int,
flagValues: Int,
checkAdjustPolicyFlagPermission: Boolean,
userId: Int
) {
TODO("Not yet implemented")
}
override fun updatePermissionFlagsForAllApps(flagMask: Int, flagValues: Int, userId: Int) {
TODO("Not yet implemented")
}
override fun addAllowlistedRestrictedPermission(
packageName: String,
permissionName: String,
flags: Int,
userId: Int
): Boolean {
TODO("Not yet implemented")
}
override fun getAllowlistedRestrictedPermissions(
packageName: String,
flags: Int,
userId: Int
): MutableList<String> {
TODO("Not yet implemented")
}
override fun removeAllowlistedRestrictedPermission(
packageName: String,
permissionName: String,
flags: Int,
userId: Int
): Boolean {
TODO("Not yet implemented")
}
override fun resetRuntimePermissions(androidPackage: AndroidPackage, userId: Int) {
TODO("Not yet implemented")
}
override fun resetRuntimePermissionsForUser(userId: Int) {
TODO("Not yet implemented")
}
override fun addOnRuntimePermissionStateChangedListener(
listener: PermissionManagerServiceInternal.OnRuntimePermissionStateChangedListener
) {
TODO("Not yet implemented")
}
override fun removeOnRuntimePermissionStateChangedListener(
listener: PermissionManagerServiceInternal.OnRuntimePermissionStateChangedListener
) {
TODO("Not yet implemented")
}
override fun getSplitPermissions(): List<SplitPermissionInfoParcelable> {
TODO("Not yet implemented")
}
override fun getAppOpPermissionPackages(permissionName: String): Array<String> {
TODO("Not yet implemented")
}
override fun getAllAppOpPermissionPackages(): Map<String, Set<String>> {
TODO("Not yet implemented")
}
override fun getGidsForUid(uid: Int): IntArray {
TODO("Not yet implemented")
}
override fun backupRuntimePermissions(userId: Int): ByteArray? {
TODO("Not yet implemented")
}
override fun restoreRuntimePermissions(backup: ByteArray, userId: Int) {
TODO("Not yet implemented")
}
override fun restoreDelayedRuntimePermissions(packageName: String, userId: Int) {
TODO("Not yet implemented")
}
override fun dump(fd: FileDescriptor, pw: PrintWriter, args: Array<out String>?) {
TODO("Not yet implemented")
}
override fun getPermissionTEMP(
permissionName: String
): com.android.server.pm.permission.Permission? {
TODO("Not yet implemented")
}
override fun getLegacyPermissions(): List<LegacyPermission> {
TODO("Not yet implemented")
}
override fun readLegacyPermissionsTEMP(legacyPermissionSettings: LegacyPermissionSettings) {
TODO("Not yet implemented")
}
override fun writeLegacyPermissionsTEMP(legacyPermissionSettings: LegacyPermissionSettings) {
TODO("Not yet implemented")
}
override fun getLegacyPermissionState(appId: Int): LegacyPermissionState {
TODO("Not yet implemented")
}
override fun readLegacyPermissionStateTEMP() {
TODO("Not yet implemented")
}
override fun writeLegacyPermissionStateTEMP() {
TODO("Not yet implemented")
}
override fun onSystemReady() {
TODO("Not yet implemented")
}
override fun onUserCreated(userId: Int) {
TODO("Not yet implemented")
}
override fun onUserRemoved(userId: Int) {
TODO("Not yet implemented")
}
override fun onStorageVolumeMounted(volumeUuid: String, fingerprintChanged: Boolean) {
TODO("Not yet implemented")
}
override fun onPackageAdded(
androidPackage: AndroidPackage,
isInstantApp: Boolean,
oldPackage: AndroidPackage?
) {
TODO("Not yet implemented")
}
override fun onPackageInstalled(
androidPackage: AndroidPackage,
previousAppId: Int,
params: PermissionManagerServiceInternal.PackageInstalledParams,
userId: Int
) {
TODO("Not yet implemented")
}
override fun onPackageUninstalled(
packageName: String,
appId: Int,
androidPackage: AndroidPackage?,
sharedUserPkgs: MutableList<AndroidPackage>,
userId: Int
) {
TODO("Not yet implemented")
}
override fun onPackageRemoved(androidPackage: AndroidPackage) {
TODO("Not yet implemented")
}
/**
* Check whether a UID belongs to an instant app.
*/
private fun PackageManagerLocal.UnfilteredSnapshot.isUidInstantApp(uid: Int): Boolean {
if (Process.isIsolatedUid(uid)) {
// Unfortunately we don't have the API for getting the owner UID of an isolated UID yet,
// so for now we just keep calling the old API.
return packageManagerInternal.getInstantAppPackageName(uid) != null
}
val appId = UserHandle.getAppId(uid)
// Instant apps can't have shared UIDs, so we can just take the first package.
val firstPackageState = packageStates.values.firstOrNull { it.appId == appId }
?: return false
val userId = UserHandle.getUserId(uid)
return firstPackageState.getUserStateOrDefault(userId).isInstantApp
}
/**
* Check whether a package is visible to a UID within the same user as the UID.
*/
private fun PackageManagerLocal.UnfilteredSnapshot.isPackageVisibleToUid(
packageName: String,
uid: Int
): Boolean = isPackageVisibleToUid(packageName, UserHandle.getUserId(uid), uid)
/**
* Check whether a package in a particular user is visible to a UID.
*/
private fun PackageManagerLocal.UnfilteredSnapshot.isPackageVisibleToUid(
packageName: String,
userId: Int,
uid: Int
): Boolean {
val user = UserHandle.of(userId)
return filtered(uid, user).use { it.getPackageState(packageName) != null }
}
}

View File

@@ -18,6 +18,7 @@ package com.android.server.permission.access.permission
import android.Manifest
import android.content.pm.PackageManager
import android.content.pm.PermissionGroupInfo
import android.content.pm.PermissionInfo
import android.os.Build
import android.os.UserHandle
@@ -26,6 +27,8 @@ import com.android.modules.utils.BinaryXmlPullParser
import com.android.modules.utils.BinaryXmlSerializer
import com.android.server.permission.access.AccessState
import com.android.server.permission.access.AccessUri
import com.android.server.permission.access.GetStateScope
import com.android.server.permission.access.MutateStateScope
import com.android.server.permission.access.PermissionUri
import com.android.server.permission.access.SchemePolicy
import com.android.server.permission.access.SystemState
@@ -52,19 +55,17 @@ class UidPermissionPolicy : SchemePolicy() {
override val objectScheme: String
get() = PermissionUri.SCHEME
override fun getDecision(subject: AccessUri, `object`: AccessUri, state: AccessState): Int {
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
}
override fun setDecision(
override fun MutateStateScope.setDecision(
subject: AccessUri,
`object`: AccessUri,
decision: Int,
oldState: AccessState,
newState: AccessState
decision: Int
) {
subject as UidUri
`object` as PermissionUri
@@ -73,64 +74,58 @@ class UidPermissionPolicy : SchemePolicy() {
uidFlags[`object`.permissionName] = decision
}
override fun onUserAdded(userId: Int, oldState: AccessState, newState: AccessState) {
override fun MutateStateScope.onUserAdded(userId: Int) {
newState.systemState.packageStates.forEachValueIndexed { _, packageState ->
evaluateAllPermissionStatesForPackageAndUser(
packageState, null, userId, oldState, newState
)
grantImplicitPermissions(packageState, userId, oldState, newState)
evaluateAllPermissionStatesForPackageAndUser(packageState, null, userId)
grantImplicitPermissions(packageState, userId)
}
}
override fun onAppIdAdded(appId: Int, oldState: AccessState, newState: AccessState) {
override fun MutateStateScope.onAppIdAdded(appId: Int) {
newState.userStates.forEachIndexed { _, _, userState ->
userState.permissionFlags.getOrPut(appId) { IndexedMap() }
}
}
override fun onAppIdRemoved(appId: Int, oldState: AccessState, newState: AccessState) {
override fun MutateStateScope.onAppIdRemoved(appId: Int) {
newState.userStates.forEachIndexed { _, _, userState -> userState.permissionFlags -= appId }
}
override fun onPackageAdded(
packageState: PackageState,
oldState: AccessState,
newState: AccessState
) {
override fun MutateStateScope.onPackageAdded(packageState: PackageState) {
val changedPermissionNames = IndexedSet<String>()
adoptPermissions(packageState, changedPermissionNames, newState)
addPermissionGroups(packageState, newState)
addPermissions(packageState, changedPermissionNames, newState)
adoptPermissions(packageState, changedPermissionNames)
addPermissionGroups(packageState)
addPermissions(packageState, changedPermissionNames)
// TODO: revokeStoragePermissionsIfScopeExpandedInternal()
trimPermissions(packageState.packageName, newState)
changedPermissionNames.forEachIndexed { _, it ->
evaluatePermissionStateForAllPackages(it, packageState, oldState, newState)
trimPermissions(packageState.packageName)
changedPermissionNames.forEachIndexed { _, permissionName ->
evaluatePermissionStateForAllPackages(permissionName, packageState)
}
evaluateAllPermissionStatesForPackage(packageState, packageState, oldState, newState)
newState.systemState.userIds.forEachIndexed { _, it ->
grantImplicitPermissions(packageState, it, oldState, newState)
evaluateAllPermissionStatesForPackage(packageState, packageState)
newState.systemState.userIds.forEachIndexed { _, userId ->
grantImplicitPermissions(packageState, userId)
}
// TODO: add trimPermissionStates() here for removing the permission states that are
// no longer requested. (equivalent to revokeUnusedSharedUserPermissionsLocked())
}
private fun adoptPermissions(
private fun MutateStateScope.adoptPermissions(
packageState: PackageState,
changedPermissionNames: IndexedSet<String>,
newState: AccessState
changedPermissionNames: IndexedSet<String>
) {
val `package` = packageState.androidPackage!!
`package`.adoptPermissions.forEachIndexed { _, originalPackageName ->
val packageName = `package`.packageName
if (!canAdoptPermissions(packageName, originalPackageName, newState)) {
if (!canAdoptPermissions(packageName, originalPackageName)) {
return@forEachIndexed
}
newState.systemState.permissions.let { permissions ->
permissions.forEachIndexed { i, permissionName, oldPermission ->
permissions.forEachIndexed permissions@ {
permissionIndex, permissionName, oldPermission ->
if (oldPermission.packageName != originalPackageName) {
return@forEachIndexed
return@permissions
}
@Suppress("DEPRECATION")
val newPermissionInfo = PermissionInfo().apply {
@@ -140,16 +135,15 @@ class UidPermissionPolicy : SchemePolicy() {
}
val newPermission = Permission(newPermissionInfo, false, oldPermission.type, 0)
changedPermissionNames += permissionName
permissions.setValueAt(i, newPermission)
permissions.setValueAt(permissionIndex, newPermission)
}
}
}
}
private fun canAdoptPermissions(
private fun MutateStateScope.canAdoptPermissions(
packageName: String,
originalPackageName: String,
newState: AccessState
originalPackageName: String
): Boolean {
val originalPackageState = newState.systemState.packageStates[originalPackageName]
?: return false
@@ -170,7 +164,7 @@ class UidPermissionPolicy : SchemePolicy() {
return true
}
private fun addPermissionGroups(packageState: PackageState, newState: AccessState) {
private fun MutateStateScope.addPermissionGroups(packageState: PackageState) {
// Different from the old implementation, which decides whether the app is an instant app by
// the install flags, now for consistent behavior we allow adding permission groups if the
// app is non-instant in at least one user.
@@ -202,10 +196,9 @@ class UidPermissionPolicy : SchemePolicy() {
}
}
private fun addPermissions(
private fun MutateStateScope.addPermissions(
packageState: PackageState,
changedPermissionNames: IndexedSet<String>,
newState: AccessState
changedPermissionNames: IndexedSet<String>
) {
packageState.androidPackage!!.permissions.forEachIndexed { _, parsedPermission ->
// TODO:
@@ -229,7 +222,7 @@ class UidPermissionPolicy : SchemePolicy() {
// Different from the old implementation, which may add an (incomplete) signature
// permission inside another package's permission tree, we now consistently ignore such
// permissions.
val permissionTree = getPermissionTree(permissionName, newState)
val permissionTree = getPermissionTree(permissionName)
val newPackageName = newPermissionInfo.packageName
if (permissionTree != null && newPackageName != permissionTree.packageName) {
Log.w(
@@ -294,10 +287,7 @@ class UidPermissionPolicy : SchemePolicy() {
}
}
private fun trimPermissions(
packageName: String,
newState: AccessState,
) {
private fun MutateStateScope.trimPermissions(packageName: String) {
val packageState = newState.systemState.packageStates[packageName]
val androidPackage = packageState?.androidPackage
if (packageState != null && androidPackage == null) {
@@ -314,20 +304,20 @@ class UidPermissionPolicy : SchemePolicy() {
}
newState.systemState.permissions.removeAllIndexed { i, permissionName, permission ->
val updatedPermission = updatePermissionIfDynamic(permission, newState)
val updatedPermission = updatePermissionIfDynamic(permission)
newState.systemState.permissions.setValueAt(i, updatedPermission)
if (updatedPermission.packageName == packageName && (
packageState == null || androidPackage!!.permissions.noneIndexed { _, it ->
!it.isTree && it.name == permissionName
}
)) {
if (!isPermissionDeclaredByDisabledSystemPackage(permission, newState)) {
if (!isPermissionDeclaredByDisabledSystemPackage(permission)) {
newState.userStates.forEachIndexed { _, userId, userState ->
userState.permissionFlags.forEachKeyIndexed { _, appId ->
setPermissionFlags(
appId, permissionName, getPermissionFlags(
appId, permissionName, userId, newState
) and PermissionFlags.INSTALL_REVOKED, userId, newState
appId, permissionName, userId
) and PermissionFlags.INSTALL_REVOKED, userId
)
}
}
@@ -339,9 +329,8 @@ class UidPermissionPolicy : SchemePolicy() {
}
}
private fun isPermissionDeclaredByDisabledSystemPackage(
permission: Permission,
newState: AccessState
private fun MutateStateScope.isPermissionDeclaredByDisabledSystemPackage(
permission: Permission
): Boolean {
val disabledSystemPackage = newState.systemState
.disabledSystemPackageStates[permission.packageName]?.androidPackage ?: return false
@@ -350,14 +339,11 @@ class UidPermissionPolicy : SchemePolicy() {
}
}
private fun updatePermissionIfDynamic(
permission: Permission,
newState: AccessState
): Permission {
private fun MutateStateScope.updatePermissionIfDynamic(permission: Permission): Permission {
if (!permission.isDynamic) {
return permission
}
val permissionTree = getPermissionTree(permission.name, newState) ?: return permission
val permissionTree = getPermissionTree(permission.name) ?: return permission
@Suppress("DEPRECATION")
return permission.copy(
permissionInfo = PermissionInfo(permission.permissionInfo).apply {
@@ -366,7 +352,7 @@ class UidPermissionPolicy : SchemePolicy() {
)
}
private fun getPermissionTree(permissionName: String, newState: AccessState): Permission? =
private fun MutateStateScope.getPermissionTree(permissionName: String): Permission? =
newState.systemState.permissionTrees.firstNotNullOfOrNullIndexed {
_, permissionTreeName, permissionTree ->
if (permissionName.startsWith(permissionTreeName) &&
@@ -378,58 +364,48 @@ class UidPermissionPolicy : SchemePolicy() {
}
}
private fun evaluatePermissionStateForAllPackages(
private fun MutateStateScope.evaluatePermissionStateForAllPackages(
permissionName: String,
installedPackageState: PackageState?,
oldState: AccessState,
newState: AccessState
installedPackageState: PackageState?
) {
newState.systemState.userIds.forEachIndexed { _, userId ->
oldState.userStates[userId]?.permissionFlags?.forEachIndexed {
_, appId, permissionFlags ->
if (permissionName in permissionFlags) {
evaluatePermissionState(
appId, permissionName, installedPackageState, userId, oldState, newState
)
evaluatePermissionState(appId, permissionName, installedPackageState, userId)
}
}
}
}
private fun evaluateAllPermissionStatesForPackage(
private fun MutateStateScope.evaluateAllPermissionStatesForPackage(
packageState: PackageState,
installedPackageState: PackageState?,
oldState: AccessState,
newState: AccessState
installedPackageState: PackageState?
) {
newState.systemState.userIds.forEachIndexed { _, userId ->
evaluateAllPermissionStatesForPackageAndUser(
packageState, installedPackageState, userId, oldState, newState
packageState, installedPackageState, userId
)
}
}
private fun evaluateAllPermissionStatesForPackageAndUser(
private fun MutateStateScope.evaluateAllPermissionStatesForPackageAndUser(
packageState: PackageState,
installedPackageState: PackageState?,
userId: Int,
oldState: AccessState,
newState: AccessState
userId: Int
) {
packageState.androidPackage?.requestedPermissions?.forEachIndexed { _, it ->
packageState.androidPackage?.requestedPermissions?.forEachIndexed { _, permissionName ->
evaluatePermissionState(
packageState.appId, it, installedPackageState, userId, oldState, newState
packageState.appId, permissionName, installedPackageState, userId
)
}
}
private fun evaluatePermissionState(
private fun MutateStateScope.evaluatePermissionState(
appId: Int,
permissionName: String,
installedPackageState: PackageState?,
userId: Int,
oldState: AccessState,
newState: AccessState
userId: Int
) {
val packageNames = newState.systemState.appIds[appId]
val hasMissingPackage = packageNames.anyIndexed { _, packageName ->
@@ -440,17 +416,17 @@ class UidPermissionPolicy : SchemePolicy() {
return
}
val permission = newState.systemState.permissions[permissionName] ?: return
val oldFlags = getPermissionFlags(appId, permissionName, userId, newState)
val oldFlags = getPermissionFlags(appId, permissionName, userId)
if (permission.isNormal) {
val wasGranted = oldFlags.hasBits(PermissionFlags.INSTALL_GRANTED)
if (!wasGranted) {
val wasRevoked = oldFlags.hasBits(PermissionFlags.INSTALL_REVOKED)
val isRequestedByInstalledPackage = installedPackageState != null &&
permissionName in installedPackageState.androidPackage!!.requestedPermissions
val isRequestedBySystemPackage = anyPackageInAppId(appId, newState) {
val isRequestedBySystemPackage = anyPackageInAppId(appId) {
it.isSystem && permissionName in it.androidPackage!!.requestedPermissions
}
val isCompatibilityPermission = anyPackageInAppId(appId, newState) {
val isCompatibilityPermission = anyPackageInAppId(appId) {
isCompatibilityPermissionForPackage(it.androidPackage!!, permissionName)
}
// If this is an existing, non-system package,
@@ -462,7 +438,7 @@ class UidPermissionPolicy : SchemePolicy() {
} else {
PermissionFlags.INSTALL_REVOKED
}
setPermissionFlags(appId, permissionName, newFlags, userId, newState)
setPermissionFlags(appId, permissionName, newFlags, userId)
}
} else if (permission.isSignature || permission.isInternal) {
val wasProtectionGranted = oldFlags.hasBits(PermissionFlags.PROTECTION_GRANTED)
@@ -471,17 +447,17 @@ class UidPermissionPolicy : SchemePolicy() {
PermissionFlags.PROTECTION_GRANTED
} else {
val mayGrantByPrivileged = !permission.isPrivileged || (
anyPackageInAppId(appId, newState) {
checkPrivilegedPermissionAllowlist(it, permission, newState)
anyPackageInAppId(appId) {
checkPrivilegedPermissionAllowlist(it, permission)
}
)
val shouldGrantBySignature = permission.isSignature && (
anyPackageInAppId(appId, newState) {
shouldGrantPermissionBySignature(it, permission, newState)
anyPackageInAppId(appId) {
shouldGrantPermissionBySignature(it, permission)
}
)
val shouldGrantByProtectionFlags = anyPackageInAppId(appId, newState) {
shouldGrantPermissionByProtectionFlags(it, permission, newState)
val shouldGrantByProtectionFlags = anyPackageInAppId(appId) {
shouldGrantPermissionByProtectionFlags(it, permission)
}
if (mayGrantByPrivileged &&
(shouldGrantBySignature || shouldGrantByProtectionFlags)) {
@@ -501,7 +477,7 @@ class UidPermissionPolicy : SchemePolicy() {
if (permission.isRole) {
newFlags = newFlags or (oldFlags and PermissionFlags.ROLE_GRANTED)
}
setPermissionFlags(appId, permissionName, newFlags, userId, newState)
setPermissionFlags(appId, permissionName, newFlags, userId)
} else if (permission.isRuntime) {
// TODO: add runtime permissions
} else {
@@ -513,12 +489,7 @@ class UidPermissionPolicy : SchemePolicy() {
// TODO: revokePermissionsNoLongerImplicitLocked() for runtime permissions
}
private fun grantImplicitPermissions(
packageState: PackageState,
userId: Int,
oldState: AccessState,
newState: AccessState
) {
private fun MutateStateScope.grantImplicitPermissions(packageState: PackageState, userId: Int) {
val appId = packageState.appId
val androidPackage = packageState.androidPackage ?: return
androidPackage.implicitPermissions.forEachIndexed implicitPermissions@ {
@@ -530,6 +501,7 @@ class UidPermissionPolicy : SchemePolicy() {
if (!implicitPermission.isRuntime) {
return@implicitPermissions
}
// Explicitly check against the old state to determine if this permission is new.
val isNewPermission = getPermissionFlags(
appId, implicitPermissionName, userId, oldState
) == 0
@@ -544,7 +516,7 @@ class UidPermissionPolicy : SchemePolicy() {
checkNotNull(sourcePermission) {
"Unknown source permission $sourcePermissionName in split permissions"
}
val sourceFlags = getPermissionFlags(appId, sourcePermissionName, userId, newState)
val sourceFlags = getPermissionFlags(appId, sourcePermissionName, userId)
val isSourceGranted = sourceFlags.hasAnyBit(PermissionFlags.MASK_GRANTED)
val isNewGranted = newFlags.hasAnyBit(PermissionFlags.MASK_GRANTED)
val isGrantingNewFromRevoke = isSourceGranted && !isNewGranted
@@ -559,23 +531,22 @@ class UidPermissionPolicy : SchemePolicy() {
}
}
newFlags = newFlags or PermissionFlags.IMPLICIT
setPermissionFlags(appId, implicitPermissionName, newFlags, userId, newState)
setPermissionFlags(appId, implicitPermissionName, newFlags, userId)
}
}
private fun getPermissionFlags(
private fun MutateStateScope.getPermissionFlags(
appId: Int,
permissionName: String,
userId: Int,
state: AccessState
state: AccessState = newState
): Int = state.userStates[userId].permissionFlags[appId].getWithDefault(permissionName, 0)
private fun setPermissionFlags(
private fun MutateStateScope.setPermissionFlags(
appId: Int,
permissionName: String,
flags: Int,
userId: Int,
newState: AccessState
userId: Int
) {
newState.userStates[userId].permissionFlags[appId]!!
.putWithDefault(permissionName, flags, 0)
@@ -585,8 +556,9 @@ class UidPermissionPolicy : SchemePolicy() {
androidPackage: AndroidPackage,
permissionName: String
): Boolean {
for (info: CompatibilityPermissionInfo in CompatibilityPermissionInfo.COMPAT_PERMS) {
if (info.name == permissionName && androidPackage.targetSdkVersion < info.sdkVersion) {
for (compatibilityPermission in CompatibilityPermissionInfo.COMPAT_PERMS) {
if (compatibilityPermission.name == permissionName &&
androidPackage.targetSdkVersion < compatibilityPermission.sdkVersion) {
Log.i(
LOG_TAG, "Auto-granting $permissionName to old package" +
" ${androidPackage.packageName}"
@@ -597,10 +569,9 @@ class UidPermissionPolicy : SchemePolicy() {
return false
}
private fun shouldGrantPermissionBySignature(
private fun MutateStateScope.shouldGrantPermissionBySignature(
packageState: PackageState,
permission: Permission,
newState: AccessState
permission: Permission
): Boolean {
// check if the package is allow to use this signature permission. A package is allowed to
// use a signature permission if:
@@ -622,10 +593,9 @@ class UidPermissionPolicy : SchemePolicy() {
SigningDetails.CertCapabilities.PERMISSION)
}
private fun checkPrivilegedPermissionAllowlist(
private fun MutateStateScope.checkPrivilegedPermissionAllowlist(
packageState: PackageState,
permission: Permission,
newState: AccessState
permission: Permission
): Boolean {
if (RoSystemProperties.CONTROL_PRIVAPP_PERMISSIONS_DISABLE) {
return true
@@ -641,10 +611,10 @@ class UidPermissionPolicy : SchemePolicy() {
newState.systemState.privilegedPermissionAllowlistSourcePackageNames) {
return true
}
if (isInSystemConfigPrivAppPermissions(androidPackage, permission.name, newState)) {
if (isInSystemConfigPrivAppPermissions(androidPackage, permission.name)) {
return true
}
if (isInSystemConfigPrivAppDenyPermissions(androidPackage, permission.name, newState)) {
if (isInSystemConfigPrivAppDenyPermissions(androidPackage, permission.name)) {
return false
}
// Updated system apps do not need to be allowlisted
@@ -655,10 +625,9 @@ class UidPermissionPolicy : SchemePolicy() {
return !RoSystemProperties.CONTROL_PRIVAPP_PERMISSIONS_ENFORCE
}
private fun isInSystemConfigPrivAppPermissions(
private fun MutateStateScope.isInSystemConfigPrivAppPermissions(
androidPackage: AndroidPackage,
permissionName: String,
newState: AccessState
permissionName: String
): Boolean {
val apexModuleName = androidPackage.apexModuleName
val systemState = newState.systemState
@@ -682,10 +651,9 @@ class UidPermissionPolicy : SchemePolicy() {
return permissionNames?.contains(permissionName) == true
}
private fun isInSystemConfigPrivAppDenyPermissions(
private fun MutateStateScope.isInSystemConfigPrivAppDenyPermissions(
androidPackage: AndroidPackage,
permissionName: String,
newState: AccessState
permissionName: String
): 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.
@@ -713,22 +681,21 @@ class UidPermissionPolicy : SchemePolicy() {
return permissionNames?.contains(permissionName) == true
}
private fun anyPackageInAppId(
private fun MutateStateScope.anyPackageInAppId(
appId: Int,
newState: AccessState,
state: AccessState = newState,
predicate: (PackageState) -> Boolean
): Boolean {
val packageNames = newState.systemState.appIds[appId]
val packageNames = state.systemState.appIds[appId]
return packageNames.anyIndexed { _, packageName ->
val packageState = newState.systemState.packageStates[packageName]!!
val packageState = state.systemState.packageStates[packageName]!!
packageState.androidPackage != null && predicate(packageState)
}
}
private fun shouldGrantPermissionByProtectionFlags(
private fun MutateStateScope.shouldGrantPermissionByProtectionFlags(
packageState: PackageState,
permission: Permission,
newState: AccessState
permission: Permission
): Boolean {
val androidPackage = packageState.androidPackage!!
val knownPackages = newState.systemState.knownPackages
@@ -741,11 +708,9 @@ class UidPermissionPolicy : SchemePolicy() {
.disabledSystemPackageStates[packageState.packageName]?.androidPackage
disabledSystemPackage != null &&
permission.name in disabledSystemPackage.requestedPermissions &&
shouldGrantPrivilegedOrOemPermission(
disabledSystemPackage, permission, newState
)
shouldGrantPrivilegedOrOemPermission(disabledSystemPackage, permission)
} else {
shouldGrantPrivilegedOrOemPermission(androidPackage, permission, newState)
shouldGrantPrivilegedOrOemPermission(androidPackage, permission)
}
if (shouldGrant) {
return true
@@ -815,7 +780,7 @@ class UidPermissionPolicy : SchemePolicy() {
}
if (permission.isRetailDemo &&
packageName in knownPackages[KnownPackages.PACKAGE_RETAIL_DEMO] &&
isDeviceOrProfileOwnerUid(packageState.appId, newState)) {
isDeviceOrProfileOwnerUid(packageState.appId)) {
// Special permission granted only to the OEM specified retail demo app.
// Note that the original code was passing app ID as UID, so this behavior is kept
// unchanged.
@@ -829,10 +794,9 @@ class UidPermissionPolicy : SchemePolicy() {
return false
}
private fun shouldGrantPrivilegedOrOemPermission(
private fun MutateStateScope.shouldGrantPrivilegedOrOemPermission(
androidPackage: AndroidPackage,
permission: Permission,
state: AccessState
permission: Permission
): Boolean {
val permissionName = permission.name
val packageName = androidPackage.packageName
@@ -855,7 +819,7 @@ class UidPermissionPolicy : SchemePolicy() {
}
permission.isOem -> {
if (androidPackage.isOem) {
val isOemAllowlisted = state.systemState
val isOemAllowlisted = newState.systemState
.oemPermissions[packageName]?.get(permissionName)
checkNotNull(isOemAllowlisted) {
"OEM permission $permissionName requested by package" +
@@ -868,19 +832,15 @@ class UidPermissionPolicy : SchemePolicy() {
return false
}
private fun isDeviceOrProfileOwnerUid(uid: Int, state: AccessState): Boolean {
private fun MutateStateScope.isDeviceOrProfileOwnerUid(uid: Int): Boolean {
val userId = UserHandle.getUserId(uid)
val ownerPackageName = state.systemState.deviceAndProfileOwners[userId] ?: return false
val ownerPackageState = state.systemState.packageStates[ownerPackageName] ?: return false
val ownerPackageName = newState.systemState.deviceAndProfileOwners[userId] ?: return false
val ownerPackageState = newState.systemState.packageStates[ownerPackageName] ?: return false
val ownerUid = UserHandle.getUid(userId, ownerPackageState.appId)
return uid == ownerUid
}
override fun onPackageRemoved(
packageState: PackageState,
oldState: AccessState,
newState: AccessState
) {
override fun MutateStateScope.onPackageRemoved(packageState: PackageState) {
// TODO
}
@@ -892,6 +852,12 @@ class UidPermissionPolicy : SchemePolicy() {
with(persistence) { this@serializeSystemState.serializeSystemState(systemState) }
}
fun GetStateScope.getPermissionGroup(permissionGroupName: String): PermissionGroupInfo? =
state.systemState.permissionGroups[permissionGroupName]
fun GetStateScope.getPermission(permissionName: String): Permission? =
state.systemState.permissions[permissionName]
companion object {
private val LOG_TAG = UidPermissionPolicy::class.java.simpleName