1 /* 2 * 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.KotlinUtils 25 import com.android.permissioncontroller.permission.utils.Utils 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 = Utils.getGroupOfPlatformPermission(requestedPerm) ?: continue 68 val granted = (pkg.requestedPermissionsFlags[idx] and 69 PackageInfo.REQUESTED_PERMISSION_GRANTED) != 0 70 if (pkg.targetSdkVersion < Build.VERSION_CODES.M || !granted) { 71 pkgGroups.add(Triple(pkg.packageName, group, user)) 72 } 73 } 74 allPackageGroups.addAll(pkgGroups) 75 } 76 } 77 78 if (allPackageGroups.isEmpty()) { 79 postCopyOfMap() 80 } else { 81 observePermStateLiveDatas(allPackageGroups) 82 } 83 } 84 85 private fun observePermStateLiveDatas(packageGroups: Set<Triple<String, String, UserHandle>>) { 86 GlobalScope.launch(Main.immediate) { 87 88 val (toAdd, toRemove) = 89 KotlinUtils.getMapAndListDifferences(packageGroups, permStateLiveDatas) 90 91 for (packagePermGroup in toRemove) { 92 removeSource(permStateLiveDatas.remove(packagePermGroup) ?: continue) 93 val packageUser = packagePermGroup.first to packagePermGroup.third 94 packageAutoRevokedPermsList[packageUser]?.remove(packagePermGroup.second) 95 if (packageAutoRevokedPermsList[packageUser]?.isEmpty() == true) { 96 packageAutoRevokedPermsList.remove(packageUser) 97 } 98 } 99 100 if (toRemove.isNotEmpty()) { 101 postCopyOfMap() 102 } 103 104 for (packagePermGroup in toAdd) { 105 permStateLiveDatas[packagePermGroup] = PermStateLiveData[packagePermGroup] 106 } 107 108 for (packagePermGroup in toAdd) { 109 val permStateLiveData = permStateLiveDatas[packagePermGroup]!! 110 val packageUser = packagePermGroup.first to packagePermGroup.third 111 112 addSource(permStateLiveData) { permState -> 113 var added = false 114 if (permState == null && permStateLiveData.isInitialized) { 115 permStateLiveDatas.remove(packagePermGroup) 116 removeSource(permStateLiveData) 117 } else if (permState != null) { 118 for ((_, state) in permState) { 119 if (state.permFlags and FLAG_PERMISSION_AUTO_REVOKED != 0) { 120 packageAutoRevokedPermsList.getOrPut(packageUser) { mutableSetOf() } 121 .add(packagePermGroup.second) 122 added = true 123 break 124 } 125 } 126 } 127 128 if (!added) { 129 packageAutoRevokedPermsList[packageUser]?.remove(packagePermGroup.second) 130 if (packageAutoRevokedPermsList[packageUser]?.isEmpty() == true) { 131 packageAutoRevokedPermsList.remove(packageUser) 132 } 133 } 134 135 if (permStateLiveDatas.all { it.value.isInitialized }) { 136 postCopyOfMap() 137 } 138 } 139 } 140 } 141 } 142 143 private fun postCopyOfMap() { 144 val autoRevokedCopy = 145 mutableMapOf<Pair<String, UserHandle>, Set<String>>() 146 for ((userPackage, permGroups) in packageAutoRevokedPermsList) { 147 autoRevokedCopy[userPackage] = permGroups.toSet() 148 } 149 Log.i(LOG_TAG, "postValue: $autoRevokedCopy") 150 postValue(autoRevokedCopy) 151 } 152 } 153 154 private val autoRevokedPackagesSetLiveData = 155 object : SmartUpdateMediatorLiveData<Set<Pair<String, UserHandle>>>() { 156 init { 157 addSource(AutoRevokedPackagesLiveData) { 158 update() 159 } 160 } 161 162 override fun onUpdate() { 163 if (!AutoRevokedPackagesLiveData.isInitialized) { 164 return 165 } 166 value = AutoRevokedPackagesLiveData.value!!.keys 167 } 168 } 169 170 val unusedAutoRevokePackagesLiveData = UnusedPackagesLiveData(autoRevokedPackagesSetLiveData)