• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
<lambda>null2  * Copyright (C) 2021 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.os.UserHandle
20 import android.provider.DeviceConfig
21 import android.provider.DeviceConfig.NAMESPACE_PERMISSIONS
22 import android.util.ArraySet
23 import android.util.Log
24 import com.android.permissioncontroller.PermissionControllerApplication
25 import com.android.permissioncontroller.hibernation.getUnusedThresholdMs
26 import com.android.permissioncontroller.hibernation.isHibernationEnabled
27 import com.android.permissioncontroller.hibernation.lastTimePackageUsed
28 import com.android.permissioncontroller.permission.utils.Utils
29 
30 /**
31  * Gets all unused packages from an existing live data that have not been opened in a few months
32  * and the permission groups that have been revoked for them, if any. This will let us removed used
33  * apps from the Unused Apps screen.
34  *
35  * @param sourceLiveData the live data for packages to base this list of unused apps on
36  * ```(packageName, user) -> [groupName]```
37  */
38 class UnusedPackagesLiveData(
39     private val sourceLiveData: SmartUpdateMediatorLiveData<Set<Pair<String, UserHandle>>>
40 ) : SmartUpdateMediatorLiveData<Map<Pair<String, UserHandle>, Set<String>>>() {
41 
42     private val LOG_TAG = UnusedPackagesLiveData::class.java.simpleName
43 
44     private var unusedThreshold = getUnusedThresholdMs()
45     private var usageStatsLiveData = UsageStatsLiveData[unusedThreshold]
46 
47     init {
48         addSource(usageStatsLiveData) {
49             update()
50         }
51         addSource(AutoRevokedPackagesLiveData) {
52             update()
53         }
54         addSource(sourceLiveData) {
55             update()
56         }
57         DeviceConfig.addOnPropertiesChangedListener(
58             NAMESPACE_PERMISSIONS,
59             PermissionControllerApplication.get().mainExecutor,
60             { properties ->
61                 for (key in properties.keyset) {
62                     if (key == Utils.PROPERTY_HIBERNATION_UNUSED_THRESHOLD_MILLIS) {
63                         removeSource(usageStatsLiveData)
64                         unusedThreshold = getUnusedThresholdMs()
65                         usageStatsLiveData = UsageStatsLiveData[unusedThreshold]
66                         addSource(usageStatsLiveData) {
67                             update()
68                         }
69                     }
70                 }
71             }
72         )
73     }
74 
75     override fun onUpdate() {
76         if (!usageStatsLiveData.isInitialized ||
77             !AutoRevokedPackagesLiveData.isInitialized ||
78             !sourceLiveData.isInitialized) {
79             return
80         }
81 
82         val sourcePackages = sourceLiveData.value!!
83         val autoRevokedPackages = AutoRevokedPackagesLiveData.value!!
84 
85         val unusedPackages = mutableMapOf<Pair<String, UserHandle>, Set<String>>()
86         for (userPackage in sourcePackages) {
87             val perms = autoRevokedPackages[userPackage] ?: ArraySet()
88             unusedPackages[userPackage] = perms.toSet()
89         }
90 
91         val now = System.currentTimeMillis()
92         for ((user, stats) in usageStatsLiveData.value!!) {
93             for (stat in stats) {
94                 val userPackage = stat.packageName to user
95                 if (userPackage in autoRevokedPackages &&
96                     (now - stat.lastTimePackageUsed()) < unusedThreshold) {
97                     unusedPackages.remove(userPackage)
98                 }
99             }
100         }
101 
102         Log.i(LOG_TAG, "onUpdate() -> $unusedPackages")
103 
104         value = unusedPackages
105     }
106 }
107 
getUnusedPackagesnull108 fun getUnusedPackages(): UnusedPackagesLiveData {
109     return if (isHibernationEnabled()) {
110         unusedHibernatedOrRevokedPackagesLiveData
111     } else {
112         unusedAutoRevokePackagesLiveData
113     }
114 }