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 update() 53 } 54 } 55 } 56 57 addSource(packagesLiveData) { 58 if (permGroupLiveDatas.all { it.value.isInitialized }) { 59 update() 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