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 AppOpsManager.opToPermission(appOpCode)?.let { permissionName -> 123 // Multiple ops might map to a single permission but only one is considered the 124 // runtime appop calculations. 125 if (appOpCode == AppOpsManager.permissionToOpCode(permissionName)) { 126 val permission = permissions[permissionName]!! 127 if (permission.isRuntime) { 128 runtimePermissionNameToAppOp[permissionName] = appOpCode 129 runtimeAppOpToPermissionNames[appOpCode] = permissionName 130 permission.permissionInfo.backgroundPermission?.let { 131 backgroundPermissionName -> 132 // Note: background permission may not be runtime, 133 // e.g. microphone/camera. 134 foregroundableOps[appOpCode] = true 135 foregroundToBackgroundPermissionName[permissionName] = 136 backgroundPermissionName 137 backgroundToForegroundPermissionNames 138 .getOrPut(backgroundPermissionName, ::ArraySet) 139 .add(permissionName) 140 } 141 } 142 } 143 } 144 } 145 } 146 147 override fun getNonDefaultUidModes(uid: Int, deviceId: String): SparseIntArray { 148 val appId = UserHandle.getAppId(uid) 149 val userId = UserHandle.getUserId(uid) 150 service.getState { 151 val modes = 152 with(appIdPolicy) { opNameMapToOpSparseArray(getAppOpModes(appId, userId)?.map) } 153 if (Flags.runtimePermissionAppopsMappingEnabled()) { 154 runtimePermissionNameToAppOp.forEachIndexed { _, permissionName, appOpCode -> 155 val mode = 156 getUidModeFromPermissionState(appId, userId, permissionName, deviceId) 157 if (mode != AppOpsManager.opToDefaultMode(appOpCode)) { 158 modes[appOpCode] = mode 159 } 160 } 161 } 162 163 return modes 164 } 165 } 166 167 override fun getNonDefaultPackageModes(packageName: String, userId: Int): SparseIntArray { 168 return opNameMapToOpSparseArray(getPackageModes(packageName, userId)) 169 } 170 171 override fun getUidMode(uid: Int, deviceId: String, op: Int): Int { 172 val appId = UserHandle.getAppId(uid) 173 val userId = UserHandle.getUserId(uid) 174 val opName = AppOpsManager.opToPublicName(op) 175 val permissionName = runtimeAppOpToPermissionNames[op] 176 177 return if (!Flags.runtimePermissionAppopsMappingEnabled() || permissionName == null) { 178 service.getState { with(appIdPolicy) { getAppOpMode(appId, userId, opName) } } 179 } else { 180 service.getState { 181 getUidModeFromPermissionState(appId, userId, permissionName, deviceId) 182 } 183 } 184 } 185 186 private fun getUidModes(uid: Int): ArrayMap<String, Int>? { 187 val appId = UserHandle.getAppId(uid) 188 val userId = UserHandle.getUserId(uid) 189 return service.getState { with(appIdPolicy) { getAppOpModes(appId, userId) } }?.map 190 } 191 192 private fun GetStateScope.getUidModeFromPermissionState( 193 appId: Int, 194 userId: Int, 195 permissionName: String, 196 deviceId: String 197 ): Int { 198 val checkDevicePermissionFlags = 199 deviceId != VirtualDeviceManager.PERSISTENT_DEVICE_ID_DEFAULT && 200 permissionName in PermissionManager.DEVICE_AWARE_PERMISSIONS 201 val permissionFlags = 202 if (checkDevicePermissionFlags) { 203 with(devicePermissionPolicy) { 204 getPermissionFlags(appId, deviceId, userId, permissionName) 205 } 206 } else { 207 with(permissionPolicy) { getPermissionFlags(appId, userId, permissionName) } 208 } 209 val backgroundPermissionName = foregroundToBackgroundPermissionName[permissionName] 210 val backgroundPermissionFlags = 211 if (backgroundPermissionName != null) { 212 if (checkDevicePermissionFlags) { 213 with(devicePermissionPolicy) { 214 getPermissionFlags(appId, deviceId, userId, backgroundPermissionName) 215 } 216 } else { 217 with(permissionPolicy) { 218 getPermissionFlags(appId, userId, backgroundPermissionName) 219 } 220 } 221 } else { 222 PermissionFlags.RUNTIME_GRANTED 223 } 224 val result = evaluateModeFromPermissionFlags(permissionFlags, backgroundPermissionFlags) 225 if (result != MODE_IGNORED) { 226 return result 227 } 228 229 val fullerPermissionName = 230 PermissionService.getFullerPermission(permissionName) ?: return result 231 return getUidModeFromPermissionState(appId, userId, fullerPermissionName, deviceId) 232 } 233 234 private fun evaluateModeFromPermissionFlags( 235 foregroundFlags: Int, 236 backgroundFlags: Int = PermissionFlags.RUNTIME_GRANTED 237 ): Int = 238 if (PermissionFlags.isAppOpGranted(foregroundFlags)) { 239 if (PermissionFlags.isAppOpGranted(backgroundFlags)) { 240 MODE_ALLOWED 241 } else { 242 MODE_FOREGROUND 243 } 244 } else { 245 MODE_IGNORED 246 } 247 248 override fun setUidMode(uid: Int, deviceId: String, code: Int, mode: Int): Boolean { 249 val appId = UserHandle.getAppId(uid) 250 val userId = UserHandle.getUserId(uid) 251 val appOpName = AppOpsManager.opToPublicName(code) 252 253 if ( 254 Flags.runtimePermissionAppopsMappingEnabled() && code in runtimeAppOpToPermissionNames 255 ) { 256 val oldMode = 257 service.getState { with(appIdPolicy) { getAppOpMode(appId, userId, appOpName) } } 258 val wouldHaveChanged = oldMode != mode 259 val logMessage = 260 (if (wouldHaveChanged) "Blocked" else "Ignored") + 261 " setUidMode call for runtime permission app op:" + 262 " uid = $uid," + 263 " code = ${AppOpsManager.opToName(code)}," + 264 " mode = ${AppOpsManager.modeToName(mode)}," + 265 " callingUid = ${Binder.getCallingUid()}," + 266 " oldMode = ${AppOpsManager.modeToName(oldMode)}" 267 if (wouldHaveChanged) { 268 Slog.e(LOG_TAG, logMessage, RuntimeException()) 269 } else { 270 Slog.w(LOG_TAG, logMessage) 271 } 272 return false 273 } 274 275 var wasChanged: Boolean 276 service.mutateState { 277 wasChanged = with(appIdPolicy) { setAppOpMode(appId, userId, appOpName, mode) } 278 } 279 return wasChanged 280 } 281 282 override fun getPackageMode(packageName: String, op: Int, userId: Int): Int { 283 val opName = AppOpsManager.opToPublicName(op) 284 return service.getState { 285 with(packagePolicy) { getAppOpMode(packageName, userId, opName) } 286 } 287 } 288 289 private fun getPackageModes(packageName: String, userId: Int): ArrayMap<String, Int>? = 290 service.getState { with(packagePolicy) { getAppOpModes(packageName, userId) } }?.map 291 292 override fun setPackageMode(packageName: String, appOpCode: Int, mode: Int, userId: Int) { 293 val appOpName = AppOpsManager.opToPublicName(appOpCode) 294 295 if ( 296 Flags.runtimePermissionAppopsMappingEnabled() && 297 appOpCode in runtimeAppOpToPermissionNames 298 ) { 299 Slog.w( 300 LOG_TAG, 301 "(packageName=$packageName, userId=$userId)'s appop state" + 302 " for runtime op $appOpName should not be set directly.", 303 RuntimeException() 304 ) 305 return 306 } 307 service.mutateState { 308 with(packagePolicy) { setAppOpMode(packageName, userId, appOpName, mode) } 309 } 310 } 311 312 override fun removeUid(uid: Int) { 313 val appId = UserHandle.getAppId(uid) 314 val userId = UserHandle.getUserId(uid) 315 service.mutateState { with(appIdPolicy) { removeAppOpModes(appId, userId) } } 316 } 317 318 override fun removePackage(packageName: String, userId: Int): Boolean { 319 var wasChanged: Boolean 320 service.mutateState { 321 wasChanged = with(packagePolicy) { removeAppOpModes(packageName, userId) } 322 } 323 return wasChanged 324 } 325 326 private fun opNameMapToOpSparseArray(modes: ArrayMap<String, Int>?): SparseIntArray = 327 if (modes == null) { 328 SparseIntArray() 329 } else { 330 val opSparseArray = SparseIntArray(modes.size) 331 modes.forEachIndexed { _, opName, opMode -> 332 opSparseArray.put(AppOpsManager.strOpToOp(opName), opMode) 333 } 334 opSparseArray 335 } 336 337 override fun clearAllModes() { 338 // We don't need to implement this because it's only called in AppOpsService#readState 339 // and we have our own persistence. 340 } 341 342 override fun getForegroundOps(uid: Int, deviceId: String): SparseBooleanArray { 343 return SparseBooleanArray().apply { 344 getUidModes(uid)?.forEachIndexed { _, op, mode -> 345 if (mode == AppOpsManager.MODE_FOREGROUND) { 346 this[AppOpsManager.strOpToOp(op)] = true 347 } 348 } 349 if (Flags.runtimePermissionAppopsMappingEnabled()) { 350 foregroundableOps.forEachIndexed { _, op, _ -> 351 if (getUidMode(uid, deviceId, op) == AppOpsManager.MODE_FOREGROUND) { 352 this[op] = true 353 } 354 } 355 } 356 } 357 } 358 359 override fun getForegroundOps(packageName: String, userId: Int): SparseBooleanArray { 360 return SparseBooleanArray().apply { 361 getPackageModes(packageName, userId)?.forEachIndexed { _, op, mode -> 362 if (mode == AppOpsManager.MODE_FOREGROUND) { 363 this[AppOpsManager.strOpToOp(op)] = true 364 } 365 } 366 if (Flags.runtimePermissionAppopsMappingEnabled()) { 367 foregroundableOps.forEachIndexed { _, op, _ -> 368 if (getPackageMode(packageName, op, userId) == AppOpsManager.MODE_FOREGROUND) { 369 this[op] = true 370 } 371 } 372 } 373 } 374 } 375 376 override fun addAppOpsModeChangedListener(listener: AppOpsModeChangedListener): Boolean { 377 synchronized(listenersLock) { 378 val newListeners = ArraySet(listeners) 379 val result = newListeners.add(listener) 380 listeners = newListeners 381 return result 382 } 383 } 384 385 override fun removeAppOpsModeChangedListener(listener: AppOpsModeChangedListener): Boolean { 386 synchronized(listenersLock) { 387 val newListeners = ArraySet(listeners) 388 val result = newListeners.remove(listener) 389 listeners = newListeners 390 return result 391 } 392 } 393 394 private inner class OnAppIdAppOpModeChangedListener : 395 AppIdAppOpPolicy.OnAppOpModeChangedListener() { 396 // (uid, appOpCode) -> newMode 397 private val pendingChanges = LongSparseArray<Int>() 398 399 override fun onAppOpModeChanged( 400 appId: Int, 401 userId: Int, 402 appOpName: String, 403 oldMode: Int, 404 newMode: Int 405 ) { 406 val uid = UserHandle.getUid(userId, appId) 407 val appOpCode = AppOpsManager.strOpToOp(appOpName) 408 val key = IntPair.of(uid, appOpCode) 409 410 pendingChanges[key] = newMode 411 } 412 413 override fun onStateMutated() { 414 val listenersLocal = listeners 415 pendingChanges.forEachIndexed { _, key, mode -> 416 listenersLocal.forEachIndexed { _, listener -> 417 val uid = IntPair.first(key) 418 val appOpCode = IntPair.second(key) 419 420 listener.onUidModeChanged( 421 uid, 422 appOpCode, 423 mode, 424 VirtualDeviceManager.PERSISTENT_DEVICE_ID_DEFAULT 425 ) 426 } 427 } 428 429 pendingChanges.clear() 430 } 431 } 432 433 private inner class OnPackageAppOpModeChangedListener : 434 PackageAppOpPolicy.OnAppOpModeChangedListener() { 435 // (packageName, userId, appOpCode) -> newMode 436 private val pendingChanges = ArrayMap<Triple<String, Int, Int>, Int>() 437 438 override fun onAppOpModeChanged( 439 packageName: String, 440 userId: Int, 441 appOpName: String, 442 oldMode: Int, 443 newMode: Int 444 ) { 445 val appOpCode = AppOpsManager.strOpToOp(appOpName) 446 val key = Triple(packageName, userId, appOpCode) 447 448 pendingChanges[key] = newMode 449 } 450 451 override fun onStateMutated() { 452 val listenersLocal = listeners 453 pendingChanges.forEachIndexed { _, key, mode -> 454 listenersLocal.forEachIndexed { _, listener -> 455 val packageName = key.first 456 val userId = key.second 457 val appOpCode = key.third 458 459 listener.onPackageModeChanged(packageName, userId, appOpCode, mode) 460 } 461 } 462 463 pendingChanges.clear() 464 } 465 } 466 467 private inner class OnPermissionFlagsChangedListener : 468 AppIdPermissionPolicy.OnPermissionFlagsChangedListener, 469 DevicePermissionPolicy.OnDevicePermissionFlagsChangedListener { 470 // (uid, deviceId, appOpCode) -> newMode 471 private val pendingChanges = ArrayMap<Triple<Int, String, Int>, Int>() 472 473 override fun onPermissionFlagsChanged( 474 appId: Int, 475 userId: Int, 476 permissionName: String, 477 oldFlags: Int, 478 newFlags: Int 479 ) { 480 onDevicePermissionFlagsChanged( 481 appId, 482 userId, 483 VirtualDeviceManager.PERSISTENT_DEVICE_ID_DEFAULT, 484 permissionName, 485 oldFlags, 486 newFlags 487 ) 488 } 489 490 override fun onDevicePermissionFlagsChanged( 491 appId: Int, 492 userId: Int, 493 deviceId: String, 494 permissionName: String, 495 oldFlags: Int, 496 newFlags: Int 497 ) { 498 backgroundToForegroundPermissionNames[permissionName]?.let { foregroundPermissions -> 499 // This is a background permission; there may be multiple foreground permissions 500 // affected. 501 foregroundPermissions.forEachIndexed { _, foregroundPermissionName -> 502 runtimePermissionNameToAppOp[foregroundPermissionName]?.let { appOpCode -> 503 val foregroundPermissionFlags = 504 getPermissionFlags(appId, userId, foregroundPermissionName) 505 addPendingChangedModeIfNeeded( 506 appId, 507 userId, 508 deviceId, 509 appOpCode, 510 foregroundPermissionFlags, 511 oldFlags, 512 foregroundPermissionFlags, 513 newFlags 514 ) 515 } 516 } 517 } 518 ?: foregroundToBackgroundPermissionName[permissionName]?.let { backgroundPermission 519 -> 520 runtimePermissionNameToAppOp[permissionName]?.let { appOpCode -> 521 val backgroundPermissionFlags = 522 getPermissionFlags(appId, userId, backgroundPermission) 523 addPendingChangedModeIfNeeded( 524 appId, 525 userId, 526 deviceId, 527 appOpCode, 528 oldFlags, 529 backgroundPermissionFlags, 530 newFlags, 531 backgroundPermissionFlags 532 ) 533 } 534 } 535 ?: runtimePermissionNameToAppOp[permissionName]?.let { appOpCode -> 536 addPendingChangedModeIfNeeded( 537 appId, 538 userId, 539 deviceId, 540 appOpCode, 541 oldFlags, 542 PermissionFlags.RUNTIME_GRANTED, 543 newFlags, 544 PermissionFlags.RUNTIME_GRANTED 545 ) 546 } 547 } 548 549 private fun getPermissionFlags(appId: Int, userId: Int, permissionName: String): Int = 550 service.getState { 551 with(permissionPolicy) { getPermissionFlags(appId, userId, permissionName) } 552 } 553 554 private fun addPendingChangedModeIfNeeded( 555 appId: Int, 556 userId: Int, 557 deviceId: String, 558 appOpCode: Int, 559 oldForegroundFlags: Int, 560 oldBackgroundFlags: Int, 561 newForegroundFlags: Int, 562 newBackgroundFlags: Int, 563 ) { 564 val oldMode = evaluateModeFromPermissionFlags(oldForegroundFlags, oldBackgroundFlags) 565 val newMode = evaluateModeFromPermissionFlags(newForegroundFlags, newBackgroundFlags) 566 567 if (oldMode != newMode) { 568 val uid = UserHandle.getUid(userId, appId) 569 pendingChanges[Triple(uid, deviceId, appOpCode)] = newMode 570 } 571 } 572 573 override fun onStateMutated() { 574 val listenersLocal = listeners 575 pendingChanges.forEachIndexed { _, key, mode -> 576 listenersLocal.forEachIndexed { _, listener -> 577 val uid = key.first 578 val deviceId = key.second 579 val appOpCode = key.third 580 581 listener.onUidModeChanged(uid, appOpCode, mode, deviceId) 582 } 583 } 584 585 pendingChanges.clear() 586 } 587 } 588 589 companion object { 590 private val LOG_TAG = AppOpService::class.java.simpleName 591 } 592 } 593