1 /*
<lambda>null2  * Copyright (C) 2019 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.Application
20 import android.content.pm.PackageInfo
21 import android.content.pm.PackageManager
22 import android.os.UserHandle
23 import com.android.permissioncontroller.PermissionControllerApplication
24 import com.android.permissioncontroller.permission.model.livedatatypes.LightPackageInfo
25 import com.android.permissioncontroller.permission.model.livedatatypes.PermState
26 import com.android.permissioncontroller.permission.utils.ContextCompat
27 import com.android.permissioncontroller.permission.utils.KotlinUtils
28 import com.android.permissioncontroller.permission.utils.Utils
29 import kotlinx.coroutines.Job
30 
31 /**
32  * A LiveData which tracks the permission state for one permission group for one package. It
33  * includes both the granted state of every permission in the group, and the flags stored in the
34  * PermissionController service.
35  *
36  * @param app The current application
37  * @param packageName The name of the package this LiveData will watch for mode changes for
38  * @param permGroupName The name of the permission group whose app ops this LiveData will watch
39  * @param user The user of the package
40  */
41 class PermStateLiveData
42 private constructor(
43     private val app: Application,
44     private val packageName: String,
45     private val permGroupName: String,
46     private val user: UserHandle,
47     private val deviceId: Int
48 ) :
49     SmartAsyncMediatorLiveData<Map<String, PermState>>(),
50     PermissionListenerMultiplexer.PermissionChangeCallback {
51 
52     private val context =
53         Utils.getUserContext(app, user).let {
54             if (deviceId == ContextCompat.DEVICE_ID_DEFAULT) {
55                 it
56             } else ContextCompat.createDeviceContext(it, deviceId)
57         }
58     private val packageInfoLiveData = LightPackageInfoLiveData[packageName, user, deviceId]
59     private val groupLiveData = PermGroupLiveData[permGroupName]
60 
61     private var uid: Int? = null
62     private var registeredUid: Int? = null
63 
64     init {
65         addSource(packageInfoLiveData) {
66             checkForUidUpdate(it)
67             updateAsync()
68         }
69 
70         addSource(groupLiveData) { updateAsync() }
71     }
72 
73     /**
74      * Gets the system flags from the package manager, and the grant state from those flags, plus
75      * the RequestedPermissionFlags of the PermState.
76      */
77     override suspend fun loadDataAndPostValue(job: Job) {
78         if (!packageInfoLiveData.isInitialized || !groupLiveData.isInitialized) {
79             return
80         }
81 
82         val packageInfo = packageInfoLiveData.value
83         val permissionGroup = groupLiveData.value
84         if (packageInfo == null || permissionGroup == null) {
85             invalidateSingle(KotlinUtils.Quadruple(packageName, permGroupName, user, deviceId))
86             postValue(null)
87             return
88         }
89         val permissionStates = mutableMapOf<String, PermState>()
90         for ((index, permissionName) in packageInfo.requestedPermissions.withIndex()) {
91             permissionGroup.permissionInfos[permissionName]?.let { permInfo ->
92                 val packageFlags = packageInfo.requestedPermissionsFlags[index]
93                 val permFlags =
94                     context.packageManager.getPermissionFlags(permInfo.name, packageName, user)
95                 val granted =
96                     packageFlags and PackageInfo.REQUESTED_PERMISSION_GRANTED != 0 &&
97                         permFlags and PackageManager.FLAG_PERMISSION_REVOKED_COMPAT == 0
98 
99                 if (job.isCancelled) {
100                     return
101                 }
102                 permissionStates[permissionName] = PermState(permFlags, granted)
103             }
104         }
105 
106         postValue(permissionStates)
107     }
108 
109     override fun onPermissionChange() {
110         updateAsync()
111     }
112 
113     private fun checkForUidUpdate(packageInfo: LightPackageInfo?) {
114         if (packageInfo == null) {
115             registeredUid?.let { PermissionListenerMultiplexer.removeCallback(it, this) }
116             return
117         }
118         uid = packageInfo.uid
119         if (uid != registeredUid && hasActiveObservers()) {
120             PermissionListenerMultiplexer.addOrReplaceCallback(registeredUid, packageInfo.uid, this)
121             registeredUid = uid
122         }
123     }
124 
125     override fun onInactive() {
126         super.onInactive()
127         registeredUid?.let {
128             PermissionListenerMultiplexer.removeCallback(it, this)
129             registeredUid = null
130         }
131     }
132 
133     override fun onActive() {
134         super.onActive()
135         uid?.let {
136             PermissionListenerMultiplexer.addCallback(it, this)
137             registeredUid = uid
138         }
139     }
140 
141     /**
142      * Repository for PermStateLiveDatas.
143      *
144      * <p> Key value is a triple of string package name, string permission group name, and
145      * UserHandle, value is its corresponding LiveData.
146      */
147     companion object :
148         DataRepositoryForDevice<
149             KotlinUtils.Quadruple<String, String, UserHandle, Int>, PermStateLiveData
150         >() {
151         override fun newValue(
152             key: KotlinUtils.Quadruple<String, String, UserHandle, Int>,
153             deviceId: Int
154         ): PermStateLiveData {
155             return PermStateLiveData(
156                 PermissionControllerApplication.get(),
157                 key.first,
158                 key.second,
159                 key.third,
160                 deviceId
161             )
162         }
163     }
164 }
165