• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2017 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.settingslib.fuelgauge;
18 
19 import android.app.admin.DevicePolicyManager;
20 import android.content.ComponentName;
21 import android.content.Context;
22 import android.content.pm.PackageManager;
23 import android.os.IDeviceIdleController;
24 import android.os.RemoteException;
25 import android.os.ServiceManager;
26 import android.telecom.DefaultDialerManager;
27 import android.text.TextUtils;
28 import android.util.ArraySet;
29 import android.util.Log;
30 
31 import androidx.annotation.VisibleForTesting;
32 
33 import com.android.internal.telephony.SmsApplication;
34 import com.android.internal.util.ArrayUtils;
35 
36 /**
37  * Handles getting/changing the allowlist for the exceptions to battery saving features.
38  */
39 public class PowerAllowlistBackend {
40 
41     private static final String TAG = "PowerAllowlistBackend";
42 
43     private static final String DEVICE_IDLE_SERVICE = "deviceidle";
44 
45     private static PowerAllowlistBackend sInstance;
46 
47     private final Context mAppContext;
48     private final IDeviceIdleController mDeviceIdleService;
49     private final ArraySet<String> mAllowlistedApps = new ArraySet<>();
50     private final ArraySet<String> mSysAllowlistedApps = new ArraySet<>();
51     private final ArraySet<String> mDefaultActiveApps = new ArraySet<>();
52 
PowerAllowlistBackend(Context context)53     public PowerAllowlistBackend(Context context) {
54         this(context, IDeviceIdleController.Stub.asInterface(
55                 ServiceManager.getService(DEVICE_IDLE_SERVICE)));
56     }
57 
58     @VisibleForTesting
PowerAllowlistBackend(Context context, IDeviceIdleController deviceIdleService)59     PowerAllowlistBackend(Context context, IDeviceIdleController deviceIdleService) {
60         mAppContext = context.getApplicationContext();
61         mDeviceIdleService = deviceIdleService;
62         refreshList();
63     }
64 
getAllowlistSize()65     public int getAllowlistSize() {
66         return mAllowlistedApps.size();
67     }
68 
69     /**
70     * Check if target package is in System allow list
71     */
isSysAllowlisted(String pkg)72     public boolean isSysAllowlisted(String pkg) {
73         return mSysAllowlistedApps.contains(pkg);
74     }
75 
76     /**
77      * Check if target package is in allow list
78      */
isAllowlisted(String pkg)79     public boolean isAllowlisted(String pkg) {
80         if (mAllowlistedApps.contains(pkg)) {
81             return true;
82         }
83 
84         if (isDefaultActiveApp(pkg)) {
85             return true;
86         }
87 
88         return false;
89     }
90 
91     /**
92      * Check if it is default active app in multiple area(i.e. SMS, Dialer, Device admin..)
93      */
isDefaultActiveApp(String pkg)94     public boolean isDefaultActiveApp(String pkg) {
95         // Additionally, check if pkg is default dialer/sms. They are considered essential apps and
96         // should be automatically allowlisted (otherwise user may be able to set restriction on
97         // them, leading to bad device behavior.)
98 
99         if (mDefaultActiveApps.contains(pkg)) {
100             return true;
101         }
102 
103         final DevicePolicyManager devicePolicyManager = mAppContext.getSystemService(
104                 DevicePolicyManager.class);
105         if (devicePolicyManager.packageHasActiveAdmins(pkg)) {
106             return true;
107         }
108 
109         return false;
110     }
111 
112     /**
113      *
114      * @param pkgs a list of packageName
115      * @return true when one of package is in allow list
116      */
isAllowlisted(String[] pkgs)117     public boolean isAllowlisted(String[] pkgs) {
118         if (ArrayUtils.isEmpty(pkgs)) {
119             return false;
120         }
121         for (String pkg : pkgs) {
122             if (isAllowlisted(pkg)) {
123                 return true;
124             }
125         }
126 
127         return false;
128     }
129 
130     /**
131      * Add app into power save allow list.
132      * @param pkg packageName
133      */
addApp(String pkg)134     public void addApp(String pkg) {
135         try {
136             mDeviceIdleService.addPowerSaveWhitelistApp(pkg);
137             mAllowlistedApps.add(pkg);
138         } catch (RemoteException e) {
139             Log.w(TAG, "Unable to reach IDeviceIdleController", e);
140         }
141     }
142 
143     /**
144      * Remove package from power save allow list.
145      * @param pkg
146      */
removeApp(String pkg)147     public void removeApp(String pkg) {
148         try {
149             mDeviceIdleService.removePowerSaveWhitelistApp(pkg);
150             mAllowlistedApps.remove(pkg);
151         } catch (RemoteException e) {
152             Log.w(TAG, "Unable to reach IDeviceIdleController", e);
153         }
154     }
155 
156     /**
157      * Refresh all of lists
158      */
159     @VisibleForTesting
refreshList()160     public void refreshList() {
161         mSysAllowlistedApps.clear();
162         mAllowlistedApps.clear();
163         mDefaultActiveApps.clear();
164         if (mDeviceIdleService == null) {
165             return;
166         }
167         try {
168             final String[] allowlistedApps = mDeviceIdleService.getFullPowerWhitelist();
169             for (String app : allowlistedApps) {
170                 mAllowlistedApps.add(app);
171             }
172             final String[] sysAllowlistedApps = mDeviceIdleService.getSystemPowerWhitelist();
173             for (String app : sysAllowlistedApps) {
174                 mSysAllowlistedApps.add(app);
175             }
176             final boolean hasTelephony = mAppContext.getPackageManager().hasSystemFeature(
177                     PackageManager.FEATURE_TELEPHONY);
178             final ComponentName defaultSms = SmsApplication.getDefaultSmsApplication(mAppContext,
179                     true /* updateIfNeeded */);
180             final String defaultDialer = DefaultDialerManager.getDefaultDialerApplication(
181                     mAppContext);
182 
183             if (hasTelephony) {
184                 if (defaultSms != null) {
185                     mDefaultActiveApps.add(defaultSms.getPackageName());
186                 }
187                 if (!TextUtils.isEmpty(defaultDialer)) {
188                     mDefaultActiveApps.add(defaultDialer);
189                 }
190             }
191         } catch (RemoteException e) {
192             Log.w(TAG, "Unable to reach IDeviceIdleController", e);
193         }
194     }
195 
196     /**
197      * @param context
198      * @return a PowerAllowlistBackend object
199      */
getInstance(Context context)200     public static PowerAllowlistBackend getInstance(Context context) {
201         if (sInstance == null) {
202             sInstance = new PowerAllowlistBackend(context);
203         }
204         return sInstance;
205     }
206 
207 }
208