• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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