1 /* <lambda>null2 * Copyright (C) 2020 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.content.pm.PackageManager.FLAG_PERMISSION_AUTO_REVOKED 20 import android.os.UserHandle 21 import com.android.permissioncontroller.PermissionControllerApplication 22 import com.android.permissioncontroller.permission.data.PackagePermissionsLiveData.Companion.NON_RUNTIME_NORMAL_PERMS 23 import com.android.permissioncontroller.permission.service.getUnusedThresholdMs 24 import com.android.permissioncontroller.permission.utils.KotlinUtils 25 import kotlinx.coroutines.Dispatchers.Main 26 import kotlinx.coroutines.GlobalScope 27 import kotlinx.coroutines.launch 28 29 /** 30 * Tracks which packages have been auto-revoked, and which groups have been auto revoked for those 31 * packages. 32 */ 33 object AutoRevokedPackagesLiveData 34 : SmartUpdateMediatorLiveData<Map<Pair<String, UserHandle>, Set<String>>>() { 35 36 init { 37 addSource(AllPackageInfosLiveData) { 38 updateIfActive() 39 } 40 } 41 42 private val permStateLiveDatas = 43 mutableMapOf<Triple<String, String, UserHandle>, PermStateLiveData>() 44 private val packagePermGroupsLiveDatas = 45 mutableMapOf<Pair<String, UserHandle>, PackagePermissionsLiveData>() 46 private val packageAutoRevokedPermsList = 47 mutableMapOf<Pair<String, UserHandle>, MutableSet<String>>() 48 49 override fun onUpdate() { 50 if (!AllPackageInfosLiveData.isInitialized) { 51 return 52 } 53 54 val packageNames = mutableListOf<Pair<String, UserHandle>>() 55 for ((user, packageList) in AllPackageInfosLiveData.value ?: emptyMap()) { 56 packageNames.addAll(packageList.mapNotNull { pkg -> 57 if (pkg.enabled) { 58 pkg.packageName to user 59 } else { 60 null 61 } 62 }) 63 } 64 65 GlobalScope.launch(Main.immediate) { 66 val (toAdd, toRemove) = 67 KotlinUtils.getMapAndListDifferences(packageNames, packagePermGroupsLiveDatas) 68 69 for (pkg in toRemove) { 70 val packagePermissionsLiveData = packagePermGroupsLiveDatas.remove(pkg) ?: continue 71 removeSource(packagePermissionsLiveData) 72 for ((groupName, _) in packagePermissionsLiveData.value ?: continue) { 73 removeSource(permStateLiveDatas.remove(Triple(pkg.first, groupName, pkg.second)) 74 ?: continue) 75 } 76 packageAutoRevokedPermsList.remove(pkg) 77 } 78 if (toRemove.isNotEmpty()) { 79 postCopyOfMap() 80 } 81 82 toAdd.forEach { packagePermGroupsLiveDatas[it] = PackagePermissionsLiveData[it] } 83 84 toAdd.forEach { userPackage -> 85 addSource(packagePermGroupsLiveDatas[userPackage]!!) { 86 if (packagePermGroupsLiveDatas.all { it.value.isInitialized }) { 87 observePermStateLiveDatas() 88 } 89 } 90 } 91 } 92 } 93 94 private fun observePermStateLiveDatas() { 95 val packageGroups = mutableListOf<Triple<String, String, UserHandle>>() 96 packageGroups.addAll(packagePermGroupsLiveDatas.flatMap { (pkgPair, liveData) -> 97 liveData.value?.keys?.toMutableSet()?.let { permGroups -> 98 permGroups.remove(NON_RUNTIME_NORMAL_PERMS) 99 permGroups.map { Triple(pkgPair.first, it, pkgPair.second) } 100 } ?: emptyList() 101 }) 102 103 GlobalScope.launch(Main.immediate) { 104 105 val (toAdd, toRemove) = 106 KotlinUtils.getMapAndListDifferences(packageGroups, permStateLiveDatas) 107 108 for (packagePermGroup in toRemove) { 109 removeSource(permStateLiveDatas.remove(packagePermGroup) ?: continue) 110 val packageUser = packagePermGroup.first to packagePermGroup.third 111 packageAutoRevokedPermsList[packageUser]?.remove(packagePermGroup.second) 112 if (packageAutoRevokedPermsList[packageUser]?.isEmpty() == true) { 113 packageAutoRevokedPermsList.remove(packageUser) 114 } 115 } 116 117 if (toRemove.isNotEmpty()) { 118 postCopyOfMap() 119 } 120 121 for (packagePermGroup in toAdd) { 122 permStateLiveDatas[packagePermGroup] = PermStateLiveData[packagePermGroup] 123 } 124 125 for (packagePermGroup in toAdd) { 126 val permStateLiveData = permStateLiveDatas[packagePermGroup]!! 127 val packageUser = packagePermGroup.first to packagePermGroup.third 128 129 addSource(permStateLiveData) { permState -> 130 var added = false 131 if (permState == null && permStateLiveData.isInitialized) { 132 permStateLiveDatas.remove(packagePermGroup) 133 removeSource(permStateLiveData) 134 } else if (permState != null) { 135 for ((_, state) in permState) { 136 if (state.permFlags and FLAG_PERMISSION_AUTO_REVOKED != 0) { 137 packageAutoRevokedPermsList.getOrPut(packageUser) { mutableSetOf() } 138 .add(packagePermGroup.second) 139 added = true 140 break 141 } 142 } 143 } 144 145 if (!added) { 146 packageAutoRevokedPermsList[packageUser]?.remove(packagePermGroup.second) 147 if (packageAutoRevokedPermsList[packageUser]?.isEmpty() == true) { 148 packageAutoRevokedPermsList.remove(packageUser) 149 } 150 } 151 152 if (permStateLiveDatas.all { it.value.isInitialized }) { 153 postCopyOfMap() 154 } 155 } 156 } 157 } 158 } 159 160 private fun postCopyOfMap() { 161 val autoRevokedCopy = 162 mutableMapOf<Pair<String, UserHandle>, Set<String>>() 163 for ((userPackage, permGroups) in packageAutoRevokedPermsList) { 164 autoRevokedCopy[userPackage] = permGroups.toSet() 165 } 166 postValue(autoRevokedCopy) 167 } 168 } 169 170 /** 171 * Gets all Auto Revoked packages that have not been opened in a few months. This will let us remove 172 * used apps from the Auto Revoke screen. 173 */ 174 object UnusedAutoRevokedPackagesLiveData 175 : SmartUpdateMediatorLiveData<Map<Pair<String, UserHandle>, Set<String>>>() { 176 private val unusedThreshold = getUnusedThresholdMs(PermissionControllerApplication.get()) 177 private val usageStatsLiveData = UsageStatsLiveData[unusedThreshold] 178 179 init { <lambda>null180 addSource(usageStatsLiveData) { 181 updateIfActive() 182 } <lambda>null183 addSource(AutoRevokedPackagesLiveData) { 184 updateIfActive() 185 } 186 } 187 onUpdatenull188 override fun onUpdate() { 189 if (!usageStatsLiveData.isInitialized || !AutoRevokedPackagesLiveData.isInitialized) { 190 return 191 } 192 193 val autoRevokedPackages = AutoRevokedPackagesLiveData.value!! 194 195 val unusedPackages = mutableMapOf<Pair<String, UserHandle>, Set<String>>() 196 for ((userPackage, perms) in autoRevokedPackages) { 197 unusedPackages[userPackage] = perms.toSet() 198 } 199 200 val now = System.currentTimeMillis() 201 for ((user, stats) in usageStatsLiveData.value!!) { 202 for (stat in stats) { 203 val userPackage = stat.packageName to user 204 if (userPackage in autoRevokedPackages && 205 (now - stat.lastTimeVisible) < unusedThreshold) { 206 unusedPackages.remove(userPackage) 207 } 208 } 209 } 210 211 value = unusedPackages 212 } 213 }