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 @file:Suppress("DEPRECATION") 17 18 package com.android.permissioncontroller.permission.data 19 20 import android.app.Application 21 import android.content.Context 22 import android.content.pm.PackageInfo 23 import android.content.pm.PackageManager 24 import android.os.UserHandle 25 import android.os.UserManager 26 import android.util.Log 27 import androidx.annotation.MainThread 28 import androidx.lifecycle.Observer 29 import com.android.modules.utils.build.SdkLevel 30 import com.android.permissioncontroller.PermissionControllerApplication 31 import com.android.permissioncontroller.permission.model.livedatatypes.LightPackageInfo 32 import com.android.permissioncontroller.permission.utils.ContextCompat 33 import com.android.permissioncontroller.permission.utils.Utils 34 import com.android.permissioncontroller.permission.utils.v35.MultiDeviceUtils.isPermissionDeviceAware 35 import kotlinx.coroutines.Job 36 37 /** 38 * LiveData for a LightPackageInfo. 39 * 40 * @param app The current Application 41 * @param packageName The name of the package this LiveData will watch for mode changes for 42 * @param user The user for whom the packageInfo will be defined 43 */ 44 class LightPackageInfoLiveData 45 private constructor( 46 private val app: Application, 47 private val packageName: String, 48 private val user: UserHandle, 49 private val deviceId: Int 50 ) : 51 SmartAsyncMediatorLiveData<LightPackageInfo?>(alwaysUpdateOnActive = false), 52 PackageBroadcastReceiver.PackageBroadcastListener, 53 PermissionListenerMultiplexer.PermissionChangeCallback { 54 55 private val LOG_TAG = LightPackageInfoLiveData::class.java.simpleName 56 private val userPackagesLiveData = UserPackageInfosLiveData[user] 57 58 private var uid: Int? = null 59 /** The currently registered UID on which this LiveData is listening for permission changes. */ 60 private var registeredUid: Int? = null 61 /** Whether or not this package livedata is watching the UserPackageInfosLiveData */ 62 private var watchingUserPackagesLiveData: Boolean = false 63 64 /** 65 * Callback from the PackageBroadcastReceiver. Either deletes or generates package data. 66 * 67 * @param packageName the name of the package which was updated. Ignored in this method 68 */ 69 override fun onPackageUpdate(packageName: String) { 70 updateAsync() 71 } 72 73 override fun setValue(newValue: LightPackageInfo?) { 74 newValue?.let { packageInfo -> 75 if (packageInfo.uid != uid) { 76 uid = packageInfo.uid 77 78 if (hasActiveObservers()) { 79 PermissionListenerMultiplexer.addOrReplaceCallback( 80 registeredUid, 81 packageInfo.uid, 82 this 83 ) 84 registeredUid = uid 85 } 86 } 87 } 88 super.setValue(newValue) 89 } 90 91 override fun updateAsync() { 92 // If we were watching the userPackageInfosLiveData, stop, since we will override its value 93 if (watchingUserPackagesLiveData) { 94 removeSource(userPackagesLiveData) 95 watchingUserPackagesLiveData = false 96 } 97 super.updateAsync() 98 } 99 100 override suspend fun loadDataAndPostValue(job: Job) { 101 if (job.isCancelled) { 102 return 103 } 104 postValue( 105 try { 106 var flags = PackageManager.GET_PERMISSIONS 107 if (SdkLevel.isAtLeastS()) { 108 flags = flags or PackageManager.GET_ATTRIBUTIONS 109 } 110 111 val packageManager = Utils.getUserContext(app, user).packageManager 112 val pI = packageManager.getPackageInfo(packageName, flags) 113 114 // PackageInfo#requestedPermissionsFlags is not device aware. Hence for device aware 115 // permissions if the deviceId is not the primary device we need to separately check 116 // permission for that device and update requestedPermissionsFlags. 117 if (SdkLevel.isAtLeastV() && deviceId != ContextCompat.DEVICE_ID_DEFAULT) { 118 val requestedPermissionsFlagsForDevice = 119 getPermissionsFlagsForDevice( 120 pI.requestedPermissions?.toList() ?: emptyList(), 121 pI.requestedPermissionsFlags?.toList() ?: emptyList(), 122 pI.applicationInfo!!.uid, 123 deviceId 124 ) 125 126 LightPackageInfo(pI, deviceId, requestedPermissionsFlagsForDevice) 127 } else { 128 LightPackageInfo(pI) 129 } 130 } catch (e: Exception) { 131 if (e is PackageManager.NameNotFoundException) { 132 Log.w(LOG_TAG, "Package \"$packageName\" not found for user $user") 133 } else { 134 val profiles = app.getSystemService(UserManager::class.java)!!.userProfiles 135 Log.e( 136 LOG_TAG, 137 "Failed to create context for user $user. " + 138 "User exists : ${user in profiles }", 139 e 140 ) 141 } 142 invalidateSingle(Triple(packageName, user, deviceId)) 143 null 144 } 145 ) 146 } 147 148 /** Callback from the PermissionListener. Either deletes or generates package data. */ 149 override fun onPermissionChange() { 150 updateAsync() 151 } 152 153 override fun onActive() { 154 super.onActive() 155 156 PackageBroadcastReceiver.addChangeCallback(packageName, this) 157 uid?.let { 158 registeredUid = uid 159 PermissionListenerMultiplexer.addCallback(it, this) 160 } 161 if ( 162 userPackagesLiveData.hasActiveObservers() && 163 !watchingUserPackagesLiveData && 164 !userPackagesLiveData.permChangeStale 165 ) { 166 watchingUserPackagesLiveData = true 167 addSource(userPackagesLiveData, userPackageInfosObserver) 168 } else { 169 updateAsync() 170 } 171 } 172 173 private val userPackageInfosObserver = 174 Observer<List<LightPackageInfo>> { updateFromUserPackageInfosLiveData() } 175 176 @MainThread 177 private fun updateFromUserPackageInfosLiveData() { 178 if (!userPackagesLiveData.isInitialized) { 179 return 180 } 181 182 val packageInfo = userPackagesLiveData.value!!.find { it.packageName == packageName } 183 if (packageInfo != null) { 184 // Once we get one non-stale update, stop listening, as any further updates will likely 185 // be individual package updates. 186 if (!userPackagesLiveData.isStale) { 187 removeSource(UserPackageInfosLiveData[user]) 188 watchingUserPackagesLiveData = false 189 } 190 191 if (SdkLevel.isAtLeastV() && deviceId != Context.DEVICE_ID_DEFAULT) { 192 packageInfo.deviceId = deviceId 193 packageInfo.requestedPermissionsFlags = 194 getPermissionsFlagsForDevice( 195 packageInfo.requestedPermissions, 196 packageInfo.requestedPermissionsFlags, 197 packageInfo.uid, 198 deviceId 199 ) 200 } 201 value = packageInfo 202 } else { 203 // If the UserPackageInfosLiveData does not contain this package, check for removal, and 204 // stop watching. 205 updateAsync() 206 } 207 } 208 209 override fun onInactive() { 210 super.onInactive() 211 212 PackageBroadcastReceiver.removeChangeCallback(packageName, this) 213 registeredUid?.let { 214 PermissionListenerMultiplexer.removeCallback(it, this) 215 registeredUid = null 216 } 217 if (watchingUserPackagesLiveData) { 218 removeSource(userPackagesLiveData) 219 watchingUserPackagesLiveData = false 220 } 221 } 222 223 // Given permission flags of the default device and an external device Id, return a new list of 224 // permission flags for that device by checking grant state of device aware permissions for the 225 // device. 226 private fun getPermissionsFlagsForDevice( 227 requestedPermissions: List<String>, 228 requestedPermissionsFlags: List<Int>, 229 uid: Int, 230 deviceId: Int 231 ): List<Int> { 232 val requestedPermissionsFlagsForDevice = requestedPermissionsFlags.toMutableList() 233 val deviceContext = ContextCompat.createDeviceContext(app, deviceId) 234 235 for ((idx, permName) in requestedPermissions.withIndex()) { 236 if (isPermissionDeviceAware(deviceContext, deviceId, permName)) { 237 val result = deviceContext.checkPermission(permName, -1, uid) 238 239 if (result == PackageManager.PERMISSION_GRANTED) { 240 requestedPermissionsFlagsForDevice[idx] = 241 requestedPermissionsFlagsForDevice[idx] or 242 PackageInfo.REQUESTED_PERMISSION_GRANTED 243 } 244 245 if (result == PackageManager.PERMISSION_DENIED) { 246 requestedPermissionsFlagsForDevice[idx] = 247 requestedPermissionsFlagsForDevice[idx] and 248 PackageInfo.REQUESTED_PERMISSION_GRANTED.inv() 249 } 250 } 251 } 252 253 return requestedPermissionsFlagsForDevice 254 } 255 256 /** 257 * Repository for LightPackageInfoLiveDatas 258 * 259 * <p> Key value is a triple of package name, UserHandle and virtual deviceId, value is its 260 * corresponding LiveData. 261 */ 262 companion object : 263 DataRepositoryForDevice<Triple<String, UserHandle, Int>, LightPackageInfoLiveData>() { 264 override fun newValue( 265 key: Triple<String, UserHandle, Int>, 266 deviceId: Int 267 ): LightPackageInfoLiveData { 268 return LightPackageInfoLiveData( 269 PermissionControllerApplication.get(), 270 key.first, 271 key.second, 272 deviceId 273 ) 274 } 275 } 276 } 277