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.server.am; 18 19 import static android.Manifest.permission.ACCESS_BACKGROUND_LOCATION; 20 import static android.app.ActivityManager.RESTRICTION_LEVEL_ADAPTIVE_BUCKET; 21 import static android.app.ActivityManager.RESTRICTION_LEVEL_BACKGROUND_RESTRICTED; 22 import static android.app.ActivityManager.RESTRICTION_LEVEL_RESTRICTED_BUCKET; 23 import static android.app.ActivityManager.RESTRICTION_LEVEL_UNKNOWN; 24 import static android.app.ActivityManager.isLowRamDeviceStatic; 25 import static android.app.usage.UsageStatsManager.REASON_MAIN_FORCED_BY_SYSTEM; 26 import static android.app.usage.UsageStatsManager.REASON_MAIN_USAGE; 27 import static android.app.usage.UsageStatsManager.REASON_SUB_FORCED_SYSTEM_FLAG_ABUSE; 28 import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_USER_INTERACTION; 29 import static android.content.pm.PackageManager.PERMISSION_GRANTED; 30 import static android.os.BatteryConsumer.POWER_COMPONENT_ANY; 31 import static android.os.BatteryConsumer.PROCESS_STATE_BACKGROUND; 32 import static android.os.BatteryConsumer.PROCESS_STATE_CACHED; 33 import static android.os.BatteryConsumer.PROCESS_STATE_COUNT; 34 import static android.os.BatteryConsumer.PROCESS_STATE_FOREGROUND; 35 import static android.os.BatteryConsumer.PROCESS_STATE_FOREGROUND_SERVICE; 36 import static android.os.BatteryConsumer.PROCESS_STATE_UNSPECIFIED; 37 import static android.os.PowerExemptionManager.REASON_DENIED; 38 import static android.util.TimeUtils.formatTime; 39 40 import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM; 41 import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME; 42 import static com.android.server.am.AppRestrictionController.DEVICE_CONFIG_SUBNAMESPACE_PREFIX; 43 44 import android.annotation.NonNull; 45 import android.annotation.Nullable; 46 import android.annotation.UserIdInt; 47 import android.app.ActivityManager.RestrictionLevel; 48 import android.content.Context; 49 import android.content.pm.ServiceInfo; 50 import android.content.res.Resources; 51 import android.content.res.TypedArray; 52 import android.os.AppBackgroundRestrictionsInfo; 53 import android.os.AppBatteryStatsProto; 54 import android.os.BatteryConsumer; 55 import android.os.BatteryConsumer.Dimensions; 56 import android.os.BatteryStatsInternal; 57 import android.os.BatteryUsageStats; 58 import android.os.BatteryUsageStatsQuery; 59 import android.os.PowerExemptionManager; 60 import android.os.PowerExemptionManager.ReasonCode; 61 import android.os.Process; 62 import android.os.SystemClock; 63 import android.os.UidBatteryConsumer; 64 import android.os.UserHandle; 65 import android.provider.DeviceConfig; 66 import android.util.ArraySet; 67 import android.util.Pair; 68 import android.util.Slog; 69 import android.util.SparseArray; 70 import android.util.SparseBooleanArray; 71 import android.util.SparseLongArray; 72 import android.util.TimeUtils; 73 import android.util.proto.ProtoOutputStream; 74 75 import com.android.internal.R; 76 import com.android.internal.annotations.GuardedBy; 77 import com.android.internal.annotations.VisibleForTesting; 78 import com.android.internal.util.ArrayUtils; 79 import com.android.internal.util.FrameworkStatsLog; 80 import com.android.server.am.AppBatteryTracker.AppBatteryPolicy; 81 import com.android.server.am.AppRestrictionController.TrackerType; 82 import com.android.server.am.AppRestrictionController.UidBatteryUsageProvider; 83 import com.android.server.pm.UserManagerInternal; 84 85 import java.io.IOException; 86 import java.io.PrintWriter; 87 import java.lang.reflect.Constructor; 88 import java.util.Arrays; 89 import java.util.List; 90 import java.util.concurrent.CountDownLatch; 91 92 /** 93 * The battery usage tracker for apps, currently we are focusing on background + FGS battery here. 94 */ 95 final class AppBatteryTracker extends BaseAppStateTracker<AppBatteryPolicy> 96 implements UidBatteryUsageProvider { 97 static final String TAG = TAG_WITH_CLASS_NAME ? "AppBatteryTracker" : TAG_AM; 98 99 static final boolean DEBUG_BACKGROUND_BATTERY_TRACKER = false; 100 101 static final boolean DEBUG_BACKGROUND_BATTERY_TRACKER_VERBOSE = 102 DEBUG_BACKGROUND_BATTERY_TRACKER | false; 103 104 // As we don't support realtime per-UID battery usage stats yet, we're polling the stats 105 // in a regular time basis. 106 private final long mBatteryUsageStatsPollingIntervalMs; 107 108 static final long BATTERY_USAGE_STATS_POLLING_INTERVAL_MS_LONG = 30 * ONE_MINUTE; // 30 mins 109 static final long BATTERY_USAGE_STATS_POLLING_INTERVAL_MS_DEBUG = 2_000L; // 2s 110 111 private final long mBatteryUsageStatsPollingMinIntervalMs; 112 113 /** 114 * The battery stats query is expensive, so we'd throttle the query. 115 */ 116 static final long BATTERY_USAGE_STATS_POLLING_MIN_INTERVAL_MS_LONG = 5 * ONE_MINUTE; // 5 mins 117 static final long BATTERY_USAGE_STATS_POLLING_MIN_INTERVAL_MS_DEBUG = 2_000L; // 2s 118 119 static final ImmutableBatteryUsage BATTERY_USAGE_NONE = new ImmutableBatteryUsage(); 120 121 private final Runnable mBgBatteryUsageStatsPolling = this::updateBatteryUsageStatsAndCheck; 122 private final Runnable mBgBatteryUsageStatsCheck = this::checkBatteryUsageStats; 123 124 /** 125 * This tracks the user ids which are or were active during the last polling window, 126 * the index is the user id, and the value is if it's still running or not by now. 127 */ 128 @GuardedBy("mLock") 129 private final SparseBooleanArray mActiveUserIdStates = new SparseBooleanArray(); 130 131 /** 132 * When was the last battery usage sampled. 133 */ 134 @GuardedBy("mLock") 135 private long mLastBatteryUsageSamplingTs; 136 137 /** 138 * Whether or not there is an ongoing battery stats update. 139 */ 140 @GuardedBy("mLock") 141 private boolean mBatteryUsageStatsUpdatePending; 142 143 /** 144 * The current known battery usage data for each UID, since the system boots or 145 * the last battery stats reset prior to that (whoever is earlier). 146 */ 147 @GuardedBy("mLock") 148 private final SparseArray<BatteryUsage> mUidBatteryUsage = new SparseArray<>(); 149 150 /** 151 * The battery usage for each UID, in the rolling window of the past. 152 */ 153 @GuardedBy("mLock") 154 private final SparseArray<ImmutableBatteryUsage> mUidBatteryUsageInWindow = new SparseArray<>(); 155 156 /** 157 * The uid battery usage stats data from our last query, it consists of the data since 158 * last battery stats reset. 159 */ 160 @GuardedBy("mLock") 161 private final SparseArray<ImmutableBatteryUsage> mLastUidBatteryUsage = new SparseArray<>(); 162 163 // No lock is needed. 164 private final SparseArray<BatteryUsage> mTmpUidBatteryUsage = new SparseArray<>(); 165 166 // No lock is needed. 167 private final SparseArray<ImmutableBatteryUsage> mTmpUidBatteryUsage2 = new SparseArray<>(); 168 169 // No lock is needed. 170 private final SparseArray<ImmutableBatteryUsage> mTmpUidBatteryUsageInWindow = 171 new SparseArray<>(); 172 173 // No lock is needed. 174 private final ArraySet<UserHandle> mTmpUserIds = new ArraySet<>(); 175 176 /** 177 * The start timestamp of the battery usage stats result from our last query. 178 */ 179 @GuardedBy("mLock") 180 private long mLastUidBatteryUsageStartTs; 181 182 /** 183 * elapseRealTime of last time the AppBatteryTracker is reported to statsd. 184 */ 185 @GuardedBy("mLock") 186 private long mLastReportTime = 0; 187 188 // For debug only. 189 private final SparseArray<ImmutableBatteryUsage> mDebugUidPercentages = new SparseArray<>(); 190 AppBatteryTracker(Context context, AppRestrictionController controller)191 AppBatteryTracker(Context context, AppRestrictionController controller) { 192 this(context, controller, null, null); 193 } 194 AppBatteryTracker(Context context, AppRestrictionController controller, Constructor<? extends Injector<AppBatteryPolicy>> injector, Object outerContext)195 AppBatteryTracker(Context context, AppRestrictionController controller, 196 Constructor<? extends Injector<AppBatteryPolicy>> injector, 197 Object outerContext) { 198 super(context, controller, injector, outerContext); 199 if (injector == null) { 200 mBatteryUsageStatsPollingIntervalMs = DEBUG_BACKGROUND_BATTERY_TRACKER 201 ? BATTERY_USAGE_STATS_POLLING_INTERVAL_MS_DEBUG 202 : BATTERY_USAGE_STATS_POLLING_INTERVAL_MS_LONG; 203 mBatteryUsageStatsPollingMinIntervalMs = DEBUG_BACKGROUND_BATTERY_TRACKER 204 ? BATTERY_USAGE_STATS_POLLING_MIN_INTERVAL_MS_DEBUG 205 : BATTERY_USAGE_STATS_POLLING_MIN_INTERVAL_MS_LONG; 206 } else { 207 mBatteryUsageStatsPollingIntervalMs = BATTERY_USAGE_STATS_POLLING_INTERVAL_MS_DEBUG; 208 mBatteryUsageStatsPollingMinIntervalMs = 209 BATTERY_USAGE_STATS_POLLING_MIN_INTERVAL_MS_DEBUG; 210 } 211 mInjector.setPolicy(new AppBatteryPolicy(mInjector, this)); 212 } 213 214 @Override getType()215 @TrackerType int getType() { 216 return AppRestrictionController.TRACKER_TYPE_BATTERY; 217 } 218 219 @Override onSystemReady()220 void onSystemReady() { 221 super.onSystemReady(); 222 final UserManagerInternal um = mInjector.getUserManagerInternal(); 223 final int[] userIds = um.getUserIds(); 224 for (int userId : userIds) { 225 if (um.isUserRunning(userId)) { 226 synchronized (mLock) { 227 mActiveUserIdStates.put(userId, true); 228 } 229 } 230 } 231 scheduleBatteryUsageStatsUpdateIfNecessary(mBatteryUsageStatsPollingIntervalMs); 232 } 233 scheduleBatteryUsageStatsUpdateIfNecessary(long delay)234 private void scheduleBatteryUsageStatsUpdateIfNecessary(long delay) { 235 if (mInjector.getPolicy().isEnabled()) { 236 synchronized (mLock) { 237 if (!mBgHandler.hasCallbacks(mBgBatteryUsageStatsPolling)) { 238 mBgHandler.postDelayed(mBgBatteryUsageStatsPolling, delay); 239 } 240 } 241 logAppBatteryTrackerIfNeeded(); 242 } 243 } 244 245 /** 246 * Log per-uid BatteryTrackerInfo to statsd every 24 hours (as the window specified in 247 * {@link AppBatteryPolicy#mBgCurrentDrainWindowMs}) 248 */ logAppBatteryTrackerIfNeeded()249 private void logAppBatteryTrackerIfNeeded() { 250 final long now = SystemClock.elapsedRealtime(); 251 synchronized (mLock) { 252 final AppBatteryPolicy bgPolicy = mInjector.getPolicy(); 253 if (now - mLastReportTime < bgPolicy.mBgCurrentDrainWindowMs) { 254 return; 255 } else { 256 mLastReportTime = now; 257 } 258 } 259 updateBatteryUsageStatsIfNecessary(mInjector.currentTimeMillis(), true); 260 synchronized (mLock) { 261 for (int i = 0, size = mUidBatteryUsageInWindow.size(); i < size; i++) { 262 final int uid = mUidBatteryUsageInWindow.keyAt(i); 263 if (!UserHandle.isCore(uid) && !UserHandle.isApp(uid)) { 264 continue; 265 } 266 if (BATTERY_USAGE_NONE.equals(mUidBatteryUsageInWindow.valueAt(i))) { 267 continue; 268 } 269 FrameworkStatsLog.write(FrameworkStatsLog.APP_BACKGROUND_RESTRICTIONS_INFO, 270 uid, 271 AppBackgroundRestrictionsInfo.LEVEL_UNKNOWN, // RestrictionLevel 272 AppBackgroundRestrictionsInfo.THRESHOLD_UNKNOWN, 273 AppBackgroundRestrictionsInfo.UNKNOWN_TRACKER, 274 null, // FgsTrackerInfo 275 getTrackerInfoForStatsd(uid), 276 null, // BroadcastEventsTrackerInfo 277 null, // BindServiceEventsTrackerInfo 278 AppBackgroundRestrictionsInfo.REASON_UNKNOWN, // ExemptionReason 279 AppBackgroundRestrictionsInfo.UNKNOWN, // OptimizationLevel 280 AppBackgroundRestrictionsInfo.SDK_UNKNOWN, // TargetSdk 281 isLowRamDeviceStatic(), 282 AppBackgroundRestrictionsInfo.LEVEL_UNKNOWN // previous RestrictionLevel 283 ); 284 } 285 } 286 } 287 288 /** 289 * Get the BatteryTrackerInfo object of the given uid. 290 * @return byte array of the proto object. 291 */ 292 @Override getTrackerInfoForStatsd(int uid)293 byte[] getTrackerInfoForStatsd(int uid) { 294 final ImmutableBatteryUsage temp; 295 synchronized (mLock) { 296 temp = mUidBatteryUsageInWindow.get(uid); 297 } 298 if (temp == null) { 299 return null; 300 } 301 final BatteryUsage bgUsage = temp.calcPercentage(uid, mInjector.getPolicy()); 302 final double allUsage = bgUsage.mPercentage[BatteryUsage.BATTERY_USAGE_INDEX_UNSPECIFIED] 303 + bgUsage.mPercentage[BatteryUsage.BATTERY_USAGE_INDEX_FOREGROUND] 304 + bgUsage.mPercentage[BatteryUsage.BATTERY_USAGE_INDEX_BACKGROUND] 305 + bgUsage.mPercentage[BatteryUsage.BATTERY_USAGE_INDEX_FOREGROUND_SERVICE] 306 + bgUsage.mPercentage[BatteryUsage.BATTERY_USAGE_INDEX_CACHED]; 307 final double usageBackground = 308 bgUsage.mPercentage[BatteryUsage.BATTERY_USAGE_INDEX_BACKGROUND]; 309 final double usageFgs = 310 bgUsage.mPercentage[BatteryUsage.BATTERY_USAGE_INDEX_FOREGROUND_SERVICE]; 311 final double usageForeground = 312 bgUsage.mPercentage[BatteryUsage.BATTERY_USAGE_INDEX_FOREGROUND]; 313 final double usageCached = 314 bgUsage.mPercentage[BatteryUsage.BATTERY_USAGE_INDEX_CACHED]; 315 if (DEBUG_BACKGROUND_BATTERY_TRACKER_VERBOSE) { 316 Slog.d(TAG, "getBatteryTrackerInfoProtoLocked uid:" + uid 317 + " allUsage:" + String.format("%4.2f%%", allUsage) 318 + " usageBackground:" + String.format("%4.2f%%", usageBackground) 319 + " usageFgs:" + String.format("%4.2f%%", usageFgs) 320 + " usageForeground:" + String.format("%4.2f%%", usageForeground) 321 + " usageCached:" + String.format("%4.2f%%", usageCached)); 322 } 323 final ProtoOutputStream proto = new ProtoOutputStream(); 324 proto.write(AppBackgroundRestrictionsInfo.BatteryTrackerInfo.BATTERY_24H, 325 allUsage * 10000); 326 proto.write(AppBackgroundRestrictionsInfo.BatteryTrackerInfo.BATTERY_USAGE_BACKGROUND, 327 usageBackground * 10000); 328 proto.write(AppBackgroundRestrictionsInfo.BatteryTrackerInfo.BATTERY_USAGE_FGS, 329 usageFgs * 10000); 330 proto.write(AppBackgroundRestrictionsInfo.BatteryTrackerInfo.BATTERY_USAGE_FOREGROUND, 331 usageForeground * 10000); 332 proto.write(AppBackgroundRestrictionsInfo.BatteryTrackerInfo.BATTERY_USAGE_CACHED, 333 usageCached * 10000); 334 proto.flush(); 335 return proto.getBytes(); 336 } 337 338 @Override onUserStarted(final @UserIdInt int userId)339 void onUserStarted(final @UserIdInt int userId) { 340 synchronized (mLock) { 341 mActiveUserIdStates.put(userId, true); 342 } 343 } 344 345 @Override onUserStopped(final @UserIdInt int userId)346 void onUserStopped(final @UserIdInt int userId) { 347 synchronized (mLock) { 348 mActiveUserIdStates.put(userId, false); 349 } 350 } 351 352 @Override onUserRemoved(final @UserIdInt int userId)353 void onUserRemoved(final @UserIdInt int userId) { 354 synchronized (mLock) { 355 mActiveUserIdStates.delete(userId); 356 for (int i = mUidBatteryUsage.size() - 1; i >= 0; i--) { 357 if (UserHandle.getUserId(mUidBatteryUsage.keyAt(i)) == userId) { 358 mUidBatteryUsage.removeAt(i); 359 } 360 } 361 for (int i = mUidBatteryUsageInWindow.size() - 1; i >= 0; i--) { 362 if (UserHandle.getUserId(mUidBatteryUsageInWindow.keyAt(i)) == userId) { 363 mUidBatteryUsageInWindow.removeAt(i); 364 } 365 } 366 mInjector.getPolicy().onUserRemovedLocked(userId); 367 } 368 } 369 370 @Override onUidRemoved(final int uid)371 void onUidRemoved(final int uid) { 372 synchronized (mLock) { 373 mUidBatteryUsage.delete(uid); 374 mUidBatteryUsageInWindow.delete(uid); 375 mInjector.getPolicy().onUidRemovedLocked(uid); 376 } 377 } 378 379 @Override onUserInteractionStarted(String packageName, int uid)380 void onUserInteractionStarted(String packageName, int uid) { 381 mInjector.getPolicy().onUserInteractionStarted(packageName, uid); 382 } 383 384 @Override onBackgroundRestrictionChanged(int uid, String pkgName, boolean restricted)385 void onBackgroundRestrictionChanged(int uid, String pkgName, boolean restricted) { 386 mInjector.getPolicy().onBackgroundRestrictionChanged(uid, pkgName, restricted); 387 } 388 389 /** 390 * @return The total battery usage of the given UID since the system boots or last battery 391 * stats reset prior to that (whoever is earlier). 392 * 393 * <p> 394 * Note: as there are throttling in polling the battery usage stats by 395 * the {@link #mBatteryUsageStatsPollingMinIntervalMs}, the returned data here 396 * could be either from the most recent polling, or the very fresh one - if the most recent 397 * polling is outdated, it'll trigger an immediate update. 398 * </p> 399 */ 400 @Override 401 @NonNull getUidBatteryUsage(int uid)402 public ImmutableBatteryUsage getUidBatteryUsage(int uid) { 403 final long now = mInjector.currentTimeMillis(); 404 final boolean updated = updateBatteryUsageStatsIfNecessary(now, false); 405 synchronized (mLock) { 406 if (updated) { 407 // We just got fresh data, schedule a check right a way. 408 mBgHandler.removeCallbacks(mBgBatteryUsageStatsPolling); 409 scheduleBgBatteryUsageStatsCheck(); 410 } 411 final BatteryUsage usage = mUidBatteryUsage.get(uid); 412 return usage != null ? new ImmutableBatteryUsage(usage) : BATTERY_USAGE_NONE; 413 } 414 } 415 scheduleBgBatteryUsageStatsCheck()416 private void scheduleBgBatteryUsageStatsCheck() { 417 if (!mBgHandler.hasCallbacks(mBgBatteryUsageStatsCheck)) { 418 mBgHandler.post(mBgBatteryUsageStatsCheck); 419 } 420 } 421 updateBatteryUsageStatsAndCheck()422 private void updateBatteryUsageStatsAndCheck() { 423 final long now = mInjector.currentTimeMillis(); 424 if (updateBatteryUsageStatsIfNecessary(now, false)) { 425 checkBatteryUsageStats(); 426 } else { 427 // We didn't do the battery stats update above, schedule a check later. 428 synchronized (mLock) { 429 scheduleBatteryUsageStatsUpdateIfNecessary( 430 mLastBatteryUsageSamplingTs + mBatteryUsageStatsPollingMinIntervalMs - now); 431 } 432 } 433 } 434 checkBatteryUsageStats()435 private void checkBatteryUsageStats() { 436 final long now = SystemClock.elapsedRealtime(); 437 final AppBatteryPolicy bgPolicy = mInjector.getPolicy(); 438 try { 439 final SparseArray<ImmutableBatteryUsage> uidConsumers = mTmpUidBatteryUsageInWindow; 440 synchronized (mLock) { 441 copyUidBatteryUsage(mUidBatteryUsageInWindow, uidConsumers); 442 } 443 final long since = Math.max(0, now - bgPolicy.mBgCurrentDrainWindowMs); 444 for (int i = 0, size = uidConsumers.size(); i < size; i++) { 445 final int uid = uidConsumers.keyAt(i); 446 final ImmutableBatteryUsage actualUsage = uidConsumers.valueAt(i); 447 final ImmutableBatteryUsage exemptedUsage = mAppRestrictionController 448 .getUidBatteryExemptedUsageSince(uid, since, now, 449 bgPolicy.mBgCurrentDrainExemptedTypes); 450 // It's possible the exemptedUsage could be larger than actualUsage, 451 // as the former one is an approximate value. 452 final ImmutableBatteryUsage bgUsage = actualUsage.mutate() 453 .subtract(exemptedUsage) 454 .calcPercentage(uid, bgPolicy) 455 .unmutate(); 456 if (DEBUG_BACKGROUND_BATTERY_TRACKER_VERBOSE 457 && !BATTERY_USAGE_NONE.equals(actualUsage)) { 458 Slog.i(TAG, String.format( 459 "UID %d: %s (%s) | %s | %s over the past %s", 460 uid, 461 bgUsage.toString(), 462 bgUsage.percentageToString(), 463 exemptedUsage.toString(), 464 actualUsage.toString(), 465 TimeUtils.formatDuration(bgPolicy.mBgCurrentDrainWindowMs))); 466 } 467 bgPolicy.handleUidBatteryUsage(uid, bgUsage); 468 } 469 // For debugging only. 470 for (int i = 0, size = mDebugUidPercentages.size(); i < size; i++) { 471 bgPolicy.handleUidBatteryUsage(mDebugUidPercentages.keyAt(i), 472 mDebugUidPercentages.valueAt(i)); 473 } 474 } finally { 475 scheduleBatteryUsageStatsUpdateIfNecessary(mBatteryUsageStatsPollingIntervalMs); 476 } 477 } 478 479 /** 480 * Update the battery usage stats data, if it's allowed to do so. 481 * 482 * @return {@code true} if the battery stats is up to date. 483 */ updateBatteryUsageStatsIfNecessary(long now, boolean forceUpdate)484 private boolean updateBatteryUsageStatsIfNecessary(long now, boolean forceUpdate) { 485 boolean needUpdate = false; 486 boolean updated = false; 487 synchronized (mLock) { 488 if (mLastBatteryUsageSamplingTs + mBatteryUsageStatsPollingMinIntervalMs < now 489 || forceUpdate) { 490 // The data we have is outdated. 491 if (mBatteryUsageStatsUpdatePending) { 492 // An update is ongoing in parallel, just wait for it. 493 try { 494 mLock.wait(); 495 } catch (InterruptedException e) { 496 } 497 } else { 498 mBatteryUsageStatsUpdatePending = true; 499 needUpdate = true; 500 } 501 updated = true; 502 } else { 503 // The data is still fresh, no need to update it. 504 return false; 505 } 506 } 507 if (needUpdate) { 508 // We don't want to query the battery usage stats with mLock held. 509 updateBatteryUsageStatsOnce(now); 510 synchronized (mLock) { 511 mLastBatteryUsageSamplingTs = now; 512 mBatteryUsageStatsUpdatePending = false; 513 mLock.notifyAll(); 514 } 515 } 516 return updated; 517 } 518 updateBatteryUsageStatsOnce(long now)519 private void updateBatteryUsageStatsOnce(long now) { 520 final AppBatteryPolicy bgPolicy = mInjector.getPolicy(); 521 final ArraySet<UserHandle> userIds = mTmpUserIds; 522 final SparseArray<BatteryUsage> buf = mTmpUidBatteryUsage; 523 final BatteryStatsInternal batteryStatsInternal = mInjector.getBatteryStatsInternal(); 524 final long windowSize = bgPolicy.mBgCurrentDrainWindowMs; 525 526 buf.clear(); 527 userIds.clear(); 528 synchronized (mLock) { 529 for (int i = mActiveUserIdStates.size() - 1; i >= 0; i--) { 530 userIds.add(UserHandle.of(mActiveUserIdStates.keyAt(i))); 531 if (!mActiveUserIdStates.valueAt(i)) { 532 mActiveUserIdStates.removeAt(i); 533 } 534 } 535 } 536 537 if (DEBUG_BACKGROUND_BATTERY_TRACKER_VERBOSE) { 538 Slog.i(TAG, "updateBatteryUsageStatsOnce"); 539 } 540 541 // Query the current battery usage stats. 542 BatteryUsageStatsQuery.Builder builder = new BatteryUsageStatsQuery.Builder() 543 .includeProcessStateData() 544 .setMaxStatsAgeMs(0); 545 final BatteryUsageStats stats = updateBatteryUsageStatsOnceInternal(0, 546 buf, builder, userIds, batteryStatsInternal); 547 final long curStart = stats != null ? stats.getStatsStartTimestamp() : 0L; 548 final long curEnd = stats != null ? stats.getStatsEndTimestamp() : now; 549 long curDuration = curEnd - curStart; 550 boolean needUpdateUidBatteryUsageInWindow = true; 551 552 if (curDuration >= windowSize) { 553 // If we do have long enough data for the window, save it. 554 synchronized (mLock) { 555 copyUidBatteryUsage(buf, mUidBatteryUsageInWindow, windowSize * 1.0d / curDuration); 556 } 557 needUpdateUidBatteryUsageInWindow = false; 558 } 559 560 // Save the current data, which includes the battery usage since last reset. 561 mTmpUidBatteryUsage2.clear(); 562 copyUidBatteryUsage(buf, mTmpUidBatteryUsage2); 563 564 final long lastUidBatteryUsageStartTs; 565 synchronized (mLock) { 566 lastUidBatteryUsageStartTs = mLastUidBatteryUsageStartTs; 567 mLastUidBatteryUsageStartTs = curStart; 568 } 569 if (curStart > lastUidBatteryUsageStartTs && lastUidBatteryUsageStartTs > 0) { 570 // The battery usage stats committed data since our last query, 571 // let's query the snapshots to get the data since last start. 572 builder = new BatteryUsageStatsQuery.Builder() 573 .includeProcessStateData() 574 .aggregateSnapshots(lastUidBatteryUsageStartTs, curStart); 575 final BatteryUsageStats statsCommit = 576 updateBatteryUsageStatsOnceInternal(0, 577 buf, 578 builder, 579 userIds, 580 batteryStatsInternal); 581 curDuration += curStart - lastUidBatteryUsageStartTs; 582 try { 583 if (statsCommit != null) { 584 statsCommit.close(); 585 } else { 586 Slog.w(TAG, "Stat was null"); 587 } 588 } catch (IOException e) { 589 Slog.w(TAG, "Failed to close a stat"); 590 } 591 } 592 if (needUpdateUidBatteryUsageInWindow && curDuration >= windowSize) { 593 // If we do have long enough data for the window, save it. 594 synchronized (mLock) { 595 copyUidBatteryUsage(buf, mUidBatteryUsageInWindow, windowSize * 1.0d / curDuration); 596 } 597 needUpdateUidBatteryUsageInWindow = false; 598 } 599 600 // Add the delta into the global records. 601 synchronized (mLock) { 602 for (int i = 0, size = buf.size(); i < size; i++) { 603 final int uid = buf.keyAt(i); 604 final int index = mUidBatteryUsage.indexOfKey(uid); 605 final BatteryUsage lastUsage = mLastUidBatteryUsage.get(uid, BATTERY_USAGE_NONE); 606 final BatteryUsage curUsage = buf.valueAt(i); 607 final BatteryUsage before; 608 final BatteryUsage totalUsage; 609 if (index >= 0) { 610 totalUsage = mUidBatteryUsage.valueAt(index); 611 before = DEBUG_BACKGROUND_BATTERY_TRACKER_VERBOSE 612 ? new BatteryUsage(totalUsage) : BATTERY_USAGE_NONE; 613 totalUsage.subtract(lastUsage).add(curUsage); 614 } else { 615 before = totalUsage = BATTERY_USAGE_NONE; 616 mUidBatteryUsage.put(uid, curUsage); 617 } 618 if (DEBUG_BACKGROUND_BATTERY_TRACKER_VERBOSE) { 619 final BatteryUsage actualDelta = new BatteryUsage(curUsage).subtract(lastUsage); 620 String msg = "Updating mUidBatteryUsage uid=" + uid + ", before=" + before 621 + ", after=" + mUidBatteryUsage.get(uid, BATTERY_USAGE_NONE) 622 + ", delta=" + actualDelta 623 + ", last=" + lastUsage 624 + ", curStart=" + curStart 625 + ", lastLastStart=" + lastUidBatteryUsageStartTs 626 + ", thisLastStart=" + mLastUidBatteryUsageStartTs; 627 if (!actualDelta.isValid()) { 628 // Something is wrong, the battery usage shouldn't be negative. 629 Slog.e(TAG, msg); 630 } else if (!BATTERY_USAGE_NONE.equals(actualDelta)) { 631 Slog.i(TAG, msg); 632 } 633 } 634 } 635 // Now update the mLastUidBatteryUsage with the data we just saved above. 636 copyUidBatteryUsage(mTmpUidBatteryUsage2, mLastUidBatteryUsage); 637 } 638 mTmpUidBatteryUsage2.clear(); 639 640 if (needUpdateUidBatteryUsageInWindow) { 641 // No sufficient data for the full window still, query snapshots again. 642 final long start = now - windowSize; 643 final long end = lastUidBatteryUsageStartTs - 1; 644 builder = new BatteryUsageStatsQuery.Builder() 645 .includeProcessStateData() 646 .aggregateSnapshots(start, end); 647 updateBatteryUsageStatsOnceInternal(end - start, 648 buf, builder, userIds, batteryStatsInternal); 649 synchronized (mLock) { 650 copyUidBatteryUsage(buf, mUidBatteryUsageInWindow); 651 } 652 } 653 if (DEBUG_BACKGROUND_BATTERY_TRACKER_VERBOSE) { 654 synchronized (mLock) { 655 for (int i = 0, size = mUidBatteryUsageInWindow.size(); i < size; i++) { 656 final ImmutableBatteryUsage usage = mUidBatteryUsageInWindow.valueAt(i); 657 if (BATTERY_USAGE_NONE.equals(usage)) { 658 // Skip the logging to avoid spamming. 659 continue; 660 } 661 Slog.i(TAG, "mUidBatteryUsageInWindow uid=" + mUidBatteryUsageInWindow.keyAt(i) 662 + " usage=" + usage); 663 } 664 } 665 } 666 try { 667 if (stats != null) { 668 stats.close(); 669 } else { 670 Slog.w(TAG, "Stat was null"); 671 } 672 } catch (IOException e) { 673 Slog.w(TAG, "Failed to close a stat"); 674 } 675 } 676 677 // The BatteryUsageStats object MUST BE CLOSED when finished using updateBatteryUsageStatsOnceInternal(long expectedDuration, SparseArray<BatteryUsage> buf, BatteryUsageStatsQuery.Builder builder, ArraySet<UserHandle> userIds, BatteryStatsInternal batteryStatsInternal)678 private BatteryUsageStats updateBatteryUsageStatsOnceInternal(long expectedDuration, 679 SparseArray<BatteryUsage> buf, BatteryUsageStatsQuery.Builder builder, 680 ArraySet<UserHandle> userIds, BatteryStatsInternal batteryStatsInternal) { 681 for (int i = 0, size = userIds.size(); i < size; i++) { 682 builder.addUser(userIds.valueAt(i)); 683 } 684 final List<BatteryUsageStats> statsList = batteryStatsInternal 685 .getBatteryUsageStats(Arrays.asList(builder.build())); 686 if (ArrayUtils.isEmpty(statsList)) { 687 // Shouldn't happen unless in test. 688 return null; 689 } 690 // We need the first stat in the list, so we should 691 // close out the others. 692 final BatteryUsageStats stats = statsList.get(0); 693 for (int i = 1; i < statsList.size(); i++) { 694 try { 695 if (statsList.get(i) != null) { 696 statsList.get(i).close(); 697 } else { 698 Slog.w(TAG, "Stat was null"); 699 } 700 } catch (IOException e) { 701 Slog.w(TAG, "Failed to close a stat in BatteryUsageStats List"); 702 } 703 } 704 final List<UidBatteryConsumer> uidConsumers = stats.getUidBatteryConsumers(); 705 if (uidConsumers != null) { 706 final long start = stats.getStatsStartTimestamp(); 707 final long end = stats.getStatsEndTimestamp(); 708 final double scale = expectedDuration > 0 709 ? Math.min((expectedDuration * 1.0d) / (end - start), 1.0d) : 1.0d; 710 final AppBatteryPolicy bgPolicy = mInjector.getPolicy(); 711 for (UidBatteryConsumer uidConsumer : uidConsumers) { 712 // TODO: b/200326767 - as we are not supporting per proc state attribution yet, 713 // we couldn't distinguish between a real FGS vs. a bound FGS proc state. 714 final int rawUid = uidConsumer.getUid(); 715 if (UserHandle.isIsolated(rawUid)) { 716 // Isolated processes should have been attributed to their parent processes. 717 continue; 718 } 719 int uid = rawUid; 720 // Keep the logic in sync with BatteryAppListPreferenceController.java 721 // Check if this UID is a shared GID. If so, we combine it with the OWNER's 722 // actual app UID. 723 final int sharedAppId = UserHandle.getAppIdFromSharedAppGid(uid); 724 if (sharedAppId > 0) { 725 uid = UserHandle.getUid(UserHandle.USER_SYSTEM, sharedAppId); 726 } 727 final BatteryUsage bgUsage = new BatteryUsage(uidConsumer, bgPolicy) 728 .scale(scale); 729 int index = buf.indexOfKey(uid); 730 if (index < 0) { 731 buf.put(uid, bgUsage); 732 } else { 733 final BatteryUsage before = buf.valueAt(index); 734 before.add(bgUsage); 735 } 736 if (DEBUG_BACKGROUND_BATTERY_TRACKER_VERBOSE 737 && !BATTERY_USAGE_NONE.equals(bgUsage)) { 738 Slog.i(TAG, "updateBatteryUsageStatsOnceInternal uid=" + rawUid 739 + ", bgUsage=" + bgUsage 740 + (rawUid == uid ? "" 741 : ", realUid=" + uid 742 + ", realUsage=" + buf.get(uid)) 743 + ", start=" + start 744 + ", end=" + end); 745 } 746 } 747 } 748 return stats; 749 } 750 copyUidBatteryUsage(SparseArray<? extends BatteryUsage> source, SparseArray<ImmutableBatteryUsage> dest)751 private static void copyUidBatteryUsage(SparseArray<? extends BatteryUsage> source, 752 SparseArray<ImmutableBatteryUsage> dest) { 753 dest.clear(); 754 for (int i = source.size() - 1; i >= 0; i--) { 755 dest.put(source.keyAt(i), new ImmutableBatteryUsage(source.valueAt(i))); 756 } 757 } 758 copyUidBatteryUsage(SparseArray<? extends BatteryUsage> source, SparseArray<ImmutableBatteryUsage> dest, double scale)759 private static void copyUidBatteryUsage(SparseArray<? extends BatteryUsage> source, 760 SparseArray<ImmutableBatteryUsage> dest, double scale) { 761 dest.clear(); 762 for (int i = source.size() - 1; i >= 0; i--) { 763 dest.put(source.keyAt(i), new ImmutableBatteryUsage(source.valueAt(i), scale)); 764 } 765 } 766 onCurrentDrainMonitorEnabled(boolean enabled)767 private void onCurrentDrainMonitorEnabled(boolean enabled) { 768 if (enabled) { 769 if (!mBgHandler.hasCallbacks(mBgBatteryUsageStatsPolling)) { 770 mBgHandler.postDelayed(mBgBatteryUsageStatsPolling, 771 mBatteryUsageStatsPollingIntervalMs); 772 } 773 } else { 774 mBgHandler.removeCallbacks(mBgBatteryUsageStatsPolling); 775 synchronized (mLock) { 776 if (mBatteryUsageStatsUpdatePending) { 777 // An update is ongoing in parallel, just wait for it. 778 try { 779 mLock.wait(); 780 } catch (InterruptedException e) { 781 } 782 } 783 mUidBatteryUsage.clear(); 784 mUidBatteryUsageInWindow.clear(); 785 mLastUidBatteryUsage.clear(); 786 mLastUidBatteryUsageStartTs = mLastBatteryUsageSamplingTs = 0L; 787 } 788 } 789 } 790 setDebugUidPercentage(int[] uids, double[][] percentages)791 void setDebugUidPercentage(int[] uids, double[][] percentages) { 792 mDebugUidPercentages.clear(); 793 for (int i = 0; i < uids.length; i++) { 794 mDebugUidPercentages.put(uids[i], 795 new BatteryUsage().setPercentage(percentages[i]).unmutate()); 796 } 797 scheduleBgBatteryUsageStatsCheck(); 798 } 799 clearDebugUidPercentage()800 void clearDebugUidPercentage() { 801 mDebugUidPercentages.clear(); 802 scheduleBgBatteryUsageStatsCheck(); 803 } 804 805 @VisibleForTesting reset()806 void reset() { 807 synchronized (mLock) { 808 mUidBatteryUsage.clear(); 809 mUidBatteryUsageInWindow.clear(); 810 mLastUidBatteryUsage.clear(); 811 mLastUidBatteryUsageStartTs = mLastBatteryUsageSamplingTs = 0L; 812 } 813 mBgHandler.removeCallbacks(mBgBatteryUsageStatsPolling); 814 updateBatteryUsageStatsAndCheck(); 815 } 816 817 @Override dump(PrintWriter pw, String prefix)818 void dump(PrintWriter pw, String prefix) { 819 pw.print(prefix); 820 pw.println("APP BATTERY STATE TRACKER:"); 821 if (mInjector.getActivityManagerInternal().isBooted()) { 822 // Force an update. 823 updateBatteryUsageStatsIfNecessary(mInjector.currentTimeMillis(), true); 824 } 825 // Force a check. 826 scheduleBgBatteryUsageStatsCheck(); 827 // Wait for its completion (as it runs in handler thread for the sake of thread safe) 828 final CountDownLatch latch = new CountDownLatch(1); 829 mBgHandler.getLooper().getQueue().addIdleHandler(() -> { 830 latch.countDown(); 831 return false; 832 }); 833 try { 834 latch.await(); 835 } catch (InterruptedException e) { 836 } 837 synchronized (mLock) { 838 final SparseArray<ImmutableBatteryUsage> uidConsumers = mUidBatteryUsageInWindow; 839 pw.print(" " + prefix); 840 pw.print(" Last battery usage start="); 841 TimeUtils.dumpTime(pw, mLastUidBatteryUsageStartTs); 842 pw.println(); 843 pw.print(" " + prefix); 844 pw.print("Battery usage over last "); 845 final String newPrefix = " " + prefix; 846 final AppBatteryPolicy bgPolicy = mInjector.getPolicy(); 847 final long now = SystemClock.elapsedRealtime(); 848 final long since = Math.max(0, now - bgPolicy.mBgCurrentDrainWindowMs); 849 pw.println(TimeUtils.formatDuration(now - since)); 850 if (uidConsumers.size() == 0) { 851 pw.print(newPrefix); 852 pw.println("(none)"); 853 } else { 854 for (int i = 0, size = uidConsumers.size(); i < size; i++) { 855 final int uid = uidConsumers.keyAt(i); 856 final BatteryUsage bgUsage = uidConsumers.valueAt(i) 857 .calcPercentage(uid, bgPolicy); 858 final BatteryUsage exemptedUsage = mAppRestrictionController 859 .getUidBatteryExemptedUsageSince(uid, since, now, 860 bgPolicy.mBgCurrentDrainExemptedTypes) 861 .calcPercentage(uid, bgPolicy); 862 final BatteryUsage reportedUsage = new BatteryUsage(bgUsage) 863 .subtract(exemptedUsage) 864 .calcPercentage(uid, bgPolicy); 865 pw.format("%s%s: [%s] %s (%s) | %s (%s) | %s (%s) | %s\n", 866 newPrefix, UserHandle.formatUid(uid), 867 PowerExemptionManager.reasonCodeToString(bgPolicy.shouldExemptUid(uid)), 868 bgUsage.toString(), 869 bgUsage.percentageToString(), 870 exemptedUsage.toString(), 871 exemptedUsage.percentageToString(), 872 reportedUsage.toString(), 873 reportedUsage.percentageToString(), 874 mUidBatteryUsage.get(uid, BATTERY_USAGE_NONE).toString()); 875 } 876 } 877 } 878 super.dump(pw, prefix); 879 } 880 881 @Override dumpAsProto(ProtoOutputStream proto, int uid)882 void dumpAsProto(ProtoOutputStream proto, int uid) { 883 if (mInjector.getActivityManagerInternal().isBooted()) { 884 // Force an update. 885 updateBatteryUsageStatsIfNecessary(mInjector.currentTimeMillis(), true); 886 } 887 synchronized (mLock) { 888 final SparseArray<ImmutableBatteryUsage> uidConsumers = mUidBatteryUsageInWindow; 889 if (uid != android.os.Process.INVALID_UID) { 890 final BatteryUsage usage = uidConsumers.get(uid); 891 if (usage != null) { 892 dumpUidStats(proto, uid, usage); 893 } 894 } else { 895 for (int i = 0, size = uidConsumers.size(); i < size; i++) { 896 final int aUid = uidConsumers.keyAt(i); 897 final BatteryUsage usage = uidConsumers.valueAt(i); 898 dumpUidStats(proto, aUid, usage); 899 } 900 } 901 } 902 } 903 dumpUidStats(ProtoOutputStream proto, int uid, BatteryUsage usage)904 private void dumpUidStats(ProtoOutputStream proto, int uid, BatteryUsage usage) { 905 if (usage.mUsage == null) { 906 return; 907 } 908 909 final double foregroundUsage = usage.getUsagePowerMah(PROCESS_STATE_FOREGROUND); 910 final double backgroundUsage = usage.getUsagePowerMah(PROCESS_STATE_BACKGROUND); 911 final double fgsUsage = usage.getUsagePowerMah(PROCESS_STATE_FOREGROUND_SERVICE); 912 final double cachedUsage = usage.getUsagePowerMah(PROCESS_STATE_CACHED); 913 914 if (foregroundUsage == 0 && backgroundUsage == 0 && fgsUsage == 0) { 915 return; 916 } 917 918 final long token = proto.start(AppBatteryStatsProto.UID_STATS); 919 proto.write(AppBatteryStatsProto.UidStats.UID, uid); 920 dumpProcessStateStats(proto, 921 AppBatteryStatsProto.UidStats.ProcessStateStats.FOREGROUND, 922 foregroundUsage); 923 dumpProcessStateStats(proto, 924 AppBatteryStatsProto.UidStats.ProcessStateStats.BACKGROUND, 925 backgroundUsage); 926 dumpProcessStateStats(proto, 927 AppBatteryStatsProto.UidStats.ProcessStateStats.FOREGROUND_SERVICE, 928 fgsUsage); 929 dumpProcessStateStats(proto, 930 AppBatteryStatsProto.UidStats.ProcessStateStats.CACHED, 931 cachedUsage); 932 proto.end(token); 933 } 934 dumpProcessStateStats(ProtoOutputStream proto, int processState, double powerMah)935 private void dumpProcessStateStats(ProtoOutputStream proto, int processState, double powerMah) { 936 if (powerMah == 0) { 937 return; 938 } 939 940 final long token = proto.start(AppBatteryStatsProto.UidStats.PROCESS_STATE_STATS); 941 proto.write(AppBatteryStatsProto.UidStats.ProcessStateStats.PROCESS_STATE, processState); 942 proto.write(AppBatteryStatsProto.UidStats.ProcessStateStats.POWER_MAH, powerMah); 943 proto.end(token); 944 } 945 946 static class BatteryUsage { 947 static final int BATTERY_USAGE_INDEX_UNSPECIFIED = PROCESS_STATE_UNSPECIFIED; 948 static final int BATTERY_USAGE_INDEX_FOREGROUND = PROCESS_STATE_FOREGROUND; 949 static final int BATTERY_USAGE_INDEX_BACKGROUND = PROCESS_STATE_BACKGROUND; 950 static final int BATTERY_USAGE_INDEX_FOREGROUND_SERVICE = PROCESS_STATE_FOREGROUND_SERVICE; 951 static final int BATTERY_USAGE_INDEX_CACHED = PROCESS_STATE_CACHED; 952 static final int BATTERY_USAGE_COUNT = PROCESS_STATE_COUNT; 953 954 static final Dimensions[] BATT_DIMENS = new Dimensions[] { 955 new Dimensions(AppBatteryPolicy.DEFAULT_BG_CURRENT_DRAIN_POWER_COMPONENTS, 956 PROCESS_STATE_UNSPECIFIED), 957 new Dimensions(AppBatteryPolicy.DEFAULT_BG_CURRENT_DRAIN_POWER_COMPONENTS, 958 PROCESS_STATE_FOREGROUND), 959 new Dimensions(AppBatteryPolicy.DEFAULT_BG_CURRENT_DRAIN_POWER_COMPONENTS, 960 PROCESS_STATE_BACKGROUND), 961 new Dimensions(AppBatteryPolicy.DEFAULT_BG_CURRENT_DRAIN_POWER_COMPONENTS, 962 PROCESS_STATE_FOREGROUND_SERVICE), 963 new Dimensions(AppBatteryPolicy.DEFAULT_BG_CURRENT_DRAIN_POWER_COMPONENTS, 964 PROCESS_STATE_CACHED), 965 }; 966 967 @NonNull double[] mUsage; 968 @Nullable double[] mPercentage; 969 BatteryUsage()970 BatteryUsage() { 971 this(0.0d, 0.0d, 0.0d, 0.0d, 0.0d); 972 } 973 BatteryUsage(double unspecifiedUsage, double fgUsage, double bgUsage, double fgsUsage, double cachedUsage)974 BatteryUsage(double unspecifiedUsage, double fgUsage, double bgUsage, double fgsUsage, 975 double cachedUsage) { 976 mUsage = new double[] {unspecifiedUsage, fgUsage, bgUsage, fgsUsage, cachedUsage}; 977 } 978 BatteryUsage(@onNull double[] usage)979 BatteryUsage(@NonNull double[] usage) { 980 mUsage = usage; 981 } 982 BatteryUsage(@onNull BatteryUsage other, double scale)983 BatteryUsage(@NonNull BatteryUsage other, double scale) { 984 this(other); 985 scaleInternal(scale); 986 } 987 BatteryUsage(@onNull BatteryUsage other)988 BatteryUsage(@NonNull BatteryUsage other) { 989 mUsage = new double[other.mUsage.length]; 990 setToInternal(other); 991 } 992 BatteryUsage(@onNull UidBatteryConsumer consumer, @NonNull AppBatteryPolicy policy)993 BatteryUsage(@NonNull UidBatteryConsumer consumer, @NonNull AppBatteryPolicy policy) { 994 final Dimensions[] dims = policy.mBatteryDimensions; 995 mUsage = new double[] { 996 getConsumedPowerNoThrow(consumer, dims[BATTERY_USAGE_INDEX_UNSPECIFIED]), 997 getConsumedPowerNoThrow(consumer, dims[BATTERY_USAGE_INDEX_FOREGROUND]), 998 getConsumedPowerNoThrow(consumer, dims[BATTERY_USAGE_INDEX_BACKGROUND]), 999 getConsumedPowerNoThrow(consumer, dims[BATTERY_USAGE_INDEX_FOREGROUND_SERVICE]), 1000 getConsumedPowerNoThrow(consumer, dims[BATTERY_USAGE_INDEX_CACHED]), 1001 }; 1002 } 1003 setTo(@onNull BatteryUsage other)1004 BatteryUsage setTo(@NonNull BatteryUsage other) { 1005 return setToInternal(other); 1006 } 1007 setToInternal(@onNull BatteryUsage other)1008 private BatteryUsage setToInternal(@NonNull BatteryUsage other) { 1009 System.arraycopy(other.mUsage, 0, mUsage, 0, other.mUsage.length); 1010 if (other.mPercentage != null) { 1011 mPercentage = new double[other.mPercentage.length]; 1012 System.arraycopy(other.mPercentage, 0, mPercentage, 0, other.mPercentage.length); 1013 } else { 1014 mPercentage = null; 1015 } 1016 return this; 1017 } 1018 add(@onNull BatteryUsage other)1019 BatteryUsage add(@NonNull BatteryUsage other) { 1020 for (int i = 0; i < other.mUsage.length; i++) { 1021 mUsage[i] += other.mUsage[i]; 1022 } 1023 return this; 1024 } 1025 subtract(@onNull BatteryUsage other)1026 BatteryUsage subtract(@NonNull BatteryUsage other) { 1027 for (int i = 0; i < other.mUsage.length; i++) { 1028 mUsage[i] = Math.max(0.0d, mUsage[i] - other.mUsage[i]); 1029 } 1030 return this; 1031 } 1032 scale(double scale)1033 BatteryUsage scale(double scale) { 1034 return scaleInternal(scale); 1035 } 1036 scaleInternal(double scale)1037 private BatteryUsage scaleInternal(double scale) { 1038 for (int i = 0; i < mUsage.length; i++) { 1039 mUsage[i] *= scale; 1040 } 1041 return this; 1042 } 1043 unmutate()1044 ImmutableBatteryUsage unmutate() { 1045 return new ImmutableBatteryUsage(this); 1046 } 1047 calcPercentage(int uid, @NonNull AppBatteryPolicy policy)1048 BatteryUsage calcPercentage(int uid, @NonNull AppBatteryPolicy policy) { 1049 if (mPercentage == null || mPercentage.length != mUsage.length) { 1050 mPercentage = new double[mUsage.length]; 1051 } 1052 policy.calcPercentage(uid, mUsage, mPercentage); 1053 return this; 1054 } 1055 setPercentage(@onNull double[] percentage)1056 BatteryUsage setPercentage(@NonNull double[] percentage) { 1057 mPercentage = percentage; 1058 return this; 1059 } 1060 getPercentage()1061 double[] getPercentage() { 1062 return mPercentage; 1063 } 1064 percentageToString()1065 String percentageToString() { 1066 return formatBatteryUsagePercentage(mPercentage); 1067 } 1068 1069 @Override toString()1070 public String toString() { 1071 return formatBatteryUsage(mUsage); 1072 } 1073 getUsagePowerMah(@atteryConsumer.ProcessState int processState)1074 double getUsagePowerMah(@BatteryConsumer.ProcessState int processState) { 1075 switch (processState) { 1076 case PROCESS_STATE_FOREGROUND: 1077 return mUsage[BATTERY_USAGE_INDEX_FOREGROUND]; 1078 case PROCESS_STATE_BACKGROUND: 1079 return mUsage[BATTERY_USAGE_INDEX_BACKGROUND]; 1080 case PROCESS_STATE_FOREGROUND_SERVICE: 1081 return mUsage[BATTERY_USAGE_INDEX_FOREGROUND_SERVICE]; 1082 case PROCESS_STATE_CACHED: 1083 return mUsage[BATTERY_USAGE_INDEX_CACHED]; 1084 } 1085 return 0; 1086 } 1087 isValid()1088 boolean isValid() { 1089 for (int i = 0; i < mUsage.length; i++) { 1090 if (mUsage[i] < 0.0d) { 1091 return false; 1092 } 1093 } 1094 return true; 1095 } 1096 isEmpty()1097 boolean isEmpty() { 1098 for (int i = 0; i < mUsage.length; i++) { 1099 if (mUsage[i] > 0.0d) { 1100 return false; 1101 } 1102 } 1103 return true; 1104 } 1105 1106 @Override equals(Object other)1107 public boolean equals(Object other) { 1108 if (other == null) { 1109 return false; 1110 } 1111 final BatteryUsage otherUsage = (BatteryUsage) other; 1112 for (int i = 0; i < mUsage.length; i++) { 1113 if (Double.compare(mUsage[i], otherUsage.mUsage[i]) != 0) { 1114 return false; 1115 } 1116 } 1117 return true; 1118 } 1119 1120 @Override hashCode()1121 public int hashCode() { 1122 int hashCode = 0; 1123 for (int i = 0; i < mUsage.length; i++) { 1124 hashCode = Double.hashCode(mUsage[i]) + hashCode * 31; 1125 } 1126 return hashCode; 1127 } 1128 formatBatteryUsage(double[] usage)1129 private static String formatBatteryUsage(double[] usage) { 1130 return String.format("%.3f %.3f %.3f %.3f %.3f mAh", 1131 usage[BATTERY_USAGE_INDEX_UNSPECIFIED], 1132 usage[BATTERY_USAGE_INDEX_FOREGROUND], 1133 usage[BATTERY_USAGE_INDEX_BACKGROUND], 1134 usage[BATTERY_USAGE_INDEX_FOREGROUND_SERVICE], 1135 usage[BATTERY_USAGE_INDEX_CACHED]); 1136 } 1137 formatBatteryUsagePercentage(double[] percentage)1138 static String formatBatteryUsagePercentage(double[] percentage) { 1139 return String.format("%4.2f%% %4.2f%% %4.2f%% %4.2f%% %4.2f%%", 1140 percentage[BATTERY_USAGE_INDEX_UNSPECIFIED], 1141 percentage[BATTERY_USAGE_INDEX_FOREGROUND], 1142 percentage[BATTERY_USAGE_INDEX_BACKGROUND], 1143 percentage[BATTERY_USAGE_INDEX_FOREGROUND_SERVICE], 1144 percentage[BATTERY_USAGE_INDEX_CACHED]); 1145 } 1146 getConsumedPowerNoThrow(final UidBatteryConsumer uidConsumer, final Dimensions dimens)1147 private static double getConsumedPowerNoThrow(final UidBatteryConsumer uidConsumer, 1148 final Dimensions dimens) { 1149 try { 1150 return uidConsumer.getConsumedPower(dimens); 1151 } catch (IllegalArgumentException e) { 1152 return 0.0d; 1153 } 1154 } 1155 } 1156 1157 static final class ImmutableBatteryUsage extends BatteryUsage { ImmutableBatteryUsage()1158 ImmutableBatteryUsage() { 1159 super(); 1160 } 1161 ImmutableBatteryUsage(double unspecifiedUsage, double fgUsage, double bgUsage, double fgsUsage, double cachedUsage)1162 ImmutableBatteryUsage(double unspecifiedUsage, double fgUsage, double bgUsage, 1163 double fgsUsage, double cachedUsage) { 1164 super(unspecifiedUsage, fgUsage, bgUsage, fgsUsage, cachedUsage); 1165 } 1166 ImmutableBatteryUsage(@onNull double[] usage)1167 ImmutableBatteryUsage(@NonNull double[] usage) { 1168 super(usage); 1169 } 1170 ImmutableBatteryUsage(@onNull BatteryUsage other, double scale)1171 ImmutableBatteryUsage(@NonNull BatteryUsage other, double scale) { 1172 super(other, scale); 1173 } 1174 ImmutableBatteryUsage(@onNull BatteryUsage other)1175 ImmutableBatteryUsage(@NonNull BatteryUsage other) { 1176 super(other); 1177 } 1178 ImmutableBatteryUsage(@onNull UidBatteryConsumer consumer, @NonNull AppBatteryPolicy policy)1179 ImmutableBatteryUsage(@NonNull UidBatteryConsumer consumer, 1180 @NonNull AppBatteryPolicy policy) { 1181 super(consumer, policy); 1182 } 1183 1184 @Override setTo(@onNull BatteryUsage other)1185 BatteryUsage setTo(@NonNull BatteryUsage other) { 1186 throw new RuntimeException("Readonly"); 1187 } 1188 1189 @Override add(@onNull BatteryUsage other)1190 BatteryUsage add(@NonNull BatteryUsage other) { 1191 throw new RuntimeException("Readonly"); 1192 } 1193 1194 @Override subtract(@onNull BatteryUsage other)1195 BatteryUsage subtract(@NonNull BatteryUsage other) { 1196 throw new RuntimeException("Readonly"); 1197 } 1198 1199 @Override scale(double scale)1200 BatteryUsage scale(double scale) { 1201 throw new RuntimeException("Readonly"); 1202 } 1203 1204 @Override setPercentage(@onNull double[] percentage)1205 BatteryUsage setPercentage(@NonNull double[] percentage) { 1206 throw new RuntimeException("Readonly"); 1207 } 1208 mutate()1209 BatteryUsage mutate() { 1210 return new BatteryUsage(this); 1211 } 1212 } 1213 1214 static final class AppBatteryPolicy extends BaseAppStatePolicy<AppBatteryTracker> { 1215 /** 1216 * The type of battery usage we could choose to apply the policy on. 1217 * 1218 * Must be in sync with android.os.BatteryConsumer.PROCESS_STATE_*. 1219 */ 1220 static final int BATTERY_USAGE_TYPE_UNSPECIFIED = 1; 1221 static final int BATTERY_USAGE_TYPE_FOREGROUND = 1 << 1; 1222 static final int BATTERY_USAGE_TYPE_BACKGROUND = 1 << 2; 1223 static final int BATTERY_USAGE_TYPE_FOREGROUND_SERVICE = 1 << 3; 1224 static final int BATTERY_USAGE_TYPE_CACHED = 1 << 4; 1225 1226 /** 1227 * Whether or not we should enable the monitoring on background current drains. 1228 */ 1229 static final String KEY_BG_CURRENT_DRAIN_MONITOR_ENABLED = 1230 DEVICE_CONFIG_SUBNAMESPACE_PREFIX + "current_drain_monitor_enabled"; 1231 1232 /** 1233 * The threshold of the background current drain (in percentage) to the restricted 1234 * standby bucket. In conjunction with the {@link #KEY_BG_CURRENT_DRAIN_WINDOW}, 1235 * the app could be moved to more restricted standby bucket when its background current 1236 * drain rate is over this limit. 1237 */ 1238 static final String KEY_BG_CURRENT_DRAIN_THRESHOLD_TO_RESTRICTED_BUCKET = 1239 DEVICE_CONFIG_SUBNAMESPACE_PREFIX + "current_drain_threshold_to_restricted_bucket"; 1240 1241 /** 1242 * The threshold of the background current drain (in percentage) to the background 1243 * restricted level. In conjunction with the {@link #KEY_BG_CURRENT_DRAIN_WINDOW}, 1244 * the app could be moved to more restricted level when its background current 1245 * drain rate is over this limit. 1246 */ 1247 static final String KEY_BG_CURRENT_DRAIN_THRESHOLD_TO_BG_RESTRICTED = 1248 DEVICE_CONFIG_SUBNAMESPACE_PREFIX + "current_drain_threshold_to_bg_restricted"; 1249 1250 /** 1251 * The background current drain window size. In conjunction with the 1252 * {@link #KEY_BG_CURRENT_DRAIN_THRESHOLD_TO_RESTRICTED_BUCKET}, the app could be moved to 1253 * more restrictive bucket when its background current drain rate is over this limit. 1254 */ 1255 static final String KEY_BG_CURRENT_DRAIN_WINDOW = 1256 DEVICE_CONFIG_SUBNAMESPACE_PREFIX + "current_drain_window"; 1257 1258 /** 1259 * The grace period after an interaction event with the app, if the background current 1260 * drain goes beyond the threshold within that period, the system won't apply the 1261 * restrictions. 1262 */ 1263 static final String KEY_BG_CURRENT_DRAIN_INTERACTION_GRACE_PERIOD = 1264 DEVICE_CONFIG_SUBNAMESPACE_PREFIX + "current_drain_interaction_grace_period"; 1265 1266 /** 1267 * Similar to {@link #KEY_BG_CURRENT_DRAIN_THRESHOLD_TO_RESTRICTED_BUCKET}, but a higher 1268 * value for the legitimate cases with higher background current drain. 1269 */ 1270 static final String KEY_BG_CURRENT_DRAIN_HIGH_THRESHOLD_TO_RESTRICTED_BUCKET = 1271 DEVICE_CONFIG_SUBNAMESPACE_PREFIX 1272 + "current_drain_high_threshold_to_restricted_bucket"; 1273 1274 /** 1275 * Similar to {@link #KEY_BG_CURRENT_DRAIN_THRESHOLD_TO_BG_RESTRICTED}, but a higher value 1276 * for the legitimate cases with higher background current drain. 1277 */ 1278 static final String KEY_BG_CURRENT_DRAIN_HIGH_THRESHOLD_TO_BG_RESTRICTED = 1279 DEVICE_CONFIG_SUBNAMESPACE_PREFIX + "current_drain_high_threshold_to_bg_restricted"; 1280 1281 /** 1282 * The threshold of minimal time of hosting a foreground service with type "mediaPlayback" 1283 * or a media session, over the given window, so it'd subject towards the higher 1284 * background current drain threshold as defined in 1285 * {@link #mBgCurrentDrainBgRestrictedHighThreshold}. 1286 */ 1287 static final String KEY_BG_CURRENT_DRAIN_MEDIA_PLAYBACK_MIN_DURATION = 1288 DEVICE_CONFIG_SUBNAMESPACE_PREFIX + "current_drain_media_playback_min_duration"; 1289 1290 /** 1291 * Similar to {@link #KEY_BG_CURRENT_DRAIN_MEDIA_PLAYBACK_MIN_DURATION} but for foreground 1292 * service with type "location". 1293 */ 1294 static final String KEY_BG_CURRENT_DRAIN_LOCATION_MIN_DURATION = 1295 DEVICE_CONFIG_SUBNAMESPACE_PREFIX + "current_drain_location_min_duration"; 1296 1297 /** 1298 * Whether or not we should enable the different threshold based on the durations of 1299 * certain event type. 1300 */ 1301 static final String KEY_BG_CURRENT_DRAIN_EVENT_DURATION_BASED_THRESHOLD_ENABLED = 1302 DEVICE_CONFIG_SUBNAMESPACE_PREFIX 1303 + "current_drain_event_duration_based_threshold_enabled"; 1304 1305 /** 1306 * Whether or not we should move the app into the restricted bucket level if its background 1307 * battery usage goes beyond the threshold. Note this different from the flag 1308 * {@link AppRestrictionController.ConstantsObserver#KEY_BG_AUTO_RESTRICT_ABUSIVE_APPS} 1309 * which is to control the overall auto bg restrictions. 1310 */ 1311 static final String KEY_BG_CURRENT_DRAIN_AUTO_RESTRICT_ABUSIVE_APPS_ENABLED = 1312 DEVICE_CONFIG_SUBNAMESPACE_PREFIX 1313 + "current_drain_auto_restrict_abusive_apps_enabled"; 1314 1315 /** 1316 * The types of battery drain we're checking on each app; if the sum of the battery drain 1317 * exceeds the threshold, it'll be moved to restricted standby bucket; the type here 1318 * must be one of, or combination of {@link #BATTERY_USAGE_TYPE_BACKGROUND}, 1319 * {@link #BATTERY_USAGE_TYPE_FOREGROUND_SERVICE} and {@link #BATTERY_USAGE_TYPE_CACHED}. 1320 */ 1321 static final String KEY_BG_CURRENT_DRAIN_TYPES_TO_RESTRICTED_BUCKET = 1322 DEVICE_CONFIG_SUBNAMESPACE_PREFIX + "current_drain_types_to_restricted_bucket"; 1323 1324 /** 1325 * The types of battery drain we're checking on each app; if the sum of the battery drain 1326 * exceeds the threshold, it'll be moved to background restricted level; the type here 1327 * must be one of, or combination of {@link #BATTERY_USAGE_TYPE_BACKGROUND}, 1328 * {@link #BATTERY_USAGE_TYPE_FOREGROUND_SERVICE} and {@link #BATTERY_USAGE_TYPE_CACHED}. 1329 */ 1330 static final String KEY_BG_CURRENT_DRAIN_TYPES_TO_BG_RESTRICTED = 1331 DEVICE_CONFIG_SUBNAMESPACE_PREFIX + "current_drain_types_to_bg_restricted"; 1332 1333 /** 1334 * The power usage components we're monitoring. 1335 */ 1336 static final String KEY_BG_CURRENT_DRAIN_POWER_COMPONENTS = 1337 DEVICE_CONFIG_SUBNAMESPACE_PREFIX + "current_drain_power_components"; 1338 1339 /** 1340 * The types of state where we'll exempt its battery usage when it's in that state. 1341 * The state here must be one or a combination of STATE_TYPE_* in BaseAppStateTracker. 1342 */ 1343 static final String KEY_BG_CURRENT_DRAIN_EXEMPTED_TYPES = 1344 DEVICE_CONFIG_SUBNAMESPACE_PREFIX + "current_drain_exempted_types"; 1345 1346 /** 1347 * The behavior when an app has the permission ACCESS_BACKGROUND_LOCATION granted, 1348 * whether or not the system will use a higher threshold towards its background battery 1349 * usage because of it. 1350 */ 1351 static final String KEY_BG_CURRENT_DRAIN_HIGH_THRESHOLD_BY_BG_LOCATION = 1352 DEVICE_CONFIG_SUBNAMESPACE_PREFIX + "current_drain_high_threshold_by_bg_location"; 1353 1354 /** 1355 * Whether or not the battery usage of the offending app should fulfill the 1st threshold 1356 * before taking actions for the 2nd threshold. 1357 */ 1358 static final String KEY_BG_CURRENT_DRAIN_DECOUPLE_THRESHOLDS = 1359 DEVICE_CONFIG_SUBNAMESPACE_PREFIX + "current_drain_decouple_thresholds"; 1360 1361 /** 1362 * Default value to the {@link #INDEX_REGULAR_CURRENT_DRAIN_THRESHOLD} of 1363 * the {@link #mBgCurrentDrainRestrictedBucketThreshold}. 1364 */ 1365 final float mDefaultBgCurrentDrainRestrictedBucket; 1366 1367 /** 1368 * Default value to the {@link #INDEX_REGULAR_CURRENT_DRAIN_THRESHOLD} of 1369 * the {@link #mBgCurrentDrainBgRestrictedThreshold}. 1370 */ 1371 final float mDefaultBgCurrentDrainBgRestrictedThreshold; 1372 1373 /** 1374 * Default value to {@link #mBgCurrentDrainWindowMs}. 1375 */ 1376 final long mDefaultBgCurrentDrainWindowMs; 1377 1378 /** 1379 * Default value to {@link #mBgCurrentDrainInteractionGracePeriodMs}. 1380 */ 1381 final long mDefaultBgCurrentDrainInteractionGracePeriodMs; 1382 1383 /** 1384 * Default value to the {@link #INDEX_HIGH_CURRENT_DRAIN_THRESHOLD} of 1385 * the {@link #mBgCurrentDrainRestrictedBucketThreshold}. 1386 */ 1387 final float mDefaultBgCurrentDrainRestrictedBucketHighThreshold; 1388 1389 /** 1390 * Default value to the {@link #INDEX_HIGH_CURRENT_DRAIN_THRESHOLD} of 1391 * the {@link #mBgCurrentDrainBgRestrictedThreshold}. 1392 */ 1393 final float mDefaultBgCurrentDrainBgRestrictedHighThreshold; 1394 1395 /** 1396 * Default value to {@link #mBgCurrentDrainMediaPlaybackMinDuration}. 1397 */ 1398 final long mDefaultBgCurrentDrainMediaPlaybackMinDuration; 1399 1400 /** 1401 * Default value to {@link #mBgCurrentDrainLocationMinDuration}. 1402 */ 1403 final long mDefaultBgCurrentDrainLocationMinDuration; 1404 1405 /** 1406 * Default value to {@link #mBgCurrentDrainEventDurationBasedThresholdEnabled}. 1407 */ 1408 final boolean mDefaultBgCurrentDrainEventDurationBasedThresholdEnabled; 1409 1410 /** 1411 * Default value to {@link #mBgCurrentDrainAutoRestrictAbusiveAppsEnabled}. 1412 */ 1413 final boolean mDefaultBgCurrentDrainAutoRestrictAbusiveAppsEnabled; 1414 1415 /** 1416 * Default value to {@link #mBgCurrentDrainRestrictedBucketTypes}. 1417 */ 1418 final int mDefaultCurrentDrainTypesToRestrictedBucket; 1419 1420 /** 1421 * Default value to {@link #mBgCurrentDrainBgRestrictedTypes}. 1422 */ 1423 final int mDefaultBgCurrentDrainTypesToBgRestricted; 1424 1425 /** 1426 * Default value to {@link #mBgCurrentDrainPowerComponents}. 1427 **/ 1428 @BatteryConsumer.PowerComponent 1429 static final int DEFAULT_BG_CURRENT_DRAIN_POWER_COMPONENTS = POWER_COMPONENT_ANY; 1430 1431 final int mDefaultBgCurrentDrainPowerComponent; 1432 1433 /** 1434 * Default value to {@link #mBgCurrentDrainExemptedTypes}. 1435 **/ 1436 final int mDefaultBgCurrentDrainExemptedTypes; 1437 1438 /** 1439 * Default value to {@link #mBgCurrentDrainHighThresholdByBgLocation}. 1440 */ 1441 final boolean mDefaultBgCurrentDrainHighThresholdByBgLocation; 1442 1443 /** 1444 * Default value to {@link #mBgCurrentDrainDecoupleThresholds}. 1445 */ 1446 static final boolean DEFAULT_BG_CURRENT_DRAIN_DECOUPLE_THRESHOLD = true; 1447 1448 /** 1449 * The index to {@link #mBgCurrentDrainRestrictedBucketThreshold} 1450 * and {@link #mBgCurrentDrainBgRestrictedThreshold}. 1451 */ 1452 static final int INDEX_REGULAR_CURRENT_DRAIN_THRESHOLD = 0; 1453 static final int INDEX_HIGH_CURRENT_DRAIN_THRESHOLD = 1; 1454 1455 /** 1456 * @see #KEY_BG_CURRENT_DRAIN_THRESHOLD_TO_RESTRICTED_BUCKET. 1457 * @see #KEY_BG_CURRENT_DRAIN_HIGH_THRESHOLD_TO_RESTRICTED_BUCKET. 1458 */ 1459 volatile float[] mBgCurrentDrainRestrictedBucketThreshold = new float[2]; 1460 1461 /** 1462 * @see #KEY_BG_CURRENT_DRAIN_THRESHOLD_TO_BG_RESTRICTED. 1463 * @see #KEY_BG_CURRENT_DRAIN_HIGH_THRESHOLD_TO_BG_RESTRICTED. 1464 */ 1465 volatile float[] mBgCurrentDrainBgRestrictedThreshold = new float[2]; 1466 1467 /** 1468 * @see #KEY_BG_CURRENT_DRAIN_WINDOW. 1469 */ 1470 volatile long mBgCurrentDrainWindowMs; 1471 1472 /** 1473 * @see #KEY_BG_CURRENT_DRAIN_INTERACTION_GRACE_PERIOD. 1474 */ 1475 volatile long mBgCurrentDrainInteractionGracePeriodMs; 1476 1477 /** 1478 * @see #KEY_BG_CURRENT_DRAIN_MEDIA_PLAYBACK_MIN_DURATION. 1479 */ 1480 volatile long mBgCurrentDrainMediaPlaybackMinDuration; 1481 1482 /** 1483 * @see #KEY_BG_CURRENT_DRAIN_LOCATION_MIN_DURATION. 1484 */ 1485 volatile long mBgCurrentDrainLocationMinDuration; 1486 1487 /** 1488 * @see #KEY_BG_CURRENT_DRAIN_EVENT_DURATION_BASED_THRESHOLD_ENABLED. 1489 */ 1490 volatile boolean mBgCurrentDrainEventDurationBasedThresholdEnabled; 1491 1492 /** 1493 * @see #KEY_BG_CURRENT_DRAIN_AUTO_RESTRICT_ABUSIVE_APPS_ENABLED. 1494 */ 1495 volatile boolean mBgCurrentDrainAutoRestrictAbusiveAppsEnabled; 1496 1497 /** 1498 * @see #KEY_BG_CURRENT_DRAIN_TYPES_TO_RESTRICTED_BUCKET. 1499 */ 1500 volatile int mBgCurrentDrainRestrictedBucketTypes; 1501 1502 /** 1503 * @see #KEY_BG_CURRENT_DRAIN_TYPES_TO_BG_RESTRICTED. 1504 */ 1505 volatile int mBgCurrentDrainBgRestrictedTypes; 1506 1507 /** 1508 * @see #KEY_BG_CURRENT_DRAIN_POWER_COMPONENTS. 1509 */ 1510 @BatteryConsumer.PowerComponent 1511 volatile int mBgCurrentDrainPowerComponents; 1512 1513 volatile Dimensions[] mBatteryDimensions; 1514 1515 /** 1516 * @see #KEY_BG_CURRENT_DRAIN_EXEMPTED_TYPES. 1517 */ 1518 volatile int mBgCurrentDrainExemptedTypes; 1519 1520 /** 1521 * @see #KEY_BG_CURRENT_DRAIN_HIGH_THRESHOLD_BY_BG_LOCATION. 1522 */ 1523 volatile boolean mBgCurrentDrainHighThresholdByBgLocation; 1524 1525 /** 1526 * @see #KEY_BG_CURRENT_DRAIN_DECOUPLE_THRESHOLDS. 1527 */ 1528 volatile boolean mBgCurrentDrainDecoupleThresholds; 1529 1530 /** 1531 * The capacity of the battery when fully charged in mAh. 1532 */ 1533 private int mBatteryFullChargeMah; 1534 1535 /** 1536 * List of the packages with significant background battery usage, key is the UID of 1537 * the package and value is the pair of {timestamp[], battery usage snapshot[]} 1538 * when the UID is found guilty and should be moved to the next level of restriction. 1539 */ 1540 @GuardedBy("mLock") 1541 private final SparseArray<Pair<long[], ImmutableBatteryUsage[]>> mHighBgBatteryPackages = 1542 new SparseArray<>(); 1543 1544 /** 1545 * The timestamp of the last interaction, key is the UID. 1546 */ 1547 @GuardedBy("mLock") 1548 private final SparseLongArray mLastInteractionTime = new SparseLongArray(); 1549 1550 @NonNull 1551 private final Object mLock; 1552 1553 private static final int TIME_STAMP_INDEX_RESTRICTED_BUCKET = 0; 1554 private static final int TIME_STAMP_INDEX_BG_RESTRICTED = 1; 1555 private static final int TIME_STAMP_INDEX_LAST = 2; 1556 AppBatteryPolicy(@onNull Injector injector, @NonNull AppBatteryTracker tracker)1557 AppBatteryPolicy(@NonNull Injector injector, @NonNull AppBatteryTracker tracker) { 1558 super(injector, tracker, KEY_BG_CURRENT_DRAIN_MONITOR_ENABLED, 1559 tracker.mContext.getResources() 1560 .getBoolean(R.bool.config_bg_current_drain_monitor_enabled)); 1561 mLock = tracker.mLock; 1562 final Resources resources = tracker.mContext.getResources(); 1563 float[] val = getFloatArray(resources.obtainTypedArray( 1564 R.array.config_bg_current_drain_threshold_to_restricted_bucket)); 1565 mDefaultBgCurrentDrainRestrictedBucket = 1566 isLowRamDeviceStatic() ? val[1] : val[0]; 1567 val = getFloatArray(resources.obtainTypedArray( 1568 R.array.config_bg_current_drain_threshold_to_bg_restricted)); 1569 mDefaultBgCurrentDrainBgRestrictedThreshold = 1570 isLowRamDeviceStatic() ? val[1] : val[0]; 1571 mDefaultBgCurrentDrainWindowMs = resources.getInteger( 1572 R.integer.config_bg_current_drain_window) * 1_000; 1573 mDefaultBgCurrentDrainInteractionGracePeriodMs = mDefaultBgCurrentDrainWindowMs; 1574 val = getFloatArray(resources.obtainTypedArray( 1575 R.array.config_bg_current_drain_high_threshold_to_restricted_bucket)); 1576 mDefaultBgCurrentDrainRestrictedBucketHighThreshold = 1577 isLowRamDeviceStatic() ? val[1] : val[0]; 1578 val = getFloatArray(resources.obtainTypedArray( 1579 R.array.config_bg_current_drain_high_threshold_to_bg_restricted)); 1580 mDefaultBgCurrentDrainBgRestrictedHighThreshold = 1581 isLowRamDeviceStatic() ? val[1] : val[0]; 1582 mDefaultBgCurrentDrainMediaPlaybackMinDuration = resources.getInteger( 1583 R.integer.config_bg_current_drain_media_playback_min_duration) * 1_000; 1584 mDefaultBgCurrentDrainLocationMinDuration = resources.getInteger( 1585 R.integer.config_bg_current_drain_location_min_duration) * 1_000; 1586 mDefaultBgCurrentDrainEventDurationBasedThresholdEnabled = resources.getBoolean( 1587 R.bool.config_bg_current_drain_event_duration_based_threshold_enabled); 1588 mDefaultBgCurrentDrainAutoRestrictAbusiveAppsEnabled = resources.getBoolean( 1589 R.bool.config_bg_current_drain_auto_restrict_abusive_apps); 1590 mDefaultCurrentDrainTypesToRestrictedBucket = resources.getInteger( 1591 R.integer.config_bg_current_drain_types_to_restricted_bucket); 1592 mDefaultBgCurrentDrainTypesToBgRestricted = resources.getInteger( 1593 R.integer.config_bg_current_drain_types_to_bg_restricted); 1594 mDefaultBgCurrentDrainPowerComponent = resources.getInteger( 1595 R.integer.config_bg_current_drain_power_components); 1596 mDefaultBgCurrentDrainExemptedTypes = resources.getInteger( 1597 R.integer.config_bg_current_drain_exempted_types); 1598 mDefaultBgCurrentDrainHighThresholdByBgLocation = resources.getBoolean( 1599 R.bool.config_bg_current_drain_high_threshold_by_bg_location); 1600 mBgCurrentDrainRestrictedBucketThreshold[0] = 1601 mDefaultBgCurrentDrainRestrictedBucket; 1602 mBgCurrentDrainRestrictedBucketThreshold[1] = 1603 mDefaultBgCurrentDrainRestrictedBucketHighThreshold; 1604 mBgCurrentDrainBgRestrictedThreshold[0] = 1605 mDefaultBgCurrentDrainBgRestrictedThreshold; 1606 mBgCurrentDrainBgRestrictedThreshold[1] = 1607 mDefaultBgCurrentDrainBgRestrictedHighThreshold; 1608 mBgCurrentDrainWindowMs = mDefaultBgCurrentDrainWindowMs; 1609 mBgCurrentDrainInteractionGracePeriodMs = 1610 mDefaultBgCurrentDrainInteractionGracePeriodMs; 1611 mBgCurrentDrainMediaPlaybackMinDuration = 1612 mDefaultBgCurrentDrainMediaPlaybackMinDuration; 1613 mBgCurrentDrainLocationMinDuration = mDefaultBgCurrentDrainLocationMinDuration; 1614 } 1615 getFloatArray(TypedArray array)1616 static float[] getFloatArray(TypedArray array) { 1617 int length = array.length(); 1618 float[] floatArray = new float[length]; 1619 for (int i = 0; i < length; i++) { 1620 floatArray[i] = array.getFloat(i, Float.NaN); 1621 } 1622 array.recycle(); 1623 return floatArray; 1624 } 1625 1626 @Override onPropertiesChanged(String name)1627 public void onPropertiesChanged(String name) { 1628 switch (name) { 1629 case KEY_BG_CURRENT_DRAIN_THRESHOLD_TO_RESTRICTED_BUCKET: 1630 case KEY_BG_CURRENT_DRAIN_THRESHOLD_TO_BG_RESTRICTED: 1631 case KEY_BG_CURRENT_DRAIN_HIGH_THRESHOLD_BY_BG_LOCATION: 1632 case KEY_BG_CURRENT_DRAIN_HIGH_THRESHOLD_TO_RESTRICTED_BUCKET: 1633 case KEY_BG_CURRENT_DRAIN_HIGH_THRESHOLD_TO_BG_RESTRICTED: 1634 case KEY_BG_CURRENT_DRAIN_TYPES_TO_RESTRICTED_BUCKET: 1635 case KEY_BG_CURRENT_DRAIN_TYPES_TO_BG_RESTRICTED: 1636 case KEY_BG_CURRENT_DRAIN_POWER_COMPONENTS: 1637 updateCurrentDrainThreshold(); 1638 break; 1639 case KEY_BG_CURRENT_DRAIN_AUTO_RESTRICT_ABUSIVE_APPS_ENABLED: 1640 updateBgCurrentDrainAutoRestrictAbusiveAppsEnabled(); 1641 break; 1642 case KEY_BG_CURRENT_DRAIN_WINDOW: 1643 updateCurrentDrainWindow(); 1644 break; 1645 case KEY_BG_CURRENT_DRAIN_INTERACTION_GRACE_PERIOD: 1646 updateCurrentDrainInteractionGracePeriod(); 1647 break; 1648 case KEY_BG_CURRENT_DRAIN_MEDIA_PLAYBACK_MIN_DURATION: 1649 updateCurrentDrainMediaPlaybackMinDuration(); 1650 break; 1651 case KEY_BG_CURRENT_DRAIN_LOCATION_MIN_DURATION: 1652 updateCurrentDrainLocationMinDuration(); 1653 break; 1654 case KEY_BG_CURRENT_DRAIN_EVENT_DURATION_BASED_THRESHOLD_ENABLED: 1655 updateCurrentDrainEventDurationBasedThresholdEnabled(); 1656 break; 1657 case KEY_BG_CURRENT_DRAIN_EXEMPTED_TYPES: 1658 updateCurrentDrainExemptedTypes(); 1659 break; 1660 case KEY_BG_CURRENT_DRAIN_DECOUPLE_THRESHOLDS: 1661 updateCurrentDrainDecoupleThresholds(); 1662 break; 1663 default: 1664 super.onPropertiesChanged(name); 1665 break; 1666 } 1667 } 1668 updateTrackerEnabled()1669 void updateTrackerEnabled() { 1670 if (mBatteryFullChargeMah > 0) { 1671 super.updateTrackerEnabled(); 1672 } else { 1673 mTrackerEnabled = false; 1674 onTrackerEnabled(false); 1675 } 1676 } 1677 onTrackerEnabled(boolean enabled)1678 public void onTrackerEnabled(boolean enabled) { 1679 mTracker.onCurrentDrainMonitorEnabled(enabled); 1680 } 1681 updateCurrentDrainThreshold()1682 private void updateCurrentDrainThreshold() { 1683 mBgCurrentDrainRestrictedBucketThreshold[INDEX_REGULAR_CURRENT_DRAIN_THRESHOLD] = 1684 DeviceConfig.getFloat(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, 1685 KEY_BG_CURRENT_DRAIN_THRESHOLD_TO_RESTRICTED_BUCKET, 1686 mDefaultBgCurrentDrainRestrictedBucket); 1687 mBgCurrentDrainRestrictedBucketThreshold[INDEX_HIGH_CURRENT_DRAIN_THRESHOLD] = 1688 DeviceConfig.getFloat(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, 1689 KEY_BG_CURRENT_DRAIN_HIGH_THRESHOLD_TO_RESTRICTED_BUCKET, 1690 mDefaultBgCurrentDrainRestrictedBucketHighThreshold); 1691 mBgCurrentDrainBgRestrictedThreshold[INDEX_REGULAR_CURRENT_DRAIN_THRESHOLD] = 1692 DeviceConfig.getFloat(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, 1693 KEY_BG_CURRENT_DRAIN_THRESHOLD_TO_BG_RESTRICTED, 1694 mDefaultBgCurrentDrainBgRestrictedThreshold); 1695 mBgCurrentDrainBgRestrictedThreshold[INDEX_HIGH_CURRENT_DRAIN_THRESHOLD] = 1696 DeviceConfig.getFloat(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, 1697 KEY_BG_CURRENT_DRAIN_HIGH_THRESHOLD_TO_BG_RESTRICTED, 1698 mDefaultBgCurrentDrainBgRestrictedHighThreshold); 1699 mBgCurrentDrainRestrictedBucketTypes = 1700 DeviceConfig.getInt(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, 1701 KEY_BG_CURRENT_DRAIN_TYPES_TO_RESTRICTED_BUCKET, 1702 mDefaultCurrentDrainTypesToRestrictedBucket); 1703 mBgCurrentDrainBgRestrictedTypes = 1704 DeviceConfig.getInt(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, 1705 KEY_BG_CURRENT_DRAIN_TYPES_TO_BG_RESTRICTED, 1706 mDefaultBgCurrentDrainTypesToBgRestricted); 1707 mBgCurrentDrainPowerComponents = 1708 DeviceConfig.getInt(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, 1709 KEY_BG_CURRENT_DRAIN_POWER_COMPONENTS, 1710 mDefaultBgCurrentDrainPowerComponent); 1711 if (mBgCurrentDrainPowerComponents == DEFAULT_BG_CURRENT_DRAIN_POWER_COMPONENTS) { 1712 mBatteryDimensions = BatteryUsage.BATT_DIMENS; 1713 } else { 1714 mBatteryDimensions = new Dimensions[BatteryUsage.BATTERY_USAGE_COUNT]; 1715 for (int i = 0; i < BatteryUsage.BATTERY_USAGE_COUNT; i++) { 1716 mBatteryDimensions[i] = new Dimensions(mBgCurrentDrainPowerComponents, i); 1717 } 1718 } 1719 mBgCurrentDrainHighThresholdByBgLocation = 1720 DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, 1721 KEY_BG_CURRENT_DRAIN_HIGH_THRESHOLD_BY_BG_LOCATION, 1722 mDefaultBgCurrentDrainHighThresholdByBgLocation); 1723 } 1724 updateCurrentDrainWindow()1725 private void updateCurrentDrainWindow() { 1726 mBgCurrentDrainWindowMs = DeviceConfig.getLong( 1727 DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, 1728 KEY_BG_CURRENT_DRAIN_WINDOW, 1729 mDefaultBgCurrentDrainWindowMs); 1730 } 1731 updateCurrentDrainInteractionGracePeriod()1732 private void updateCurrentDrainInteractionGracePeriod() { 1733 mBgCurrentDrainInteractionGracePeriodMs = DeviceConfig.getLong( 1734 DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, 1735 KEY_BG_CURRENT_DRAIN_INTERACTION_GRACE_PERIOD, 1736 mDefaultBgCurrentDrainInteractionGracePeriodMs); 1737 } 1738 updateCurrentDrainMediaPlaybackMinDuration()1739 private void updateCurrentDrainMediaPlaybackMinDuration() { 1740 mBgCurrentDrainMediaPlaybackMinDuration = DeviceConfig.getLong( 1741 DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, 1742 KEY_BG_CURRENT_DRAIN_MEDIA_PLAYBACK_MIN_DURATION, 1743 mDefaultBgCurrentDrainMediaPlaybackMinDuration); 1744 } 1745 updateCurrentDrainLocationMinDuration()1746 private void updateCurrentDrainLocationMinDuration() { 1747 mBgCurrentDrainLocationMinDuration = DeviceConfig.getLong( 1748 DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, 1749 KEY_BG_CURRENT_DRAIN_LOCATION_MIN_DURATION, 1750 mDefaultBgCurrentDrainLocationMinDuration); 1751 } 1752 updateCurrentDrainEventDurationBasedThresholdEnabled()1753 private void updateCurrentDrainEventDurationBasedThresholdEnabled() { 1754 mBgCurrentDrainEventDurationBasedThresholdEnabled = DeviceConfig.getBoolean( 1755 DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, 1756 KEY_BG_CURRENT_DRAIN_EVENT_DURATION_BASED_THRESHOLD_ENABLED, 1757 mDefaultBgCurrentDrainEventDurationBasedThresholdEnabled); 1758 } 1759 updateCurrentDrainExemptedTypes()1760 private void updateCurrentDrainExemptedTypes() { 1761 mBgCurrentDrainExemptedTypes = DeviceConfig.getInt( 1762 DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, 1763 KEY_BG_CURRENT_DRAIN_EXEMPTED_TYPES, 1764 mDefaultBgCurrentDrainExemptedTypes); 1765 } 1766 updateCurrentDrainDecoupleThresholds()1767 private void updateCurrentDrainDecoupleThresholds() { 1768 mBgCurrentDrainDecoupleThresholds = DeviceConfig.getBoolean( 1769 DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, 1770 KEY_BG_CURRENT_DRAIN_DECOUPLE_THRESHOLDS, 1771 DEFAULT_BG_CURRENT_DRAIN_DECOUPLE_THRESHOLD); 1772 } 1773 updateBgCurrentDrainAutoRestrictAbusiveAppsEnabled()1774 private void updateBgCurrentDrainAutoRestrictAbusiveAppsEnabled() { 1775 mBgCurrentDrainAutoRestrictAbusiveAppsEnabled = DeviceConfig.getBoolean( 1776 DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, 1777 KEY_BG_CURRENT_DRAIN_AUTO_RESTRICT_ABUSIVE_APPS_ENABLED, 1778 mDefaultBgCurrentDrainAutoRestrictAbusiveAppsEnabled); 1779 } 1780 1781 @Override onSystemReady()1782 public void onSystemReady() { 1783 mBatteryFullChargeMah = 1784 mInjector.getBatteryManagerInternal().getBatteryFullCharge() / 1000; 1785 super.onSystemReady(); 1786 updateCurrentDrainThreshold(); 1787 updateCurrentDrainWindow(); 1788 updateCurrentDrainInteractionGracePeriod(); 1789 updateCurrentDrainMediaPlaybackMinDuration(); 1790 updateCurrentDrainLocationMinDuration(); 1791 updateCurrentDrainEventDurationBasedThresholdEnabled(); 1792 updateCurrentDrainExemptedTypes(); 1793 updateCurrentDrainDecoupleThresholds(); 1794 updateBgCurrentDrainAutoRestrictAbusiveAppsEnabled(); 1795 } 1796 1797 @Override 1798 @RestrictionLevel getProposedRestrictionLevel(String packageName, int uid, @RestrictionLevel int maxLevel)1799 public int getProposedRestrictionLevel(String packageName, int uid, 1800 @RestrictionLevel int maxLevel) { 1801 if (maxLevel <= RESTRICTION_LEVEL_ADAPTIVE_BUCKET) { 1802 return RESTRICTION_LEVEL_UNKNOWN; 1803 } 1804 synchronized (mLock) { 1805 final Pair<long[], ImmutableBatteryUsage[]> pair = mHighBgBatteryPackages.get(uid); 1806 if (pair != null) { 1807 final long lastInteractionTime = mLastInteractionTime.get(uid, 0L); 1808 final long[] ts = pair.first; 1809 final boolean noInteractionRecently = ts[TIME_STAMP_INDEX_RESTRICTED_BUCKET] 1810 > (lastInteractionTime + mBgCurrentDrainInteractionGracePeriodMs); 1811 final boolean canRestrict = 1812 mTracker.mAppRestrictionController.isAutoRestrictAbusiveAppEnabled() 1813 && mBgCurrentDrainAutoRestrictAbusiveAppsEnabled; 1814 final int restrictedLevel = noInteractionRecently && canRestrict 1815 ? RESTRICTION_LEVEL_RESTRICTED_BUCKET 1816 : RESTRICTION_LEVEL_ADAPTIVE_BUCKET; 1817 if (maxLevel > RESTRICTION_LEVEL_BACKGROUND_RESTRICTED) { 1818 return ts[TIME_STAMP_INDEX_BG_RESTRICTED] > 0 1819 ? RESTRICTION_LEVEL_BACKGROUND_RESTRICTED : restrictedLevel; 1820 } else if (maxLevel == RESTRICTION_LEVEL_BACKGROUND_RESTRICTED) { 1821 return restrictedLevel; 1822 } 1823 } 1824 return RESTRICTION_LEVEL_ADAPTIVE_BUCKET; 1825 } 1826 } 1827 calcPercentage(final int uid, final double[] usage, double[] percentage)1828 double[] calcPercentage(final int uid, final double[] usage, double[] percentage) { 1829 final BatteryUsage debugUsage = uid > 0 ? mTracker.mDebugUidPercentages.get(uid) : null; 1830 final double[] forced = debugUsage != null ? debugUsage.getPercentage() : null; 1831 for (int i = 0; i < usage.length; i++) { 1832 percentage[i] = forced != null ? forced[i] : usage[i] / mBatteryFullChargeMah * 100; 1833 } 1834 return percentage; 1835 } 1836 sumPercentageOfTypes(double[] percentage, int types)1837 private double sumPercentageOfTypes(double[] percentage, int types) { 1838 double result = 0.0d; 1839 for (int type = Integer.highestOneBit(types); type != 0; 1840 type = Integer.highestOneBit(types)) { 1841 final int index = Integer.numberOfTrailingZeros(type); 1842 result += percentage[index]; 1843 types &= ~type; 1844 } 1845 return result; 1846 } 1847 batteryUsageTypesToString(int types)1848 private static String batteryUsageTypesToString(int types) { 1849 final StringBuilder sb = new StringBuilder("["); 1850 boolean needDelimiter = false; 1851 for (int type = Integer.highestOneBit(types); type != 0; 1852 type = Integer.highestOneBit(types)) { 1853 if (needDelimiter) { 1854 sb.append('|'); 1855 } 1856 needDelimiter = true; 1857 switch (type) { 1858 case BATTERY_USAGE_TYPE_UNSPECIFIED: 1859 sb.append("UNSPECIFIED"); 1860 break; 1861 case BATTERY_USAGE_TYPE_FOREGROUND: 1862 sb.append("FOREGROUND"); 1863 break; 1864 case BATTERY_USAGE_TYPE_BACKGROUND: 1865 sb.append("BACKGROUND"); 1866 break; 1867 case BATTERY_USAGE_TYPE_FOREGROUND_SERVICE: 1868 sb.append("FOREGROUND_SERVICE"); 1869 break; 1870 case BATTERY_USAGE_TYPE_CACHED: 1871 sb.append("CACHED"); 1872 break; 1873 default: 1874 return "[UNKNOWN(" + Integer.toHexString(types) + ")]"; 1875 } 1876 types &= ~type; 1877 } 1878 sb.append("]"); 1879 return sb.toString(); 1880 } 1881 handleUidBatteryUsage(final int uid, final ImmutableBatteryUsage usage)1882 void handleUidBatteryUsage(final int uid, final ImmutableBatteryUsage usage) { 1883 final @ReasonCode int reason = shouldExemptUid(uid); 1884 if (reason != REASON_DENIED) { 1885 if (DEBUG_BACKGROUND_BATTERY_TRACKER_VERBOSE && !BATTERY_USAGE_NONE.equals(usage)) { 1886 Slog.i(TAG, "Exempting battery usage in " + UserHandle.formatUid(uid) 1887 + " " + PowerExemptionManager.reasonCodeToString(reason)); 1888 } 1889 return; 1890 } 1891 boolean notifyController = false; 1892 boolean excessive = false; 1893 int index = 0; 1894 final double rbPercentage = sumPercentageOfTypes(usage.getPercentage(), 1895 mBgCurrentDrainRestrictedBucketTypes); 1896 final double brPercentage = sumPercentageOfTypes(usage.getPercentage(), 1897 mBgCurrentDrainBgRestrictedTypes); 1898 synchronized (mLock) { 1899 final int curLevel = mTracker.mAppRestrictionController.getRestrictionLevel(uid); 1900 if (curLevel >= RESTRICTION_LEVEL_BACKGROUND_RESTRICTED) { 1901 // We're already in the background restricted level, nothing more we could do. 1902 return; 1903 } 1904 final long lastInteractionTime = mLastInteractionTime.get(uid, 0L); 1905 final long now = SystemClock.elapsedRealtime(); 1906 final int thresholdIndex = getCurrentDrainThresholdIndex(uid, now, 1907 mBgCurrentDrainWindowMs); 1908 index = mHighBgBatteryPackages.indexOfKey(uid); 1909 final boolean decoupleThresholds = mBgCurrentDrainDecoupleThresholds; 1910 final double rbThreshold = mBgCurrentDrainRestrictedBucketThreshold[thresholdIndex]; 1911 final double brThreshold = mBgCurrentDrainBgRestrictedThreshold[thresholdIndex]; 1912 if (index < 0) { 1913 long[] ts = null; 1914 ImmutableBatteryUsage[] usages = null; 1915 if (rbPercentage >= rbThreshold) { 1916 if (now > lastInteractionTime + mBgCurrentDrainInteractionGracePeriodMs) { 1917 // New findings to us, track it and let the controller know. 1918 ts = new long[TIME_STAMP_INDEX_LAST]; 1919 ts[TIME_STAMP_INDEX_RESTRICTED_BUCKET] = now; 1920 usages = new ImmutableBatteryUsage[TIME_STAMP_INDEX_LAST]; 1921 usages[TIME_STAMP_INDEX_RESTRICTED_BUCKET] = usage; 1922 mHighBgBatteryPackages.put(uid, Pair.create(ts, usages)); 1923 // It's beeen long enough since last interaction with this app. 1924 notifyController = true; 1925 } 1926 excessive = true; 1927 } 1928 if (decoupleThresholds && brPercentage >= brThreshold) { 1929 if (ts == null) { 1930 ts = new long[TIME_STAMP_INDEX_LAST]; 1931 usages = new ImmutableBatteryUsage[TIME_STAMP_INDEX_LAST]; 1932 mHighBgBatteryPackages.put(uid, Pair.create(ts, usages)); 1933 } 1934 ts[TIME_STAMP_INDEX_BG_RESTRICTED] = now; 1935 usages[TIME_STAMP_INDEX_BG_RESTRICTED] = usage; 1936 notifyController = excessive = true; 1937 } 1938 } else { 1939 final Pair<long[], ImmutableBatteryUsage[]> pair = 1940 mHighBgBatteryPackages.valueAt(index); 1941 final long[] ts = pair.first; 1942 final long lastRestrictBucketTs = ts[TIME_STAMP_INDEX_RESTRICTED_BUCKET]; 1943 if (rbPercentage >= rbThreshold) { 1944 if (now > lastInteractionTime + mBgCurrentDrainInteractionGracePeriodMs) { 1945 if (lastRestrictBucketTs == 0) { 1946 ts[TIME_STAMP_INDEX_RESTRICTED_BUCKET] = now; 1947 pair.second[TIME_STAMP_INDEX_RESTRICTED_BUCKET] = usage; 1948 } 1949 // It's been long enough since last interaction with this app. 1950 notifyController = true; 1951 } 1952 excessive = true; 1953 } else { 1954 // It's actually back to normal, but we don't untrack it until 1955 // explicit user interactions, because the restriction could be the cause 1956 // of going back to normal. 1957 } 1958 if (brPercentage >= brThreshold) { 1959 // If either 1960 // a) It's configured to goto threshold 2 directly without threshold 1; 1961 // b) It's already in the restricted standby bucket, but still seeing 1962 // high current drains, and it's been a while since it's restricted; 1963 // tell the controller. 1964 notifyController = decoupleThresholds 1965 || (curLevel == RESTRICTION_LEVEL_RESTRICTED_BUCKET 1966 && (now > lastRestrictBucketTs + mBgCurrentDrainWindowMs)); 1967 if (notifyController) { 1968 ts[TIME_STAMP_INDEX_BG_RESTRICTED] = now; 1969 pair.second[TIME_STAMP_INDEX_BG_RESTRICTED] = usage; 1970 } 1971 excessive = true; 1972 } else { 1973 // Reset the track now - if it's already background restricted, it requires 1974 // user consent to unrestrict it; or if it's in restricted bucket level, 1975 // resetting this won't lift it from that level. 1976 ts[TIME_STAMP_INDEX_BG_RESTRICTED] = 0; 1977 pair.second[TIME_STAMP_INDEX_BG_RESTRICTED] = null; 1978 // Now need to notify the controller. 1979 } 1980 } 1981 } 1982 1983 if (excessive) { 1984 if (DEBUG_BACKGROUND_BATTERY_TRACKER_VERBOSE) { 1985 Slog.i(TAG, "Excessive background current drain " + uid + " " 1986 + usage + " (" + usage.percentageToString() + " ) over " 1987 + TimeUtils.formatDuration(mBgCurrentDrainWindowMs)); 1988 } 1989 if (notifyController) { 1990 mTracker.mAppRestrictionController.refreshAppRestrictionLevelForUid( 1991 uid, REASON_MAIN_FORCED_BY_SYSTEM, 1992 REASON_SUB_FORCED_SYSTEM_FLAG_ABUSE, true); 1993 } 1994 } else { 1995 if (DEBUG_BACKGROUND_BATTERY_TRACKER_VERBOSE && index >= 0) { 1996 Slog.i(TAG, "Background current drain backs to normal " + uid + " " 1997 + usage + " (" + usage.percentageToString() + " ) over " 1998 + TimeUtils.formatDuration(mBgCurrentDrainWindowMs)); 1999 } 2000 // For now, we're not lifting the restrictions if the bg current drain backs to 2001 // normal util an explicit user interaction. 2002 } 2003 } 2004 getCurrentDrainThresholdIndex(int uid, long now, long window)2005 private int getCurrentDrainThresholdIndex(int uid, long now, long window) { 2006 return (hasMediaPlayback(uid, now, window) || hasLocation(uid, now, window)) 2007 ? INDEX_HIGH_CURRENT_DRAIN_THRESHOLD 2008 : INDEX_REGULAR_CURRENT_DRAIN_THRESHOLD; 2009 } 2010 hasMediaPlayback(int uid, long now, long window)2011 private boolean hasMediaPlayback(int uid, long now, long window) { 2012 return mBgCurrentDrainEventDurationBasedThresholdEnabled 2013 && mTracker.mAppRestrictionController.getCompositeMediaPlaybackDurations( 2014 uid, now, window) >= mBgCurrentDrainMediaPlaybackMinDuration; 2015 } 2016 hasLocation(int uid, long now, long window)2017 private boolean hasLocation(int uid, long now, long window) { 2018 if (!mBgCurrentDrainHighThresholdByBgLocation) { 2019 return false; 2020 } 2021 if (mTracker.mInjector.checkPermission(ACCESS_BACKGROUND_LOCATION, 2022 Process.INVALID_PID, uid) == PERMISSION_GRANTED) { 2023 return true; 2024 } 2025 if (!mBgCurrentDrainEventDurationBasedThresholdEnabled) { 2026 return false; 2027 } 2028 final long since = Math.max(0, now - window); 2029 final AppRestrictionController controller = mTracker.mAppRestrictionController; 2030 final long locationDuration = controller.getForegroundServiceTotalDurationsSince( 2031 uid, since, now, ServiceInfo.FOREGROUND_SERVICE_TYPE_LOCATION); 2032 return locationDuration >= mBgCurrentDrainLocationMinDuration; 2033 } 2034 onUserInteractionStarted(String packageName, int uid)2035 void onUserInteractionStarted(String packageName, int uid) { 2036 boolean changed = false; 2037 synchronized (mLock) { 2038 mLastInteractionTime.put(uid, SystemClock.elapsedRealtime()); 2039 final int curLevel = mTracker.mAppRestrictionController.getRestrictionLevel( 2040 uid, packageName); 2041 if (curLevel == RESTRICTION_LEVEL_BACKGROUND_RESTRICTED) { 2042 // It's a sticky state, user interaction won't change it, still track it. 2043 } else { 2044 // Remove the given UID from our tracking list, as user interacted with it. 2045 final int index = mHighBgBatteryPackages.indexOfKey(uid); 2046 if (index >= 0) { 2047 mHighBgBatteryPackages.removeAt(index); 2048 changed = true; 2049 } 2050 } 2051 } 2052 if (changed) { 2053 // Request to refresh the app restriction level. 2054 mTracker.mAppRestrictionController.refreshAppRestrictionLevelForUid(uid, 2055 REASON_MAIN_USAGE, REASON_SUB_USAGE_USER_INTERACTION, true); 2056 } 2057 } 2058 onBackgroundRestrictionChanged(int uid, String pkgName, boolean restricted)2059 void onBackgroundRestrictionChanged(int uid, String pkgName, boolean restricted) { 2060 if (restricted) { 2061 return; 2062 } 2063 synchronized (mLock) { 2064 // User has explicitly removed it from background restricted level, 2065 // clear the timestamp of the background-restricted 2066 final Pair<long[], ImmutableBatteryUsage[]> pair = mHighBgBatteryPackages.get(uid); 2067 if (pair != null) { 2068 pair.first[TIME_STAMP_INDEX_BG_RESTRICTED] = 0; 2069 pair.second[TIME_STAMP_INDEX_BG_RESTRICTED] = null; 2070 } 2071 } 2072 } 2073 2074 @VisibleForTesting reset()2075 void reset() { 2076 mHighBgBatteryPackages.clear(); 2077 mLastInteractionTime.clear(); 2078 mTracker.reset(); 2079 } 2080 2081 @GuardedBy("mLock") onUserRemovedLocked(final @UserIdInt int userId)2082 void onUserRemovedLocked(final @UserIdInt int userId) { 2083 for (int i = mHighBgBatteryPackages.size() - 1; i >= 0; i--) { 2084 if (UserHandle.getUserId(mHighBgBatteryPackages.keyAt(i)) == userId) { 2085 mHighBgBatteryPackages.removeAt(i); 2086 } 2087 } 2088 for (int i = mLastInteractionTime.size() - 1; i >= 0; i--) { 2089 if (UserHandle.getUserId(mLastInteractionTime.keyAt(i)) == userId) { 2090 mLastInteractionTime.removeAt(i); 2091 } 2092 } 2093 } 2094 2095 @GuardedBy("mLock") onUidRemovedLocked(final int uid)2096 void onUidRemovedLocked(final int uid) { 2097 mHighBgBatteryPackages.remove(uid); 2098 mLastInteractionTime.delete(uid); 2099 } 2100 2101 @Override dump(PrintWriter pw, String prefix)2102 void dump(PrintWriter pw, String prefix) { 2103 pw.print(prefix); 2104 pw.println("APP BATTERY TRACKER POLICY SETTINGS:"); 2105 final String indent = " "; 2106 prefix = indent + prefix; 2107 super.dump(pw, prefix); 2108 if (isEnabled()) { 2109 pw.print(prefix); 2110 pw.print(KEY_BG_CURRENT_DRAIN_THRESHOLD_TO_RESTRICTED_BUCKET); 2111 pw.print('='); 2112 pw.println(mBgCurrentDrainRestrictedBucketThreshold[ 2113 INDEX_REGULAR_CURRENT_DRAIN_THRESHOLD]); 2114 pw.print(prefix); 2115 pw.print(KEY_BG_CURRENT_DRAIN_HIGH_THRESHOLD_TO_RESTRICTED_BUCKET); 2116 pw.print('='); 2117 pw.println(mBgCurrentDrainRestrictedBucketThreshold[ 2118 INDEX_HIGH_CURRENT_DRAIN_THRESHOLD]); 2119 pw.print(prefix); 2120 pw.print(KEY_BG_CURRENT_DRAIN_THRESHOLD_TO_BG_RESTRICTED); 2121 pw.print('='); 2122 pw.println(mBgCurrentDrainBgRestrictedThreshold[ 2123 INDEX_REGULAR_CURRENT_DRAIN_THRESHOLD]); 2124 pw.print(prefix); 2125 pw.print(KEY_BG_CURRENT_DRAIN_HIGH_THRESHOLD_TO_BG_RESTRICTED); 2126 pw.print('='); 2127 pw.println(mBgCurrentDrainBgRestrictedThreshold[ 2128 INDEX_HIGH_CURRENT_DRAIN_THRESHOLD]); 2129 pw.print(prefix); 2130 pw.print(KEY_BG_CURRENT_DRAIN_WINDOW); 2131 pw.print('='); 2132 pw.println(mBgCurrentDrainWindowMs); 2133 pw.print(prefix); 2134 pw.print(KEY_BG_CURRENT_DRAIN_INTERACTION_GRACE_PERIOD); 2135 pw.print('='); 2136 pw.println(mBgCurrentDrainInteractionGracePeriodMs); 2137 pw.print(prefix); 2138 pw.print(KEY_BG_CURRENT_DRAIN_MEDIA_PLAYBACK_MIN_DURATION); 2139 pw.print('='); 2140 pw.println(mBgCurrentDrainMediaPlaybackMinDuration); 2141 pw.print(prefix); 2142 pw.print(KEY_BG_CURRENT_DRAIN_LOCATION_MIN_DURATION); 2143 pw.print('='); 2144 pw.println(mBgCurrentDrainLocationMinDuration); 2145 pw.print(prefix); 2146 pw.print(KEY_BG_CURRENT_DRAIN_EVENT_DURATION_BASED_THRESHOLD_ENABLED); 2147 pw.print('='); 2148 pw.println(mBgCurrentDrainEventDurationBasedThresholdEnabled); 2149 pw.print(prefix); 2150 pw.print(KEY_BG_CURRENT_DRAIN_AUTO_RESTRICT_ABUSIVE_APPS_ENABLED); 2151 pw.print('='); 2152 pw.println(mBgCurrentDrainAutoRestrictAbusiveAppsEnabled); 2153 pw.print(prefix); 2154 pw.print(KEY_BG_CURRENT_DRAIN_TYPES_TO_RESTRICTED_BUCKET); 2155 pw.print('='); 2156 pw.println(batteryUsageTypesToString(mBgCurrentDrainRestrictedBucketTypes)); 2157 pw.print(prefix); 2158 pw.print(KEY_BG_CURRENT_DRAIN_TYPES_TO_BG_RESTRICTED); 2159 pw.print('='); 2160 pw.println(batteryUsageTypesToString(mBgCurrentDrainBgRestrictedTypes)); 2161 pw.print(prefix); 2162 pw.print(KEY_BG_CURRENT_DRAIN_POWER_COMPONENTS); 2163 pw.print('='); 2164 pw.println(mBgCurrentDrainPowerComponents); 2165 pw.print(prefix); 2166 pw.print(KEY_BG_CURRENT_DRAIN_EXEMPTED_TYPES); 2167 pw.print('='); 2168 pw.println(BaseAppStateTracker.stateTypesToString(mBgCurrentDrainExemptedTypes)); 2169 pw.print(prefix); 2170 pw.print(KEY_BG_CURRENT_DRAIN_HIGH_THRESHOLD_BY_BG_LOCATION); 2171 pw.print('='); 2172 pw.println(mBgCurrentDrainHighThresholdByBgLocation); 2173 pw.print(prefix); 2174 pw.print("Full charge capacity="); 2175 pw.print(mBatteryFullChargeMah); 2176 pw.println(" mAh"); 2177 2178 pw.print(prefix); 2179 pw.println("Excessive current drain detected:"); 2180 synchronized (mLock) { 2181 final int size = mHighBgBatteryPackages.size(); 2182 prefix = indent + prefix; 2183 if (size > 0) { 2184 final long now = SystemClock.elapsedRealtime(); 2185 for (int i = 0; i < size; i++) { 2186 final int uid = mHighBgBatteryPackages.keyAt(i); 2187 final Pair<long[], ImmutableBatteryUsage[]> pair = 2188 mHighBgBatteryPackages.valueAt(i); 2189 final long[] ts = pair.first; 2190 final ImmutableBatteryUsage[] usages = pair.second; 2191 final int thresholdIndex = getCurrentDrainThresholdIndex(uid, now, 2192 mBgCurrentDrainWindowMs); 2193 pw.format("%s%s: (threshold=%4.2f%%/%4.2f%%) %s / %s\n", 2194 prefix, 2195 UserHandle.formatUid(uid), 2196 mBgCurrentDrainRestrictedBucketThreshold[thresholdIndex], 2197 mBgCurrentDrainBgRestrictedThreshold[thresholdIndex], 2198 formatHighBgBatteryRecord( 2199 ts[TIME_STAMP_INDEX_RESTRICTED_BUCKET], now, 2200 usages[TIME_STAMP_INDEX_RESTRICTED_BUCKET]), 2201 formatHighBgBatteryRecord( 2202 ts[TIME_STAMP_INDEX_BG_RESTRICTED], now, 2203 usages[TIME_STAMP_INDEX_BG_RESTRICTED]) 2204 ); 2205 } 2206 } else { 2207 pw.print(prefix); 2208 pw.println("(none)"); 2209 } 2210 } 2211 } 2212 } 2213 formatHighBgBatteryRecord(long ts, long now, ImmutableBatteryUsage usage)2214 private String formatHighBgBatteryRecord(long ts, long now, ImmutableBatteryUsage usage) { 2215 if (ts > 0 && usage != null) { 2216 return String.format("%s %s (%s)", 2217 formatTime(ts, now), usage.toString(), usage.percentageToString()); 2218 } else { 2219 return "0"; 2220 } 2221 } 2222 } 2223 } 2224