• 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.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