1 /* <lambda>null2 * Copyright (C) 2020 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.AppOpsManager 20 import android.app.AppOpsManager.OPSTR_AUTO_REVOKE_PERMISSIONS_IF_UNUSED 21 import android.app.Application 22 import android.content.pm.PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT 23 import android.content.pm.PackageManager.FLAG_PERMISSION_GRANTED_BY_ROLE 24 import android.os.UserHandle 25 import com.android.permissioncontroller.PermissionControllerApplication 26 import com.android.permissioncontroller.permission.data.PackagePermissionsLiveData.Companion.NON_RUNTIME_NORMAL_PERMS 27 import com.android.permissioncontroller.permission.model.livedatatypes.AutoRevokeState 28 import com.android.permissioncontroller.permission.service.ExemptServicesLiveData 29 import com.android.permissioncontroller.permission.service.isAutoRevokeEnabled 30 import com.android.permissioncontroller.permission.service.isPackageAutoRevokeExempt 31 import com.android.permissioncontroller.permission.service.isPackageAutoRevokePermanentlyExempt 32 import kotlinx.coroutines.Job 33 34 /** 35 * A LiveData which tracks the AutoRevoke state for one user package. 36 * 37 * @param app The current application 38 * @param packageName The package name whose state we want 39 * @param user The user for whom we want the package 40 */ 41 class AutoRevokeStateLiveData private constructor( 42 private val app: Application, 43 private val packageName: String, 44 private val user: UserHandle 45 ) : SmartAsyncMediatorLiveData<AutoRevokeState>(), AppOpsManager.OnOpChangedListener { 46 47 private val packagePermsLiveData = 48 PackagePermissionsLiveData[packageName, user] 49 private val packageLiveData = LightPackageInfoLiveData[packageName, user] 50 private val permStateLiveDatas = mutableMapOf<String, PermStateLiveData>() 51 private val exemptServicesLiveData = ExemptServicesLiveData[user] 52 private val appOpsManager = app.getSystemService(AppOpsManager::class.java)!! 53 54 init { 55 addSource(packagePermsLiveData) { 56 updateIfActive() 57 } 58 addSource(packageLiveData) { 59 updateIfActive() 60 } 61 addSource(exemptServicesLiveData) { 62 updateIfActive() 63 } 64 } 65 66 override suspend fun loadDataAndPostValue(job: Job) { 67 if (!packageLiveData.isInitialized || !packagePermsLiveData.isInitialized || 68 !exemptServicesLiveData.isInitialized) { 69 return 70 } 71 72 val groups = packagePermsLiveData.value?.keys?.filter { it != NON_RUNTIME_NORMAL_PERMS } 73 74 if (packageLiveData.value?.uid == null || groups == null) { 75 postValue(null) 76 return 77 } 78 79 val getLiveData = { groupName: String -> PermStateLiveData[packageName, groupName, user] } 80 setSourcesToDifference(groups, permStateLiveDatas, getLiveData) 81 82 if (!permStateLiveDatas.all { it.value.isInitialized }) { 83 return 84 } 85 86 val revocable = !isPackageAutoRevokeExempt(app, packageLiveData.value!!) 87 val revocableGroups = mutableListOf<String>() 88 if (!isPackageAutoRevokePermanentlyExempt(packageLiveData.value!!, user)) { 89 permStateLiveDatas.forEach { (groupName, liveData) -> 90 val default = liveData.value?.any { (_, permState) -> 91 permState.permFlags and (FLAG_PERMISSION_GRANTED_BY_DEFAULT or 92 FLAG_PERMISSION_GRANTED_BY_ROLE) != 0 93 } ?: false 94 if (!default) { 95 revocableGroups.add(groupName) 96 } 97 } 98 } 99 100 postValue(AutoRevokeState(isAutoRevokeEnabled(app), revocable, revocableGroups)) 101 } 102 103 override fun onOpChanged(op: String?, packageName: String?) { 104 if (op == OPSTR_AUTO_REVOKE_PERMISSIONS_IF_UNUSED && packageName == packageName) { 105 updateIfActive() 106 } 107 } 108 109 override fun onActive() { 110 super.onActive() 111 appOpsManager.startWatchingMode(OPSTR_AUTO_REVOKE_PERMISSIONS_IF_UNUSED, packageName, this) 112 updateIfActive() 113 } 114 115 override fun onInactive() { 116 super.onInactive() 117 appOpsManager.stopWatchingMode(this) 118 } 119 /** 120 * Repository for AutoRevokeStateLiveDatas. 121 * <p> Key value is a pair of string package name and UserHandle, value is its corresponding 122 * LiveData. 123 */ 124 companion object : DataRepositoryForPackage<Pair<String, UserHandle>, 125 AutoRevokeStateLiveData>() { 126 override fun newValue(key: Pair<String, UserHandle>): AutoRevokeStateLiveData { 127 return AutoRevokeStateLiveData(PermissionControllerApplication.get(), 128 key.first, key.second) 129 } 130 } 131 } 132