|
|
|
|
@@ -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
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|