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

Commit 7e8b4c01 authored by Hai Zhang's avatar Hai Zhang
Browse files

Implement retailDemo protection flag in the new subsystem.

Hopefully we can remove this later once we have the retail demo role.

Bug: 263504888
Test: Enroll in retail demo, reboot, then permission is granted.
Change-Id: I0aa75559114aa21f0def548258c10532ace0fb4a
parent 87522959
Loading
Loading
Loading
Loading
+54 −43
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

package com.android.server.permission.access

import android.app.admin.DevicePolicyManagerInternal
import android.content.Context
import android.content.pm.PackageManager
import android.content.pm.PackageManagerInternal
@@ -75,7 +76,7 @@ class AccessCheckingService(context: Context) : SystemService(context) {

        val userIds = MutableIntSet(userManagerService.userIdsIncludingPreCreated)
        val (packageStates, disabledSystemPackageStates) = packageManagerLocal.allPackageStates
        val knownPackages = packageManagerInternal.knownPackages
        val knownPackages = packageManagerInternal.getKnownPackages(packageStates)
        val isLeanback = systemConfig.isLeanback
        val configPermissions = systemConfig.permissions
        val privilegedPermissionAllowlistPackages =
@@ -154,7 +155,7 @@ class AccessCheckingService(context: Context) : SystemService(context) {

    internal fun onStorageVolumeMounted(volumeUuid: String?, isSystemUpdated: Boolean) {
        val (packageStates, disabledSystemPackageStates) = packageManagerLocal.allPackageStates
        val knownPackages = packageManagerInternal.knownPackages
        val knownPackages = packageManagerInternal.getKnownPackages(packageStates)
        mutateState {
            with(policy) {
                onStorageVolumeMounted(
@@ -167,7 +168,7 @@ class AccessCheckingService(context: Context) : SystemService(context) {

    internal fun onPackageAdded(packageName: String) {
        val (packageStates, disabledSystemPackageStates) = packageManagerLocal.allPackageStates
        val knownPackages = packageManagerInternal.knownPackages
        val knownPackages = packageManagerInternal.getKnownPackages(packageStates)
        mutateState {
            with(policy) {
                onPackageAdded(
@@ -179,7 +180,7 @@ class AccessCheckingService(context: Context) : SystemService(context) {

    internal fun onPackageRemoved(packageName: String, appId: Int) {
        val (packageStates, disabledSystemPackageStates) = packageManagerLocal.allPackageStates
        val knownPackages = packageManagerInternal.knownPackages
        val knownPackages = packageManagerInternal.getKnownPackages(packageStates)
        mutateState {
            with(policy) {
                onPackageRemoved(
@@ -191,7 +192,7 @@ class AccessCheckingService(context: Context) : SystemService(context) {

    internal fun onPackageInstalled(packageName: String, userId: Int) {
        val (packageStates, disabledSystemPackageStates) = packageManagerLocal.allPackageStates
        val knownPackages = packageManagerInternal.knownPackages
        val knownPackages = packageManagerInternal.getKnownPackages(packageStates)
        mutateState {
            with(policy) {
                onPackageInstalled(
@@ -203,7 +204,7 @@ class AccessCheckingService(context: Context) : SystemService(context) {

    internal fun onPackageUninstalled(packageName: String, appId: Int, userId: Int) {
        val (packageStates, disabledSystemPackageStates) = packageManagerLocal.allPackageStates
        val knownPackages = packageManagerInternal.knownPackages
        val knownPackages = packageManagerInternal.getKnownPackages(packageStates)
        mutateState {
            with(policy) {
                onPackageUninstalled(
@@ -215,8 +216,12 @@ class AccessCheckingService(context: Context) : SystemService(context) {
    }

    internal fun onSystemReady() {
        val (packageStates, disabledSystemPackageStates) = packageManagerLocal.allPackageStates
        val knownPackages = packageManagerInternal.getKnownPackages(packageStates)
        mutateState {
            with(policy) { onSystemReady() }
            with(policy) {
                onSystemReady(packageStates, disabledSystemPackageStates, knownPackages)
            }
        }
    }

@@ -224,41 +229,47 @@ class AccessCheckingService(context: Context) : SystemService(context) {
        Pair<Map<String, PackageState>, Map<String, PackageState>>
        get() = withUnfilteredSnapshot().use { it.packageStates to it.disabledSystemPackageStates }

    private val PackageManagerInternal.knownPackages: IntMap<Array<String>>
        get() = MutableIntMap<Array<String>>().apply {
            this[KnownPackages.PACKAGE_INSTALLER] = getKnownPackageNames(
                KnownPackages.PACKAGE_INSTALLER, UserHandle.USER_SYSTEM
            )
    private fun PackageManagerInternal.getKnownPackages(
        packageStates: Map<String, PackageState>
    ): IntMap<Array<String>> = MutableIntMap<Array<String>>().apply {
        this[KnownPackages.PACKAGE_INSTALLER] =
            getKnownPackageNames(KnownPackages.PACKAGE_INSTALLER, UserHandle.USER_SYSTEM)
        this[KnownPackages.PACKAGE_PERMISSION_CONTROLLER] = getKnownPackageNames(
            KnownPackages.PACKAGE_PERMISSION_CONTROLLER, UserHandle.USER_SYSTEM
        )
            this[KnownPackages.PACKAGE_VERIFIER] = getKnownPackageNames(
                KnownPackages.PACKAGE_VERIFIER, UserHandle.USER_SYSTEM
            )
            this[KnownPackages.PACKAGE_SETUP_WIZARD] = getKnownPackageNames(
                KnownPackages.PACKAGE_SETUP_WIZARD, UserHandle.USER_SYSTEM
            )
        this[KnownPackages.PACKAGE_VERIFIER] =
            getKnownPackageNames(KnownPackages.PACKAGE_VERIFIER, UserHandle.USER_SYSTEM)
        this[KnownPackages.PACKAGE_SETUP_WIZARD] =
            getKnownPackageNames(KnownPackages.PACKAGE_SETUP_WIZARD, UserHandle.USER_SYSTEM)
        this[KnownPackages.PACKAGE_SYSTEM_TEXT_CLASSIFIER] = getKnownPackageNames(
            KnownPackages.PACKAGE_SYSTEM_TEXT_CLASSIFIER, UserHandle.USER_SYSTEM
        )
            this[KnownPackages.PACKAGE_CONFIGURATOR] = getKnownPackageNames(
                KnownPackages.PACKAGE_CONFIGURATOR, UserHandle.USER_SYSTEM
            )
        this[KnownPackages.PACKAGE_CONFIGURATOR] =
            getKnownPackageNames(KnownPackages.PACKAGE_CONFIGURATOR, UserHandle.USER_SYSTEM)
        this[KnownPackages.PACKAGE_INCIDENT_REPORT_APPROVER] = getKnownPackageNames(
            KnownPackages.PACKAGE_INCIDENT_REPORT_APPROVER, UserHandle.USER_SYSTEM
        )
            this[KnownPackages.PACKAGE_APP_PREDICTOR] = getKnownPackageNames(
                KnownPackages.PACKAGE_APP_PREDICTOR, UserHandle.USER_SYSTEM
            )
            this[KnownPackages.PACKAGE_COMPANION] = getKnownPackageNames(
                KnownPackages.PACKAGE_COMPANION, UserHandle.USER_SYSTEM
            )
            this[KnownPackages.PACKAGE_RETAIL_DEMO] = getKnownPackageNames(
                KnownPackages.PACKAGE_RETAIL_DEMO, UserHandle.USER_SYSTEM
            )
            this[KnownPackages.PACKAGE_RECENTS] = getKnownPackageNames(
                KnownPackages.PACKAGE_RECENTS, UserHandle.USER_SYSTEM
            )
        this[KnownPackages.PACKAGE_APP_PREDICTOR] =
            getKnownPackageNames(KnownPackages.PACKAGE_APP_PREDICTOR, UserHandle.USER_SYSTEM)
        this[KnownPackages.PACKAGE_COMPANION] =
            getKnownPackageNames(KnownPackages.PACKAGE_COMPANION, UserHandle.USER_SYSTEM)
        this[KnownPackages.PACKAGE_RETAIL_DEMO] =
            getKnownPackageNames(KnownPackages.PACKAGE_RETAIL_DEMO, UserHandle.USER_SYSTEM)
                .filter { isProfileOwner(it, packageStates) }.toTypedArray()
        this[KnownPackages.PACKAGE_RECENTS] =
            getKnownPackageNames(KnownPackages.PACKAGE_RECENTS, UserHandle.USER_SYSTEM)
    }

    private fun isProfileOwner(
        packageName: String,
        packageStates: Map<String, PackageState>
    ): Boolean {
        val appId = packageStates[packageName]?.appId ?: return false
        val devicePolicyManagerInternal =
            LocalServices.getService(DevicePolicyManagerInternal::class.java) ?: return false
        // TODO(b/169395065): Figure out if this flow makes sense in Device Owner mode.
        return devicePolicyManagerInternal.isActiveProfileOwner(appId) ||
            devicePolicyManagerInternal.isActiveDeviceOwner(appId)
    }

    @OptIn(ExperimentalContracts::class)
+11 −2
Original line number Diff line number Diff line
@@ -277,8 +277,17 @@ class AccessPolicy private constructor(
        }
    }

    fun MutateStateScope.onSystemReady() {
        newState.mutateExternalState().setSystemReady(true)
    fun MutateStateScope.onSystemReady(
        packageStates: Map<String, PackageState>,
        disabledSystemPackageStates: Map<String, PackageState>,
        knownPackages: IntMap<Array<String>>
    ) {
        newState.mutateExternalState().apply {
            setPackageStates(packageStates)
            setDisabledSystemPackageStates(disabledSystemPackageStates)
            setKnownPackages(knownPackages)
            setSystemReady(true)
        }
        forEachSchemePolicy {
            with(it) { onSystemReady() }
        }
+5 −19
Original line number Diff line number Diff line
@@ -102,9 +102,7 @@ sealed class ExternalState(
    privilegedPermissionAllowlistPackages: IndexedListSet<String>,
    permissionAllowlist: PermissionAllowlist,
    implicitToSourcePermissions: IndexedMap<String, IndexedListSet<String>>,
    isSystemReady: Boolean,
    // TODO: STOPSHIP: Get and watch the state for deviceAndProfileOwners
    deviceAndProfileOwners: IntMap<String>
    isSystemReady: Boolean
) : Immutable<MutableExternalState> {
    val userIds: IntSet
        get() = userIdsReference.get()
@@ -141,9 +139,6 @@ sealed class ExternalState(
    var isSystemReady: Boolean = isSystemReady
        protected set

    var deviceAndProfileOwners: IntMap<String> = deviceAndProfileOwners
        protected set

    override fun toMutable(): MutableExternalState = MutableExternalState(this)
}

@@ -158,8 +153,7 @@ class MutableExternalState private constructor(
    privilegedPermissionAllowlistPackages: IndexedListSet<String>,
    permissionAllowlist: PermissionAllowlist,
    implicitToSourcePermissions: IndexedMap<String, IndexedListSet<String>>,
    isSystemReady: Boolean,
    deviceAndProfileOwners: IntMap<String>
    isSystemReady: Boolean
) : ExternalState(
    userIdsReference,
    packageStates,
@@ -171,8 +165,7 @@ class MutableExternalState private constructor(
    privilegedPermissionAllowlistPackages,
    permissionAllowlist,
    implicitToSourcePermissions,
    isSystemReady,
    deviceAndProfileOwners
    isSystemReady
) {
    constructor() : this(
        UserIdsReference(MutableIntSet()),
@@ -185,8 +178,7 @@ class MutableExternalState private constructor(
        MutableIndexedListSet(),
        PermissionAllowlist(),
        MutableIndexedMap(),
        false,
        MutableIntMap()
        false
    )

    internal constructor(externalState: ExternalState) : this(
@@ -200,8 +192,7 @@ class MutableExternalState private constructor(
        externalState.privilegedPermissionAllowlistPackages,
        externalState.permissionAllowlist,
        externalState.implicitToSourcePermissions,
        externalState.isSystemReady,
        externalState.deviceAndProfileOwners
        externalState.isSystemReady
    )

    fun mutateUserIds(): MutableIntSet = userIdsReference.mutate()
@@ -256,11 +247,6 @@ class MutableExternalState private constructor(
    fun setSystemReady(isSystemReady: Boolean) {
        this.isSystemReady = isSystemReady
    }

    @JvmName("setDeviceAndProfileOwnersPublic")
    fun setDeviceAndProfileOwners(deviceAndProfileOwners: IntMap<String>) {
        this.deviceAndProfileOwners = deviceAndProfileOwners
    }
}

private typealias PermissionGroupsReference = MutableReference<
+19 −12
Original line number Diff line number Diff line
@@ -22,7 +22,6 @@ import android.content.pm.PermissionGroupInfo
import android.content.pm.PermissionInfo
import android.content.pm.SigningDetails
import android.os.Build
import android.os.UserHandle
import android.util.Log
import com.android.internal.os.RoSystemProperties
import com.android.modules.utils.BinaryXmlPullParser
@@ -1200,8 +1199,7 @@ class AppIdPermissionPolicy : SchemePolicy() {
            return true
        }
        if (permission.isRetailDemo &&
            packageName in knownPackages[KnownPackages.PACKAGE_RETAIL_DEMO]!! &&
            isDeviceOrProfileOwnerUid(packageState.appId)) {
            packageName in knownPackages[KnownPackages.PACKAGE_RETAIL_DEMO]!!) {
            // Special permission granted only to the OEM specified retail demo app.
            // Note that the original code was passing app ID as UID, so this behavior is kept
            // unchanged.
@@ -1257,16 +1255,25 @@ class AppIdPermissionPolicy : SchemePolicy() {
        return false
    }

    private fun MutateStateScope.isDeviceOrProfileOwnerUid(uid: Int): Boolean {
        val userId = UserHandle.getUserId(uid)
        val ownerPackageName = newState.externalState.deviceAndProfileOwners[userId] ?: return false
        val ownerPackageState = newState.externalState.packageStates[ownerPackageName]
            ?: return false
        val ownerUid = UserHandle.getUid(userId, ownerPackageState.appId)
        return uid == ownerUid
    }

    override fun MutateStateScope.onSystemReady() {
        // HACK: PACKAGE_USAGE_STATS is the only permission with the retailDemo protection flag,
        // and we have to wait until DevicePolicyManagerService is started to know whether the
        // retail demo package is a profile owner so that it can have the permission.
        // Since there's no simple callback for profile owner change, and we are deprecating and
        // removing the retailDemo protection flag in favor of a proper role soon, we can just
        // re-evaluate the permission here, which is also how the old implementation has been
        // working.
        // TODO: Partially revert ag/22690114 once we can remove support for the retailDemo
        //  protection flag.
        val externalState = newState.externalState
        for (packageName in externalState.knownPackages[KnownPackages.PACKAGE_RETAIL_DEMO]!!) {
            val appId = externalState.packageStates[packageName]?.appId ?: continue
            newState.userStates.forEachIndexed { _, userId, _ ->
                evaluatePermissionState(
                    appId, userId, Manifest.permission.PACKAGE_USAGE_STATS, null
                )
            }
        }
        if (!privilegedPermissionAllowlistViolations.isEmpty()) {
            throw IllegalStateException("Signature|privileged permissions not in privileged" +
                " permission allowlist: $privilegedPermissionAllowlistViolations")