summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--services/permission/java/com/android/server/permission/access/AccessCheckingService.kt2
-rw-r--r--services/permission/java/com/android/server/permission/access/AccessPolicy.kt37
-rw-r--r--services/permission/java/com/android/server/permission/access/appop/BaseAppOpPolicy.kt43
-rw-r--r--services/permission/java/com/android/server/permission/access/appop/PackageAppOpPolicy.kt89
-rw-r--r--services/permission/java/com/android/server/permission/access/appop/UidAppOpPolicy.kt92
-rw-r--r--services/permission/java/com/android/server/permission/access/collection/IntMap.kt12
6 files changed, 171 insertions, 104 deletions
diff --git a/services/permission/java/com/android/server/permission/access/AccessCheckingService.kt b/services/permission/java/com/android/server/permission/access/AccessCheckingService.kt
index 73c2cccc550d..cc4c95f8327d 100644
--- a/services/permission/java/com/android/server/permission/access/AccessCheckingService.kt
+++ b/services/permission/java/com/android/server/permission/access/AccessCheckingService.kt
@@ -140,7 +140,7 @@ class AccessCheckingService(context: Context) : SystemService(context) {
internal inline fun <T> getState(action: GetStateScope.() -> T): T =
GetStateScope(state).action()
- internal inline fun mutateState(action: MutateStateScope.() -> Unit) {
+ internal inline fun mutateState(crossinline action: MutateStateScope.() -> Unit) {
synchronized(stateLock) {
val oldState = state
val newState = oldState.copy()
diff --git a/services/permission/java/com/android/server/permission/access/AccessPolicy.kt b/services/permission/java/com/android/server/permission/access/AccessPolicy.kt
index 0201dd0d0c79..c4182f487c2e 100644
--- a/services/permission/java/com/android/server/permission/access/AccessPolicy.kt
+++ b/services/permission/java/com/android/server/permission/access/AccessPolicy.kt
@@ -241,10 +241,6 @@ class AccessPolicy private constructor(
}
abstract class SchemePolicy {
- @Volatile
- private var onDecisionChangedListeners = IndexedListSet<OnDecisionChangedListener>()
- private val onDecisionChangedListenersLock = Any()
-
abstract val subjectScheme: String
abstract val objectScheme: String
@@ -257,30 +253,6 @@ abstract class SchemePolicy {
decision: Int
)
- fun addOnDecisionChangedListener(listener: OnDecisionChangedListener) {
- synchronized(onDecisionChangedListenersLock) {
- onDecisionChangedListeners = onDecisionChangedListeners + listener
- }
- }
-
- fun removeOnDecisionChangedListener(listener: OnDecisionChangedListener) {
- synchronized(onDecisionChangedListenersLock) {
- onDecisionChangedListeners = onDecisionChangedListeners - listener
- }
- }
-
- protected fun notifyOnDecisionChangedListeners(
- subject: AccessUri,
- `object`: AccessUri,
- oldDecision: Int,
- newDecision: Int
- ) {
- val listeners = onDecisionChangedListeners
- listeners.forEachIndexed { _, it ->
- it.onDecisionChanged(subject, `object`, oldDecision, newDecision)
- }
- }
-
open fun MutateStateScope.onUserAdded(userId: Int) {}
open fun MutateStateScope.onUserRemoved(userId: Int) {}
@@ -313,13 +285,4 @@ abstract class SchemePolicy {
open fun BinaryXmlPullParser.parseUserState(userId: Int, userState: UserState) {}
open fun BinaryXmlSerializer.serializeUserState(userId: Int, userState: UserState) {}
-
- fun interface OnDecisionChangedListener {
- fun onDecisionChanged(
- subject: AccessUri,
- `object`: AccessUri,
- oldDecision: Int,
- newDecision: Int
- )
- }
}
diff --git a/services/permission/java/com/android/server/permission/access/appop/BaseAppOpPolicy.kt b/services/permission/java/com/android/server/permission/access/appop/BaseAppOpPolicy.kt
index a1a5e2d90091..7f4e0f72537e 100644
--- a/services/permission/java/com/android/server/permission/access/appop/BaseAppOpPolicy.kt
+++ b/services/permission/java/com/android/server/permission/access/appop/BaseAppOpPolicy.kt
@@ -16,50 +16,17 @@
package com.android.server.permission.access.appop
-import android.app.AppOpsManager
import com.android.modules.utils.BinaryXmlPullParser
import com.android.modules.utils.BinaryXmlSerializer
-import com.android.server.permission.access.AccessUri
import com.android.server.permission.access.AppOpUri
-import com.android.server.permission.access.GetStateScope
-import com.android.server.permission.access.MutateStateScope
import com.android.server.permission.access.SchemePolicy
import com.android.server.permission.access.UserState
-import com.android.server.permission.access.collection.* // ktlint-disable no-wildcard-imports
-abstract class BaseAppOpPolicy(private val persistence: BaseAppOpPersistence) : SchemePolicy() {
- override fun GetStateScope.getDecision(subject: AccessUri, `object`: AccessUri): Int {
- `object` as AppOpUri
- return getModes(subject)
- .getWithDefault(`object`.appOpName, opToDefaultMode(`object`.appOpName))
- }
-
- override fun MutateStateScope.setDecision(
- subject: AccessUri,
- `object`: AccessUri,
- decision: Int
- ) {
- `object` as AppOpUri
- val modes = getOrCreateModes(subject)
- val oldMode = modes.putWithDefault(`object`.appOpName, decision,
- opToDefaultMode(`object`.appOpName))
- if (modes.isEmpty()) {
- removeModes(subject)
- }
- if (oldMode != decision) {
- notifyOnDecisionChangedListeners(subject, `object`, oldMode, decision)
- }
- }
-
- abstract fun GetStateScope.getModes(subject: AccessUri): IndexedMap<String, Int>?
-
- abstract fun MutateStateScope.getOrCreateModes(subject: AccessUri): IndexedMap<String, Int>
-
- abstract fun MutateStateScope.removeModes(subject: AccessUri)
-
- // TODO need to check that [AppOpsManager.getSystemAlertWindowDefault] works; likely no issue
- // since running in system process.
- private fun opToDefaultMode(appOpName: String) = AppOpsManager.opToDefaultMode(appOpName)
+abstract class BaseAppOpPolicy(
+ private val persistence: BaseAppOpPersistence
+) : SchemePolicy() {
+ override val objectScheme: String
+ get() = AppOpUri.SCHEME
override fun BinaryXmlPullParser.parseUserState(userId: Int, userState: UserState) {
with(persistence) { this@parseUserState.parseUserState(userId, userState) }
diff --git a/services/permission/java/com/android/server/permission/access/appop/PackageAppOpPolicy.kt b/services/permission/java/com/android/server/permission/access/appop/PackageAppOpPolicy.kt
index f4d6bfd0a000..607e5120fb37 100644
--- a/services/permission/java/com/android/server/permission/access/appop/PackageAppOpPolicy.kt
+++ b/services/permission/java/com/android/server/permission/access/appop/PackageAppOpPolicy.kt
@@ -16,40 +16,101 @@
package com.android.server.permission.access.appop
+import android.app.AppOpsManager
import com.android.server.permission.access.AccessUri
import com.android.server.permission.access.AppOpUri
import com.android.server.permission.access.GetStateScope
import com.android.server.permission.access.MutateStateScope
import com.android.server.permission.access.PackageUri
-import com.android.server.permission.access.UserState
import com.android.server.permission.access.collection.* // ktlint-disable no-wildcard-imports
class PackageAppOpPolicy : BaseAppOpPolicy(PackageAppOpPersistence()) {
+ @Volatile
+ private var onAppOpModeChangedListeners = IndexedListSet<OnAppOpModeChangedListener>()
+ private val onAppOpModeChangedListenersLock = Any()
+
override val subjectScheme: String
get() = PackageUri.SCHEME
- override val objectScheme: String
- get() = AppOpUri.SCHEME
-
- override fun GetStateScope.getModes(subject: AccessUri): IndexedMap<String, Int>? {
- subject as PackageUri
- return state.userStates[subject.userId]?.packageAppOpModes?.get(subject.packageName)
- }
-
- override fun MutateStateScope.getOrCreateModes(subject: AccessUri): IndexedMap<String, Int> {
+ override fun GetStateScope.getDecision(subject: AccessUri, `object`: AccessUri): Int {
subject as PackageUri
- return newState.userStates.getOrPut(subject.userId) { UserState() }
- .packageAppOpModes.getOrPut(subject.packageName) { IndexedMap() }
+ `object` as AppOpUri
+ return getAppOpMode(subject.packageName, subject.userId, `object`.appOpName)
}
- override fun MutateStateScope.removeModes(subject: AccessUri) {
+ override fun MutateStateScope.setDecision(
+ subject: AccessUri,
+ `object`: AccessUri,
+ decision: Int
+ ) {
subject as PackageUri
- newState.userStates[subject.userId]?.packageAppOpModes?.remove(subject.packageName)
+ `object` as AppOpUri
+ setAppOpMode(subject.packageName, subject.userId, `object`.appOpName, decision)
}
override fun MutateStateScope.onPackageRemoved(packageName: String, appId: Int) {
newState.userStates.forEachIndexed { _, _, userState ->
userState.packageAppOpModes -= packageName
+ userState.requestWrite()
+ // Skip notifying the change listeners since the package no longer exists.
+ }
+ }
+
+ fun MutateStateScope.removeAppOpModes(packageName: String, userId: Int): Boolean =
+ newState.userStates[userId].packageAppOpModes.remove(packageName) != null
+
+ fun GetStateScope.getAppOpMode(packageName: String, userId: Int, appOpName: String): Int =
+ state.userStates[userId].packageAppOpModes[packageName]
+ .getWithDefault(appOpName, AppOpsManager.opToDefaultMode(appOpName))
+
+ fun MutateStateScope.setAppOpMode(
+ packageName: String,
+ userId: Int,
+ appOpName: String,
+ mode: Int
+ ): Boolean {
+ val userState = newState.userStates[userId]
+ val packageAppOpModes = userState.packageAppOpModes
+ var appOpModes = packageAppOpModes[packageName]
+ val defaultMode = AppOpsManager.opToDefaultMode(appOpName)
+ val oldMode = appOpModes.getWithDefault(appOpName, defaultMode)
+ if (oldMode == mode) {
+ return false
+ }
+ if (appOpModes == null) {
+ appOpModes = IndexedMap()
+ packageAppOpModes[packageName] = appOpModes
}
+ appOpModes.putWithDefault(appOpName, mode, defaultMode)
+ if (appOpModes.isEmpty()) {
+ packageAppOpModes -= packageName
+ }
+ userState.requestWrite()
+ onAppOpModeChangedListeners.forEachIndexed { _, it ->
+ it.onAppOpModeChanged(packageName, userId, appOpName, oldMode, mode)
+ }
+ return true
+ }
+
+ fun addOnAppOpModeChangedListener(listener: OnAppOpModeChangedListener) {
+ synchronized(onAppOpModeChangedListenersLock) {
+ onAppOpModeChangedListeners = onAppOpModeChangedListeners + listener
+ }
+ }
+
+ fun removeOnAppOpModeChangedListener(listener: OnAppOpModeChangedListener) {
+ synchronized(onAppOpModeChangedListenersLock) {
+ onAppOpModeChangedListeners = onAppOpModeChangedListeners - listener
+ }
+ }
+
+ fun interface OnAppOpModeChangedListener {
+ fun onAppOpModeChanged(
+ packageName: String,
+ userId: Int,
+ appOpName: String,
+ oldMode: Int,
+ newMode: Int
+ )
}
}
diff --git a/services/permission/java/com/android/server/permission/access/appop/UidAppOpPolicy.kt b/services/permission/java/com/android/server/permission/access/appop/UidAppOpPolicy.kt
index 862db8f35390..0b0103815e12 100644
--- a/services/permission/java/com/android/server/permission/access/appop/UidAppOpPolicy.kt
+++ b/services/permission/java/com/android/server/permission/access/appop/UidAppOpPolicy.kt
@@ -16,40 +16,104 @@
package com.android.server.permission.access.appop
+import android.app.AppOpsManager
import com.android.server.permission.access.AccessUri
import com.android.server.permission.access.AppOpUri
import com.android.server.permission.access.GetStateScope
import com.android.server.permission.access.MutateStateScope
import com.android.server.permission.access.UidUri
-import com.android.server.permission.access.UserState
import com.android.server.permission.access.collection.* // ktlint-disable no-wildcard-imports
class UidAppOpPolicy : BaseAppOpPolicy(UidAppOpPersistence()) {
+ @Volatile
+ private var onAppOpModeChangedListeners = IndexedListSet<OnAppOpModeChangedListener>()
+ private val onAppOpModeChangedListenersLock = Any()
+
override val subjectScheme: String
get() = UidUri.SCHEME
- override val objectScheme: String
- get() = AppOpUri.SCHEME
-
- override fun GetStateScope.getModes(subject: AccessUri): IndexedMap<String, Int>? {
- subject as UidUri
- return state.userStates[subject.userId]?.uidAppOpModes?.get(subject.appId)
- }
-
- override fun MutateStateScope.getOrCreateModes(subject: AccessUri): IndexedMap<String, Int> {
+ override fun GetStateScope.getDecision(subject: AccessUri, `object`: AccessUri): Int {
subject as UidUri
- return newState.userStates.getOrPut(subject.userId) { UserState() }
- .uidAppOpModes.getOrPut(subject.appId) { IndexedMap() }
+ `object` as AppOpUri
+ return getAppOpMode(subject.appId, subject.userId, `object`.appOpName)
}
- override fun MutateStateScope.removeModes(subject: AccessUri) {
+ override fun MutateStateScope.setDecision(
+ subject: AccessUri,
+ `object`: AccessUri,
+ decision: Int
+ ) {
subject as UidUri
- newState.userStates[subject.userId]?.uidAppOpModes?.remove(subject.appId)
+ `object` as AppOpUri
+ setAppOpMode(subject.appId, subject.userId, `object`.appOpName, decision)
}
override fun MutateStateScope.onAppIdRemoved(appId: Int) {
newState.userStates.forEachIndexed { _, _, userState ->
userState.uidAppOpModes -= appId
+ userState.requestWrite()
+ // Skip notifying the change listeners since the app ID no longer exists.
+ }
+ }
+
+ fun GetStateScope.getAppOpModes(appId: Int, userId: Int): IndexedMap<String, Int>? =
+ state.userStates[userId].uidAppOpModes[appId]
+
+ fun MutateStateScope.removeAppOpModes(appId: Int, userId: Int): Boolean =
+ newState.userStates[userId].uidAppOpModes.removeReturnOld(appId) != null
+
+ fun GetStateScope.getAppOpMode(appId: Int, userId: Int, appOpName: String): Int =
+ state.userStates[userId].uidAppOpModes[appId]
+ .getWithDefault(appOpName, AppOpsManager.opToDefaultMode(appOpName))
+
+ fun MutateStateScope.setAppOpMode(
+ appId: Int,
+ userId: Int,
+ appOpName: String,
+ mode: Int
+ ): Boolean {
+ val userState = newState.userStates[userId]
+ val uidAppOpModes = userState.uidAppOpModes
+ var appOpModes = uidAppOpModes[appId]
+ val defaultMode = AppOpsManager.opToDefaultMode(appOpName)
+ val oldMode = appOpModes.getWithDefault(appOpName, defaultMode)
+ if (oldMode == mode) {
+ return false
}
+ if (appOpModes == null) {
+ appOpModes = IndexedMap()
+ uidAppOpModes[appId] = appOpModes
+ }
+ appOpModes.putWithDefault(appOpName, mode, defaultMode)
+ if (appOpModes.isEmpty()) {
+ uidAppOpModes -= appId
+ }
+ userState.requestWrite()
+ onAppOpModeChangedListeners.forEachIndexed { _, it ->
+ it.onAppOpModeChanged(appId, userId, appOpName, oldMode, mode)
+ }
+ return true
+ }
+
+ fun addOnAppOpModeChangedListener(listener: OnAppOpModeChangedListener) {
+ synchronized(onAppOpModeChangedListenersLock) {
+ onAppOpModeChangedListeners = onAppOpModeChangedListeners + listener
+ }
+ }
+
+ fun removeOnAppOpModeChangedListener(listener: OnAppOpModeChangedListener) {
+ synchronized(onAppOpModeChangedListenersLock) {
+ onAppOpModeChangedListeners = onAppOpModeChangedListeners - listener
+ }
+ }
+
+ fun interface OnAppOpModeChangedListener {
+ fun onAppOpModeChanged(
+ appId: Int,
+ userId: Int,
+ appOpName: String,
+ oldMode: Int,
+ newMode: Int
+ )
}
}
diff --git a/services/permission/java/com/android/server/permission/access/collection/IntMap.kt b/services/permission/java/com/android/server/permission/access/collection/IntMap.kt
index 0044b7359ef3..21031015c8fa 100644
--- a/services/permission/java/com/android/server/permission/access/collection/IntMap.kt
+++ b/services/permission/java/com/android/server/permission/access/collection/IntMap.kt
@@ -120,6 +120,18 @@ inline fun <T> IntMap<T>.putWithDefault(key: Int, value: T, defaultValue: T): T
}
}
+// SparseArray.removeReturnOld() is @hide, so a backup once we move to APIs.
+fun <T> IntMap<T>.removeReturnOld(key: Int): T? {
+ val index = indexOfKey(key)
+ return if (index >= 0) {
+ val oldValue = valueAt(index)
+ removeAt(index)
+ oldValue
+ } else {
+ null
+ }
+}
+
inline fun <T> IntMap<T>.removeAllIndexed(predicate: (Int, Int, T) -> Boolean): Boolean {
var isChanged = false
for (index in lastIndex downTo 0) {