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), it)) 86 } 87 } 88 89 return appPermissionDiscreteAccesses 90 } 91 92 /** 93 * Creates a list of [AttributedAppPermissionDiscreteAccesses] for the provided package, 94 * user and ops. 95 */ 96 private fun HistoricalPackageOps.getAttributedAppPermissionDiscreteAccesses( 97 userHandle: UserHandle, 98 opNames: Set<String> 99 ): List<AttributedAppPermissionDiscreteAccesses> { 100 val permissionsToOpNames = partitionOpsByPermission(opNames) 101 val attributedAppPermissionDiscreteAccesses = 102 mutableMapOf<AppPermissionId, MutableMap<String, List<DiscreteAccess>>>() 103 104 val attributedHistoricalOpsList = mutableListOf<AttributedHistoricalOps>() 105 for (i in 0 until attributedOpsCount) { 106 attributedHistoricalOpsList.add(getAttributedOpsAt(i)) 107 } 108 109 for (permissionToOpNames in permissionsToOpNames.entries) { 110 attributedHistoricalOpsList.forEach { attributedHistoricalOps -> 111 attributedHistoricalOps.getDiscreteAccesses(permissionToOpNames.value)?.let { 112 discAccessData -> 113 val appPermissionId = 114 AppPermissionId(packageName, userHandle, permissionToOpNames.key) 115 if (!attributedAppPermissionDiscreteAccesses.containsKey(appPermissionId)) { 116 attributedAppPermissionDiscreteAccesses[appPermissionId] = 117 mutableMapOf() 118 } 119 attributedAppPermissionDiscreteAccesses[appPermissionId]?.put( 120 attributedHistoricalOps.tag ?: NO_ATTRIBUTION_TAG, discAccessData) 121 } 122 } 123 } 124 125 return attributedAppPermissionDiscreteAccesses.map { 126 AttributedAppPermissionDiscreteAccesses(it.key, it.value) 127 } 128 } 129 130 /** 131 * Retrieves all discrete accesses for the provided op names, if any. 132 * 133 * Returns null if there are no accesses. 134 */ 135 private fun HistoricalPackageOps.getDiscreteAccesses( 136 opNames: List<String> 137 ): List<DiscreteAccess>? { 138 if (opCount == 0) { 139 return null 140 } 141 142 val historicalOps = mutableListOf<HistoricalOp>() 143 for (opName in opNames) { 144 getOp(opName)?.let { historicalOps.add(it) } 145 } 146 147 val discreteAccessList = mutableListOf<DiscreteAccess>() 148 historicalOps.forEach { 149 for (i in 0 until it.discreteAccessCount) { 150 val opEntry: AttributedOpEntry = it.getDiscreteAccessAt(i) 151 discreteAccessList.add( 152 DiscreteAccess( 153 opEntry.getLastAccessTime(DISCRETE_ACCESS_OP_FLAGS), 154 opEntry.getLastDuration(DISCRETE_ACCESS_OP_FLAGS), 155 opEntry.getLastProxyInfo(DISCRETE_ACCESS_OP_FLAGS))) 156 } 157 } 158 159 if (discreteAccessList.isEmpty()) { 160 return null 161 } 162 return discreteAccessList.sortedWith(compareBy { -it.accessTimeMs }) 163 } 164 165 /** 166 * Retrieves all discrete accesses for the provided op names, if any. 167 * 168 * Returns null if there are no accesses. 169 */ 170 private fun AttributedHistoricalOps.getDiscreteAccesses( 171 opNames: List<String> 172 ): List<DiscreteAccess>? { 173 if (opCount == 0) { 174 return null 175 } 176 177 val historicalOps = mutableListOf<HistoricalOp>() 178 for (opName in opNames) { 179 getOp(opName)?.let { historicalOps.add(it) } 180 } 181 182 val discreteAccessList = mutableListOf<DiscreteAccess>() 183 historicalOps.forEach { 184 for (i in 0 until it.discreteAccessCount) { 185 val attributedOpEntry: AttributedOpEntry = it.getDiscreteAccessAt(i) 186 discreteAccessList.add( 187 DiscreteAccess( 188 attributedOpEntry.getLastAccessTime(DISCRETE_ACCESS_OP_FLAGS), 189 attributedOpEntry.getLastDuration(DISCRETE_ACCESS_OP_FLAGS), 190 attributedOpEntry.getLastProxyInfo(DISCRETE_ACCESS_OP_FLAGS))) 191 } 192 } 193 194 if (discreteAccessList.isEmpty()) { 195 return null 196 } 197 return discreteAccessList.sortedWith(compareBy { -it.accessTimeMs }) 198 } 199 200 private fun partitionOpsByPermission(ops: Set<String>): Map<String, List<String>> = 201 ops.groupBy { getPlatformPermissionGroupForOp(it) ?: NO_PERM_GROUP } 202 .filter { it.key != NO_PERM_GROUP } 203 } 204 205 /** 206 * Data class representing permissions accesses for a particular permission group by a 207 * particular package and user. 208 */ 209 data class AppPermissionDiscreteAccesses( 210 val appPermissionId: AppPermissionId, 211 val discreteAccesses: List<DiscreteAccess> 212 ) 213 214 /** 215 * Data class representing permissions accesses for a particular permission group by a 216 * particular package and user, partitioned by attribution tag. 217 */ 218 data class AttributedAppPermissionDiscreteAccesses( 219 val appPermissionId: AppPermissionId, 220 val attributedDiscreteAccesses: Map<String, List<DiscreteAccess>> 221 ) 222 223 /** Data class representing a discrete permission access. */ 224 data class DiscreteAccess( 225 val accessTimeMs: Long, 226 val accessDurationMs: Long, 227 val proxy: OpEventProxyInfo? 228 ) 229 } 230