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.util.Slog 21 import com.android.server.permission.access.GetStateScope 22 import com.android.server.permission.access.MutableAccessState 23 import com.android.server.permission.access.MutateStateScope 24 import com.android.server.permission.access.UidUri 25 import com.android.server.permission.access.collection.* // ktlint-disable no-wildcard-imports 26 import com.android.server.permission.access.immutable.* // ktlint-disable no-wildcard-imports 27 import com.android.server.pm.pkg.PackageState 28 29 class AppIdAppOpPolicy : BaseAppOpPolicy(AppIdAppOpPersistence()) { 30 private val migration = AppIdAppOpMigration() 31 32 private val upgrade = AppIdAppOpUpgrade(this) 33 34 @Volatile 35 private var onAppOpModeChangedListeners: IndexedListSet<OnAppOpModeChangedListener> = 36 MutableIndexedListSet() 37 private val onAppOpModeChangedListenersLock = Any() 38 39 override val subjectScheme: String 40 get() = UidUri.SCHEME 41 42 override fun GetStateScope.onStateMutated() { 43 onAppOpModeChangedListeners.forEachIndexed { _, it -> it.onStateMutated() } 44 } 45 46 override fun MutateStateScope.onAppIdRemoved(appId: Int) { 47 newState.userStates.forEachIndexed { userStateIndex, _, userState -> 48 val appIdIndex = userState.appIdAppOpModes.indexOfKey(appId) 49 if (appIdIndex >= 0) { 50 newState 51 .mutateUserStateAt(userStateIndex) 52 .mutateAppIdAppOpModes() 53 .removeAt(appIdIndex) 54 // Skip notifying the change listeners since the app ID no longer exists. 55 } 56 } 57 } 58 59 fun GetStateScope.getAppOpModes(appId: Int, userId: Int): IndexedMap<String, Int>? = 60 state.userStates[userId]?.appIdAppOpModes?.get(appId) 61 62 fun MutateStateScope.removeAppOpModes(appId: Int, userId: Int): Boolean { 63 val userStateIndex = newState.userStates.indexOfKey(userId) 64 if (userStateIndex < 0) { 65 return false 66 } 67 val appIdIndex = 68 newState.userStates.valueAt(userStateIndex).appIdAppOpModes.indexOfKey(appId) 69 if (appIdIndex < 0) { 70 return false 71 } 72 newState.mutateUserStateAt(userStateIndex).mutateAppIdAppOpModes().removeAt(appIdIndex) 73 return true 74 } 75 76 fun GetStateScope.getAppOpMode(appId: Int, userId: Int, appOpName: String): Int = 77 state.userStates[userId] 78 ?.appIdAppOpModes 79 ?.get(appId) 80 .getWithDefault(appOpName, AppOpsManager.opToDefaultMode(appOpName)) 81 82 fun MutateStateScope.setAppOpMode( 83 appId: Int, 84 userId: Int, 85 appOpName: String, 86 mode: Int 87 ): Boolean { 88 if (userId !in newState.userStates) { 89 Slog.e(LOG_TAG, "Unable to set app op mode for missing user $userId") 90 return false 91 } 92 val defaultMode = AppOpsManager.opToDefaultMode(appOpName) 93 val oldMode = 94 newState.userStates[userId]!! 95 .appIdAppOpModes[appId] 96 .getWithDefault(appOpName, defaultMode) 97 if (oldMode == mode) { 98 return false 99 } 100 val appIdAppOpModes = newState.mutateUserState(userId)!!.mutateAppIdAppOpModes() 101 val appOpModes = appIdAppOpModes.mutateOrPut(appId) { MutableIndexedMap() } 102 appOpModes.putWithDefault(appOpName, mode, defaultMode) 103 if (appOpModes.isEmpty()) { 104 appIdAppOpModes -= appId 105 } 106 onAppOpModeChangedListeners.forEachIndexed { _, it -> 107 it.onAppOpModeChanged(appId, userId, appOpName, oldMode, mode) 108 } 109 return true 110 } 111 112 fun addOnAppOpModeChangedListener(listener: OnAppOpModeChangedListener) { 113 synchronized(onAppOpModeChangedListenersLock) { 114 onAppOpModeChangedListeners = onAppOpModeChangedListeners + listener 115 } 116 } 117 118 fun removeOnAppOpModeChangedListener(listener: OnAppOpModeChangedListener) { 119 synchronized(onAppOpModeChangedListenersLock) { 120 onAppOpModeChangedListeners = onAppOpModeChangedListeners - listener 121 } 122 } 123 124 override fun migrateUserState(state: MutableAccessState, userId: Int) { 125 with(migration) { migrateUserState(state, userId) } 126 } 127 128 override fun MutateStateScope.upgradePackageState( 129 packageState: PackageState, 130 userId: Int, 131 version: Int, 132 ) { 133 with(upgrade) { upgradePackageState(packageState, userId, version) } 134 } 135 136 /** Listener for app op mode changes. */ 137 abstract class OnAppOpModeChangedListener { 138 /** 139 * Called when an app op mode change has been made to the upcoming new state. 140 * 141 * Implementations should keep this method fast to avoid stalling the locked state mutation, 142 * and only call external code after [onStateMutated] when the new state has actually become 143 * the current state visible to external code. 144 */ 145 abstract fun onAppOpModeChanged( 146 appId: Int, 147 userId: Int, 148 appOpName: String, 149 oldMode: Int, 150 newMode: Int 151 ) 152 153 /** 154 * Called when the upcoming new state has become the current state. 155 * 156 * Implementations should keep this method fast to avoid stalling the locked state mutation. 157 */ 158 abstract fun onStateMutated() 159 } 160 161 companion object { 162 private val LOG_TAG = AppIdAppOpPolicy::class.java.simpleName 163 } 164 } 165