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