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

Commit dbac6528 authored by Chaohui Wang's avatar Chaohui Wang Committed by Android (Google) Code Review
Browse files

Merge "Fix ApplicationInfo.hasGrantPermission()"

parents 734d22ca 7c687a41
Loading
Loading
Loading
Loading
+45 −12
Original line number Diff line number Diff line
@@ -26,43 +26,76 @@ import com.android.settingslib.spa.framework.util.asyncFilter

private const val TAG = "PackageManagers"

object PackageManagers {
interface IPackageManagers {
    fun getPackageInfoAsUser(packageName: String, userId: Int): PackageInfo?
    fun getApplicationInfoAsUser(packageName: String, userId: Int): ApplicationInfo?

    /** Checks whether a package is installed for a given user. */
    fun isPackageInstalledAsUser(packageName: String, userId: Int): Boolean
    fun ApplicationInfo.hasRequestPermission(permission: String): Boolean

    /** Checks whether a permission is currently granted to the application. */
    fun ApplicationInfo.hasGrantPermission(permission: String): Boolean

    suspend fun getAppOpPermissionPackages(userId: Int, permission: String): Set<String>
    fun getPackageInfoAsUser(packageName: String, flags: Int, userId: Int): PackageInfo?
}

object PackageManagers : IPackageManagers by PackageManagersImpl(PackageManagerWrapperImpl)

internal interface PackageManagerWrapper {
    fun getPackageInfoAsUserCached(
        packageName: String,
        flags: Long,
        userId: Int,
    ): PackageInfo?
}

internal object PackageManagerWrapperImpl : PackageManagerWrapper {
    override fun getPackageInfoAsUserCached(
        packageName: String,
        flags: Long,
        userId: Int,
    ): PackageInfo? = PackageManager.getPackageInfoAsUserCached(packageName, flags, userId)
}

internal class PackageManagersImpl(
    private val packageManagerWrapper: PackageManagerWrapper,
) : IPackageManagers {
    private val iPackageManager by lazy { AppGlobals.getPackageManager() }

    fun getPackageInfoAsUser(packageName: String, userId: Int): PackageInfo? =
    override fun getPackageInfoAsUser(packageName: String, userId: Int): PackageInfo? =
        getPackageInfoAsUser(packageName, 0, userId)

    fun getApplicationInfoAsUser(packageName: String, userId: Int): ApplicationInfo? =
    override fun getApplicationInfoAsUser(packageName: String, userId: Int): ApplicationInfo? =
        PackageManager.getApplicationInfoAsUserCached(packageName, 0, userId)

    /** Checks whether a package is installed for a given user. */
    fun isPackageInstalledAsUser(packageName: String, userId: Int): Boolean =
    override fun isPackageInstalledAsUser(packageName: String, userId: Int): Boolean =
        getApplicationInfoAsUser(packageName, userId)?.hasFlag(ApplicationInfo.FLAG_INSTALLED)
            ?: false

    fun ApplicationInfo.hasRequestPermission(permission: String): Boolean {
    override fun ApplicationInfo.hasRequestPermission(permission: String): Boolean {
        val packageInfo = getPackageInfoAsUser(packageName, PackageManager.GET_PERMISSIONS, userId)
        return packageInfo?.requestedPermissions?.let {
            permission in it
        } ?: false
    }

    fun ApplicationInfo.hasGrantPermission(permission: String): Boolean {
    override fun ApplicationInfo.hasGrantPermission(permission: String): Boolean {
        val packageInfo = getPackageInfoAsUser(packageName, PackageManager.GET_PERMISSIONS, userId)
            ?: return false
        val index = packageInfo.requestedPermissions.indexOf(permission)
        val index = packageInfo?.requestedPermissions?.indexOf(permission) ?: return false
        return index >= 0 &&
            packageInfo.requestedPermissionsFlags[index].hasFlag(REQUESTED_PERMISSION_GRANTED)
    }

    suspend fun getAppOpPermissionPackages(userId: Int, permission: String): Set<String> =
    override suspend fun getAppOpPermissionPackages(userId: Int, permission: String): Set<String> =
        iPackageManager.getAppOpPermissionPackages(permission, userId).asIterable().asyncFilter {
            iPackageManager.isPackageAvailable(it, userId)
        }.toSet()

    fun getPackageInfoAsUser(packageName: String, flags: Int, userId: Int): PackageInfo? =
    override fun getPackageInfoAsUser(packageName: String, flags: Int, userId: Int): PackageInfo? =
        try {
            PackageManager.getPackageInfoAsUserCached(packageName, flags.toLong(), userId)
            packageManagerWrapper.getPackageInfoAsUserCached(packageName, flags.toLong(), userId)
        } catch (e: PackageManager.NameNotFoundException) {
            Log.w(TAG, "getPackageInfoAsUserCached() failed", e)
            null
+117 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2022 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.settingslib.spaprivileged.model.app

import android.content.pm.ApplicationInfo
import android.content.pm.PackageInfo
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.google.common.truth.Truth.assertThat
import org.junit.Test
import org.junit.runner.RunWith

@RunWith(AndroidJUnit4::class)
class PackageManagersTest {

    private val fakePackageManagerWrapper = FakePackageManagerWrapper()

    private val packageManagersImpl = PackageManagersImpl(fakePackageManagerWrapper)

    @Test
    fun hasGrantPermission_packageInfoIsNull_returnFalse() {
        fakePackageManagerWrapper.fakePackageInfo = null

        val hasGrantPermission = with(packageManagersImpl) {
            APP.hasGrantPermission(PERMISSION_A)
        }

        assertThat(hasGrantPermission).isFalse()
    }

    @Test
    fun hasGrantPermission_requestedPermissionsIsNull_returnFalse() {
        fakePackageManagerWrapper.fakePackageInfo = PackageInfo()

        val hasGrantPermission = with(packageManagersImpl) {
            APP.hasGrantPermission(PERMISSION_A)
        }

        assertThat(hasGrantPermission).isFalse()
    }

    @Test
    fun hasGrantPermission_notRequested_returnFalse() {
        fakePackageManagerWrapper.fakePackageInfo = PackageInfo().apply {
            requestedPermissions = arrayOf(PERMISSION_B)
            requestedPermissionsFlags = intArrayOf(PackageInfo.REQUESTED_PERMISSION_GRANTED)
        }

        val hasGrantPermission = with(packageManagersImpl) {
            APP.hasGrantPermission(PERMISSION_A)
        }

        assertThat(hasGrantPermission).isFalse()
    }

    @Test
    fun hasGrantPermission_notGranted_returnFalse() {
        fakePackageManagerWrapper.fakePackageInfo = PackageInfo().apply {
            requestedPermissions = arrayOf(PERMISSION_A, PERMISSION_B)
            requestedPermissionsFlags = intArrayOf(0, PackageInfo.REQUESTED_PERMISSION_GRANTED)
        }

        val hasGrantPermission = with(packageManagersImpl) {
            APP.hasGrantPermission(PERMISSION_A)
        }

        assertThat(hasGrantPermission).isFalse()
    }

    @Test
    fun hasGrantPermission_granted_returnTrue() {
        fakePackageManagerWrapper.fakePackageInfo = PackageInfo().apply {
            requestedPermissions = arrayOf(PERMISSION_A, PERMISSION_B)
            requestedPermissionsFlags = intArrayOf(PackageInfo.REQUESTED_PERMISSION_GRANTED, 0)
        }

        val hasGrantPermission = with(packageManagersImpl) {
            APP.hasGrantPermission(PERMISSION_A)
        }

        assertThat(hasGrantPermission).isTrue()
    }

    private inner class FakePackageManagerWrapper : PackageManagerWrapper {
        var fakePackageInfo: PackageInfo? = null

        override fun getPackageInfoAsUserCached(
            packageName: String,
            flags: Long,
            userId: Int,
        ): PackageInfo? = fakePackageInfo
    }

    private companion object {
        const val PACKAGE_NAME = "packageName"
        const val PERMISSION_A = "permission.A"
        const val PERMISSION_B = "permission.B"
        const val UID = 123
        val APP = ApplicationInfo().apply {
            packageName = PACKAGE_NAME
            uid = UID
        }
    }
}