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