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.app.Application 20 import android.content.pm.PackageInfo 21 import android.content.pm.PackageManager 22 import android.os.UserHandle 23 import com.android.permissioncontroller.PermissionControllerApplication 24 import com.android.permissioncontroller.permission.model.livedatatypes.LightPackageInfo 25 import com.android.permissioncontroller.permission.model.livedatatypes.PermState 26 import com.android.permissioncontroller.permission.utils.ContextCompat 27 import com.android.permissioncontroller.permission.utils.KotlinUtils 28 import com.android.permissioncontroller.permission.utils.Utils 29 import kotlinx.coroutines.Job 30 31 /** 32 * A LiveData which tracks the permission state for one permission group for one package. It 33 * includes both the granted state of every permission in the group, and the flags stored in the 34 * PermissionController service. 35 * 36 * @param app The current application 37 * @param packageName The name of the package this LiveData will watch for mode changes for 38 * @param permGroupName The name of the permission group whose app ops this LiveData will watch 39 * @param user The user of the package 40 */ 41 class PermStateLiveData 42 private constructor( 43 private val app: Application, 44 private val packageName: String, 45 private val permGroupName: String, 46 private val user: UserHandle, 47 private val deviceId: Int 48 ) : 49 SmartAsyncMediatorLiveData<Map<String, PermState>>(), 50 PermissionListenerMultiplexer.PermissionChangeCallback { 51 52 private val context = 53 Utils.getUserContext(app, user).let { 54 if (deviceId == ContextCompat.DEVICE_ID_DEFAULT) { 55 it 56 } else ContextCompat.createDeviceContext(it, deviceId) 57 } 58 private val packageInfoLiveData = LightPackageInfoLiveData[packageName, user, deviceId] 59 private val groupLiveData = PermGroupLiveData[permGroupName] 60 61 private var uid: Int? = null 62 private var registeredUid: Int? = null 63 64 init { 65 addSource(packageInfoLiveData) { 66 checkForUidUpdate(it) 67 updateAsync() 68 } 69 70 addSource(groupLiveData) { updateAsync() } 71 } 72 73 /** 74 * Gets the system flags from the package manager, and the grant state from those flags, plus 75 * the RequestedPermissionFlags of the PermState. 76 */ 77 override suspend fun loadDataAndPostValue(job: Job) { 78 if (!packageInfoLiveData.isInitialized || !groupLiveData.isInitialized) { 79 return 80 } 81 82 val packageInfo = packageInfoLiveData.value 83 val permissionGroup = groupLiveData.value 84 if (packageInfo == null || permissionGroup == null) { 85 invalidateSingle(KotlinUtils.Quadruple(packageName, permGroupName, user, deviceId)) 86 postValue(null) 87 return 88 } 89 val permissionStates = mutableMapOf<String, PermState>() 90 for ((index, permissionName) in packageInfo.requestedPermissions.withIndex()) { 91 permissionGroup.permissionInfos[permissionName]?.let { permInfo -> 92 val packageFlags = packageInfo.requestedPermissionsFlags[index] 93 val permFlags = 94 context.packageManager.getPermissionFlags(permInfo.name, packageName, user) 95 val granted = 96 packageFlags and PackageInfo.REQUESTED_PERMISSION_GRANTED != 0 && 97 permFlags and PackageManager.FLAG_PERMISSION_REVOKED_COMPAT == 0 98 99 if (job.isCancelled) { 100 return 101 } 102 permissionStates[permissionName] = PermState(permFlags, granted) 103 } 104 } 105 106 postValue(permissionStates) 107 } 108 109 override fun onPermissionChange() { 110 updateAsync() 111 } 112 113 private fun checkForUidUpdate(packageInfo: LightPackageInfo?) { 114 if (packageInfo == null) { 115 registeredUid?.let { PermissionListenerMultiplexer.removeCallback(it, this) } 116 return 117 } 118 uid = packageInfo.uid 119 if (uid != registeredUid && hasActiveObservers()) { 120 PermissionListenerMultiplexer.addOrReplaceCallback(registeredUid, packageInfo.uid, this) 121 registeredUid = uid 122 } 123 } 124 125 override fun onInactive() { 126 super.onInactive() 127 registeredUid?.let { 128 PermissionListenerMultiplexer.removeCallback(it, this) 129 registeredUid = null 130 } 131 } 132 133 override fun onActive() { 134 super.onActive() 135 uid?.let { 136 PermissionListenerMultiplexer.addCallback(it, this) 137 registeredUid = uid 138 } 139 } 140 141 /** 142 * Repository for PermStateLiveDatas. 143 * 144 * <p> Key value is a triple of string package name, string permission group name, and 145 * UserHandle, value is its corresponding LiveData. 146 */ 147 companion object : 148 DataRepositoryForDevice< 149 KotlinUtils.Quadruple<String, String, UserHandle, Int>, PermStateLiveData 150 >() { 151 override fun newValue( 152 key: KotlinUtils.Quadruple<String, String, UserHandle, Int>, 153 deviceId: Int 154 ): PermStateLiveData { 155 return PermStateLiveData( 156 PermissionControllerApplication.get(), 157 key.first, 158 key.second, 159 key.third, 160 deviceId 161 ) 162 } 163 } 164 } 165