1 /*
<lambda>null2  * Copyright (C) 2019 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.Manifest
20 import android.app.Application
21 import android.os.Build
22 import android.os.UserHandle
23 import androidx.lifecycle.LiveData
24 import com.android.permissioncontroller.PermissionControllerApplication
25 import com.android.permissioncontroller.permission.model.livedatatypes.PermGroup
26 import com.android.permissioncontroller.permission.utils.Utils.OS_PKG
27 
28 /**
29  * A LiveData which tracks either all platform permission groups, or all custom permission groups,
30  * and the packages which contain runtime permissions in one of those group.
31  *
32  * @param app The current application
33  */
34 class PermGroupsPackagesLiveData private constructor(
35     private val app: Application,
36     groupNamesLiveData: LiveData<List<String>>
37 ) : SmartUpdateMediatorLiveData<Map<String, Set<Pair<String, UserHandle>>>>() {
38 
39     private val packagesLiveData = AllPackageInfosLiveData
40     private val permGroupLiveDatas = mutableMapOf<String, PermGroupLiveData>()
41 
42     private var groupNames = emptyList<String>()
43 
44     init {
45         addSource(groupNamesLiveData) {
46             groupNames = it ?: emptyList()
47 
48             val getLiveData = { groupName: String -> PermGroupLiveData[groupName] }
49             setSourcesToDifference(groupNames, permGroupLiveDatas, getLiveData) {
50                 if (packagesLiveData.isInitialized &&
51                     permGroupLiveDatas.all { it.value.isInitialized }) {
52                     updateIfActive()
53                 }
54             }
55         }
56 
57         addSource(packagesLiveData) {
58             if (permGroupLiveDatas.all { it.value.isInitialized }) {
59                 updateIfActive()
60             }
61         }
62     }
63 
64     /**
65      * Using the current list of permission groups, go through all packages in the system,
66      * and figure out which permission groups they have permissions for. If applicable, remove
67      * any lone-permission permission that are not requested by any packages.
68      */
69     override fun onUpdate() {
70         if (groupNames.isEmpty()) {
71             return
72         }
73 
74         val groupApps = mutableMapOf<String, MutableSet<Pair<String, UserHandle>>>()
75         val permGroups = mutableListOf<PermGroup>()
76         for (groupName in groupNames) {
77             val permGroup = permGroupLiveDatas[groupName]?.value
78             if (permGroup == null || !permGroup.hasRuntimePermissions) {
79                 continue
80             }
81             permGroups.add(permGroup)
82             groupApps[groupName] = mutableSetOf()
83         }
84 
85         val allPackages = packagesLiveData.value ?: return
86         for ((userHandle, packageInfos) in allPackages) {
87             for (packageInfo in packageInfos) {
88                 val isPreMApp = packageInfo.targetSdkVersion < Build.VERSION_CODES.M
89 
90                 for ((groupInfo, permissionInfos) in permGroups) {
91                     // Do not allow toggling non-platform permission groups for legacy apps via app
92                     // ops.
93                     if (isPreMApp && groupInfo.packageName != OS_PKG) {
94                         continue
95                     }
96                     // Categorize all requested permissions of this package
97                     for (permissionName in packageInfo.requestedPermissions) {
98                         if (permissionInfos.containsKey(permissionName)) {
99                             groupApps[groupInfo.name]?.add(packageInfo.packageName to userHandle)
100                         }
101                     }
102                 }
103             }
104         }
105 
106         /*
107          * Remove any lone permission groups that are not used by any package, and the UNDEFINED
108          * group, if also empty.
109          */
110         for (permGroup in permGroups) {
111             if (permGroup.groupInfo.isSinglePermGroup ||
112                 permGroup.name == Manifest.permission_group.UNDEFINED) {
113                 val groupPackages = groupApps[permGroup.name] ?: continue
114                 if (groupPackages.isEmpty()) {
115                     groupApps.remove(permGroup.name)
116                 }
117             }
118         }
119 
120         value = groupApps
121     }
122 
123     companion object {
124         private val customInstance = PermGroupsPackagesLiveData(
125             PermissionControllerApplication.get(), CustomPermGroupNamesLiveData)
126         private val standardInstance = PermGroupsPackagesLiveData(
127             PermissionControllerApplication.get(), StandardPermGroupNamesLiveData)
128 
129         /**
130          * Get either the PermGroupsPackageLiveData instance corresponding either to the custom
131          * permission groups, or the standard permission group.
132          *
133          * @param customGroups Whether to get the custom groups instance, or the standard
134          *
135          * @return The specified PermGroupsPackageLiveData
136          */
137         @JvmStatic
138         fun get(customGroups: Boolean = false): PermGroupsPackagesLiveData {
139             return if (customGroups) {
140                 customInstance
141             } else {
142                 standardInstance
143             }
144         }
145     }
146 }
147