1 /* <lambda>null2 * Copyright (C) 2022 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.appop 18 19 import android.app.AppOpsManager 20 import android.companion.virtual.VirtualDeviceManager 21 import android.os.Binder 22 import android.os.Handler 23 import android.os.UserHandle 24 import android.permission.PermissionManager 25 import android.permission.flags.Flags 26 import android.util.ArrayMap 27 import android.util.ArraySet 28 import android.util.LongSparseArray 29 import android.util.Slog 30 import android.util.SparseArray 31 import android.util.SparseBooleanArray 32 import android.util.SparseIntArray 33 import com.android.internal.annotations.VisibleForTesting 34 import com.android.internal.util.IntPair 35 import com.android.server.appop.AppOpsCheckingServiceInterface 36 import com.android.server.appop.AppOpsCheckingServiceInterface.AppOpsModeChangedListener 37 import com.android.server.permission.access.AccessCheckingService 38 import com.android.server.permission.access.AppOpUri 39 import com.android.server.permission.access.DevicePermissionUri 40 import com.android.server.permission.access.GetStateScope 41 import com.android.server.permission.access.PackageUri 42 import com.android.server.permission.access.PermissionUri 43 import com.android.server.permission.access.UidUri 44 import com.android.server.permission.access.appop.AppOpModes.MODE_ALLOWED 45 import com.android.server.permission.access.appop.AppOpModes.MODE_FOREGROUND 46 import com.android.server.permission.access.appop.AppOpModes.MODE_IGNORED 47 import com.android.server.permission.access.collection.forEachIndexed 48 import com.android.server.permission.access.collection.set 49 import com.android.server.permission.access.permission.AppIdPermissionPolicy 50 import com.android.server.permission.access.permission.DevicePermissionPolicy 51 import com.android.server.permission.access.permission.PermissionFlags 52 import com.android.server.permission.access.permission.PermissionService 53 54 class AppOpService(private val service: AccessCheckingService) : AppOpsCheckingServiceInterface { 55 private val packagePolicy = 56 service.getSchemePolicy(PackageUri.SCHEME, AppOpUri.SCHEME) as PackageAppOpPolicy 57 private val appIdPolicy = 58 service.getSchemePolicy(UidUri.SCHEME, AppOpUri.SCHEME) as AppIdAppOpPolicy 59 private val permissionPolicy = 60 service.getSchemePolicy(UidUri.SCHEME, PermissionUri.SCHEME) as AppIdPermissionPolicy 61 private val devicePermissionPolicy = 62 service.getSchemePolicy(UidUri.SCHEME, DevicePermissionUri.SCHEME) as DevicePermissionPolicy 63 64 private val context = service.context 65 66 // Maps appop code to its runtime permission 67 private val runtimeAppOpToPermissionNames = SparseArray<String>() 68 69 // Maps runtime permission to its appop codes 70 private val runtimePermissionNameToAppOp = ArrayMap<String, Int>() 71 72 private var foregroundableOps = SparseBooleanArray() 73 74 /* Maps foreground permissions to their background permission. Background permissions aren't 75 required to be runtime */ 76 private val foregroundToBackgroundPermissionName = ArrayMap<String, String>() 77 78 /* Maps background permissions to their foreground permissions. Background permissions aren't 79 required to be runtime */ 80 private val backgroundToForegroundPermissionNames = ArrayMap<String, ArraySet<String>>() 81 82 private lateinit var handler: Handler 83 84 @Volatile private var listeners = ArraySet<AppOpsModeChangedListener>() 85 private val listenersLock = Any() 86 87 fun initialize() { 88 // TODO(b/252883039): Wrong handler. Inject main thread handler here. 89 handler = Handler(context.mainLooper) 90 91 appIdPolicy.addOnAppOpModeChangedListener(OnAppIdAppOpModeChangedListener()) 92 packagePolicy.addOnAppOpModeChangedListener(OnPackageAppOpModeChangedListener()) 93 } 94 95 @VisibleForTesting 96 override fun writeState() { 97 // Not implemented because writes are handled automatically. 98 } 99 100 override fun readState() { 101 // Not implemented because reads are handled automatically. 102 } 103 104 @VisibleForTesting 105 override fun shutdown() { 106 // Not implemented because writes are handled automatically. 107 } 108 109 override fun systemReady() { 110 if (Flags.runtimePermissionAppopsMappingEnabled()) { 111 createPermissionAppOpMapping() 112 val permissionListener = OnPermissionFlagsChangedListener() 113 permissionPolicy.addOnPermissionFlagsChangedListener(permissionListener) 114 devicePermissionPolicy.addOnPermissionFlagsChangedListener(permissionListener) 115 } 116 } 117 118 private fun createPermissionAppOpMapping() { 119 val permissions = service.getState { with(permissionPolicy) { getPermissions() } } 120 121 for (appOpCode in 0 until AppOpsManager._NUM_OP) { 122 // Ops that default to MODE_FOREGROUND are foregroundable. 123 if (AppOpsManager.opToDefaultMode(appOpCode) == AppOpsManager.MODE_FOREGROUND) { 124 foregroundableOps[appOpCode] = true 125 } 126 AppOpsManager.opToPermission(appOpCode)?.let { permissionName -> 127 // Multiple ops might map to a single permission but only one is considered the 128 // runtime appop calculations. 129 if (appOpCode == AppOpsManager.permissionToOpCode(permissionName)) { 130 val permission = permissions[permissionName]!! 131 if (permission.isRuntime) { 132 runtimePermissionNameToAppOp[permissionName] = appOpCode 133 runtimeAppOpToPermissionNames[appOpCode] = permissionName 134 permission.permissionInfo.backgroundPermission?.let { 135 backgroundPermissionName -> 136 // Note: background permission may not be runtime, 137 // e.g. microphone/camera. 138 foregroundableOps[appOpCode] = true 139 foregroundToBackgroundPermissionName[permissionName] = 140 backgroundPermissionName 141 backgroundToForegroundPermissionNames 142 .getOrPut(backgroundPermissionName, ::ArraySet) 143 .add(permissionName) 144 } 145 } 146 } 147 } 148 } 149 } 150 151 override fun getNonDefaultUidModes(uid: Int, deviceId: String): SparseIntArray { 152 val appId = UserHandle.getAppId(uid) 153 val userId = UserHandle.getUserId(uid) 154 service.getState { 155 val modes = 156 with(appIdPolicy) { opNameMapToOpSparseArray(getAppOpModes(appId, userId)?.map) } 157 if (Flags.runtimePermissionAppopsMappingEnabled()) { 158 runtimePermissionNameToAppOp.forEachIndexed { _, permissionName, appOpCode -> 159 val mode = 160 getUidModeFromPermissionState(appId, userId, permissionName, deviceId) 161 if (mode != AppOpsManager.opToDefaultMode(appOpCode)) { 162 modes[appOpCode] = mode 163 } 164 } 165 } 166 167 return modes 168 } 169 } 170 171 override fun getNonDefaultPackageModes(packageName: String, userId: Int): SparseIntArray { 172 return opNameMapToOpSparseArray(getPackageModes(packageName, userId)) 173 } 174 175 override fun getUidMode(uid: Int, deviceId: String, op: Int): Int { 176 val appId = UserHandle.getAppId(uid) 177 val userId = UserHandle.getUserId(uid) 178 val opName = AppOpsManager.opToPublicName(op) 179 val permissionName = runtimeAppOpToPermissionNames[op] 180 181 return if (!Flags.runtimePermissionAppopsMappingEnabled() || permissionName == null) { 182 service.getState { with(appIdPolicy) { getAppOpMode(appId, userId, opName) } } 183 } else { 184 service.getState { 185 getUidModeFromPermissionState(appId, userId, permissionName, deviceId) 186 } 187 } 188 } 189 190 private fun getUidModes(uid: Int): ArrayMap<String, Int>? { 191 val appId = UserHandle.getAppId(uid) 192 val userId = UserHandle.getUserId(uid) 193 return service.getState { with(appIdPolicy) { getAppOpModes(appId, userId) } }?.map 194 } 195 196 private fun GetStateScope.getUidModeFromPermissionState( 197 appId: Int, 198 userId: Int, 199 permissionName: String, 200 deviceId: String 201 ): Int { 202 val checkDevicePermissionFlags = 203 deviceId != VirtualDeviceManager.PERSISTENT_DEVICE_ID_DEFAULT && 204 permissionName in PermissionManager.DEVICE_AWARE_PERMISSIONS 205 val permissionFlags = 206 if (checkDevicePermissionFlags) { 207 with(devicePermissionPolicy) { 208 getPermissionFlags(appId, deviceId, userId, permissionName) 209 } 210 } else { 211 with(permissionPolicy) { getPermissionFlags(appId, userId, permissionName) } 212 } 213 val backgroundPermissionName = foregroundToBackgroundPermissionName[permissionName] 214 val backgroundPermissionFlags = 215 if (backgroundPermissionName != null) { 216 if (checkDevicePermissionFlags) { 217 with(devicePermissionPolicy) { 218 getPermissionFlags(appId, deviceId, userId, backgroundPermissionName) 219 } 220 } else { 221 with(permissionPolicy) { 222 getPermissionFlags(appId, userId, backgroundPermissionName) 223 } 224 } 225 } else { 226 PermissionFlags.RUNTIME_GRANTED 227 } 228 val result = evaluateModeFromPermissionFlags(permissionFlags, backgroundPermissionFlags) 229 if (result != MODE_IGNORED) { 230 return result 231 } 232 233 val fullerPermissionName = 234 PermissionService.getFullerPermission(permissionName) ?: return result 235 return getUidModeFromPermissionState(appId, userId, fullerPermissionName, deviceId) 236 } 237 238 private fun evaluateModeFromPermissionFlags( 239 foregroundFlags: Int, 240 backgroundFlags: Int = PermissionFlags.RUNTIME_GRANTED 241 ): Int = 242 if (PermissionFlags.isAppOpGranted(foregroundFlags)) { 243 if (PermissionFlags.isAppOpGranted(backgroundFlags)) { 244 MODE_ALLOWED 245 } else { 246 MODE_FOREGROUND 247 } 248 } else { 249 MODE_IGNORED 250 } 251 252 override fun setUidMode(uid: Int, deviceId: String, code: Int, mode: Int): Boolean { 253 val appId = UserHandle.getAppId(uid) 254 val userId = UserHandle.getUserId(uid) 255 val appOpName = AppOpsManager.opToPublicName(code) 256 257 if ( 258 Flags.runtimePermissionAppopsMappingEnabled() && code in runtimeAppOpToPermissionNames 259 ) { 260 val oldMode = 261 service.getState { with(appIdPolicy) { getAppOpMode(appId, userId, appOpName) } } 262 val wouldHaveChanged = oldMode != mode 263 val logMessage = 264 (if (wouldHaveChanged) "Blocked" else "Ignored") + 265 " setUidMode call for runtime permission app op:" + 266 " uid = $uid," + 267 " code = ${AppOpsManager.opToName(code)}," + 268 " mode = ${AppOpsManager.modeToName(mode)}," + 269 " callingUid = ${Binder.getCallingUid()}," + 270 " oldMode = ${AppOpsManager.modeToName(oldMode)}" 271 if (wouldHaveChanged) { 272 Slog.e(LOG_TAG, logMessage, RuntimeException()) 273 } else { 274 Slog.w(LOG_TAG, logMessage) 275 } 276 return false 277 } 278 279 var wasChanged: Boolean 280 service.mutateState { 281 wasChanged = with(appIdPolicy) { setAppOpMode(appId, userId, appOpName, mode) } 282 } 283 return wasChanged 284 } 285 286 override fun getPackageMode(packageName: String, op: Int, userId: Int): Int { 287 val opName = AppOpsManager.opToPublicName(op) 288 return service.getState { 289 with(packagePolicy) { getAppOpMode(packageName, userId, opName) } 290 } 291 } 292 293 private fun getPackageModes(packageName: String, userId: Int): ArrayMap<String, Int>? = 294 service.getState { with(packagePolicy) { getAppOpModes(packageName, userId) } }?.map 295 296 override fun setPackageMode(packageName: String, appOpCode: Int, mode: Int, userId: Int) { 297 val appOpName = AppOpsManager.opToPublicName(appOpCode) 298 299 if ( 300 Flags.runtimePermissionAppopsMappingEnabled() && 301 appOpCode in runtimeAppOpToPermissionNames 302 ) { 303 Slog.w( 304 LOG_TAG, 305 "(packageName=$packageName, userId=$userId)'s appop state" + 306 " for runtime op $appOpName should not be set directly.", 307 RuntimeException() 308 ) 309 return 310 } 311 service.mutateState { 312 with(packagePolicy) { setAppOpMode(packageName, userId, appOpName, mode) } 313 } 314 } 315 316 override fun removeUid(uid: Int) { 317 val appId = UserHandle.getAppId(uid) 318 val userId = UserHandle.getUserId(uid) 319 service.mutateState { with(appIdPolicy) { removeAppOpModes(appId, userId) } } 320 } 321 322 override fun removePackage(packageName: String, userId: Int): Boolean { 323 var wasChanged: Boolean 324 service.mutateState { 325 wasChanged = with(packagePolicy) { removeAppOpModes(packageName, userId) } 326 } 327 return wasChanged 328 } 329 330 private fun opNameMapToOpSparseArray(modes: ArrayMap<String, Int>?): SparseIntArray = 331 if (modes == null) { 332 SparseIntArray() 333 } else { 334 val opSparseArray = SparseIntArray(modes.size) 335 modes.forEachIndexed { _, opName, opMode -> 336 opSparseArray.put(AppOpsManager.strOpToOp(opName), opMode) 337 } 338 opSparseArray 339 } 340 341 override fun clearAllModes() { 342 // We don't need to implement this because it's only called in AppOpsService#readState 343 // and we have our own persistence. 344 } 345 346 override fun getForegroundOps(uid: Int, deviceId: String): SparseBooleanArray { 347 return SparseBooleanArray().apply { 348 getUidModes(uid)?.forEachIndexed { _, op, mode -> 349 if (mode == AppOpsManager.MODE_FOREGROUND) { 350 this[AppOpsManager.strOpToOp(op)] = true 351 } 352 } 353 if (Flags.runtimePermissionAppopsMappingEnabled()) { 354 foregroundableOps.forEachIndexed { _, op, _ -> 355 if (getUidMode(uid, deviceId, op) == AppOpsManager.MODE_FOREGROUND) { 356 this[op] = true 357 } 358 } 359 } 360 } 361 } 362 363 override fun getForegroundOps(packageName: String, userId: Int): SparseBooleanArray { 364 return SparseBooleanArray().apply { 365 getPackageModes(packageName, userId)?.forEachIndexed { _, op, mode -> 366 if (mode == AppOpsManager.MODE_FOREGROUND) { 367 this[AppOpsManager.strOpToOp(op)] = true 368 } 369 } 370 if (Flags.runtimePermissionAppopsMappingEnabled()) { 371 foregroundableOps.forEachIndexed { _, op, _ -> 372 if (getPackageMode(packageName, op, userId) == AppOpsManager.MODE_FOREGROUND) { 373 this[op] = true 374 } 375 } 376 } 377 } 378 } 379 380 override fun addAppOpsModeChangedListener(listener: AppOpsModeChangedListener): Boolean { 381 synchronized(listenersLock) { 382 val newListeners = ArraySet(listeners) 383 val result = newListeners.add(listener) 384 listeners = newListeners 385 return result 386 } 387 } 388 389 override fun removeAppOpsModeChangedListener(listener: AppOpsModeChangedListener): Boolean { 390 synchronized(listenersLock) { 391 val newListeners = ArraySet(listeners) 392 val result = newListeners.remove(listener) 393 listeners = newListeners 394 return result 395 } 396 } 397 398 private inner class OnAppIdAppOpModeChangedListener : 399 AppIdAppOpPolicy.OnAppOpModeChangedListener() { 400 // (uid, appOpCode) -> newMode 401 private val pendingChanges = LongSparseArray<Int>() 402 403 override fun onAppOpModeChanged( 404 appId: Int, 405 userId: Int, 406 appOpName: String, 407 oldMode: Int, 408 newMode: Int 409 ) { 410 val uid = UserHandle.getUid(userId, appId) 411 val appOpCode = AppOpsManager.strOpToOp(appOpName) 412 val key = IntPair.of(uid, appOpCode) 413 414 pendingChanges[key] = newMode 415 } 416 417 override fun onStateMutated() { 418 val listenersLocal = listeners 419 pendingChanges.forEachIndexed { _, key, mode -> 420 listenersLocal.forEachIndexed { _, listener -> 421 val uid = IntPair.first(key) 422 val appOpCode = IntPair.second(key) 423 424 listener.onUidModeChanged( 425 uid, 426 appOpCode, 427 mode, 428 VirtualDeviceManager.PERSISTENT_DEVICE_ID_DEFAULT 429 ) 430 } 431 } 432 433 pendingChanges.clear() 434 } 435 } 436 437 private inner class OnPackageAppOpModeChangedListener : 438 PackageAppOpPolicy.OnAppOpModeChangedListener() { 439 // (packageName, userId, appOpCode) -> newMode 440 private val pendingChanges = ArrayMap<Triple<String, Int, Int>, Int>() 441 442 override fun onAppOpModeChanged( 443 packageName: String, 444 userId: Int, 445 appOpName: String, 446 oldMode: Int, 447 newMode: Int 448 ) { 449 val appOpCode = AppOpsManager.strOpToOp(appOpName) 450 val key = Triple(packageName, userId, appOpCode) 451 452 pendingChanges[key] = newMode 453 } 454 455 override fun onStateMutated() { 456 val listenersLocal = listeners 457 pendingChanges.forEachIndexed { _, key, mode -> 458 listenersLocal.forEachIndexed { _, listener -> 459 val packageName = key.first 460 val userId = key.second 461 val appOpCode = key.third 462 463 listener.onPackageModeChanged(packageName, userId, appOpCode, mode) 464 } 465 } 466 467 pendingChanges.clear() 468 } 469 } 470 471 private inner class OnPermissionFlagsChangedListener : 472 AppIdPermissionPolicy.OnPermissionFlagsChangedListener, 473 DevicePermissionPolicy.OnDevicePermissionFlagsChangedListener { 474 // (uid, deviceId, appOpCode) -> newMode 475 private val pendingChanges = ArrayMap<Triple<Int, String, Int>, Int>() 476 477 override fun onPermissionFlagsChanged( 478 appId: Int, 479 userId: Int, 480 permissionName: String, 481 oldFlags: Int, 482 newFlags: Int 483 ) { 484 onDevicePermissionFlagsChanged( 485 appId, 486 userId, 487 VirtualDeviceManager.PERSISTENT_DEVICE_ID_DEFAULT, 488 permissionName, 489 oldFlags, 490 newFlags 491 ) 492 } 493 494 override fun onDevicePermissionFlagsChanged( 495 appId: Int, 496 userId: Int, 497 deviceId: String, 498 permissionName: String, 499 oldFlags: Int, 500 newFlags: Int 501 ) { 502 backgroundToForegroundPermissionNames[permissionName]?.let { foregroundPermissions -> 503 // This is a background permission; there may be multiple foreground permissions 504 // affected. 505 foregroundPermissions.forEachIndexed { _, foregroundPermissionName -> 506 runtimePermissionNameToAppOp[foregroundPermissionName]?.let { appOpCode -> 507 val foregroundPermissionFlags = 508 getPermissionFlags(appId, userId, foregroundPermissionName) 509 addPendingChangedModeIfNeeded( 510 appId, 511 userId, 512 deviceId, 513 appOpCode, 514 foregroundPermissionFlags, 515 oldFlags, 516 foregroundPermissionFlags, 517 newFlags 518 ) 519 } 520 } 521 } 522 ?: foregroundToBackgroundPermissionName[permissionName]?.let { backgroundPermission 523 -> 524 runtimePermissionNameToAppOp[permissionName]?.let { appOpCode -> 525 val backgroundPermissionFlags = 526 getPermissionFlags(appId, userId, backgroundPermission) 527 addPendingChangedModeIfNeeded( 528 appId, 529 userId, 530 deviceId, 531 appOpCode, 532 oldFlags, 533 backgroundPermissionFlags, 534 newFlags, 535 backgroundPermissionFlags 536 ) 537 } 538 } 539 ?: runtimePermissionNameToAppOp[permissionName]?.let { appOpCode -> 540 addPendingChangedModeIfNeeded( 541 appId, 542 userId, 543 deviceId, 544 appOpCode, 545 oldFlags, 546 PermissionFlags.RUNTIME_GRANTED, 547 newFlags, 548 PermissionFlags.RUNTIME_GRANTED 549 ) 550 } 551 } 552 553 private fun getPermissionFlags(appId: Int, userId: Int, permissionName: String): Int = 554 service.getState { 555 with(permissionPolicy) { getPermissionFlags(appId, userId, permissionName) } 556 } 557 558 private fun addPendingChangedModeIfNeeded( 559 appId: Int, 560 userId: Int, 561 deviceId: String, 562 appOpCode: Int, 563 oldForegroundFlags: Int, 564 oldBackgroundFlags: Int, 565 newForegroundFlags: Int, 566 newBackgroundFlags: Int, 567 ) { 568 val oldMode = evaluateModeFromPermissionFlags(oldForegroundFlags, oldBackgroundFlags) 569 val newMode = evaluateModeFromPermissionFlags(newForegroundFlags, newBackgroundFlags) 570 571 if (oldMode != newMode) { 572 val uid = UserHandle.getUid(userId, appId) 573 pendingChanges[Triple(uid, deviceId, appOpCode)] = newMode 574 } 575 } 576 577 override fun onStateMutated() { 578 val listenersLocal = listeners 579 pendingChanges.forEachIndexed { _, key, mode -> 580 listenersLocal.forEachIndexed { _, listener -> 581 val uid = key.first 582 val deviceId = key.second 583 val appOpCode = key.third 584 585 listener.onUidModeChanged(uid, appOpCode, mode, deviceId) 586 } 587 } 588 589 pendingChanges.clear() 590 } 591 } 592 593 companion object { 594 private val LOG_TAG = AppOpService::class.java.simpleName 595 } 596 } 597