• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.pm.PackageManager
22 import android.os.UserHandle
23 import android.os.UserManager
24 import android.util.Log
25 import androidx.annotation.MainThread
26 import androidx.lifecycle.Observer
27 import com.android.modules.utils.build.SdkLevel
28 import com.android.permissioncontroller.PermissionControllerApplication
29 import com.android.permissioncontroller.permission.model.livedatatypes.LightPackageInfo
30 import com.android.permissioncontroller.permission.utils.Utils
31 import kotlinx.coroutines.Job
32 
33 /**
34  * LiveData for a LightPackageInfo.
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 user The user for whom the packageInfo will be defined
39  */
40 class LightPackageInfoLiveData private constructor(
41     private val app: Application,
42     private val packageName: String,
43     private val user: UserHandle
44 ) : SmartAsyncMediatorLiveData<LightPackageInfo?>(alwaysUpdateOnActive = false),
45     PackageBroadcastReceiver.PackageBroadcastListener,
46     PermissionListenerMultiplexer.PermissionChangeCallback {
47 
48     private val LOG_TAG = LightPackageInfoLiveData::class.java.simpleName
49     private val userPackagesLiveData = UserPackageInfosLiveData[user]
50 
51     private var uid: Int? = null
52     /**
53      * The currently registered UID on which this LiveData is listening for permission changes.
54      */
55     private var registeredUid: Int? = null
56     /**
57      * Whether or not this package livedata is watching the UserPackageInfosLiveData
58      */
59     private var watchingUserPackagesLiveData: Boolean = false
60 
61     /**
62      * Callback from the PackageBroadcastReceiver. Either deletes or generates package data.
63      *
64      * @param packageName the name of the package which was updated. Ignored in this method
65      */
66     override fun onPackageUpdate(packageName: String) {
67         updateAsync()
68     }
69 
70     override fun setValue(newValue: LightPackageInfo?) {
71         newValue?.let { packageInfo ->
72             if (packageInfo.uid != uid) {
73                 uid = packageInfo.uid
74 
75                 if (hasActiveObservers()) {
76                     PermissionListenerMultiplexer.addOrReplaceCallback(registeredUid,
77                             packageInfo.uid, this)
78                     registeredUid = uid
79                 }
80             }
81         }
82         super.setValue(newValue)
83     }
84 
85     override fun updateAsync() {
86         // If we were watching the userPackageInfosLiveData, stop, since we will override its value
87         if (watchingUserPackagesLiveData) {
88             removeSource(userPackagesLiveData)
89             watchingUserPackagesLiveData = false
90         }
91         super.updateAsync()
92     }
93 
94     override suspend fun loadDataAndPostValue(job: Job) {
95         if (job.isCancelled) {
96             return
97         }
98         postValue(try {
99             var flags = PackageManager.GET_PERMISSIONS
100             if (SdkLevel.isAtLeastS()) {
101                 flags = flags or PackageManager.GET_ATTRIBUTIONS
102             }
103 
104             LightPackageInfo(Utils.getUserContext(app, user).packageManager
105                 .getPackageInfo(packageName, flags))
106         } catch (e: Exception) {
107             if (e is PackageManager.NameNotFoundException) {
108                 Log.w(LOG_TAG, "Package \"$packageName\" not found for user $user")
109             } else {
110                 val profiles = app.getSystemService(UserManager::class.java)!!.userProfiles
111                 Log.e(LOG_TAG, "Failed to create context for user $user. " +
112                         "User exists : ${user in profiles }", e)
113             }
114             invalidateSingle(packageName to user)
115             null
116         })
117     }
118 
119     /**
120      * Callback from the PermissionListener. Either deletes or generates package data.
121      */
122     override fun onPermissionChange() {
123         updateAsync()
124     }
125 
126     override fun onActive() {
127         super.onActive()
128 
129         PackageBroadcastReceiver.addChangeCallback(packageName, this)
130         uid?.let {
131             registeredUid = uid
132             PermissionListenerMultiplexer.addCallback(it, this)
133         }
134         if (userPackagesLiveData.hasActiveObservers() && !watchingUserPackagesLiveData &&
135             !userPackagesLiveData.permChangeStale) {
136             watchingUserPackagesLiveData = true
137             addSource(userPackagesLiveData, userPackageInfosObserver)
138         } else {
139             updateAsync()
140         }
141     }
142 
143     private val userPackageInfosObserver = Observer<List<LightPackageInfo>> {
144         updateFromUserPackageInfosLiveData()
145     }
146 
147     @MainThread
148     private fun updateFromUserPackageInfosLiveData() {
149         if (!userPackagesLiveData.isInitialized) {
150             return
151         }
152 
153         val packageInfo = userPackagesLiveData.value!!.find { it.packageName == packageName }
154         if (packageInfo != null) {
155             // Once we get one non-stale update, stop listening, as any further updates will likely
156             // be individual package updates.
157             if (!userPackagesLiveData.isStale) {
158                 removeSource(UserPackageInfosLiveData[user])
159                 watchingUserPackagesLiveData = false
160             }
161 
162             value = packageInfo
163         } else {
164             // If the UserPackageInfosLiveData does not contain this package, check for removal, and
165             // stop watching.
166             updateAsync()
167         }
168     }
169 
170     override fun onInactive() {
171         super.onInactive()
172 
173         PackageBroadcastReceiver.removeChangeCallback(packageName, this)
174         registeredUid?.let {
175             PermissionListenerMultiplexer.removeCallback(it, this)
176             registeredUid = null
177         }
178         if (watchingUserPackagesLiveData) {
179             removeSource(userPackagesLiveData)
180             watchingUserPackagesLiveData = false
181         }
182     }
183 
184     /**
185      * Repository for LightPackageInfoLiveDatas
186      * <p> Key value is a string package name and UserHandle pair, value is its corresponding
187      * LiveData.
188      */
189     companion object : DataRepositoryForPackage<Pair<String, UserHandle>,
190         LightPackageInfoLiveData>() {
191         override fun newValue(key: Pair<String, UserHandle>): LightPackageInfoLiveData {
192             return LightPackageInfoLiveData(PermissionControllerApplication.get(),
193                 key.first, key.second)
194         }
195     }
196 }
197