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.app.AppOpsManager.permissionToOp
20 import android.app.Application
21 import com.android.permissioncontroller.PermissionControllerApplication
22 import com.android.permissioncontroller.permission.utils.PermissionMapping.getPlatformPermissionNamesOfGroup
23 import kotlin.collections.set
24 
25 /**
26  * LiveData that loads the last usage of permission group for every package/attributionTag-pair.
27  *
28  * <p>This relies on app-ops data, hence this only works for platform defined permission groups.
29  *
30  * <p>For app-ops with duration the end of the access is considered.
31  *
32  * <p>Returns map perm-group-name -> {@link OpUsageLiveData.OpAccess}
33  *
34  * @param app The current application
35  * @param permGroupsNames The names of the permission groups we wish to search for
36  * @param usageDurationMs how much ago can an access have happened to be considered
37  */
38 class PermGroupUsageLiveData(
39     private val app: Application,
40     private val permGroupsNames: List<String>,
41     private val usageDurationMs: Long
42 ) : SmartUpdateMediatorLiveData<Map<String, List<OpAccess>>>() {
43     /** Perm group name -> OpUsageLiveData */
44     private val permGroupUsages =
45         permGroupsNames
46             .map { permGroup ->
47                 val appops =
48                     getPlatformPermissionNamesOfGroup(permGroup).mapNotNull { permName ->
49                         permissionToOp(permName)
50                     }
51 
52                 permGroup to OpUsageLiveData[appops, usageDurationMs]
53             }
54             .toMap()
55 
56     init {
57         for (usage in permGroupUsages.values) {
58             addSource(usage) { update() }
59         }
60     }
61 
62     override fun onUpdate() {
63         if (permGroupUsages.values.any { !it.isInitialized }) {
64             return
65         }
66 
67         if (permGroupUsages.values.any { it.value == null }) {
68             value = null
69             return
70         }
71 
72         // Only keep the last access for a permission group
73         value =
74             permGroupUsages
75                 .map { (permGroupName, usageLiveData) ->
76                     // (packageName, attributionTag) -> access
77                     val lastAccess = mutableMapOf<Pair<String, String?>, OpAccess>()
78                     for (access in usageLiveData.value!!.values.flatten()) {
79                         val key = access.packageName to access.attributionTag
80                         if (
81                             access.isRunning ||
82                                 lastAccess[key]?.lastAccessTime ?: 0 < access.lastAccessTime
83                         ) {
84                             lastAccess[key] = access
85                         }
86                     }
87 
88                     permGroupName to lastAccess.values.toList()
89                 }
90                 .toMap()
91     }
92 
93     companion object : DataRepository<Pair<List<String>, Long>, PermGroupUsageLiveData>() {
94         override fun newValue(key: Pair<List<String>, Long>): PermGroupUsageLiveData {
95             return PermGroupUsageLiveData(
96                 PermissionControllerApplication.get(),
97                 key.first,
98                 key.second
99             )
100         }
101     }
102 }
103