• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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