1 /* 2 * 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.settingslib.spaprivileged.model.app 18 19 import android.app.AppGlobals 20 import android.content.pm.ApplicationInfo 21 import android.content.pm.PackageInfo 22 import android.content.pm.PackageInfo.REQUESTED_PERMISSION_GRANTED 23 import android.content.pm.PackageManager 24 import com.android.settingslib.spa.framework.util.asyncFilter 25 26 interface IPackageManagers { 27 fun getPackageInfoAsUser(packageName: String, userId: Int): PackageInfo? 28 fun getApplicationInfoAsUser(packageName: String, userId: Int): ApplicationInfo? 29 30 /** Checks whether a package is installed for a given user. */ 31 fun isPackageInstalledAsUser(packageName: String, userId: Int): Boolean 32 fun ApplicationInfo.hasRequestPermission(permission: String): Boolean 33 34 /** Checks whether a permission is currently granted to the application. */ 35 fun ApplicationInfo.hasGrantPermission(permission: String): Boolean 36 37 suspend fun getAppOpPermissionPackages(userId: Int, permission: String): Set<String> 38 fun getPackageInfoAsUser(packageName: String, flags: Int, userId: Int): PackageInfo? 39 } 40 41 object PackageManagers : IPackageManagers by PackageManagersImpl(PackageManagerWrapperImpl) 42 43 internal interface PackageManagerWrapper { 44 fun getPackageInfoAsUserCached( 45 packageName: String, 46 flags: Long, 47 userId: Int, 48 ): PackageInfo? 49 } 50 51 internal object PackageManagerWrapperImpl : PackageManagerWrapper { 52 override fun getPackageInfoAsUserCached( 53 packageName: String, 54 flags: Long, 55 userId: Int, 56 ): PackageInfo? = PackageManager.getPackageInfoAsUserCached(packageName, flags, userId) 57 } 58 59 internal class PackageManagersImpl( 60 private val packageManagerWrapper: PackageManagerWrapper, 61 ) : IPackageManagers { 62 private val iPackageManager by lazy { AppGlobals.getPackageManager() } 63 64 override fun getPackageInfoAsUser(packageName: String, userId: Int): PackageInfo? = 65 getPackageInfoAsUser(packageName, 0, userId) 66 67 override fun getApplicationInfoAsUser(packageName: String, userId: Int): ApplicationInfo? = 68 PackageManager.getApplicationInfoAsUserCached(packageName, 0, userId) 69 70 override fun isPackageInstalledAsUser(packageName: String, userId: Int): Boolean = 71 getApplicationInfoAsUser(packageName, userId)?.hasFlag(ApplicationInfo.FLAG_INSTALLED) 72 ?: false 73 74 override fun ApplicationInfo.hasRequestPermission(permission: String): Boolean { 75 val packageInfo = getPackageInfoAsUser(packageName, PackageManager.GET_PERMISSIONS, userId) 76 return packageInfo?.requestedPermissions?.let { 77 permission in it 78 } ?: false 79 } 80 81 override fun ApplicationInfo.hasGrantPermission(permission: String): Boolean { 82 val packageInfo = getPackageInfoAsUser(packageName, PackageManager.GET_PERMISSIONS, userId) 83 val index = packageInfo?.requestedPermissions?.indexOf(permission) ?: return false 84 return index >= 0 && 85 packageInfo.requestedPermissionsFlags[index].hasFlag(REQUESTED_PERMISSION_GRANTED) 86 } 87 88 override suspend fun getAppOpPermissionPackages(userId: Int, permission: String): Set<String> = 89 iPackageManager.getAppOpPermissionPackages(permission, userId).asIterable().asyncFilter { 90 iPackageManager.isPackageAvailable(it, userId) 91 }.toSet() 92 93 override fun getPackageInfoAsUser(packageName: String, flags: Int, userId: Int): PackageInfo? = 94 packageManagerWrapper.getPackageInfoAsUserCached(packageName, flags.toLong(), userId) 95 96 private fun Int.hasFlag(flag: Int) = (this and flag) > 0 97 } 98