Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 75a1b8f1 authored by Hai Zhang's avatar Hai Zhang Committed by Android (Google) Code Review
Browse files

Merge "Expose app op mode getter/setter/change listener directly on policy."

parents 3fb248ae e455c28f
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -154,7 +154,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()
+0 −37
Original line number Diff line number Diff line
@@ -272,10 +272,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
@@ -288,30 +284,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) {}
@@ -340,13 +312,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
        )
    }
}
+5 −38
Original line number Diff line number Diff line
@@ -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) }
+75 −14
Original line number Diff line number Diff line
@@ -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
        )
    }
}
+78 −14
Original line number Diff line number Diff line
@@ -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
        )
    }
}
Loading