1 /* <lambda>null2 * Copyright (C) 2023 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.server.permission.access.permission 18 19 import android.permission.PermissionManager 20 import android.util.Slog 21 import com.android.modules.utils.BinaryXmlPullParser 22 import com.android.modules.utils.BinaryXmlSerializer 23 import com.android.server.permission.access.AccessState 24 import com.android.server.permission.access.DevicePermissionUri 25 import com.android.server.permission.access.GetStateScope 26 import com.android.server.permission.access.MutableAccessState 27 import com.android.server.permission.access.MutateStateScope 28 import com.android.server.permission.access.SchemePolicy 29 import com.android.server.permission.access.UidUri 30 import com.android.server.permission.access.collection.* // ktlint-disable no-wildcard-imports 31 import com.android.server.permission.access.immutable.* // ktlint-disable no-wildcard-imports 32 import com.android.server.permission.access.util.andInv 33 import com.android.server.pm.pkg.PackageState 34 35 class DevicePermissionPolicy : SchemePolicy() { 36 private val persistence = DevicePermissionPersistence() 37 38 @Volatile 39 private var listeners: IndexedListSet<OnDevicePermissionFlagsChangedListener> = 40 MutableIndexedListSet() 41 private val listenersLock = Any() 42 43 override val subjectScheme: String 44 get() = UidUri.SCHEME 45 46 override val objectScheme: String 47 get() = DevicePermissionUri.SCHEME 48 49 override fun GetStateScope.onStateMutated() { 50 listeners.forEachIndexed { _, it -> it.onStateMutated() } 51 } 52 53 override fun MutateStateScope.onAppIdRemoved(appId: Int) { 54 newState.userStates.forEachIndexed { userStateIndex, _, userState -> 55 if (appId in userState.appIdDevicePermissionFlags) { 56 newState.mutateUserStateAt(userStateIndex).mutateAppIdDevicePermissionFlags() -= 57 appId 58 } 59 } 60 } 61 62 fun MutateStateScope.trimDevicePermissionStates(deviceIds: Set<String>) { 63 newState.userStates.forEachIndexed { _, userId, userState -> 64 userState.appIdDevicePermissionFlags.forEachReversedIndexed { _, appId, _ -> 65 val appIdDevicePermissionFlags = 66 newState.mutateUserState(userId)!!.mutateAppIdDevicePermissionFlags() 67 val devicePermissionFlags = 68 appIdDevicePermissionFlags.mutate(appId) ?: return@forEachReversedIndexed 69 70 devicePermissionFlags.forEachReversedIndexed { _, deviceId, _ -> 71 if (deviceId !in deviceIds) { 72 devicePermissionFlags -= deviceId 73 } 74 } 75 } 76 } 77 } 78 79 fun MutateStateScope.onDeviceIdRemoved(deviceId: String) { 80 newState.userStates.forEachIndexed { _, userId, userState -> 81 userState.appIdDevicePermissionFlags.forEachReversedIndexed { _, appId, _ -> 82 val appIdDevicePermissionFlags = 83 newState.mutateUserState(userId)!!.mutateAppIdDevicePermissionFlags() 84 val devicePermissionFlags = 85 appIdDevicePermissionFlags.mutate(appId) ?: return@forEachReversedIndexed 86 devicePermissionFlags -= deviceId 87 } 88 } 89 } 90 91 override fun MutateStateScope.onStorageVolumeMounted( 92 volumeUuid: String?, 93 packageNames: List<String>, 94 isSystemUpdated: Boolean 95 ) { 96 packageNames.forEachIndexed { _, packageName -> 97 // The package may still be removed even if it was once notified as installed. 98 val packageState = 99 newState.externalState.packageStates[packageName] ?: return@forEachIndexed 100 trimPermissionStates(packageState.appId) 101 } 102 } 103 104 override fun MutateStateScope.onPackageAdded(packageState: PackageState) { 105 trimPermissionStates(packageState.appId) 106 } 107 108 override fun MutateStateScope.onPackageRemoved(packageName: String, appId: Int) { 109 if (appId in newState.externalState.appIdPackageNames) { 110 trimPermissionStates(appId) 111 } 112 } 113 114 override fun MutateStateScope.onPackageUninstalled( 115 packageName: String, 116 appId: Int, 117 userId: Int 118 ) { 119 resetRuntimePermissions(packageName, userId) 120 } 121 122 /** 123 * Reset permission states for all permissions requested by the given package, if no other 124 * package (sharing the App ID) request these permissions. 125 */ 126 fun MutateStateScope.resetRuntimePermissions(packageName: String, userId: Int) { 127 // It's okay to skip resetting permissions for packages that are removed, 128 // because their states will be trimmed in onPackageRemoved()/onAppIdRemoved() 129 val packageState = newState.externalState.packageStates[packageName] ?: return 130 val androidPackage = packageState.androidPackage ?: return 131 val appId = packageState.appId 132 // The user may happen removed due to DeletePackageHelper.removeUnusedPackagesLPw() calling 133 // deletePackageX() asynchronously. 134 val userState = newState.userStates[userId] ?: return 135 val devicePermissionFlags = userState.appIdDevicePermissionFlags[appId] ?: return 136 androidPackage.requestedPermissions.forEach { permissionName -> 137 val isRequestedByOtherPackages = 138 anyPackageInAppId(appId) { 139 it.packageName != packageName && 140 permissionName in it.androidPackage!!.requestedPermissions 141 } 142 if (isRequestedByOtherPackages) { 143 return@forEach 144 } 145 devicePermissionFlags.forEachIndexed { _, deviceId, _ -> 146 setPermissionFlags(appId, deviceId, userId, permissionName, 0) 147 } 148 } 149 } 150 151 // Trims permission state for permissions not requested by the App ID anymore. 152 private fun MutateStateScope.trimPermissionStates(appId: Int) { 153 val requestedPermissions = MutableIndexedSet<String>() 154 forEachPackageInAppId(appId) { 155 requestedPermissions += it.androidPackage!!.requestedPermissions 156 } 157 newState.userStates.forEachIndexed { _, userId, userState -> 158 userState.appIdDevicePermissionFlags[appId]?.forEachReversedIndexed { 159 _, 160 deviceId, 161 permissionFlags -> 162 permissionFlags.forEachReversedIndexed { _, permissionName, _ -> 163 if (permissionName !in requestedPermissions) { 164 setPermissionFlags(appId, deviceId, userId, permissionName, 0) 165 } 166 } 167 } 168 } 169 } 170 171 private inline fun MutateStateScope.anyPackageInAppId( 172 appId: Int, 173 state: AccessState = newState, 174 predicate: (PackageState) -> Boolean 175 ): Boolean { 176 val packageNames = state.externalState.appIdPackageNames[appId]!! 177 return packageNames.anyIndexed { _, packageName -> 178 val packageState = state.externalState.packageStates[packageName]!! 179 packageState.androidPackage != null && predicate(packageState) 180 } 181 } 182 183 private inline fun MutateStateScope.forEachPackageInAppId( 184 appId: Int, 185 state: AccessState = newState, 186 action: (PackageState) -> Unit 187 ) { 188 val packageNames = state.externalState.appIdPackageNames[appId]!! 189 packageNames.forEachIndexed { _, packageName -> 190 val packageState = state.externalState.packageStates[packageName]!! 191 if (packageState.androidPackage != null) { 192 action(packageState) 193 } 194 } 195 } 196 197 override fun BinaryXmlPullParser.parseUserState(state: MutableAccessState, userId: Int) { 198 with(persistence) { this@parseUserState.parseUserState(state, userId) } 199 } 200 201 override fun BinaryXmlSerializer.serializeUserState(state: AccessState, userId: Int) { 202 with(persistence) { this@serializeUserState.serializeUserState(state, userId) } 203 } 204 205 fun GetStateScope.getPermissionFlags( 206 appId: Int, 207 deviceId: String, 208 userId: Int, 209 permissionName: String 210 ): Int { 211 val flags = 212 state.userStates[userId] 213 ?.appIdDevicePermissionFlags 214 ?.get(appId) 215 ?.get(deviceId) 216 ?.getWithDefault(permissionName, 0) 217 ?: 0 218 if (PermissionManager.DEBUG_DEVICE_PERMISSIONS) { 219 Slog.i( 220 LOG_TAG, 221 "getPermissionFlags: appId=$appId, userId=$userId," + 222 " deviceId=$deviceId, permissionName=$permissionName," + 223 " flags=${PermissionFlags.toString(flags)}" 224 ) 225 } 226 return flags 227 } 228 229 fun GetStateScope.getAllPermissionFlags( 230 appId: Int, 231 persistentDeviceId: String, 232 userId: Int 233 ): IndexedMap<String, Int>? = 234 state.userStates[userId] 235 ?.appIdDevicePermissionFlags 236 ?.get(appId) 237 ?.get(persistentDeviceId) 238 239 fun MutateStateScope.setPermissionFlags( 240 appId: Int, 241 deviceId: String, 242 userId: Int, 243 permissionName: String, 244 flags: Int 245 ): Boolean = 246 updatePermissionFlags( 247 appId, 248 deviceId, 249 userId, 250 permissionName, 251 PermissionFlags.MASK_ALL, 252 flags 253 ) 254 255 private fun MutateStateScope.updatePermissionFlags( 256 appId: Int, 257 deviceId: String, 258 userId: Int, 259 permissionName: String, 260 flagMask: Int, 261 flagValues: Int 262 ): Boolean { 263 if (userId !in newState.userStates) { 264 // Despite that we check UserManagerInternal.exists() in PermissionService, we may still 265 // sometimes get race conditions between that check and the actual mutateState() call. 266 // This should rarely happen but at least we should not crash. 267 Slog.e(LOG_TAG, "Unable to update permission flags for missing user $userId") 268 return false 269 } 270 val oldFlags = 271 newState.userStates[userId]!! 272 .appIdDevicePermissionFlags[appId] 273 ?.get(deviceId) 274 .getWithDefault(permissionName, 0) 275 val newFlags = (oldFlags andInv flagMask) or (flagValues and flagMask) 276 if (oldFlags == newFlags) { 277 return false 278 } 279 val appIdDevicePermissionFlags = 280 newState.mutateUserState(userId)!!.mutateAppIdDevicePermissionFlags() 281 val devicePermissionFlags = 282 appIdDevicePermissionFlags.mutateOrPut(appId) { MutableIndexedReferenceMap() } 283 if (PermissionManager.DEBUG_DEVICE_PERMISSIONS) { 284 Slog.i( 285 LOG_TAG, 286 "setPermissionFlags(): appId=$appId, userId=$userId," + 287 " deviceId=$deviceId, permissionName=$permissionName," + 288 " newFlags=${PermissionFlags.toString(newFlags)}" 289 ) 290 } 291 val permissionFlags = devicePermissionFlags.mutateOrPut(deviceId) { MutableIndexedMap() } 292 permissionFlags.putWithDefault(permissionName, newFlags, 0) 293 if (permissionFlags.isEmpty()) { 294 devicePermissionFlags -= deviceId 295 if (devicePermissionFlags.isEmpty()) { 296 appIdDevicePermissionFlags -= appId 297 } 298 } 299 listeners.forEachIndexed { _, it -> 300 it.onDevicePermissionFlagsChanged( 301 appId, 302 userId, 303 deviceId, 304 permissionName, 305 oldFlags, 306 newFlags 307 ) 308 } 309 return true 310 } 311 312 fun addOnPermissionFlagsChangedListener(listener: OnDevicePermissionFlagsChangedListener) { 313 synchronized(listenersLock) { listeners = listeners + listener } 314 } 315 316 companion object { 317 private val LOG_TAG = DevicePermissionPolicy::class.java.simpleName 318 } 319 320 /** Listener for permission flags changes. */ 321 interface OnDevicePermissionFlagsChangedListener { 322 /** 323 * Called when a permission flags change has been made to the upcoming new state. 324 * 325 * Implementations should keep this method fast to avoid stalling the locked state mutation, 326 * and only call external code after [onStateMutated] when the new state has actually become 327 * the current state visible to external code. 328 */ 329 fun onDevicePermissionFlagsChanged( 330 appId: Int, 331 userId: Int, 332 deviceId: String, 333 permissionName: String, 334 oldFlags: Int, 335 newFlags: Int 336 ) 337 338 /** 339 * Called when the upcoming new state has become the current state. 340 * 341 * Implementations should keep this method fast to avoid stalling the locked state mutation. 342 */ 343 fun onStateMutated() 344 } 345 } 346