Home | History | Annotate | Download | only in fuelgauge
      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