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.PackageInfo
20 import android.content.pm.PackageManager.FLAG_PERMISSION_AUTO_REVOKED
21 import android.os.Build
22 import android.os.UserHandle
23 import android.util.Log
24 import com.android.permissioncontroller.permission.utils.KotlinUtils
25 import com.android.permissioncontroller.permission.utils.PermissionMapping
26 import kotlinx.coroutines.Dispatchers.Main
27 import kotlinx.coroutines.GlobalScope
28 import kotlinx.coroutines.Job
29 import kotlinx.coroutines.launch
30 
31 /**
32  * Tracks which packages have been auto-revoked, and which groups have been auto revoked for those
33  * packages.
34  *
35  * ```(packageName, user) -> [groupName]```
36  */
37 object AutoRevokedPackagesLiveData :
38     SmartAsyncMediatorLiveData<Map<Pair<String, UserHandle>, Set<String>>>() {
39 
40     private val LOG_TAG = AutoRevokedPackagesLiveData::class.java.simpleName
41 
42     init {
43         addSource(AllPackageInfosLiveData) { update() }
44     }
45 
46     private val permStateLiveDatas =
47         mutableMapOf<Triple<String, String, UserHandle>, PermStateLiveData>()
48     private val packageAutoRevokedPermsList =
49         mutableMapOf<Pair<String, UserHandle>, MutableSet<String>>()
50 
51     override suspend fun loadDataAndPostValue(job: Job) {
52         if (!AllPackageInfosLiveData.isInitialized) {
53             return
54         }
55 
56         val allPackageGroups = mutableSetOf<Triple<String, String, UserHandle>>()
57         for ((user, packageList) in AllPackageInfosLiveData.value ?: emptyMap()) {
58             for (pkg in packageList) {
59                 if (job.isCancelled) {
60                     return
61                 }
62 
63                 val pkgGroups = mutableSetOf<Triple<String, String, UserHandle>>()
64                 for ((idx, requestedPerm) in pkg.requestedPermissions.withIndex()) {
65                     val group =
66                         PermissionMapping.getGroupOfPlatformPermission(requestedPerm) ?: continue
67                     val granted =
68                         (pkg.requestedPermissionsFlags[idx] and
69                             PackageInfo.REQUESTED_PERMISSION_GRANTED) != 0
70                     if (pkg.targetSdkVersion < Build.VERSION_CODES.M || !granted) {
71                         pkgGroups.add(Triple(pkg.packageName, group, user))
72                     }
73                 }
74                 allPackageGroups.addAll(pkgGroups)
75             }
76         }
77 
78         if (allPackageGroups.isEmpty()) {
79             postCopyOfMap()
80         } else {
81             observePermStateLiveDatas(allPackageGroups)
82         }
83     }
84 
85     private fun observePermStateLiveDatas(packageGroups: Set<Triple<String, String, UserHandle>>) {
86         GlobalScope.launch(Main.immediate) {
87             val (toAdd, toRemove) =
88                 KotlinUtils.getMapAndListDifferences(packageGroups, permStateLiveDatas)
89 
90             for (packagePermGroup in toRemove) {
91                 removeSource(permStateLiveDatas.remove(packagePermGroup) ?: continue)
92                 val packageUser = packagePermGroup.first to packagePermGroup.third
93                 packageAutoRevokedPermsList[packageUser]?.remove(packagePermGroup.second)
94                 if (packageAutoRevokedPermsList[packageUser]?.isEmpty() == true) {
95                     packageAutoRevokedPermsList.remove(packageUser)
96                 }
97             }
98 
99             if (toRemove.isNotEmpty()) {
100                 postCopyOfMap()
101             }
102 
103             for (packagePermGroup in toAdd) {
104                 permStateLiveDatas[packagePermGroup] = PermStateLiveData[packagePermGroup]
105             }
106 
107             for (packagePermGroup in toAdd) {
108                 val permStateLiveData = permStateLiveDatas[packagePermGroup]!!
109                 val packageUser = packagePermGroup.first to packagePermGroup.third
110 
111                 addSource(permStateLiveData) { permState ->
112                     var added = false
113                     if (permState == null && permStateLiveData.isInitialized) {
114                         permStateLiveDatas.remove(packagePermGroup)
115                         removeSource(permStateLiveData)
116                     } else if (permState != null) {
117                         for ((_, state) in permState) {
118                             if (state.permFlags and FLAG_PERMISSION_AUTO_REVOKED != 0) {
119                                 packageAutoRevokedPermsList
120                                     .getOrPut(packageUser) { mutableSetOf() }
121                                     .add(packagePermGroup.second)
122                                 added = true
123                                 break
124                             }
125                         }
126                     }
127 
128                     if (!added) {
129                         packageAutoRevokedPermsList[packageUser]?.remove(packagePermGroup.second)
130                         if (packageAutoRevokedPermsList[packageUser]?.isEmpty() == true) {
131                             packageAutoRevokedPermsList.remove(packageUser)
132                         }
133                     }
134 
135                     if (permStateLiveDatas.all { it.value.isInitialized }) {
136                         postCopyOfMap()
137                     }
138                 }
139             }
140         }
141     }
142 
143     private fun postCopyOfMap() {
144         val autoRevokedCopy = mutableMapOf<Pair<String, UserHandle>, Set<String>>()
145         for ((userPackage, permGroups) in packageAutoRevokedPermsList) {
146             autoRevokedCopy[userPackage] = permGroups.toSet()
147         }
148         Log.i(LOG_TAG, "postValue: $autoRevokedCopy")
149         postValue(autoRevokedCopy)
150     }
151 }
152 
153 private val autoRevokedPackagesSetLiveData =
154     object : SmartUpdateMediatorLiveData<Set<Pair<String, UserHandle>>>() {
155         init {
<lambda>null156             addSource(AutoRevokedPackagesLiveData) { update() }
157         }
158 
onUpdatenull159         override fun onUpdate() {
160             if (!AutoRevokedPackagesLiveData.isInitialized) {
161                 return
162             }
163             value = AutoRevokedPackagesLiveData.value!!.keys
164         }
165     }
166 
167 val unusedAutoRevokePackagesLiveData = UnusedPackagesLiveData(autoRevokedPackagesSetLiveData)
168