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.pm.PackageManager 22 import android.os.UserHandle 23 import android.os.UserManager 24 import android.util.Log 25 import androidx.annotation.MainThread 26 import androidx.lifecycle.Observer 27 import com.android.modules.utils.build.SdkLevel 28 import com.android.permissioncontroller.PermissionControllerApplication 29 import com.android.permissioncontroller.permission.model.livedatatypes.LightPackageInfo 30 import com.android.permissioncontroller.permission.utils.Utils 31 import kotlinx.coroutines.Job 32 33 /** 34 * LiveData for a LightPackageInfo. 35 * 36 * @param app The current Application 37 * @param packageName The name of the package this LiveData will watch for mode changes for 38 * @param user The user for whom the packageInfo will be defined 39 */ 40 class LightPackageInfoLiveData private constructor( 41 private val app: Application, 42 private val packageName: String, 43 private val user: UserHandle 44 ) : SmartAsyncMediatorLiveData<LightPackageInfo?>(alwaysUpdateOnActive = false), 45 PackageBroadcastReceiver.PackageBroadcastListener, 46 PermissionListenerMultiplexer.PermissionChangeCallback { 47 48 private val LOG_TAG = LightPackageInfoLiveData::class.java.simpleName 49 private val userPackagesLiveData = UserPackageInfosLiveData[user] 50 51 private var uid: Int? = null 52 /** 53 * The currently registered UID on which this LiveData is listening for permission changes. 54 */ 55 private var registeredUid: Int? = null 56 /** 57 * Whether or not this package livedata is watching the UserPackageInfosLiveData 58 */ 59 private var watchingUserPackagesLiveData: Boolean = false 60 61 /** 62 * Callback from the PackageBroadcastReceiver. Either deletes or generates package data. 63 * 64 * @param packageName the name of the package which was updated. Ignored in this method 65 */ 66 override fun onPackageUpdate(packageName: String) { 67 updateAsync() 68 } 69 70 override fun setValue(newValue: LightPackageInfo?) { 71 newValue?.let { packageInfo -> 72 if (packageInfo.uid != uid) { 73 uid = packageInfo.uid 74 75 if (hasActiveObservers()) { 76 PermissionListenerMultiplexer.addOrReplaceCallback(registeredUid, 77 packageInfo.uid, this) 78 registeredUid = uid 79 } 80 } 81 } 82 super.setValue(newValue) 83 } 84 85 override fun updateAsync() { 86 // If we were watching the userPackageInfosLiveData, stop, since we will override its value 87 if (watchingUserPackagesLiveData) { 88 removeSource(userPackagesLiveData) 89 watchingUserPackagesLiveData = false 90 } 91 super.updateAsync() 92 } 93 94 override suspend fun loadDataAndPostValue(job: Job) { 95 if (job.isCancelled) { 96 return 97 } 98 postValue(try { 99 var flags = PackageManager.GET_PERMISSIONS 100 if (SdkLevel.isAtLeastS()) { 101 flags = flags or PackageManager.GET_ATTRIBUTIONS 102 } 103 104 LightPackageInfo(Utils.getUserContext(app, user).packageManager 105 .getPackageInfo(packageName, flags)) 106 } catch (e: Exception) { 107 if (e is PackageManager.NameNotFoundException) { 108 Log.w(LOG_TAG, "Package \"$packageName\" not found for user $user") 109 } else { 110 val profiles = app.getSystemService(UserManager::class.java)!!.userProfiles 111 Log.e(LOG_TAG, "Failed to create context for user $user. " + 112 "User exists : ${user in profiles }", e) 113 } 114 invalidateSingle(packageName to user) 115 null 116 }) 117 } 118 119 /** 120 * Callback from the PermissionListener. Either deletes or generates package data. 121 */ 122 override fun onPermissionChange() { 123 updateAsync() 124 } 125 126 override fun onActive() { 127 super.onActive() 128 129 PackageBroadcastReceiver.addChangeCallback(packageName, this) 130 uid?.let { 131 registeredUid = uid 132 PermissionListenerMultiplexer.addCallback(it, this) 133 } 134 if (userPackagesLiveData.hasActiveObservers() && !watchingUserPackagesLiveData && 135 !userPackagesLiveData.permChangeStale) { 136 watchingUserPackagesLiveData = true 137 addSource(userPackagesLiveData, userPackageInfosObserver) 138 } else { 139 updateAsync() 140 } 141 } 142 143 private val userPackageInfosObserver = Observer<List<LightPackageInfo>> { 144 updateFromUserPackageInfosLiveData() 145 } 146 147 @MainThread 148 private fun updateFromUserPackageInfosLiveData() { 149 if (!userPackagesLiveData.isInitialized) { 150 return 151 } 152 153 val packageInfo = userPackagesLiveData.value!!.find { it.packageName == packageName } 154 if (packageInfo != null) { 155 // Once we get one non-stale update, stop listening, as any further updates will likely 156 // be individual package updates. 157 if (!userPackagesLiveData.isStale) { 158 removeSource(UserPackageInfosLiveData[user]) 159 watchingUserPackagesLiveData = false 160 } 161 162 value = packageInfo 163 } else { 164 // If the UserPackageInfosLiveData does not contain this package, check for removal, and 165 // stop watching. 166 updateAsync() 167 } 168 } 169 170 override fun onInactive() { 171 super.onInactive() 172 173 PackageBroadcastReceiver.removeChangeCallback(packageName, this) 174 registeredUid?.let { 175 PermissionListenerMultiplexer.removeCallback(it, this) 176 registeredUid = null 177 } 178 if (watchingUserPackagesLiveData) { 179 removeSource(userPackagesLiveData) 180 watchingUserPackagesLiveData = false 181 } 182 } 183 184 /** 185 * Repository for LightPackageInfoLiveDatas 186 * <p> Key value is a string package name and UserHandle pair, value is its corresponding 187 * LiveData. 188 */ 189 companion object : DataRepositoryForPackage<Pair<String, UserHandle>, 190 LightPackageInfoLiveData>() { 191 override fun newValue(key: Pair<String, UserHandle>): LightPackageInfoLiveData { 192 return LightPackageInfoLiveData(PermissionControllerApplication.get(), 193 key.first, key.second) 194 } 195 } 196 } 197