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