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.content.pm.PackageManager.FLAG_PERMISSION_AUTO_REVOKED
20 import android.os.UserHandle
21 import com.android.permissioncontroller.PermissionControllerApplication
22 import com.android.permissioncontroller.permission.data.PackagePermissionsLiveData.Companion.NON_RUNTIME_NORMAL_PERMS
23 import com.android.permissioncontroller.permission.service.getUnusedThresholdMs
24 import com.android.permissioncontroller.permission.utils.KotlinUtils
25 import kotlinx.coroutines.Dispatchers.Main
26 import kotlinx.coroutines.GlobalScope
27 import kotlinx.coroutines.launch
28 
29 /**
30  * Tracks which packages have been auto-revoked, and which groups have been auto revoked for those
31  * packages.
32  */
33 object AutoRevokedPackagesLiveData
34     : SmartUpdateMediatorLiveData<Map<Pair<String, UserHandle>, Set<String>>>() {
35 
36     init {
37         addSource(AllPackageInfosLiveData) {
38             updateIfActive()
39         }
40     }
41 
42     private val permStateLiveDatas =
43         mutableMapOf<Triple<String, String, UserHandle>, PermStateLiveData>()
44     private val packagePermGroupsLiveDatas =
45         mutableMapOf<Pair<String, UserHandle>, PackagePermissionsLiveData>()
46     private val packageAutoRevokedPermsList =
47         mutableMapOf<Pair<String, UserHandle>, MutableSet<String>>()
48 
49     override fun onUpdate() {
50         if (!AllPackageInfosLiveData.isInitialized) {
51             return
52         }
53 
54         val packageNames = mutableListOf<Pair<String, UserHandle>>()
55         for ((user, packageList) in AllPackageInfosLiveData.value ?: emptyMap()) {
56             packageNames.addAll(packageList.mapNotNull { pkg ->
57                 if (pkg.enabled) {
58                     pkg.packageName to user
59                 } else {
60                     null
61                 }
62             })
63         }
64 
65         GlobalScope.launch(Main.immediate) {
66             val (toAdd, toRemove) =
67                 KotlinUtils.getMapAndListDifferences(packageNames, packagePermGroupsLiveDatas)
68 
69             for (pkg in toRemove) {
70                 val packagePermissionsLiveData = packagePermGroupsLiveDatas.remove(pkg) ?: continue
71                 removeSource(packagePermissionsLiveData)
72                 for ((groupName, _) in packagePermissionsLiveData.value ?: continue) {
73                     removeSource(permStateLiveDatas.remove(Triple(pkg.first, groupName, pkg.second))
74                         ?: continue)
75                 }
76                 packageAutoRevokedPermsList.remove(pkg)
77             }
78             if (toRemove.isNotEmpty()) {
79                 postCopyOfMap()
80             }
81 
82             toAdd.forEach { packagePermGroupsLiveDatas[it] = PackagePermissionsLiveData[it] }
83 
84             toAdd.forEach { userPackage ->
85                 addSource(packagePermGroupsLiveDatas[userPackage]!!) {
86                     if (packagePermGroupsLiveDatas.all { it.value.isInitialized }) {
87                         observePermStateLiveDatas()
88                     }
89                 }
90             }
91         }
92     }
93 
94     private fun observePermStateLiveDatas() {
95         val packageGroups = mutableListOf<Triple<String, String, UserHandle>>()
96         packageGroups.addAll(packagePermGroupsLiveDatas.flatMap { (pkgPair, liveData) ->
97             liveData.value?.keys?.toMutableSet()?.let { permGroups ->
98                 permGroups.remove(NON_RUNTIME_NORMAL_PERMS)
99                 permGroups.map { Triple(pkgPair.first, it, pkgPair.second) }
100             } ?: emptyList()
101         })
102 
103         GlobalScope.launch(Main.immediate) {
104 
105             val (toAdd, toRemove) =
106                 KotlinUtils.getMapAndListDifferences(packageGroups, permStateLiveDatas)
107 
108             for (packagePermGroup in toRemove) {
109                 removeSource(permStateLiveDatas.remove(packagePermGroup) ?: continue)
110                 val packageUser = packagePermGroup.first to packagePermGroup.third
111                 packageAutoRevokedPermsList[packageUser]?.remove(packagePermGroup.second)
112                 if (packageAutoRevokedPermsList[packageUser]?.isEmpty() == true) {
113                     packageAutoRevokedPermsList.remove(packageUser)
114                 }
115             }
116 
117             if (toRemove.isNotEmpty()) {
118                 postCopyOfMap()
119             }
120 
121             for (packagePermGroup in toAdd) {
122                 permStateLiveDatas[packagePermGroup] = PermStateLiveData[packagePermGroup]
123             }
124 
125             for (packagePermGroup in toAdd) {
126                 val permStateLiveData = permStateLiveDatas[packagePermGroup]!!
127                 val packageUser = packagePermGroup.first to packagePermGroup.third
128 
129                 addSource(permStateLiveData) { permState ->
130                     var added = false
131                     if (permState == null && permStateLiveData.isInitialized) {
132                         permStateLiveDatas.remove(packagePermGroup)
133                         removeSource(permStateLiveData)
134                     } else if (permState != null) {
135                         for ((_, state) in permState) {
136                             if (state.permFlags and FLAG_PERMISSION_AUTO_REVOKED != 0) {
137                                 packageAutoRevokedPermsList.getOrPut(packageUser) { mutableSetOf() }
138                                     .add(packagePermGroup.second)
139                                 added = true
140                                 break
141                             }
142                         }
143                     }
144 
145                     if (!added) {
146                         packageAutoRevokedPermsList[packageUser]?.remove(packagePermGroup.second)
147                         if (packageAutoRevokedPermsList[packageUser]?.isEmpty() == true) {
148                             packageAutoRevokedPermsList.remove(packageUser)
149                         }
150                     }
151 
152                     if (permStateLiveDatas.all { it.value.isInitialized }) {
153                         postCopyOfMap()
154                     }
155                 }
156             }
157         }
158     }
159 
160     private fun postCopyOfMap() {
161         val autoRevokedCopy =
162             mutableMapOf<Pair<String, UserHandle>, Set<String>>()
163         for ((userPackage, permGroups) in packageAutoRevokedPermsList) {
164             autoRevokedCopy[userPackage] = permGroups.toSet()
165         }
166         postValue(autoRevokedCopy)
167     }
168 }
169 
170 /**
171  * Gets all Auto Revoked packages that have not been opened in a few months. This will let us remove
172  * used apps from the Auto Revoke screen.
173  */
174 object UnusedAutoRevokedPackagesLiveData
175     : SmartUpdateMediatorLiveData<Map<Pair<String, UserHandle>, Set<String>>>() {
176     private val unusedThreshold = getUnusedThresholdMs(PermissionControllerApplication.get())
177     private val usageStatsLiveData = UsageStatsLiveData[unusedThreshold]
178 
179     init {
<lambda>null180         addSource(usageStatsLiveData) {
181             updateIfActive()
182         }
<lambda>null183         addSource(AutoRevokedPackagesLiveData) {
184             updateIfActive()
185         }
186     }
187 
onUpdatenull188     override fun onUpdate() {
189         if (!usageStatsLiveData.isInitialized || !AutoRevokedPackagesLiveData.isInitialized) {
190             return
191         }
192 
193         val autoRevokedPackages = AutoRevokedPackagesLiveData.value!!
194 
195         val unusedPackages = mutableMapOf<Pair<String, UserHandle>, Set<String>>()
196         for ((userPackage, perms) in autoRevokedPackages) {
197             unusedPackages[userPackage] = perms.toSet()
198         }
199 
200         val now = System.currentTimeMillis()
201         for ((user, stats) in usageStatsLiveData.value!!) {
202             for (stat in stats) {
203                 val userPackage = stat.packageName to user
204                 if (userPackage in autoRevokedPackages &&
205                     (now - stat.lastTimeVisible) < unusedThreshold) {
206                     unusedPackages.remove(userPackage)
207                 }
208             }
209         }
210 
211         value = unusedPackages
212     }
213 }