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