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