1 /* <lambda>null2 * Copyright (C) 2022 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.model.livedatatypes.v31 18 19 import android.app.AppOpsManager.AttributedHistoricalOps 20 import android.app.AppOpsManager.AttributedOpEntry 21 import android.app.AppOpsManager.HistoricalOp 22 import android.app.AppOpsManager.HistoricalPackageOps 23 import android.app.AppOpsManager.OP_FLAG_SELF 24 import android.app.AppOpsManager.OP_FLAG_TRUSTED_PROXIED 25 import android.app.AppOpsManager.OP_FLAG_TRUSTED_PROXY 26 import android.app.AppOpsManager.OpEventProxyInfo 27 import android.os.UserHandle 28 import com.android.permissioncontroller.permission.utils.PermissionMapping.getPlatformPermissionGroupForOp 29 30 /** 31 * Light version of [HistoricalPackageOps] class, tracking the last permission access for system 32 * permission groups. 33 */ 34 data class LightHistoricalPackageOps( 35 /** Name of the package. */ 36 val packageName: String, 37 /** [UserHandle] running the package. */ 38 val userHandle: UserHandle, 39 /** 40 * Data about permission accesses, one [AppPermissionDiscreteAccesses] for each permission 41 * group. 42 */ 43 // TODO(b/262042582): Consider removing this field and using attributed accesses aggregated over 44 // attribution tags instead. 45 val appPermissionDiscreteAccesses: List<AppPermissionDiscreteAccesses>, 46 /** 47 * Attributed data about permission accesses, one [AttributedAppPermissionDiscreteAccesses] for 48 * each permission group. 49 */ 50 val attributedAppPermissionDiscreteAccesses: List<AttributedAppPermissionDiscreteAccesses> 51 ) { 52 constructor( 53 historicalPackageOps: HistoricalPackageOps, 54 userHandle: UserHandle, 55 opNames: Set<String> 56 ) : this( 57 historicalPackageOps.packageName, 58 userHandle, 59 historicalPackageOps.getAppPermissionDiscreteAccesses(userHandle, opNames), 60 historicalPackageOps.getAttributedAppPermissionDiscreteAccesses(userHandle, opNames), 61 ) 62 63 /** Companion object for [LightHistoricalPackageOps]. */ 64 companion object { 65 /** String to represent the absence of an attribution tag. */ 66 const val NO_ATTRIBUTION_TAG = "no_attribution_tag" 67 /** String to represent the absence of a permission group. */ 68 private const val NO_PERM_GROUP = "no_perm_group" 69 private const val DISCRETE_ACCESS_OP_FLAGS = 70 OP_FLAG_SELF or OP_FLAG_TRUSTED_PROXIED or OP_FLAG_TRUSTED_PROXY 71 72 /** 73 * Creates a list of [AppPermissionDiscreteAccesses] for the provided package, user and ops. 74 */ 75 private fun HistoricalPackageOps.getAppPermissionDiscreteAccesses( 76 userHandle: UserHandle, 77 opNames: Set<String> 78 ): List<AppPermissionDiscreteAccesses> { 79 val permissionsToOpNames = partitionOpsByPermission(opNames) 80 val appPermissionDiscreteAccesses = mutableListOf<AppPermissionDiscreteAccesses>() 81 for (permissionToOpNames in permissionsToOpNames.entries) { 82 this.getDiscreteAccesses(permissionToOpNames.value)?.let { 83 appPermissionDiscreteAccesses.add( 84 AppPermissionDiscreteAccesses( 85 AppPermissionId(packageName, userHandle, permissionToOpNames.key), 86 it 87 ) 88 ) 89 } 90 } 91 92 return appPermissionDiscreteAccesses 93 } 94 95 /** 96 * Creates a list of [AttributedAppPermissionDiscreteAccesses] for the provided package, 97 * user and ops. 98 */ 99 private fun HistoricalPackageOps.getAttributedAppPermissionDiscreteAccesses( 100 userHandle: UserHandle, 101 opNames: Set<String> 102 ): List<AttributedAppPermissionDiscreteAccesses> { 103 val permissionsToOpNames = partitionOpsByPermission(opNames) 104 val attributedAppPermissionDiscreteAccesses = 105 mutableMapOf<AppPermissionId, MutableMap<String, List<DiscreteAccess>>>() 106 107 val attributedHistoricalOpsList = mutableListOf<AttributedHistoricalOps>() 108 for (i in 0 until attributedOpsCount) { 109 attributedHistoricalOpsList.add(getAttributedOpsAt(i)) 110 } 111 112 for (permissionToOpNames in permissionsToOpNames.entries) { 113 attributedHistoricalOpsList.forEach { attributedHistoricalOps -> 114 attributedHistoricalOps.getDiscreteAccesses(permissionToOpNames.value)?.let { 115 discAccessData -> 116 val appPermissionId = 117 AppPermissionId(packageName, userHandle, permissionToOpNames.key) 118 if (!attributedAppPermissionDiscreteAccesses.containsKey(appPermissionId)) { 119 attributedAppPermissionDiscreteAccesses[appPermissionId] = 120 mutableMapOf() 121 } 122 attributedAppPermissionDiscreteAccesses[appPermissionId]?.put( 123 attributedHistoricalOps.tag ?: NO_ATTRIBUTION_TAG, 124 discAccessData 125 ) 126 } 127 } 128 } 129 130 return attributedAppPermissionDiscreteAccesses.map { 131 AttributedAppPermissionDiscreteAccesses(it.key, it.value) 132 } 133 } 134 135 /** 136 * Retrieves all discrete accesses for the provided op names, if any. 137 * 138 * Returns null if there are no accesses. 139 */ 140 private fun HistoricalPackageOps.getDiscreteAccesses( 141 opNames: List<String> 142 ): List<DiscreteAccess>? { 143 if (opCount == 0) { 144 return null 145 } 146 147 val historicalOps = mutableListOf<HistoricalOp>() 148 for (opName in opNames) { 149 getOp(opName)?.let { historicalOps.add(it) } 150 } 151 152 val discreteAccessList = mutableListOf<DiscreteAccess>() 153 historicalOps.forEach { 154 for (i in 0 until it.discreteAccessCount) { 155 val opEntry: AttributedOpEntry = it.getDiscreteAccessAt(i) 156 discreteAccessList.add( 157 DiscreteAccess( 158 opEntry.getLastAccessTime(DISCRETE_ACCESS_OP_FLAGS), 159 opEntry.getLastDuration(DISCRETE_ACCESS_OP_FLAGS), 160 opEntry.getLastProxyInfo(DISCRETE_ACCESS_OP_FLAGS) 161 ) 162 ) 163 } 164 } 165 166 if (discreteAccessList.isEmpty()) { 167 return null 168 } 169 return discreteAccessList.sortedWith(compareBy { -it.accessTimeMs }) 170 } 171 172 /** 173 * Retrieves all discrete accesses for the provided op names, if any. 174 * 175 * Returns null if there are no accesses. 176 */ 177 private fun AttributedHistoricalOps.getDiscreteAccesses( 178 opNames: List<String> 179 ): List<DiscreteAccess>? { 180 if (opCount == 0) { 181 return null 182 } 183 184 val historicalOps = mutableListOf<HistoricalOp>() 185 for (opName in opNames) { 186 getOp(opName)?.let { historicalOps.add(it) } 187 } 188 189 val discreteAccessList = mutableListOf<DiscreteAccess>() 190 historicalOps.forEach { 191 for (i in 0 until it.discreteAccessCount) { 192 val attributedOpEntry: AttributedOpEntry = it.getDiscreteAccessAt(i) 193 discreteAccessList.add( 194 DiscreteAccess( 195 attributedOpEntry.getLastAccessTime(DISCRETE_ACCESS_OP_FLAGS), 196 attributedOpEntry.getLastDuration(DISCRETE_ACCESS_OP_FLAGS), 197 attributedOpEntry.getLastProxyInfo(DISCRETE_ACCESS_OP_FLAGS) 198 ) 199 ) 200 } 201 } 202 203 if (discreteAccessList.isEmpty()) { 204 return null 205 } 206 return discreteAccessList.sortedWith(compareBy { -it.accessTimeMs }) 207 } 208 209 private fun partitionOpsByPermission(ops: Set<String>): Map<String, List<String>> = 210 ops.groupBy { getPlatformPermissionGroupForOp(it) ?: NO_PERM_GROUP } 211 .filter { it.key != NO_PERM_GROUP } 212 } 213 214 /** 215 * Data class representing permissions accesses for a particular permission group by a 216 * particular package and user. 217 */ 218 data class AppPermissionDiscreteAccesses( 219 val appPermissionId: AppPermissionId, 220 val discreteAccesses: List<DiscreteAccess> 221 ) 222 223 /** 224 * Data class representing permissions accesses for a particular permission group by a 225 * particular package and user, partitioned by attribution tag. 226 */ 227 data class AttributedAppPermissionDiscreteAccesses( 228 val appPermissionId: AppPermissionId, 229 val attributedDiscreteAccesses: Map<String, List<DiscreteAccess>> 230 ) 231 232 /** Data class representing a discrete permission access. */ 233 data class DiscreteAccess( 234 val accessTimeMs: Long, 235 val accessDurationMs: Long, 236 val proxy: OpEventProxyInfo? 237 ) 238 } 239