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 whitelist for the exceptions to battery saving features. 38 */ 39 public class PowerWhitelistBackend { 40 41 private static final String TAG = "PowerWhitelistBackend"; 42 43 private static final String DEVICE_IDLE_SERVICE = "deviceidle"; 44 45 private static PowerWhitelistBackend sInstance; 46 47 private final Context mAppContext; 48 private final IDeviceIdleController mDeviceIdleService; 49 private final ArraySet<String> mWhitelistedApps = new ArraySet<>(); 50 private final ArraySet<String> mSysWhitelistedApps = new ArraySet<>(); 51 private final ArraySet<String> mSysWhitelistedAppsExceptIdle = new ArraySet<>(); 52 private final ArraySet<String> mDefaultActiveApps = new ArraySet<>(); 53 PowerWhitelistBackend(Context context)54 public PowerWhitelistBackend(Context context) { 55 this(context, IDeviceIdleController.Stub.asInterface( 56 ServiceManager.getService(DEVICE_IDLE_SERVICE))); 57 } 58 59 @VisibleForTesting PowerWhitelistBackend(Context context, IDeviceIdleController deviceIdleService)60 PowerWhitelistBackend(Context context, IDeviceIdleController deviceIdleService) { 61 mAppContext = context.getApplicationContext(); 62 mDeviceIdleService = deviceIdleService; 63 refreshList(); 64 } 65 getWhitelistSize()66 public int getWhitelistSize() { 67 return mWhitelistedApps.size(); 68 } 69 isSysWhitelisted(String pkg)70 public boolean isSysWhitelisted(String pkg) { 71 return mSysWhitelistedApps.contains(pkg); 72 } 73 isWhitelisted(String pkg)74 public boolean isWhitelisted(String pkg) { 75 if (mWhitelistedApps.contains(pkg)) { 76 return true; 77 } 78 79 if (isDefaultActiveApp(pkg)) { 80 return true; 81 } 82 83 return false; 84 } 85 86 /** 87 * Check if it is default active app in multiple area(i.e. SMS, Dialer, Device admin..) 88 */ isDefaultActiveApp(String pkg)89 public boolean isDefaultActiveApp(String pkg) { 90 // Additionally, check if pkg is default dialer/sms. They are considered essential apps and 91 // should be automatically whitelisted (otherwise user may be able to set restriction on 92 // them, leading to bad device behavior.) 93 94 if (mDefaultActiveApps.contains(pkg)) { 95 return true; 96 } 97 98 final DevicePolicyManager devicePolicyManager = mAppContext.getSystemService( 99 DevicePolicyManager.class); 100 if (devicePolicyManager.packageHasActiveAdmins(pkg)) { 101 return true; 102 } 103 104 return false; 105 } 106 isWhitelisted(String[] pkgs)107 public boolean isWhitelisted(String[] pkgs) { 108 if (ArrayUtils.isEmpty(pkgs)) { 109 return false; 110 } 111 for (String pkg : pkgs) { 112 if (isWhitelisted(pkg)) { 113 return true; 114 } 115 } 116 117 return false; 118 } 119 isSysWhitelistedExceptIdle(String pkg)120 public boolean isSysWhitelistedExceptIdle(String pkg) { 121 return mSysWhitelistedAppsExceptIdle.contains(pkg); 122 } 123 isSysWhitelistedExceptIdle(String[] pkgs)124 public boolean isSysWhitelistedExceptIdle(String[] pkgs) { 125 if (ArrayUtils.isEmpty(pkgs)) { 126 return false; 127 } 128 for (String pkg : pkgs) { 129 if (isSysWhitelistedExceptIdle(pkg)) { 130 return true; 131 } 132 } 133 134 return false; 135 } 136 addApp(String pkg)137 public void addApp(String pkg) { 138 try { 139 mDeviceIdleService.addPowerSaveWhitelistApp(pkg); 140 mWhitelistedApps.add(pkg); 141 } catch (RemoteException e) { 142 Log.w(TAG, "Unable to reach IDeviceIdleController", e); 143 } 144 } 145 removeApp(String pkg)146 public void removeApp(String pkg) { 147 try { 148 mDeviceIdleService.removePowerSaveWhitelistApp(pkg); 149 mWhitelistedApps.remove(pkg); 150 } catch (RemoteException e) { 151 Log.w(TAG, "Unable to reach IDeviceIdleController", e); 152 } 153 } 154 155 @VisibleForTesting refreshList()156 public void refreshList() { 157 mSysWhitelistedApps.clear(); 158 mSysWhitelistedAppsExceptIdle.clear(); 159 mWhitelistedApps.clear(); 160 mDefaultActiveApps.clear(); 161 if (mDeviceIdleService == null) { 162 return; 163 } 164 try { 165 final String[] whitelistedApps = mDeviceIdleService.getFullPowerWhitelist(); 166 for (String app : whitelistedApps) { 167 mWhitelistedApps.add(app); 168 } 169 final String[] sysWhitelistedApps = mDeviceIdleService.getSystemPowerWhitelist(); 170 for (String app : sysWhitelistedApps) { 171 mSysWhitelistedApps.add(app); 172 } 173 final String[] sysWhitelistedAppsExceptIdle = 174 mDeviceIdleService.getSystemPowerWhitelistExceptIdle(); 175 for (String app : sysWhitelistedAppsExceptIdle) { 176 mSysWhitelistedAppsExceptIdle.add(app); 177 } 178 final boolean hasTelephony = mAppContext.getPackageManager().hasSystemFeature( 179 PackageManager.FEATURE_TELEPHONY); 180 final ComponentName defaultSms = SmsApplication.getDefaultSmsApplication(mAppContext, 181 true /* updateIfNeeded */); 182 final String defaultDialer = DefaultDialerManager.getDefaultDialerApplication( 183 mAppContext); 184 185 if (hasTelephony) { 186 if (defaultSms != null) { 187 mDefaultActiveApps.add(defaultSms.getPackageName()); 188 } 189 if (!TextUtils.isEmpty(defaultDialer)) { 190 mDefaultActiveApps.add(defaultDialer); 191 } 192 } 193 } catch (RemoteException e) { 194 Log.w(TAG, "Unable to reach IDeviceIdleController", e); 195 } 196 } 197 getInstance(Context context)198 public static PowerWhitelistBackend getInstance(Context context) { 199 if (sInstance == null) { 200 sInstance = new PowerWhitelistBackend(context); 201 } 202 return sInstance; 203 } 204 205 } 206