1 /* <lambda>null2 * Copyright (C) 2019 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.permissioncontroller.permission.data 18 19 import android.app.Application 20 import android.content.Context 21 import android.content.pm.ApplicationInfo 22 import android.content.pm.PackageManager 23 import android.os.Process 24 import android.os.Process.INVALID_UID 25 import android.os.UserHandle 26 import com.android.permissioncontroller.PermissionControllerApplication 27 import com.android.permissioncontroller.permission.model.livedatatypes.UidSensitivityState 28 import com.android.permissioncontroller.permission.utils.KotlinUtils 29 import com.android.permissioncontroller.permission.utils.PermissionMapping 30 import com.android.permissioncontroller.permission.utils.Utils 31 import java.lang.IllegalArgumentException 32 import kotlinx.coroutines.Job 33 34 /** 35 * Live data of the user sensitivity of either one uid, or all uids that belong to a user. Maps 36 * <uid, user sensitive state> 37 * 38 * @param app The current application 39 * @param uid The uid whose user sensitivity we would like to observer, or INVALID_UID if we want 40 * all uids for a user 41 * @param user The user for whom we want the uid/s 42 */ 43 class UserSensitivityLiveData 44 private constructor( 45 private val app: Application, 46 private val uid: Int, 47 private val user: UserHandle 48 ) : SmartAsyncMediatorLiveData<Map<Int, UidSensitivityState>?>() { 49 50 private val context: Context 51 private val packageLiveDatas = mutableMapOf<String, LightPackageInfoLiveData>() 52 private val userPackageInfosLiveData = UserPackageInfosLiveData[user] 53 private val getAllUids = uid == INVALID_UID 54 55 init { 56 try { 57 context = Utils.getUserContext(app, user) 58 } catch (cannotHappen: PackageManager.NameNotFoundException) { 59 throw IllegalStateException(cannotHappen) 60 } 61 62 if (getAllUids) { 63 addSource(userPackageInfosLiveData) { update() } 64 addSource(LauncherPackagesLiveData) { update() } 65 } else { 66 update() 67 } 68 } 69 70 override suspend fun loadDataAndPostValue(job: Job) { 71 val pm = context.packageManager 72 if (!getAllUids) { 73 val uidHasPackages = getAndObservePackageLiveDatas() 74 75 if ( 76 !uidHasPackages || 77 packageLiveDatas.all { it.value.isInitialized && it.value.value == null } 78 ) { 79 packageLiveDatas.clear() 80 invalidateSingle(uid to user) 81 postValue(null) 82 return 83 } else if (!packageLiveDatas.all { it.value.isInitialized }) { 84 return 85 } 86 } 87 val pkgs = 88 if (getAllUids) { 89 userPackageInfosLiveData.value ?: return 90 } else { 91 packageLiveDatas.mapNotNull { it.value.value } 92 } 93 if (job.isCancelled) { 94 return 95 } 96 97 // map of <uid, userSensitiveState> 98 val sensitiveStatePerUid = mutableMapOf<Int, UidSensitivityState>() 99 100 // TODO ntmyren: Figure out how to get custom runtime permissions in a less costly manner 101 val runtimePerms = PermissionMapping.getRuntimePlatformPermissionNames() 102 103 for (pkg in pkgs) { 104 // sensitivityState for one uid 105 val userSensitiveState = 106 sensitiveStatePerUid.getOrPut(pkg.uid) { 107 UidSensitivityState(mutableSetOf(), mutableMapOf()) 108 } 109 userSensitiveState.packages.add(pkg) 110 111 val pkgHasLauncherIcon = 112 if (getAllUids) { 113 // The launcher packages set will only be null when it is uninitialized. 114 LauncherPackagesLiveData.value?.contains(pkg.packageName) ?: return 115 } else { 116 KotlinUtils.packageHasLaunchIntent(context, pkg.packageName) 117 } 118 val pkgIsSystemApp = pkg.appFlags and ApplicationInfo.FLAG_SYSTEM != 0 119 // Iterate through all runtime perms, setting their keys 120 for (perm in pkg.requestedPermissions.intersect(runtimePerms)) { 121 /* 122 * Permissions are considered user sensitive for a package, when 123 * - the package has a launcher icon, or 124 * - the permission is not pre-granted, or 125 * - the package is not a system app (i.e. not preinstalled) 126 */ 127 var flags = 128 if (pkgIsSystemApp && !pkgHasLauncherIcon) { 129 val permGrantedByDefault = 130 pm.getPermissionFlags(perm, pkg.packageName, user) and 131 PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT != 0 132 133 if (permGrantedByDefault) { 134 0 135 } else { 136 PackageManager.FLAG_PERMISSION_USER_SENSITIVE_WHEN_GRANTED 137 } 138 } else { 139 Utils.FLAGS_ALWAYS_USER_SENSITIVE 140 } 141 142 /* 143 * If two packages share a UID there can be two cases: 144 * - for well known UIDs: if the permission for any package is non-user sensitive, 145 * it is non-sensitive. I.e. prefer to hide 146 * - for non system UIDs: if the permission for any package is user sensitive, it is 147 * user sensitive. I.e. prefer to show 148 */ 149 val previousFlags = userSensitiveState.permStates[perm] 150 if (previousFlags != null) { 151 flags = 152 if (pkg.uid < Process.FIRST_APPLICATION_UID) { 153 flags and previousFlags 154 } else { 155 flags or previousFlags 156 } 157 } 158 159 userSensitiveState.permStates[perm] = flags 160 } 161 162 if (job.isCancelled) { 163 return 164 } 165 } 166 postValue(sensitiveStatePerUid) 167 } 168 169 private fun getAndObservePackageLiveDatas(): Boolean { 170 synchronized(this) { 171 val packageNames = app.packageManager.getPackagesForUid(uid)?.toList() ?: emptyList() 172 val getLiveData = { packageName: String -> LightPackageInfoLiveData[packageName, user] } 173 setSourcesToDifference(packageNames, packageLiveDatas, getLiveData) 174 return packageNames.isNotEmpty() 175 } 176 } 177 178 /** 179 * Repository for a UserSensitivityLiveData 180 * 181 * <p> Key value is a pair of int uid (INVALID_UID for all uids), and UserHandle, value is its 182 * corresponding LiveData. 183 */ 184 companion object : DataRepository<Pair<Int, UserHandle>, UserSensitivityLiveData>() { 185 override fun newValue(key: Pair<Int, UserHandle>): UserSensitivityLiveData { 186 return UserSensitivityLiveData( 187 PermissionControllerApplication.get(), 188 key.first, 189 key.second 190 ) 191 } 192 193 /** 194 * Gets a liveData for a uid, automatically generating the UserHandle from the uid. Will 195 * throw an exception if the uid is INVALID_UID. 196 * 197 * @param uid The uid for which we want the liveData 198 * @return The liveData associated with the given UID 199 */ 200 operator fun get(uid: Int): UserSensitivityLiveData { 201 if (uid == INVALID_UID) { 202 throw IllegalArgumentException("Cannot get single uid livedata without a valid uid") 203 } 204 return get(uid, UserHandle.getUserHandleForUid(uid)) 205 } 206 207 /** 208 * Gets a liveData for a user, which will track all uids under 209 * 210 * @param user The user for whom we want the liveData 211 * @return The liveData associated with that user, for all uids 212 */ 213 operator fun get(user: UserHandle): UserSensitivityLiveData { 214 return get(INVALID_UID, user) 215 } 216 } 217 } 218