1 /*
2  * 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.Utils
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) {
44             update()
45         }
46     }
47 
48     private val permStateLiveDatas =
49         mutableMapOf<Triple<String, String, UserHandle>, PermStateLiveData>()
50     private val packageAutoRevokedPermsList =
51         mutableMapOf<Pair<String, UserHandle>, MutableSet<String>>()
52 
53     override suspend fun loadDataAndPostValue(job: Job) {
54         if (!AllPackageInfosLiveData.isInitialized) {
55             return
56         }
57 
58         val allPackageGroups = mutableSetOf<Triple<String, String, UserHandle>>()
59         for ((user, packageList) in AllPackageInfosLiveData.value ?: emptyMap()) {
60             for (pkg in packageList) {
61                 if (job.isCancelled) {
62                     return
63                 }
64 
65                 val pkgGroups = mutableSetOf<Triple<String, String, UserHandle>>()
66                 for ((idx, requestedPerm) in pkg.requestedPermissions.withIndex()) {
67                     val group = Utils.getGroupOfPlatformPermission(requestedPerm) ?: continue
68                     val granted = (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 
88             val (toAdd, toRemove) =
89                 KotlinUtils.getMapAndListDifferences(packageGroups, permStateLiveDatas)
90 
91             for (packagePermGroup in toRemove) {
92                 removeSource(permStateLiveDatas.remove(packagePermGroup) ?: continue)
93                 val packageUser = packagePermGroup.first to packagePermGroup.third
94                 packageAutoRevokedPermsList[packageUser]?.remove(packagePermGroup.second)
95                 if (packageAutoRevokedPermsList[packageUser]?.isEmpty() == true) {
96                     packageAutoRevokedPermsList.remove(packageUser)
97                 }
98             }
99 
100             if (toRemove.isNotEmpty()) {
101                 postCopyOfMap()
102             }
103 
104             for (packagePermGroup in toAdd) {
105                 permStateLiveDatas[packagePermGroup] = PermStateLiveData[packagePermGroup]
106             }
107 
108             for (packagePermGroup in toAdd) {
109                 val permStateLiveData = permStateLiveDatas[packagePermGroup]!!
110                 val packageUser = packagePermGroup.first to packagePermGroup.third
111 
112                 addSource(permStateLiveData) { permState ->
113                     var added = false
114                     if (permState == null && permStateLiveData.isInitialized) {
115                         permStateLiveDatas.remove(packagePermGroup)
116                         removeSource(permStateLiveData)
117                     } else if (permState != null) {
118                         for ((_, state) in permState) {
119                             if (state.permFlags and FLAG_PERMISSION_AUTO_REVOKED != 0) {
120                                 packageAutoRevokedPermsList.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 =
145             mutableMapOf<Pair<String, UserHandle>, Set<String>>()
146         for ((userPackage, permGroups) in packageAutoRevokedPermsList) {
147             autoRevokedCopy[userPackage] = permGroups.toSet()
148         }
149         Log.i(LOG_TAG, "postValue: $autoRevokedCopy")
150         postValue(autoRevokedCopy)
151     }
152 }
153 
154 private val autoRevokedPackagesSetLiveData =
155     object : SmartUpdateMediatorLiveData<Set<Pair<String, UserHandle>>>() {
156         init {
157             addSource(AutoRevokedPackagesLiveData) {
158                 update()
159             }
160         }
161 
162         override fun onUpdate() {
163             if (!AutoRevokedPackagesLiveData.isInitialized) {
164                 return
165             }
166             value = AutoRevokedPackagesLiveData.value!!.keys
167         }
168     }
169 
170 val unusedAutoRevokePackagesLiveData = UnusedPackagesLiveData(autoRevokedPackagesSetLiveData)