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