1 /* 2 * Copyright (C) 2022 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.settings.applications; 18 19 import android.annotation.IntDef; 20 import android.app.AppOpsManager; 21 import android.content.Context; 22 import android.os.Build; 23 import android.util.Log; 24 25 import com.android.internal.annotations.VisibleForTesting; 26 import com.android.settingslib.applications.ApplicationsState; 27 import com.android.settingslib.applications.ApplicationsState.AppEntry; 28 import com.android.settingslib.applications.ApplicationsState.AppFilter; 29 import com.android.settingslib.fuelgauge.PowerAllowlistBackend; 30 31 import java.lang.annotation.Retention; 32 import java.lang.annotation.RetentionPolicy; 33 34 /** 35 * Class for bridging the app battery usage information to ApplicationState. 36 */ 37 public class AppStateAppBatteryUsageBridge extends AppStateBaseBridge { 38 private static final String TAG = AppStateAppBatteryUsageBridge.class.getSimpleName(); 39 static final boolean DEBUG = Build.IS_DEBUGGABLE; 40 41 @VisibleForTesting 42 Context mContext; 43 @VisibleForTesting 44 AppOpsManager mAppOpsManager; 45 @VisibleForTesting 46 PowerAllowlistBackend mPowerAllowlistBackend; 47 48 @VisibleForTesting 49 static final int MODE_UNKNOWN = 0; 50 @VisibleForTesting 51 static final int MODE_UNRESTRICTED = 1; 52 @VisibleForTesting 53 static final int MODE_OPTIMIZED = 2; 54 @VisibleForTesting 55 static final int MODE_RESTRICTED = 3; 56 57 @IntDef( 58 prefix = {"MODE_"}, 59 value = { 60 MODE_UNKNOWN, 61 MODE_RESTRICTED, 62 MODE_UNRESTRICTED, 63 MODE_OPTIMIZED, 64 }) 65 @Retention(RetentionPolicy.SOURCE) 66 @interface OptimizationMode { 67 } 68 AppStateAppBatteryUsageBridge( Context context, ApplicationsState appState, Callback callback)69 public AppStateAppBatteryUsageBridge( 70 Context context, ApplicationsState appState, Callback callback) { 71 super(appState, callback); 72 mContext = context; 73 mAppOpsManager = context.getSystemService(AppOpsManager.class); 74 mPowerAllowlistBackend = PowerAllowlistBackend.getInstance(mContext); 75 } 76 77 @Override updateExtraInfo(AppEntry app, String pkg, int uid)78 protected void updateExtraInfo(AppEntry app, String pkg, int uid) { 79 app.extraInfo = getAppBatteryUsageState(pkg, uid); 80 } 81 82 @Override loadAllExtraInfo()83 protected void loadAllExtraInfo() { 84 if (DEBUG) { 85 Log.d(TAG, "Start loadAllExtraInfo()"); 86 } 87 mAppSession.getAllApps().stream().forEach(appEntry -> 88 updateExtraInfo(appEntry, appEntry.info.packageName, appEntry.info.uid)); 89 if (DEBUG) { 90 Log.d(TAG, "End loadAllExtraInfo()"); 91 } 92 } 93 getAppBatteryUsageState(String pkg, int uid)94 protected Object getAppBatteryUsageState(String pkg, int uid) { 95 // Restricted = AppOpsManager.MODE_IGNORED + !allowListed 96 // Unrestricted = AppOpsManager.MODE_ALLOWED + allowListed 97 // Optimized = AppOpsManager.MODE_ALLOWED + !allowListed 98 99 boolean allowListed = mPowerAllowlistBackend.isAllowlisted(pkg, uid); 100 int aomMode = 101 mAppOpsManager.checkOpNoThrow(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, uid, pkg); 102 @OptimizationMode int mode = MODE_UNKNOWN; 103 String modeName = ""; 104 if (aomMode == AppOpsManager.MODE_IGNORED && !allowListed) { 105 mode = MODE_RESTRICTED; 106 if (DEBUG) { 107 modeName = "RESTRICTED"; 108 } 109 } else if (aomMode == AppOpsManager.MODE_ALLOWED) { 110 mode = allowListed ? MODE_UNRESTRICTED : MODE_OPTIMIZED; 111 if (DEBUG) { 112 modeName = allowListed ? "UNRESTRICTED" : "OPTIMIZED"; 113 } 114 } 115 if (DEBUG) { 116 Log.d(TAG, "Pkg: " + pkg + ", mode: " + modeName); 117 } 118 return new AppBatteryUsageDetails(mode); 119 } 120 121 @VisibleForTesting 122 @OptimizationMode getAppBatteryUsageDetailsMode(AppEntry entry)123 static int getAppBatteryUsageDetailsMode(AppEntry entry) { 124 if (entry == null || entry.extraInfo == null) { 125 return MODE_UNKNOWN; 126 } 127 128 return entry.extraInfo instanceof AppBatteryUsageDetails 129 ? ((AppBatteryUsageDetails) entry.extraInfo).mMode 130 : MODE_UNKNOWN; 131 } 132 133 /** 134 * Used by {@link com.android.settings.applications.manageapplications.AppFilterRegistry} to 135 * determine which apps are unrestricted. 136 */ 137 public static final AppFilter FILTER_BATTERY_UNRESTRICTED_APPS = 138 new AppFilter() { 139 @Override 140 public void init() {} 141 142 @Override 143 public boolean filterApp(AppEntry info) { 144 return getAppBatteryUsageDetailsMode(info) == MODE_UNRESTRICTED; 145 } 146 }; 147 148 /** 149 * Used by {@link com.android.settings.applications.manageapplications.AppFilterRegistry} to 150 * determine which apps are optimized. 151 */ 152 public static final AppFilter FILTER_BATTERY_OPTIMIZED_APPS = 153 new AppFilter() { 154 @Override 155 public void init() {} 156 157 @Override 158 public boolean filterApp(AppEntry info) { 159 return getAppBatteryUsageDetailsMode(info) == MODE_OPTIMIZED; 160 } 161 }; 162 163 /** 164 * Used by {@link com.android.settings.applications.manageapplications.AppFilterRegistry} to 165 * determine which apps are restricted. 166 */ 167 public static final AppFilter FILTER_BATTERY_RESTRICTED_APPS = 168 new AppFilter() { 169 @Override 170 public void init() {} 171 172 @Override 173 public boolean filterApp(AppEntry info) { 174 return getAppBatteryUsageDetailsMode(info) == MODE_RESTRICTED; 175 } 176 }; 177 178 /** 179 * Extra details for app battery usage data. 180 */ 181 static final class AppBatteryUsageDetails { 182 @OptimizationMode 183 int mMode; 184 AppBatteryUsageDetails(@ptimizationMode int mode)185 AppBatteryUsageDetails(@OptimizationMode int mode) { 186 mMode = mode; 187 } 188 } 189 } 190