Loading services/permission/java/com/android/server/permission/access/collection/IndexedMap.kt +7 −0 Original line number Diff line number Diff line Loading @@ -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) Loading services/permission/java/com/android/server/permission/access/permission/Permission.kt +9 −0 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -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) Loading Loading @@ -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 Loading services/permission/java/com/android/server/permission/access/permission/PermissionService.kt +363 −14 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -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 Loading @@ -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( Loading @@ -82,7 +137,7 @@ class PermissionService( } permissionGroup = service.getState { with(policy) { getPermissionGroup(permissionGroupName) } with(policy) { getPermissionGroups()[permissionGroupName] } } ?: return null val isPermissionGroupVisible = Loading Loading @@ -120,7 +175,7 @@ class PermissionService( } permission = service.getState { with(policy) { getPermission(permissionName) } with(policy) { getPermissions()[permissionName] } } ?: return null val isPermissionVisible = Loading Loading @@ -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 { Loading @@ -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> { Loading Loading @@ -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 { Loading @@ -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( Loading @@ -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( Loading Loading @@ -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> { Loading @@ -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 { Loading Loading @@ -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. */ Loading Loading @@ -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 } } services/permission/java/com/android/server/permission/access/permission/UidPermissionPolicy.kt +10 −4 Original line number Diff line number Diff line Loading @@ -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) Loading Loading
services/permission/java/com/android/server/permission/access/collection/IndexedMap.kt +7 −0 Original line number Diff line number Diff line Loading @@ -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) Loading
services/permission/java/com/android/server/permission/access/permission/Permission.kt +9 −0 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -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) Loading Loading @@ -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 Loading
services/permission/java/com/android/server/permission/access/permission/PermissionService.kt +363 −14 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -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 Loading @@ -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( Loading @@ -82,7 +137,7 @@ class PermissionService( } permissionGroup = service.getState { with(policy) { getPermissionGroup(permissionGroupName) } with(policy) { getPermissionGroups()[permissionGroupName] } } ?: return null val isPermissionGroupVisible = Loading Loading @@ -120,7 +175,7 @@ class PermissionService( } permission = service.getState { with(policy) { getPermission(permissionName) } with(policy) { getPermissions()[permissionName] } } ?: return null val isPermissionVisible = Loading Loading @@ -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 { Loading @@ -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> { Loading Loading @@ -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 { Loading @@ -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( Loading @@ -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( Loading Loading @@ -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> { Loading @@ -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 { Loading Loading @@ -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. */ Loading Loading @@ -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 } }
services/permission/java/com/android/server/permission/access/permission/UidPermissionPolicy.kt +10 −4 Original line number Diff line number Diff line Loading @@ -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) Loading