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