Merge "Permission compatibility layer for new subsystem"
This commit is contained in:
committed by
Android (Google) Code Review
commit
ac2625acb8
@@ -148,6 +148,13 @@ inline fun <K, V> IndexedMap<K, V>.retainAllIndexed(predicate: (Int, K, V) -> Bo
|
||||
return isChanged
|
||||
}
|
||||
|
||||
inline fun <K, V, R> IndexedMap<K, V>.mapNotNullIndexed(transform: (K, V) -> R?): IndexedList<R> =
|
||||
IndexedList<R>().also { destination ->
|
||||
forEachIndexed { _, key, value ->
|
||||
transform(key, value)?.let { destination += it }
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
inline operator fun <K, V> IndexedMap<K, V>.set(key: K, value: V) {
|
||||
put(key, value)
|
||||
|
||||
@@ -31,6 +31,9 @@ data class Permission(
|
||||
inline val packageName: String
|
||||
get() = permissionInfo.packageName
|
||||
|
||||
inline val groupName: String?
|
||||
get() = permissionInfo.group
|
||||
|
||||
inline val isDynamic: Boolean
|
||||
get() = type == TYPE_DYNAMIC
|
||||
|
||||
@@ -40,6 +43,9 @@ data class Permission(
|
||||
inline val isRuntime: Boolean
|
||||
get() = permissionInfo.protection == PermissionInfo.PROTECTION_DANGEROUS
|
||||
|
||||
inline val isAppOp: Boolean
|
||||
get() = permissionInfo.protection == PermissionInfo.PROTECTION_FLAG_APPOP
|
||||
|
||||
inline val isSoftRestricted: Boolean
|
||||
get() = permissionInfo.protectionFlags.hasBits(PermissionInfo.FLAG_SOFT_RESTRICTED)
|
||||
|
||||
@@ -109,6 +115,9 @@ data class Permission(
|
||||
inline val isKnownSigner: Boolean
|
||||
get() = permissionInfo.protectionFlags.hasBits(PermissionInfo.PROTECTION_FLAG_KNOWN_SIGNER)
|
||||
|
||||
inline val hasGids: Boolean
|
||||
get() = throw NotImplementedError()
|
||||
|
||||
inline val protectionLevel: Int
|
||||
@Suppress("DEPRECATION")
|
||||
get() = permissionInfo.protectionLevel
|
||||
|
||||
@@ -16,6 +16,11 @@
|
||||
|
||||
package com.android.server.permission.access.permission
|
||||
|
||||
import android.Manifest
|
||||
import android.app.ActivityManager
|
||||
import android.compat.annotation.ChangeId
|
||||
import android.compat.annotation.EnabledAfter
|
||||
import android.content.Context
|
||||
import android.content.pm.PackageManager
|
||||
import android.content.pm.PackageManagerInternal
|
||||
import android.content.pm.PermissionGroupInfo
|
||||
@@ -23,17 +28,32 @@ import android.content.pm.PermissionInfo
|
||||
import android.content.pm.permission.SplitPermissionInfoParcelable
|
||||
import android.os.Binder
|
||||
import android.os.Build
|
||||
import android.os.Handler
|
||||
import android.os.HandlerThread
|
||||
import android.os.Looper
|
||||
import android.os.Message
|
||||
import android.os.Process
|
||||
import android.os.RemoteCallbackList
|
||||
import android.os.RemoteException
|
||||
import android.os.ServiceManager
|
||||
import android.os.UserHandle
|
||||
import android.permission.IOnPermissionsChangeListener
|
||||
import android.permission.PermissionManager
|
||||
import android.provider.Settings
|
||||
import android.util.Log
|
||||
import com.android.internal.compat.IPlatformCompat
|
||||
import com.android.server.FgThread
|
||||
import com.android.server.LocalManagerRegistry
|
||||
import com.android.server.LocalServices
|
||||
import com.android.server.ServiceThread
|
||||
import com.android.server.SystemConfig
|
||||
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.collection.* // ktlint-disable no-wildcard-imports
|
||||
import com.android.server.permission.access.util.hasAnyBit
|
||||
import com.android.server.permission.access.util.hasBits
|
||||
import com.android.server.pm.UserManagerService
|
||||
import com.android.server.pm.permission.LegacyPermission
|
||||
@@ -53,21 +73,56 @@ class PermissionService(
|
||||
private val policy =
|
||||
service.getSchemePolicy(UidUri.SCHEME, PermissionUri.SCHEME) as UidPermissionPolicy
|
||||
|
||||
private val context = service.context
|
||||
private lateinit var packageManagerInternal: PackageManagerInternal
|
||||
private lateinit var packageManagerLocal: PackageManagerLocal
|
||||
private lateinit var platformCompat: IPlatformCompat
|
||||
private lateinit var userManagerService: UserManagerService
|
||||
|
||||
private val mountedStorageVolumes = IndexedSet<String?>()
|
||||
|
||||
private lateinit var handlerThread: HandlerThread
|
||||
private lateinit var handler: Handler
|
||||
|
||||
private lateinit var onPermissionsChangeListeners: OnPermissionsChangeListeners
|
||||
private lateinit var permissionFlagsListener: OnPermissionFlagsChangedListener
|
||||
|
||||
fun initialize() {
|
||||
packageManagerInternal = LocalServices.getService(PackageManagerInternal::class.java)
|
||||
packageManagerLocal =
|
||||
LocalManagerRegistry.getManagerOrThrow(PackageManagerLocal::class.java)
|
||||
platformCompat = IPlatformCompat.Stub.asInterface(
|
||||
ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE)
|
||||
)
|
||||
userManagerService = UserManagerService.getInstance()
|
||||
|
||||
handlerThread = ServiceThread(LOG_TAG, Process.THREAD_PRIORITY_BACKGROUND, true)
|
||||
handler = Handler(handlerThread.looper)
|
||||
|
||||
onPermissionsChangeListeners = OnPermissionsChangeListeners(FgThread.get().looper)
|
||||
permissionFlagsListener = OnPermissionFlagsChangedListener()
|
||||
policy.addOnPermissionFlagsChangedListener(permissionFlagsListener)
|
||||
}
|
||||
|
||||
override fun getAllPermissionGroups(flags: Int): List<PermissionGroupInfo> {
|
||||
TODO("Not yet implemented")
|
||||
val callingUid = Binder.getCallingUid()
|
||||
packageManagerLocal.withUnfilteredSnapshot().use { snapshot ->
|
||||
if (snapshot.isUidInstantApp(callingUid)) {
|
||||
return emptyList()
|
||||
}
|
||||
|
||||
val permissionGroups = service.getState {
|
||||
with(policy) { getPermissionGroups() }
|
||||
}
|
||||
|
||||
return permissionGroups.mapNotNullIndexed { _, permissionGroup ->
|
||||
if (snapshot.isPackageVisibleToUid(permissionGroup.packageName, callingUid)) {
|
||||
permissionGroup.generatePermissionGroupInfo(flags)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun getPermissionGroupInfo(
|
||||
@@ -82,7 +137,7 @@ class PermissionService(
|
||||
}
|
||||
|
||||
permissionGroup = service.getState {
|
||||
with(policy) { getPermissionGroup(permissionGroupName) }
|
||||
with(policy) { getPermissionGroups()[permissionGroupName] }
|
||||
} ?: return null
|
||||
|
||||
val isPermissionGroupVisible =
|
||||
@@ -120,7 +175,7 @@ class PermissionService(
|
||||
}
|
||||
|
||||
permission = service.getState {
|
||||
with(policy) { getPermission(permissionName) }
|
||||
with(policy) { getPermissions()[permissionName] }
|
||||
} ?: return null
|
||||
|
||||
val isPermissionVisible =
|
||||
@@ -148,7 +203,7 @@ class PermissionService(
|
||||
*/
|
||||
private fun Permission.generatePermissionInfo(
|
||||
flags: Int,
|
||||
targetSdkVersion: Int
|
||||
targetSdkVersion: Int = Build.VERSION_CODES.CUR_DEVELOPMENT
|
||||
): PermissionInfo =
|
||||
@Suppress("DEPRECATION")
|
||||
PermissionInfo(permissionInfo).apply {
|
||||
@@ -165,10 +220,40 @@ class PermissionService(
|
||||
}
|
||||
|
||||
override fun queryPermissionsByGroup(
|
||||
permissionGroupName: String,
|
||||
permissionGroupName: String?,
|
||||
flags: Int
|
||||
): List<PermissionInfo> {
|
||||
TODO("Not yet implemented")
|
||||
): List<PermissionInfo>? {
|
||||
val callingUid = Binder.getCallingUid()
|
||||
packageManagerLocal.withUnfilteredSnapshot().use { snapshot ->
|
||||
if (snapshot.isUidInstantApp(callingUid)) {
|
||||
return null
|
||||
}
|
||||
|
||||
if (permissionGroupName != null) {
|
||||
val permissionGroup = service.getState {
|
||||
with(policy) { getPermissionGroups()[permissionGroupName] }
|
||||
} ?: return null
|
||||
|
||||
if (!snapshot.isPackageVisibleToUid(
|
||||
permissionGroup.packageName, callingUid
|
||||
)) {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
val permissions = service.getState {
|
||||
with(policy) { getPermissions() }
|
||||
}
|
||||
|
||||
return permissions.mapNotNullIndexed { _, permission ->
|
||||
if (permission.groupName == permissionGroupName &&
|
||||
snapshot.isPackageVisibleToUid(permission.packageName, callingUid)) {
|
||||
permission.generatePermissionInfo(flags)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun getAllPermissionsWithProtection(protection: Int): List<PermissionInfo> {
|
||||
@@ -224,11 +309,11 @@ class PermissionService(
|
||||
}
|
||||
|
||||
override fun addOnPermissionsChangeListener(listener: IOnPermissionsChangeListener) {
|
||||
TODO("Not yet implemented")
|
||||
onPermissionsChangeListeners.addListener(listener)
|
||||
}
|
||||
|
||||
override fun removeOnPermissionsChangeListener(listener: IOnPermissionsChangeListener) {
|
||||
TODO("Not yet implemented")
|
||||
onPermissionsChangeListeners.removeListener(listener)
|
||||
}
|
||||
|
||||
override fun getPermissionFlags(packageName: String, permissionName: String, userId: Int): Int {
|
||||
@@ -245,16 +330,49 @@ class PermissionService(
|
||||
permissionName: String,
|
||||
userId: Int
|
||||
): Boolean {
|
||||
TODO("Not yet implemented")
|
||||
if (UserHandle.getCallingUserId() != userId) {
|
||||
context.enforceCallingPermission(
|
||||
Manifest.permission.INTERACT_ACROSS_USERS_FULL,
|
||||
"isPermissionRevokedByPolicy for user $userId"
|
||||
)
|
||||
}
|
||||
|
||||
if (checkPermission(packageName, permissionName, userId) ==
|
||||
PackageManager.PERMISSION_GRANTED) {
|
||||
return false
|
||||
}
|
||||
|
||||
val callingUid = Binder.getCallingUid()
|
||||
if (packageManagerLocal.withUnfilteredSnapshot()
|
||||
.use { !it.isPackageVisibleToUid(packageName, userId, callingUid) }) {
|
||||
return false
|
||||
}
|
||||
|
||||
val permissionFlags = getPermissionFlagsUnchecked(packageName,
|
||||
permissionName, callingUid, userId)
|
||||
return permissionFlags.hasBits(PackageManager.FLAG_PERMISSION_POLICY_FIXED)
|
||||
}
|
||||
|
||||
private fun getPermissionFlagsUnchecked(
|
||||
packageName: String,
|
||||
permName: String,
|
||||
callingUid: Int,
|
||||
userId: Int
|
||||
): Int {
|
||||
throw NotImplementedError()
|
||||
}
|
||||
|
||||
override fun isPermissionsReviewRequired(packageName: String, userId: Int): Boolean {
|
||||
requireNotNull(packageName) { "packageName" }
|
||||
// TODO(b/173235285): Some caller may pass USER_ALL as userId.
|
||||
// Preconditions.checkArgumentNonnegative(userId, "userId");
|
||||
val packageState = packageManagerLocal.withUnfilteredSnapshot()
|
||||
.use { it.packageStates[packageName] } ?: return false
|
||||
val permissionFlags = service.getState {
|
||||
with(policy) { getUidPermissionFlags(packageState.appId, userId) }
|
||||
} ?: return false
|
||||
return permissionFlags.anyIndexed { _, _, flags -> PermissionFlags.isReviewRequired(flags) }
|
||||
return permissionFlags.anyIndexed { _, _, flags -> PermissionFlags.isReviewRequired(flags)
|
||||
}
|
||||
}
|
||||
|
||||
override fun shouldShowRequestPermissionRationale(
|
||||
@@ -262,7 +380,70 @@ class PermissionService(
|
||||
permissionName: String,
|
||||
userId: Int
|
||||
): Boolean {
|
||||
TODO("Not yet implemented")
|
||||
val callingUid = Binder.getCallingUid()
|
||||
if (UserHandle.getCallingUserId() != userId) {
|
||||
context.enforceCallingPermission(
|
||||
Manifest.permission.INTERACT_ACROSS_USERS_FULL,
|
||||
"canShowRequestPermissionRationale for user $userId"
|
||||
)
|
||||
}
|
||||
|
||||
val appId = packageManagerLocal.withUnfilteredSnapshot().use { snapshot ->
|
||||
snapshot.packageStates[packageName]?.appId ?: return false
|
||||
}
|
||||
if (UserHandle.getAppId(callingUid) != appId) {
|
||||
return false
|
||||
}
|
||||
|
||||
if (checkPermission(packageName, permissionName, userId) ==
|
||||
PackageManager.PERMISSION_GRANTED) {
|
||||
return false
|
||||
}
|
||||
|
||||
val identity = Binder.clearCallingIdentity()
|
||||
val permissionFlags = try {
|
||||
getPermissionFlagsInternal(packageName, permissionName, callingUid, userId)
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(identity)
|
||||
}
|
||||
|
||||
val fixedFlags = (PermissionFlags.SYSTEM_FIXED or PermissionFlags.POLICY_FIXED
|
||||
or PermissionFlags.USER_FIXED)
|
||||
|
||||
if (permissionFlags.hasAnyBit(fixedFlags) ||
|
||||
permissionFlags.hasBits(PermissionFlags.RESTRICTION_REVOKED)) {
|
||||
return false
|
||||
}
|
||||
|
||||
val token = Binder.clearCallingIdentity()
|
||||
try {
|
||||
if (permissionName == Manifest.permission.ACCESS_BACKGROUND_LOCATION &&
|
||||
platformCompat.isChangeEnabledByPackageName(
|
||||
BACKGROUND_RATIONALE_CHANGE_ID, packageName, userId)
|
||||
) {
|
||||
return true
|
||||
}
|
||||
} catch (e: RemoteException) {
|
||||
Log.e(LOG_TAG, "Unable to check if compatibility change is enabled.", e)
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(token)
|
||||
}
|
||||
|
||||
return permissionFlags and PackageManager.FLAG_PERMISSION_USER_SET != 0
|
||||
}
|
||||
|
||||
/**
|
||||
* read internal permission flags
|
||||
* @return internal permission Flags
|
||||
* @see PermissionFlags
|
||||
*/
|
||||
private fun getPermissionFlagsInternal(
|
||||
packageName: String,
|
||||
permName: String,
|
||||
callingUid: Int,
|
||||
userId: Int
|
||||
): Int {
|
||||
throw NotImplementedError()
|
||||
}
|
||||
|
||||
override fun updatePermissionFlags(
|
||||
@@ -327,7 +508,9 @@ class PermissionService(
|
||||
}
|
||||
|
||||
override fun getSplitPermissions(): List<SplitPermissionInfoParcelable> {
|
||||
TODO("Not yet implemented")
|
||||
return PermissionManager.splitPermissionInfoListToParcelableList(
|
||||
SystemConfig.getInstance().splitPermissions
|
||||
)
|
||||
}
|
||||
|
||||
override fun getAppOpPermissionPackages(permissionName: String): Array<String> {
|
||||
@@ -335,7 +518,22 @@ class PermissionService(
|
||||
}
|
||||
|
||||
override fun getAllAppOpPermissionPackages(): Map<String, Set<String>> {
|
||||
TODO("Not yet implemented")
|
||||
val appOpPermissionPackageNames = IndexedMap<String, IndexedSet<String>>()
|
||||
val permissions = service.getState { with(policy) { getPermissions() } }
|
||||
packageManagerLocal.withUnfilteredSnapshot().use { snapshot ->
|
||||
snapshot.packageStates.forEach packageStates@{ (_, packageState) ->
|
||||
val androidPackage = packageState.androidPackage ?: return@packageStates
|
||||
androidPackage.requestedPermissions.forEach requestedPermissions@{ permissionName ->
|
||||
val permission = permissions[permissionName] ?: return@requestedPermissions
|
||||
if (permission.isAppOp) {
|
||||
val packageNames = appOpPermissionPackageNames
|
||||
.getOrPut(permissionName) { IndexedSet() }
|
||||
packageNames += androidPackage.packageName
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return appOpPermissionPackageNames
|
||||
}
|
||||
|
||||
override fun getGidsForUid(uid: Int): IntArray {
|
||||
@@ -468,6 +666,28 @@ class PermissionService(
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This method should typically only be used when granting or revoking permissions, since the
|
||||
* app may immediately restart after this call.
|
||||
*
|
||||
* If you're doing surgery on app code/data, use [PackageFreezer] to guard your work against
|
||||
* the app being relaunched.
|
||||
*/
|
||||
private fun killUid(appId: Int, userId: Int, reason: String) {
|
||||
val activityManager = ActivityManager.getService()
|
||||
if (activityManager != null) {
|
||||
val identity = Binder.clearCallingIdentity()
|
||||
try {
|
||||
activityManager.killUidForPermissionChange(appId, userId, reason)
|
||||
} catch (e: RemoteException) {
|
||||
/* ignore - same process */
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(identity)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether a UID belongs to an instant app.
|
||||
*/
|
||||
@@ -504,4 +724,133 @@ class PermissionService(
|
||||
val user = UserHandle.of(userId)
|
||||
return filtered(uid, user).use { it.getPackageState(packageName) != null }
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback invoked when interesting actions have been taken on a permission.
|
||||
*/
|
||||
private inner class OnPermissionFlagsChangedListener :
|
||||
UidPermissionPolicy.OnPermissionFlagsChangedListener {
|
||||
override fun onPermissionFlagsChanged(
|
||||
appId: Int,
|
||||
userId: Int,
|
||||
permissionName: String,
|
||||
oldFlags: Int,
|
||||
newFlags: Int
|
||||
) {
|
||||
val uid = UserHandle.getUid(userId, appId)
|
||||
val permission = service.getState {
|
||||
with(policy) { getPermissions()[permissionName] }
|
||||
} ?: return
|
||||
|
||||
val isPermissionGranted = !PermissionFlags.isPermissionGranted(oldFlags) &&
|
||||
PermissionFlags.isPermissionGranted(newFlags)
|
||||
val isPermissionRevoked = PermissionFlags.isPermissionGranted(oldFlags) &&
|
||||
!PermissionFlags.isPermissionGranted(newFlags)
|
||||
|
||||
if (isPermissionGranted) {
|
||||
if (permission.isRuntime) {
|
||||
onPermissionsChangeListeners.onPermissionsChanged(uid)
|
||||
}
|
||||
handler.post {
|
||||
if (permission.hasGids) {
|
||||
killUid(appId, userId, PermissionManager.KILL_APP_REASON_GIDS_CHANGED)
|
||||
}
|
||||
}
|
||||
} else if (isPermissionRevoked) {
|
||||
// TODO: STOPSHIP skip kill for revokePostNotificationPermissionWithoutKillForTest
|
||||
if (permission.isRuntime) {
|
||||
onPermissionsChangeListeners.onPermissionsChanged(uid)
|
||||
handler.post {
|
||||
if (!(permissionName == Manifest.permission.POST_NOTIFICATIONS &&
|
||||
isAppBackupAndRestoreRunning(uid))) {
|
||||
killUid(
|
||||
appId, userId, PermissionManager.KILL_APP_REASON_PERMISSIONS_REVOKED
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (oldFlags != newFlags) {
|
||||
onPermissionsChangeListeners.onPermissionsChanged(uid)
|
||||
}
|
||||
}
|
||||
|
||||
private fun isAppBackupAndRestoreRunning(uid: Int): Boolean {
|
||||
if (checkUidPermission(uid, Manifest.permission.BACKUP) !=
|
||||
PackageManager.PERMISSION_GRANTED) {
|
||||
return false
|
||||
}
|
||||
return try {
|
||||
val userId = UserHandle.getUserId(uid)
|
||||
val isInSetup = Settings.Secure.getIntForUser(
|
||||
context.contentResolver, Settings.Secure.USER_SETUP_COMPLETE, userId
|
||||
) == 0
|
||||
val isInDeferredSetup = Settings.Secure.getIntForUser(
|
||||
context.contentResolver,
|
||||
Settings.Secure.USER_SETUP_PERSONALIZATION_STATE, userId
|
||||
) == Settings.Secure.USER_SETUP_PERSONALIZATION_STARTED
|
||||
isInSetup || isInDeferredSetup
|
||||
} catch (e: Settings.SettingNotFoundException) {
|
||||
Log.w(LOG_TAG, "Failed to check if the user is in restore: $e")
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class OnPermissionsChangeListeners(looper: Looper) : Handler(looper) {
|
||||
private val listeners = RemoteCallbackList<IOnPermissionsChangeListener>()
|
||||
|
||||
override fun handleMessage(msg: Message) {
|
||||
when (msg.what) {
|
||||
MSG_ON_PERMISSIONS_CHANGED -> {
|
||||
val uid = msg.arg1
|
||||
handleOnPermissionsChanged(uid)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleOnPermissionsChanged(uid: Int) {
|
||||
val count = listeners.beginBroadcast()
|
||||
try {
|
||||
for (i in 0 until count) {
|
||||
val callback = listeners.getBroadcastItem(i)
|
||||
try {
|
||||
callback.onPermissionsChanged(uid)
|
||||
} catch (e: RemoteException) {
|
||||
Log.e(LOG_TAG, "Permission listener is dead", e)
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
listeners.finishBroadcast()
|
||||
}
|
||||
}
|
||||
|
||||
fun addListener(listener: IOnPermissionsChangeListener) {
|
||||
listeners.register(listener)
|
||||
}
|
||||
|
||||
fun removeListener(listener: IOnPermissionsChangeListener) {
|
||||
listeners.unregister(listener)
|
||||
}
|
||||
|
||||
fun onPermissionsChanged(uid: Int) {
|
||||
if (listeners.registeredCallbackCount > 0) {
|
||||
obtainMessage(MSG_ON_PERMISSIONS_CHANGED, uid, 0).sendToTarget()
|
||||
}
|
||||
}
|
||||
companion object {
|
||||
private const val MSG_ON_PERMISSIONS_CHANGED = 1
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val LOG_TAG = PermissionService::class.java.simpleName
|
||||
|
||||
/**
|
||||
* This change makes it so that apps are told to show rationale for asking for background
|
||||
* location access every time they request.
|
||||
*/
|
||||
@ChangeId
|
||||
@EnabledAfter(targetSdkVersion = Build.VERSION_CODES.Q)
|
||||
private val BACKGROUND_RATIONALE_CHANGE_ID = 147316723L
|
||||
}
|
||||
}
|
||||
|
||||
@@ -836,11 +836,17 @@ class UidPermissionPolicy : SchemePolicy() {
|
||||
with(persistence) { this@serializeUserState.serializeUserState(state, userId) }
|
||||
}
|
||||
|
||||
fun GetStateScope.getPermissionGroup(permissionGroupName: String): PermissionGroupInfo? =
|
||||
state.systemState.permissionGroups[permissionGroupName]
|
||||
/**
|
||||
* returns all permission group definitions available in the system
|
||||
*/
|
||||
fun GetStateScope.getPermissionGroups(): IndexedMap<String, PermissionGroupInfo> =
|
||||
state.systemState.permissionGroups
|
||||
|
||||
fun GetStateScope.getPermission(permissionName: String): Permission? =
|
||||
state.systemState.permissions[permissionName]
|
||||
/**
|
||||
* returns all permission definitions available in the system
|
||||
*/
|
||||
fun GetStateScope.getPermissions(): IndexedMap<String, Permission> =
|
||||
state.systemState.permissions
|
||||
|
||||
fun GetStateScope.getUidPermissionFlags(appId: Int, userId: Int): IndexedMap<String, Int>? =
|
||||
state.userStates[userId]?.uidPermissionFlags?.get(appId)
|
||||
|
||||
Reference in New Issue
Block a user