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 @file:Suppress("DEPRECATION")
17 
18 package com.android.permissioncontroller.permission.data
19 
20 import android.app.Application
21 import android.content.Context
22 import android.content.pm.PackageInfo
23 import android.content.pm.PackageManager
24 import android.os.UserHandle
25 import android.os.UserManager
26 import android.util.Log
27 import androidx.annotation.MainThread
28 import androidx.lifecycle.Observer
29 import com.android.modules.utils.build.SdkLevel
30 import com.android.permissioncontroller.PermissionControllerApplication
31 import com.android.permissioncontroller.permission.model.livedatatypes.LightPackageInfo
32 import com.android.permissioncontroller.permission.utils.ContextCompat
33 import com.android.permissioncontroller.permission.utils.Utils
34 import com.android.permissioncontroller.permission.utils.v35.MultiDeviceUtils.isPermissionDeviceAware
35 import kotlinx.coroutines.Job
36 
37 /**
38  * LiveData for a LightPackageInfo.
39  *
40  * @param app The current Application
41  * @param packageName The name of the package this LiveData will watch for mode changes for
42  * @param user The user for whom the packageInfo will be defined
43  */
44 class LightPackageInfoLiveData
45 private constructor(
46     private val app: Application,
47     private val packageName: String,
48     private val user: UserHandle,
49     private val deviceId: Int
50 ) :
51     SmartAsyncMediatorLiveData<LightPackageInfo?>(alwaysUpdateOnActive = false),
52     PackageBroadcastReceiver.PackageBroadcastListener,
53     PermissionListenerMultiplexer.PermissionChangeCallback {
54 
55     private val LOG_TAG = LightPackageInfoLiveData::class.java.simpleName
56     private val userPackagesLiveData = UserPackageInfosLiveData[user]
57 
58     private var uid: Int? = null
59     /** The currently registered UID on which this LiveData is listening for permission changes. */
60     private var registeredUid: Int? = null
61     /** Whether or not this package livedata is watching the UserPackageInfosLiveData */
62     private var watchingUserPackagesLiveData: Boolean = false
63 
64     /**
65      * Callback from the PackageBroadcastReceiver. Either deletes or generates package data.
66      *
67      * @param packageName the name of the package which was updated. Ignored in this method
68      */
69     override fun onPackageUpdate(packageName: String) {
70         updateAsync()
71     }
72 
73     override fun setValue(newValue: LightPackageInfo?) {
74         newValue?.let { packageInfo ->
75             if (packageInfo.uid != uid) {
76                 uid = packageInfo.uid
77 
78                 if (hasActiveObservers()) {
79                     PermissionListenerMultiplexer.addOrReplaceCallback(
80                         registeredUid,
81                         packageInfo.uid,
82                         this
83                     )
84                     registeredUid = uid
85                 }
86             }
87         }
88         super.setValue(newValue)
89     }
90 
91     override fun updateAsync() {
92         // If we were watching the userPackageInfosLiveData, stop, since we will override its value
93         if (watchingUserPackagesLiveData) {
94             removeSource(userPackagesLiveData)
95             watchingUserPackagesLiveData = false
96         }
97         super.updateAsync()
98     }
99 
100     override suspend fun loadDataAndPostValue(job: Job) {
101         if (job.isCancelled) {
102             return
103         }
104         postValue(
105             try {
106                 var flags = PackageManager.GET_PERMISSIONS
107                 if (SdkLevel.isAtLeastS()) {
108                     flags = flags or PackageManager.GET_ATTRIBUTIONS
109                 }
110 
111                 val packageManager = Utils.getUserContext(app, user).packageManager
112                 val pI = packageManager.getPackageInfo(packageName, flags)
113 
114                 // PackageInfo#requestedPermissionsFlags is not device aware. Hence for device aware
115                 // permissions if the deviceId is not the primary device we need to separately check
116                 // permission for that device and update requestedPermissionsFlags.
117                 if (SdkLevel.isAtLeastV() && deviceId != ContextCompat.DEVICE_ID_DEFAULT) {
118                     val requestedPermissionsFlagsForDevice =
119                         getPermissionsFlagsForDevice(
120                             pI.requestedPermissions?.toList() ?: emptyList(),
121                             pI.requestedPermissionsFlags?.toList() ?: emptyList(),
122                             pI.applicationInfo!!.uid,
123                             deviceId
124                         )
125 
126                     LightPackageInfo(pI, deviceId, requestedPermissionsFlagsForDevice)
127                 } else {
128                     LightPackageInfo(pI)
129                 }
130             } catch (e: Exception) {
131                 if (e is PackageManager.NameNotFoundException) {
132                     Log.w(LOG_TAG, "Package \"$packageName\" not found for user $user")
133                 } else {
134                     val profiles = app.getSystemService(UserManager::class.java)!!.userProfiles
135                     Log.e(
136                         LOG_TAG,
137                         "Failed to create context for user $user. " +
138                             "User exists : ${user in profiles }",
139                         e
140                     )
141                 }
142                 invalidateSingle(Triple(packageName, user, deviceId))
143                 null
144             }
145         )
146     }
147 
148     /** Callback from the PermissionListener. Either deletes or generates package data. */
149     override fun onPermissionChange() {
150         updateAsync()
151     }
152 
153     override fun onActive() {
154         super.onActive()
155 
156         PackageBroadcastReceiver.addChangeCallback(packageName, this)
157         uid?.let {
158             registeredUid = uid
159             PermissionListenerMultiplexer.addCallback(it, this)
160         }
161         if (
162             userPackagesLiveData.hasActiveObservers() &&
163                 !watchingUserPackagesLiveData &&
164                 !userPackagesLiveData.permChangeStale
165         ) {
166             watchingUserPackagesLiveData = true
167             addSource(userPackagesLiveData, userPackageInfosObserver)
168         } else {
169             updateAsync()
170         }
171     }
172 
173     private val userPackageInfosObserver =
174         Observer<List<LightPackageInfo>> { updateFromUserPackageInfosLiveData() }
175 
176     @MainThread
177     private fun updateFromUserPackageInfosLiveData() {
178         if (!userPackagesLiveData.isInitialized) {
179             return
180         }
181 
182         val packageInfo = userPackagesLiveData.value!!.find { it.packageName == packageName }
183         if (packageInfo != null) {
184             // Once we get one non-stale update, stop listening, as any further updates will likely
185             // be individual package updates.
186             if (!userPackagesLiveData.isStale) {
187                 removeSource(UserPackageInfosLiveData[user])
188                 watchingUserPackagesLiveData = false
189             }
190 
191             if (SdkLevel.isAtLeastV() && deviceId != Context.DEVICE_ID_DEFAULT) {
192                 packageInfo.deviceId = deviceId
193                 packageInfo.requestedPermissionsFlags =
194                     getPermissionsFlagsForDevice(
195                         packageInfo.requestedPermissions,
196                         packageInfo.requestedPermissionsFlags,
197                         packageInfo.uid,
198                         deviceId
199                     )
200             }
201             value = packageInfo
202         } else {
203             // If the UserPackageInfosLiveData does not contain this package, check for removal, and
204             // stop watching.
205             updateAsync()
206         }
207     }
208 
209     override fun onInactive() {
210         super.onInactive()
211 
212         PackageBroadcastReceiver.removeChangeCallback(packageName, this)
213         registeredUid?.let {
214             PermissionListenerMultiplexer.removeCallback(it, this)
215             registeredUid = null
216         }
217         if (watchingUserPackagesLiveData) {
218             removeSource(userPackagesLiveData)
219             watchingUserPackagesLiveData = false
220         }
221     }
222 
223     // Given permission flags of the default device and an external device Id, return a new list of
224     // permission flags for that device by checking grant state of device aware permissions for the
225     // device.
226     private fun getPermissionsFlagsForDevice(
227         requestedPermissions: List<String>,
228         requestedPermissionsFlags: List<Int>,
229         uid: Int,
230         deviceId: Int
231     ): List<Int> {
232         val requestedPermissionsFlagsForDevice = requestedPermissionsFlags.toMutableList()
233         val deviceContext = ContextCompat.createDeviceContext(app, deviceId)
234 
235         for ((idx, permName) in requestedPermissions.withIndex()) {
236             if (isPermissionDeviceAware(deviceContext, deviceId, permName)) {
237                 val result = deviceContext.checkPermission(permName, -1, uid)
238 
239                 if (result == PackageManager.PERMISSION_GRANTED) {
240                     requestedPermissionsFlagsForDevice[idx] =
241                         requestedPermissionsFlagsForDevice[idx] or
242                             PackageInfo.REQUESTED_PERMISSION_GRANTED
243                 }
244 
245                 if (result == PackageManager.PERMISSION_DENIED) {
246                     requestedPermissionsFlagsForDevice[idx] =
247                         requestedPermissionsFlagsForDevice[idx] and
248                             PackageInfo.REQUESTED_PERMISSION_GRANTED.inv()
249                 }
250             }
251         }
252 
253         return requestedPermissionsFlagsForDevice
254     }
255 
256     /**
257      * Repository for LightPackageInfoLiveDatas
258      *
259      * <p> Key value is a triple of package name, UserHandle and virtual deviceId, value is its
260      * corresponding LiveData.
261      */
262     companion object :
263         DataRepositoryForDevice<Triple<String, UserHandle, Int>, LightPackageInfoLiveData>() {
264         override fun newValue(
265             key: Triple<String, UserHandle, Int>,
266             deviceId: Int
267         ): LightPackageInfoLiveData {
268             return LightPackageInfoLiveData(
269                 PermissionControllerApplication.get(),
270                 key.first,
271                 key.second,
272                 deviceId
273             )
274         }
275     }
276 }
277