• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * 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.hibernation.v31
18 
19 import android.app.usage.UsageStatsManager
20 import android.apphibernation.AppHibernationManager
21 import android.content.Context
22 import android.content.Context.APP_HIBERNATION_SERVICE
23 import android.content.Context.USAGE_STATS_SERVICE
24 import android.os.Build
25 import android.os.UserHandle
26 import androidx.annotation.RequiresApi
27 import com.android.permissioncontroller.DumpableLog
28 import com.android.permissioncontroller.permission.model.livedatatypes.LightPackageInfo
29 
30 /**
31  * Hibernation controller that handles modifying hibernation state.
32  */
33 @RequiresApi(Build.VERSION_CODES.S)
34 class HibernationController(
35     private val context: Context,
36     private val unusedThreshold: Long,
37     private val targetsPreS: Boolean
38 ) {
39 
40     companion object {
41         private const val LOG_TAG = "HibernationController"
42         private const val DEBUG_HIBERNATION = true
43     }
44 
45     /**
46      * Hibernates the apps provided for each user.
47      *
48      * @param apps map of each user to a list of packages that should be hibernated for the user
49      * @return list of apps that were successfully hibernated
50      */
hibernateAppsnull51     fun hibernateApps(
52         apps: Map<UserHandle, List<LightPackageInfo>>
53     ): Set<Pair<String, UserHandle>> {
54         val hibernatedApps = mutableSetOf<Pair<String, UserHandle>>()
55         for ((user, userApps) in apps) {
56             val userContext = context.createContextAsUser(user, 0 /* flags */)
57             val hibernationManager =
58                 userContext.getSystemService(APP_HIBERNATION_SERVICE) as AppHibernationManager
59             for (pkg in userApps) {
60                 try {
61                     if (hibernationManager.isHibernatingForUser(pkg.packageName)) {
62                         continue
63                     }
64                     if (!targetsPreS &&
65                         pkg.targetSdkVersion < Build.VERSION_CODES.S) {
66                         // Only apps targeting S or above can be truly hibernated.
67                         continue
68                     }
69                     hibernationManager.setHibernatingForUser(pkg.packageName, true)
70                     hibernatedApps.add(pkg.packageName to user)
71                 } catch (e: Exception) {
72                     DumpableLog.e(LOG_TAG, "Failed to hibernate package: ${pkg.packageName}", e)
73                 }
74             }
75         }
76 
77         // Globally hibernate any of the hibernated apps that are unused by any user
78         val usageStatsManager = context.getSystemService(USAGE_STATS_SERVICE) as UsageStatsManager
79         val hibernationManager =
80             context.getSystemService(APP_HIBERNATION_SERVICE) as AppHibernationManager
81         val globallyHibernatedApps = mutableSetOf<String>()
82         for ((pkgName, _) in hibernatedApps) {
83             if (globallyHibernatedApps.contains(pkgName) ||
84                 hibernationManager.isHibernatingGlobally(pkgName)) {
85                 continue
86             }
87 
88             val now = System.currentTimeMillis()
89             val lastUsedGlobally = usageStatsManager.getLastTimeAnyComponentUsed(pkgName)
90             if (now - lastUsedGlobally < unusedThreshold) {
91                 continue
92             }
93 
94             hibernationManager.setHibernatingGlobally(pkgName, true)
95             globallyHibernatedApps.add(pkgName)
96         }
97         if (DEBUG_HIBERNATION) {
98             DumpableLog.i(LOG_TAG,
99                 "Done hibernating apps $hibernatedApps \n " +
100                 "Globally hibernating apps $globallyHibernatedApps")
101         }
102 
103         return hibernatedApps
104     }
105 }
106