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.PackageInfo 20 import android.content.pm.PackageManager.FLAG_PERMISSION_AUTO_REVOKED 21 import android.os.Build 22 import android.os.UserHandle 23 import android.util.Log 24 import com.android.permissioncontroller.permission.utils.PermissionMapping 25 import com.android.permissioncontroller.permission.utils.KotlinUtils 26 import kotlinx.coroutines.Dispatchers.Main 27 import kotlinx.coroutines.GlobalScope 28 import kotlinx.coroutines.Job 29 import kotlinx.coroutines.launch 30 31 /** 32 * Tracks which packages have been auto-revoked, and which groups have been auto revoked for those 33 * packages. 34 * 35 * ```(packageName, user) -> [groupName]``` 36 */ 37 object AutoRevokedPackagesLiveData 38 : SmartAsyncMediatorLiveData<Map<Pair<String, UserHandle>, Set<String>>>() { 39 40 private val LOG_TAG = AutoRevokedPackagesLiveData::class.java.simpleName 41 42 init { 43 addSource(AllPackageInfosLiveData) { 44 update() 45 } 46 } 47 48 private val permStateLiveDatas = 49 mutableMapOf<Triple<String, String, UserHandle>, PermStateLiveData>() 50 private val packageAutoRevokedPermsList = 51 mutableMapOf<Pair<String, UserHandle>, MutableSet<String>>() 52 53 override suspend fun loadDataAndPostValue(job: Job) { 54 if (!AllPackageInfosLiveData.isInitialized) { 55 return 56 } 57 58 val allPackageGroups = mutableSetOf<Triple<String, String, UserHandle>>() 59 for ((user, packageList) in AllPackageInfosLiveData.value ?: emptyMap()) { 60 for (pkg in packageList) { 61 if (job.isCancelled) { 62 return 63 } 64 65 val pkgGroups = mutableSetOf<Triple<String, String, UserHandle>>() 66 for ((idx, requestedPerm) in pkg.requestedPermissions.withIndex()) { 67 val group = 68 PermissionMapping.getGroupOfPlatformPermission(requestedPerm) ?: continue 69 val granted = (pkg.requestedPermissionsFlags[idx] and 70 PackageInfo.REQUESTED_PERMISSION_GRANTED) != 0 71 if (pkg.targetSdkVersion < Build.VERSION_CODES.M || !granted) { 72 pkgGroups.add(Triple(pkg.packageName, group, user)) 73 } 74 } 75 allPackageGroups.addAll(pkgGroups) 76 } 77 } 78 79 if (allPackageGroups.isEmpty()) { 80 postCopyOfMap() 81 } else { 82 observePermStateLiveDatas(allPackageGroups) 83 } 84 } 85 86 private fun observePermStateLiveDatas(packageGroups: Set<Triple<String, String, UserHandle>>) { 87 GlobalScope.launch(Main.immediate) { 88 89 val (toAdd, toRemove) = 90 KotlinUtils.getMapAndListDifferences(packageGroups, permStateLiveDatas) 91 92 for (packagePermGroup in toRemove) { 93 removeSource(permStateLiveDatas.remove(packagePermGroup) ?: continue) 94 val packageUser = packagePermGroup.first to packagePermGroup.third 95 packageAutoRevokedPermsList[packageUser]?.remove(packagePermGroup.second) 96 if (packageAutoRevokedPermsList[packageUser]?.isEmpty() == true) { 97 packageAutoRevokedPermsList.remove(packageUser) 98 } 99 } 100 101 if (toRemove.isNotEmpty()) { 102 postCopyOfMap() 103 } 104 105 for (packagePermGroup in toAdd) { 106 permStateLiveDatas[packagePermGroup] = PermStateLiveData[packagePermGroup] 107 } 108 109 for (packagePermGroup in toAdd) { 110 val permStateLiveData = permStateLiveDatas[packagePermGroup]!! 111 val packageUser = packagePermGroup.first to packagePermGroup.third 112 113 addSource(permStateLiveData) { permState -> 114 var added = false 115 if (permState == null && permStateLiveData.isInitialized) { 116 permStateLiveDatas.remove(packagePermGroup) 117 removeSource(permStateLiveData) 118 } else if (permState != null) { 119 for ((_, state) in permState) { 120 if (state.permFlags and FLAG_PERMISSION_AUTO_REVOKED != 0) { 121 packageAutoRevokedPermsList.getOrPut(packageUser) { mutableSetOf() } 122 .add(packagePermGroup.second) 123 added = true 124 break 125 } 126 } 127 } 128 129 if (!added) { 130 packageAutoRevokedPermsList[packageUser]?.remove(packagePermGroup.second) 131 if (packageAutoRevokedPermsList[packageUser]?.isEmpty() == true) { 132 packageAutoRevokedPermsList.remove(packageUser) 133 } 134 } 135 136 if (permStateLiveDatas.all { it.value.isInitialized }) { 137 postCopyOfMap() 138 } 139 } 140 } 141 } 142 } 143 144 private fun postCopyOfMap() { 145 val autoRevokedCopy = 146 mutableMapOf<Pair<String, UserHandle>, Set<String>>() 147 for ((userPackage, permGroups) in packageAutoRevokedPermsList) { 148 autoRevokedCopy[userPackage] = permGroups.toSet() 149 } 150 Log.i(LOG_TAG, "postValue: $autoRevokedCopy") 151 postValue(autoRevokedCopy) 152 } 153 } 154 155 private val autoRevokedPackagesSetLiveData = 156 object : SmartUpdateMediatorLiveData<Set<Pair<String, UserHandle>>>() { 157 init { <lambda>null158 addSource(AutoRevokedPackagesLiveData) { 159 update() 160 } 161 } 162 onUpdatenull163 override fun onUpdate() { 164 if (!AutoRevokedPackagesLiveData.isInitialized) { 165 return 166 } 167 value = AutoRevokedPackagesLiveData.value!!.keys 168 } 169 } 170 171 val unusedAutoRevokePackagesLiveData = UnusedPackagesLiveData(autoRevokedPackagesSetLiveData)