• 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.Handler
25 import android.os.UserHandle
26 import android.permission.PermissionControllerManager.HIBERNATION_ELIGIBILITY_ELIGIBLE
27 import android.permission.PermissionControllerManager.HIBERNATION_ELIGIBILITY_EXEMPT_BY_SYSTEM
28 import android.permission.PermissionControllerManager.HIBERNATION_ELIGIBILITY_EXEMPT_BY_USER
29 import android.util.Log
30 import com.android.permissioncontroller.PermissionControllerApplication
31 import com.android.permissioncontroller.hibernation.ExemptServicesLiveData
32 import com.android.permissioncontroller.hibernation.HibernationEnabledLiveData
33 import com.android.permissioncontroller.hibernation.isPackageHibernationExemptBySystem
34 import com.android.permissioncontroller.hibernation.isPackageHibernationExemptByUser
35 import com.android.permissioncontroller.permission.data.PackagePermissionsLiveData.Companion.NON_RUNTIME_NORMAL_PERMS
36 import com.android.permissioncontroller.permission.model.livedatatypes.HibernationSettingState
37 import kotlinx.coroutines.Job
38 
39 /**
40  * A LiveData which tracks the hibernation/auto-revoke state for one user package.
41  *
42  * @param app The current application
43  * @param packageName The package name whose state we want
44  * @param user The user for whom we want the package
45  */
46 class HibernationSettingStateLiveData private constructor(
47     private val app: Application,
48     private val packageName: String,
49     private val user: UserHandle
50 ) : SmartAsyncMediatorLiveData<HibernationSettingState>(), AppOpsManager.OnOpChangedListener {
51 
52     private val packagePermsLiveData =
53         PackagePermissionsLiveData[packageName, user]
54     private val packageLiveData = LightPackageInfoLiveData[packageName, user]
55     private val permStateLiveDatas = mutableMapOf<String, PermStateLiveData>()
56     private val exemptServicesLiveData = ExemptServicesLiveData[user]
57     private val appOpsManager = app.getSystemService(AppOpsManager::class.java)!!
58 
59     // TODO 206455664: remove these once issue is identified
60     private val LOG_TAG = "HibernationSettingStateLiveData"
61     private val DELAY_MS = 3000L
62     private var gotPermLiveDatas: Boolean = false
63     private var gotPastIsUserExempt: Boolean = false
64     private var gotPastIsSystemExempt: Boolean = false
65 
66     init {
67         addSource(packagePermsLiveData) {
68             update()
69         }
70         addSource(packageLiveData) {
71             update()
72         }
73         addSource(exemptServicesLiveData) {
74             update()
75         }
76         addSource(HibernationEnabledLiveData) {
77             update()
78         }
79         Handler(app.mainLooper).postDelayed({
80             logState()
81         }, DELAY_MS)
82     }
83 
84     override suspend fun loadDataAndPostValue(job: Job) {
85         if (!packageLiveData.isInitialized || !packagePermsLiveData.isInitialized ||
86             !exemptServicesLiveData.isInitialized) {
87             return
88         }
89 
90         val groups = packagePermsLiveData.value?.keys?.filter { it != NON_RUNTIME_NORMAL_PERMS }
91         val packageInfo = packageLiveData.value
92         if (packageInfo == null || groups == null) {
93             postValue(null)
94             return
95         }
96         val getLiveData = { groupName: String -> PermStateLiveData[packageName, groupName, user] }
97         setSourcesToDifference(groups, permStateLiveDatas, getLiveData)
98         gotPermLiveDatas = true
99 
100         if (!permStateLiveDatas.all { it.value.isInitialized }) {
101             return
102         }
103 
104         val exemptBySystem = isPackageHibernationExemptBySystem(packageInfo, user)
105         val exemptByUser = isPackageHibernationExemptByUser(app, packageInfo)
106         val eligibility = when {
107             !exemptBySystem && !exemptByUser -> HIBERNATION_ELIGIBILITY_ELIGIBLE
108             exemptBySystem -> HIBERNATION_ELIGIBILITY_EXEMPT_BY_SYSTEM
109             else -> HIBERNATION_ELIGIBILITY_EXEMPT_BY_USER
110         }
111         gotPastIsUserExempt = true
112         val revocableGroups = mutableListOf<String>()
113         if (!isPackageHibernationExemptBySystem(packageInfo, user)) {
114             gotPastIsSystemExempt = true
115             permStateLiveDatas.forEach { (groupName, liveData) ->
116                 val default = liveData.value?.any { (_, permState) ->
117                     permState.permFlags and (FLAG_PERMISSION_GRANTED_BY_DEFAULT or
118                             FLAG_PERMISSION_GRANTED_BY_ROLE) != 0
119                 } ?: false
120                 if (!default) {
121                     revocableGroups.add(groupName)
122                 }
123             }
124         }
125         gotPastIsSystemExempt = true
126 
127         postValue(HibernationSettingState(eligibility, revocableGroups))
128     }
129 
130     override fun onOpChanged(op: String?, packageName: String?) {
131         if (op == OPSTR_AUTO_REVOKE_PERMISSIONS_IF_UNUSED && packageName == packageName) {
132             update()
133         }
134     }
135 
136     override fun onActive() {
137         super.onActive()
138         appOpsManager.startWatchingMode(OPSTR_AUTO_REVOKE_PERMISSIONS_IF_UNUSED, packageName, this)
139     }
140 
141     override fun onInactive() {
142         super.onInactive()
143         appOpsManager.stopWatchingMode(this)
144     }
145 
146     // TODO 206455664: remove these once issue is identified
147     private fun logState() {
148         if (!isStale) {
149             return
150         }
151         Log.i(LOG_TAG, "overall state: isStale:$isStale, isInitialized:$isInitialized, " +
152                 "value:$value, got perm LiveDatas:$gotPermLiveDatas, " +
153                 "got isUserExempt$gotPastIsUserExempt, got isSystemExempt$gotPastIsSystemExempt")
154         Log.i(LOG_TAG, "packagePermsLivedata isStale:${packagePermsLiveData.isStale}, " +
155                 "isInitialized:${packagePermsLiveData.isInitialized}")
156         Log.i(LOG_TAG, "ExemptServicesLiveData isStale:${exemptServicesLiveData.isStale}, " +
157                 "isInitialized:${exemptServicesLiveData.isInitialized}")
158         Log.i(LOG_TAG, "HibernationEnabledLivedata value:${HibernationEnabledLiveData.value}")
159         for ((group, liveData) in permStateLiveDatas) {
160             Log.i(LOG_TAG, "permStateLivedata $group isStale:${liveData.isStale}, " +
161                     "isInitialized:${liveData.isInitialized}")
162         }
163     }
164     /**
165      * Repository for HibernationSettingStateLiveDatas.
166      * <p> Key value is a pair of string package name and UserHandle, value is its corresponding
167      * LiveData.
168      */
169     companion object : DataRepositoryForPackage<Pair<String, UserHandle>,
170         HibernationSettingStateLiveData>() {
171         override fun newValue(key: Pair<String, UserHandle>): HibernationSettingStateLiveData {
172             return HibernationSettingStateLiveData(PermissionControllerApplication.get(),
173                 key.first, key.second)
174         }
175     }
176 }
177