/* * Copyright (C) 2019 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.permissioncontroller.permission.data import android.app.Application import android.content.pm.PackageManager import android.content.pm.PermissionInfo import android.os.Build import android.os.UserHandle import com.android.permissioncontroller.PermissionControllerApplication import com.android.permissioncontroller.permission.utils.PermissionMapping import kotlinx.coroutines.Job /** * LiveData with a map representing the runtime permissions a group requests and all of the * installed, non-runtime, normal protection permissions. Key is the group name or * NON_RUNTIME_NORMAL_PERMS, value is the requested runtime permissions in that group (or all * installed non-runtime normal protection permissions, for NON_RUNTME_NORMAL_PERMS). * * @param app The current Application * @param packageName The name of the package this LiveData will watch for mode changes for * @param user The user for whom the packageInfo will be defined */ class PackagePermissionsLiveData private constructor( private val app: Application, packageName: String, user: UserHandle ) : SmartAsyncMediatorLiveData>?>() { private val packageInfoLiveData = LightPackageInfoLiveData[packageName, user] init { addSource(packageInfoLiveData) { if (packageInfoLiveData.isInitialized && packageInfoLiveData.value == null) { invalidateSingle(packageName to user) value = null return@addSource } update() } } override suspend fun loadDataAndPostValue(job: Job) { val packageInfo = packageInfoLiveData.value ?: return val permissionMap = mutableMapOf>() for (permName in packageInfo.requestedPermissions) { var groupName = PermissionMapping.getGroupOfPlatformPermission(permName) if (groupName == null) { val permInfo = try { app.packageManager.getPermissionInfo(permName, 0) } catch (e: PackageManager.NameNotFoundException) { continue } if (permInfo.flags and PermissionInfo.FLAG_INSTALLED == 0 || permInfo.flags and PermissionInfo.FLAG_REMOVED != 0) { continue } if (packageInfo.isInstantApp && permInfo.protectionFlags and PermissionInfo.PROTECTION_FLAG_INSTANT == 0) { continue } if (packageInfo.targetSdkVersion < Build.VERSION_CODES.M && (permInfo.protectionFlags and PermissionInfo.PROTECTION_FLAG_RUNTIME_ONLY) != 0) { continue } // If this permission is a non-runtime, normal permission, add it to the // "non runtime" group if (permInfo.protection != PermissionInfo.PROTECTION_DANGEROUS) { if (permInfo.protection == PermissionInfo.PROTECTION_NORMAL) { val otherPermsList = permissionMap.getOrPut(NON_RUNTIME_NORMAL_PERMS) { mutableListOf() } otherPermsList.add(permInfo.name) } continue } groupName = PermissionMapping.getGroupOfPermission(permInfo) ?: permName } permissionMap.getOrPut(groupName) { mutableListOf() }.add(permName) } postValue(permissionMap) } /** * Repository for PackagePermissionsLiveData objects *

Key value is a string package name and userHandle, value is its corresponding LiveData. */ companion object : DataRepositoryForPackage, PackagePermissionsLiveData>() { override fun newValue(key: Pair): PackagePermissionsLiveData { return PackagePermissionsLiveData(PermissionControllerApplication.get(), key.first, key.second) } const val NON_RUNTIME_NORMAL_PERMS = "nonRuntimeNormalPerms" } }