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