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 // Force an update. 822 updateBatteryUsageStatsIfNecessary(mInjector.currentTimeMillis(), true); 823 // Force a check. 824 scheduleBgBatteryUsageStatsCheck(); 825 // Wait for its completion (as it runs in handler thread for the sake of thread safe) 826 final CountDownLatch latch = new CountDownLatch(1); 827 mBgHandler.getLooper().getQueue().addIdleHandler(() -> { 828 latch.countDown(); 829 return false; 830 }); 831 try { 832 latch.await(); 833 } catch (InterruptedException e) { 834 } 835 synchronized (mLock) { 836 final SparseArray<ImmutableBatteryUsage> uidConsumers = mUidBatteryUsageInWindow; 837 pw.print(" " + prefix); 838 pw.print(" Last battery usage start="); 839 TimeUtils.dumpTime(pw, mLastUidBatteryUsageStartTs); 840 pw.println(); 841 pw.print(" " + prefix); 842 pw.print("Battery usage over last "); 843 final String newPrefix = " " + prefix; 844 final AppBatteryPolicy bgPolicy = mInjector.getPolicy(); 845 final long now = SystemClock.elapsedRealtime(); 846 final long since = Math.max(0, now - bgPolicy.mBgCurrentDrainWindowMs); 847 pw.println(TimeUtils.formatDuration(now - since)); 848 if (uidConsumers.size() == 0) { 849 pw.print(newPrefix); 850 pw.println("(none)"); 851 } else { 852 for (int i = 0, size = uidConsumers.size(); i < size; i++) { 853 final int uid = uidConsumers.keyAt(i); 854 final BatteryUsage bgUsage = uidConsumers.valueAt(i) 855 .calcPercentage(uid, bgPolicy); 856 final BatteryUsage exemptedUsage = mAppRestrictionController 857 .getUidBatteryExemptedUsageSince(uid, since, now, 858 bgPolicy.mBgCurrentDrainExemptedTypes) 859 .calcPercentage(uid, bgPolicy); 860 final BatteryUsage reportedUsage = new BatteryUsage(bgUsage) 861 .subtract(exemptedUsage) 862 .calcPercentage(uid, bgPolicy); 863 pw.format("%s%s: [%s] %s (%s) | %s (%s) | %s (%s) | %s\n", 864 newPrefix, UserHandle.formatUid(uid), 865 PowerExemptionManager.reasonCodeToString(bgPolicy.shouldExemptUid(uid)), 866 bgUsage.toString(), 867 bgUsage.percentageToString(), 868 exemptedUsage.toString(), 869 exemptedUsage.percentageToString(), 870 reportedUsage.toString(), 871 reportedUsage.percentageToString(), 872 mUidBatteryUsage.get(uid, BATTERY_USAGE_NONE).toString()); 873 } 874 } 875 } 876 super.dump(pw, prefix); 877 } 878 879 @Override dumpAsProto(ProtoOutputStream proto, int uid)880 void dumpAsProto(ProtoOutputStream proto, int uid) { 881 // Force an update. 882 updateBatteryUsageStatsIfNecessary(mInjector.currentTimeMillis(), true); 883 synchronized (mLock) { 884 final SparseArray<ImmutableBatteryUsage> uidConsumers = mUidBatteryUsageInWindow; 885 if (uid != android.os.Process.INVALID_UID) { 886 final BatteryUsage usage = uidConsumers.get(uid); 887 if (usage != null) { 888 dumpUidStats(proto, uid, usage); 889 } 890 } else { 891 for (int i = 0, size = uidConsumers.size(); i < size; i++) { 892 final int aUid = uidConsumers.keyAt(i); 893 final BatteryUsage usage = uidConsumers.valueAt(i); 894 dumpUidStats(proto, aUid, usage); 895 } 896 } 897 } 898 } 899 dumpUidStats(ProtoOutputStream proto, int uid, BatteryUsage usage)900 private void dumpUidStats(ProtoOutputStream proto, int uid, BatteryUsage usage) { 901 if (usage.mUsage == null) { 902 return; 903 } 904 905 final double foregroundUsage = usage.getUsagePowerMah(PROCESS_STATE_FOREGROUND); 906 final double backgroundUsage = usage.getUsagePowerMah(PROCESS_STATE_BACKGROUND); 907 final double fgsUsage = usage.getUsagePowerMah(PROCESS_STATE_FOREGROUND_SERVICE); 908 final double cachedUsage = usage.getUsagePowerMah(PROCESS_STATE_CACHED); 909 910 if (foregroundUsage == 0 && backgroundUsage == 0 && fgsUsage == 0) { 911 return; 912 } 913 914 final long token = proto.start(AppBatteryStatsProto.UID_STATS); 915 proto.write(AppBatteryStatsProto.UidStats.UID, uid); 916 dumpProcessStateStats(proto, 917 AppBatteryStatsProto.UidStats.ProcessStateStats.FOREGROUND, 918 foregroundUsage); 919 dumpProcessStateStats(proto, 920 AppBatteryStatsProto.UidStats.ProcessStateStats.BACKGROUND, 921 backgroundUsage); 922 dumpProcessStateStats(proto, 923 AppBatteryStatsProto.UidStats.ProcessStateStats.FOREGROUND_SERVICE, 924 fgsUsage); 925 dumpProcessStateStats(proto, 926 AppBatteryStatsProto.UidStats.ProcessStateStats.CACHED, 927 cachedUsage); 928 proto.end(token); 929 } 930 dumpProcessStateStats(ProtoOutputStream proto, int processState, double powerMah)931 private void dumpProcessStateStats(ProtoOutputStream proto, int processState, double powerMah) { 932 if (powerMah == 0) { 933 return; 934 } 935 936 final long token = proto.start(AppBatteryStatsProto.UidStats.PROCESS_STATE_STATS); 937 proto.write(AppBatteryStatsProto.UidStats.ProcessStateStats.PROCESS_STATE, processState); 938 proto.write(AppBatteryStatsProto.UidStats.ProcessStateStats.POWER_MAH, powerMah); 939 proto.end(token); 940 } 941 942 static class BatteryUsage { 943 static final int BATTERY_USAGE_INDEX_UNSPECIFIED = PROCESS_STATE_UNSPECIFIED; 944 static final int BATTERY_USAGE_INDEX_FOREGROUND = PROCESS_STATE_FOREGROUND; 945 static final int BATTERY_USAGE_INDEX_BACKGROUND = PROCESS_STATE_BACKGROUND; 946 static final int BATTERY_USAGE_INDEX_FOREGROUND_SERVICE = PROCESS_STATE_FOREGROUND_SERVICE; 947 static final int BATTERY_USAGE_INDEX_CACHED = PROCESS_STATE_CACHED; 948 static final int BATTERY_USAGE_COUNT = PROCESS_STATE_COUNT; 949 950 static final Dimensions[] BATT_DIMENS = new Dimensions[] { 951 new Dimensions(AppBatteryPolicy.DEFAULT_BG_CURRENT_DRAIN_POWER_COMPONENTS, 952 PROCESS_STATE_UNSPECIFIED), 953 new Dimensions(AppBatteryPolicy.DEFAULT_BG_CURRENT_DRAIN_POWER_COMPONENTS, 954 PROCESS_STATE_FOREGROUND), 955 new Dimensions(AppBatteryPolicy.DEFAULT_BG_CURRENT_DRAIN_POWER_COMPONENTS, 956 PROCESS_STATE_BACKGROUND), 957 new Dimensions(AppBatteryPolicy.DEFAULT_BG_CURRENT_DRAIN_POWER_COMPONENTS, 958 PROCESS_STATE_FOREGROUND_SERVICE), 959 new Dimensions(AppBatteryPolicy.DEFAULT_BG_CURRENT_DRAIN_POWER_COMPONENTS, 960 PROCESS_STATE_CACHED), 961 }; 962 963 @NonNull double[] mUsage; 964 @Nullable double[] mPercentage; 965 BatteryUsage()966 BatteryUsage() { 967 this(0.0d, 0.0d, 0.0d, 0.0d, 0.0d); 968 } 969 BatteryUsage(double unspecifiedUsage, double fgUsage, double bgUsage, double fgsUsage, double cachedUsage)970 BatteryUsage(double unspecifiedUsage, double fgUsage, double bgUsage, double fgsUsage, 971 double cachedUsage) { 972 mUsage = new double[] {unspecifiedUsage, fgUsage, bgUsage, fgsUsage, cachedUsage}; 973 } 974 BatteryUsage(@onNull double[] usage)975 BatteryUsage(@NonNull double[] usage) { 976 mUsage = usage; 977 } 978 BatteryUsage(@onNull BatteryUsage other, double scale)979 BatteryUsage(@NonNull BatteryUsage other, double scale) { 980 this(other); 981 scaleInternal(scale); 982 } 983 BatteryUsage(@onNull BatteryUsage other)984 BatteryUsage(@NonNull BatteryUsage other) { 985 mUsage = new double[other.mUsage.length]; 986 setToInternal(other); 987 } 988 BatteryUsage(@onNull UidBatteryConsumer consumer, @NonNull AppBatteryPolicy policy)989 BatteryUsage(@NonNull UidBatteryConsumer consumer, @NonNull AppBatteryPolicy policy) { 990 final Dimensions[] dims = policy.mBatteryDimensions; 991 mUsage = new double[] { 992 getConsumedPowerNoThrow(consumer, dims[BATTERY_USAGE_INDEX_UNSPECIFIED]), 993 getConsumedPowerNoThrow(consumer, dims[BATTERY_USAGE_INDEX_FOREGROUND]), 994 getConsumedPowerNoThrow(consumer, dims[BATTERY_USAGE_INDEX_BACKGROUND]), 995 getConsumedPowerNoThrow(consumer, dims[BATTERY_USAGE_INDEX_FOREGROUND_SERVICE]), 996 getConsumedPowerNoThrow(consumer, dims[BATTERY_USAGE_INDEX_CACHED]), 997 }; 998 } 999 setTo(@onNull BatteryUsage other)1000 BatteryUsage setTo(@NonNull BatteryUsage other) { 1001 return setToInternal(other); 1002 } 1003 setToInternal(@onNull BatteryUsage other)1004 private BatteryUsage setToInternal(@NonNull BatteryUsage other) { 1005 System.arraycopy(other.mUsage, 0, mUsage, 0, other.mUsage.length); 1006 if (other.mPercentage != null) { 1007 mPercentage = new double[other.mPercentage.length]; 1008 System.arraycopy(other.mPercentage, 0, mPercentage, 0, other.mPercentage.length); 1009 } else { 1010 mPercentage = null; 1011 } 1012 return this; 1013 } 1014 add(@onNull BatteryUsage other)1015 BatteryUsage add(@NonNull BatteryUsage other) { 1016 for (int i = 0; i < other.mUsage.length; i++) { 1017 mUsage[i] += other.mUsage[i]; 1018 } 1019 return this; 1020 } 1021 subtract(@onNull BatteryUsage other)1022 BatteryUsage subtract(@NonNull BatteryUsage other) { 1023 for (int i = 0; i < other.mUsage.length; i++) { 1024 mUsage[i] = Math.max(0.0d, mUsage[i] - other.mUsage[i]); 1025 } 1026 return this; 1027 } 1028 scale(double scale)1029 BatteryUsage scale(double scale) { 1030 return scaleInternal(scale); 1031 } 1032 scaleInternal(double scale)1033 private BatteryUsage scaleInternal(double scale) { 1034 for (int i = 0; i < mUsage.length; i++) { 1035 mUsage[i] *= scale; 1036 } 1037 return this; 1038 } 1039 unmutate()1040 ImmutableBatteryUsage unmutate() { 1041 return new ImmutableBatteryUsage(this); 1042 } 1043 calcPercentage(int uid, @NonNull AppBatteryPolicy policy)1044 BatteryUsage calcPercentage(int uid, @NonNull AppBatteryPolicy policy) { 1045 if (mPercentage == null || mPercentage.length != mUsage.length) { 1046 mPercentage = new double[mUsage.length]; 1047 } 1048 policy.calcPercentage(uid, mUsage, mPercentage); 1049 return this; 1050 } 1051 setPercentage(@onNull double[] percentage)1052 BatteryUsage setPercentage(@NonNull double[] percentage) { 1053 mPercentage = percentage; 1054 return this; 1055 } 1056 getPercentage()1057 double[] getPercentage() { 1058 return mPercentage; 1059 } 1060 percentageToString()1061 String percentageToString() { 1062 return formatBatteryUsagePercentage(mPercentage); 1063 } 1064 1065 @Override toString()1066 public String toString() { 1067 return formatBatteryUsage(mUsage); 1068 } 1069 getUsagePowerMah(@atteryConsumer.ProcessState int processState)1070 double getUsagePowerMah(@BatteryConsumer.ProcessState int processState) { 1071 switch (processState) { 1072 case PROCESS_STATE_FOREGROUND: 1073 return mUsage[BATTERY_USAGE_INDEX_FOREGROUND]; 1074 case PROCESS_STATE_BACKGROUND: 1075 return mUsage[BATTERY_USAGE_INDEX_BACKGROUND]; 1076 case PROCESS_STATE_FOREGROUND_SERVICE: 1077 return mUsage[BATTERY_USAGE_INDEX_FOREGROUND_SERVICE]; 1078 case PROCESS_STATE_CACHED: 1079 return mUsage[BATTERY_USAGE_INDEX_CACHED]; 1080 } 1081 return 0; 1082 } 1083 isValid()1084 boolean isValid() { 1085 for (int i = 0; i < mUsage.length; i++) { 1086 if (mUsage[i] < 0.0d) { 1087 return false; 1088 } 1089 } 1090 return true; 1091 } 1092 isEmpty()1093 boolean isEmpty() { 1094 for (int i = 0; i < mUsage.length; i++) { 1095 if (mUsage[i] > 0.0d) { 1096 return false; 1097 } 1098 } 1099 return true; 1100 } 1101 1102 @Override equals(Object other)1103 public boolean equals(Object other) { 1104 if (other == null) { 1105 return false; 1106 } 1107 final BatteryUsage otherUsage = (BatteryUsage) other; 1108 for (int i = 0; i < mUsage.length; i++) { 1109 if (Double.compare(mUsage[i], otherUsage.mUsage[i]) != 0) { 1110 return false; 1111 } 1112 } 1113 return true; 1114 } 1115 1116 @Override hashCode()1117 public int hashCode() { 1118 int hashCode = 0; 1119 for (int i = 0; i < mUsage.length; i++) { 1120 hashCode = Double.hashCode(mUsage[i]) + hashCode * 31; 1121 } 1122 return hashCode; 1123 } 1124 formatBatteryUsage(double[] usage)1125 private static String formatBatteryUsage(double[] usage) { 1126 return String.format("%.3f %.3f %.3f %.3f %.3f mAh", 1127 usage[BATTERY_USAGE_INDEX_UNSPECIFIED], 1128 usage[BATTERY_USAGE_INDEX_FOREGROUND], 1129 usage[BATTERY_USAGE_INDEX_BACKGROUND], 1130 usage[BATTERY_USAGE_INDEX_FOREGROUND_SERVICE], 1131 usage[BATTERY_USAGE_INDEX_CACHED]); 1132 } 1133 formatBatteryUsagePercentage(double[] percentage)1134 static String formatBatteryUsagePercentage(double[] percentage) { 1135 return String.format("%4.2f%% %4.2f%% %4.2f%% %4.2f%% %4.2f%%", 1136 percentage[BATTERY_USAGE_INDEX_UNSPECIFIED], 1137 percentage[BATTERY_USAGE_INDEX_FOREGROUND], 1138 percentage[BATTERY_USAGE_INDEX_BACKGROUND], 1139 percentage[BATTERY_USAGE_INDEX_FOREGROUND_SERVICE], 1140 percentage[BATTERY_USAGE_INDEX_CACHED]); 1141 } 1142 getConsumedPowerNoThrow(final UidBatteryConsumer uidConsumer, final Dimensions dimens)1143 private static double getConsumedPowerNoThrow(final UidBatteryConsumer uidConsumer, 1144 final Dimensions dimens) { 1145 try { 1146 return uidConsumer.getConsumedPower(dimens); 1147 } catch (IllegalArgumentException e) { 1148 return 0.0d; 1149 } 1150 } 1151 } 1152 1153 static final class ImmutableBatteryUsage extends BatteryUsage { ImmutableBatteryUsage()1154 ImmutableBatteryUsage() { 1155 super(); 1156 } 1157 ImmutableBatteryUsage(double unspecifiedUsage, double fgUsage, double bgUsage, double fgsUsage, double cachedUsage)1158 ImmutableBatteryUsage(double unspecifiedUsage, double fgUsage, double bgUsage, 1159 double fgsUsage, double cachedUsage) { 1160 super(unspecifiedUsage, fgUsage, bgUsage, fgsUsage, cachedUsage); 1161 } 1162 ImmutableBatteryUsage(@onNull double[] usage)1163 ImmutableBatteryUsage(@NonNull double[] usage) { 1164 super(usage); 1165 } 1166 ImmutableBatteryUsage(@onNull BatteryUsage other, double scale)1167 ImmutableBatteryUsage(@NonNull BatteryUsage other, double scale) { 1168 super(other, scale); 1169 } 1170 ImmutableBatteryUsage(@onNull BatteryUsage other)1171 ImmutableBatteryUsage(@NonNull BatteryUsage other) { 1172 super(other); 1173 } 1174 ImmutableBatteryUsage(@onNull UidBatteryConsumer consumer, @NonNull AppBatteryPolicy policy)1175 ImmutableBatteryUsage(@NonNull UidBatteryConsumer consumer, 1176 @NonNull AppBatteryPolicy policy) { 1177 super(consumer, policy); 1178 } 1179 1180 @Override setTo(@onNull BatteryUsage other)1181 BatteryUsage setTo(@NonNull BatteryUsage other) { 1182 throw new RuntimeException("Readonly"); 1183 } 1184 1185 @Override add(@onNull BatteryUsage other)1186 BatteryUsage add(@NonNull BatteryUsage other) { 1187 throw new RuntimeException("Readonly"); 1188 } 1189 1190 @Override subtract(@onNull BatteryUsage other)1191 BatteryUsage subtract(@NonNull BatteryUsage other) { 1192 throw new RuntimeException("Readonly"); 1193 } 1194 1195 @Override scale(double scale)1196 BatteryUsage scale(double scale) { 1197 throw new RuntimeException("Readonly"); 1198 } 1199 1200 @Override setPercentage(@onNull double[] percentage)1201 BatteryUsage setPercentage(@NonNull double[] percentage) { 1202 throw new RuntimeException("Readonly"); 1203 } 1204 mutate()1205 BatteryUsage mutate() { 1206 return new BatteryUsage(this); 1207 } 1208 } 1209 1210 static final class AppBatteryPolicy extends BaseAppStatePolicy<AppBatteryTracker> { 1211 /** 1212 * The type of battery usage we could choose to apply the policy on. 1213 * 1214 * Must be in sync with android.os.BatteryConsumer.PROCESS_STATE_*. 1215 */ 1216 static final int BATTERY_USAGE_TYPE_UNSPECIFIED = 1; 1217 static final int BATTERY_USAGE_TYPE_FOREGROUND = 1 << 1; 1218 static final int BATTERY_USAGE_TYPE_BACKGROUND = 1 << 2; 1219 static final int BATTERY_USAGE_TYPE_FOREGROUND_SERVICE = 1 << 3; 1220 static final int BATTERY_USAGE_TYPE_CACHED = 1 << 4; 1221 1222 /** 1223 * Whether or not we should enable the monitoring on background current drains. 1224 */ 1225 static final String KEY_BG_CURRENT_DRAIN_MONITOR_ENABLED = 1226 DEVICE_CONFIG_SUBNAMESPACE_PREFIX + "current_drain_monitor_enabled"; 1227 1228 /** 1229 * The threshold of the background current drain (in percentage) to the restricted 1230 * standby bucket. In conjunction with the {@link #KEY_BG_CURRENT_DRAIN_WINDOW}, 1231 * the app could be moved to more restricted standby bucket when its background current 1232 * drain rate is over this limit. 1233 */ 1234 static final String KEY_BG_CURRENT_DRAIN_THRESHOLD_TO_RESTRICTED_BUCKET = 1235 DEVICE_CONFIG_SUBNAMESPACE_PREFIX + "current_drain_threshold_to_restricted_bucket"; 1236 1237 /** 1238 * The threshold of the background current drain (in percentage) to the background 1239 * restricted level. In conjunction with the {@link #KEY_BG_CURRENT_DRAIN_WINDOW}, 1240 * the app could be moved to more restricted level when its background current 1241 * drain rate is over this limit. 1242 */ 1243 static final String KEY_BG_CURRENT_DRAIN_THRESHOLD_TO_BG_RESTRICTED = 1244 DEVICE_CONFIG_SUBNAMESPACE_PREFIX + "current_drain_threshold_to_bg_restricted"; 1245 1246 /** 1247 * The background current drain window size. In conjunction with the 1248 * {@link #KEY_BG_CURRENT_DRAIN_THRESHOLD_TO_RESTRICTED_BUCKET}, the app could be moved to 1249 * more restrictive bucket when its background current drain rate is over this limit. 1250 */ 1251 static final String KEY_BG_CURRENT_DRAIN_WINDOW = 1252 DEVICE_CONFIG_SUBNAMESPACE_PREFIX + "current_drain_window"; 1253 1254 /** 1255 * The grace period after an interaction event with the app, if the background current 1256 * drain goes beyond the threshold within that period, the system won't apply the 1257 * restrictions. 1258 */ 1259 static final String KEY_BG_CURRENT_DRAIN_INTERACTION_GRACE_PERIOD = 1260 DEVICE_CONFIG_SUBNAMESPACE_PREFIX + "current_drain_interaction_grace_period"; 1261 1262 /** 1263 * Similar to {@link #KEY_BG_CURRENT_DRAIN_THRESHOLD_TO_RESTRICTED_BUCKET}, but a higher 1264 * value for the legitimate cases with higher background current drain. 1265 */ 1266 static final String KEY_BG_CURRENT_DRAIN_HIGH_THRESHOLD_TO_RESTRICTED_BUCKET = 1267 DEVICE_CONFIG_SUBNAMESPACE_PREFIX 1268 + "current_drain_high_threshold_to_restricted_bucket"; 1269 1270 /** 1271 * Similar to {@link #KEY_BG_CURRENT_DRAIN_THRESHOLD_TO_BG_RESTRICTED}, but a higher value 1272 * for the legitimate cases with higher background current drain. 1273 */ 1274 static final String KEY_BG_CURRENT_DRAIN_HIGH_THRESHOLD_TO_BG_RESTRICTED = 1275 DEVICE_CONFIG_SUBNAMESPACE_PREFIX + "current_drain_high_threshold_to_bg_restricted"; 1276 1277 /** 1278 * The threshold of minimal time of hosting a foreground service with type "mediaPlayback" 1279 * or a media session, over the given window, so it'd subject towards the higher 1280 * background current drain threshold as defined in 1281 * {@link #mBgCurrentDrainBgRestrictedHighThreshold}. 1282 */ 1283 static final String KEY_BG_CURRENT_DRAIN_MEDIA_PLAYBACK_MIN_DURATION = 1284 DEVICE_CONFIG_SUBNAMESPACE_PREFIX + "current_drain_media_playback_min_duration"; 1285 1286 /** 1287 * Similar to {@link #KEY_BG_CURRENT_DRAIN_MEDIA_PLAYBACK_MIN_DURATION} but for foreground 1288 * service with type "location". 1289 */ 1290 static final String KEY_BG_CURRENT_DRAIN_LOCATION_MIN_DURATION = 1291 DEVICE_CONFIG_SUBNAMESPACE_PREFIX + "current_drain_location_min_duration"; 1292 1293 /** 1294 * Whether or not we should enable the different threshold based on the durations of 1295 * certain event type. 1296 */ 1297 static final String KEY_BG_CURRENT_DRAIN_EVENT_DURATION_BASED_THRESHOLD_ENABLED = 1298 DEVICE_CONFIG_SUBNAMESPACE_PREFIX 1299 + "current_drain_event_duration_based_threshold_enabled"; 1300 1301 /** 1302 * Whether or not we should move the app into the restricted bucket level if its background 1303 * battery usage goes beyond the threshold. Note this different from the flag 1304 * {@link AppRestrictionController.ConstantsObserver#KEY_BG_AUTO_RESTRICT_ABUSIVE_APPS} 1305 * which is to control the overall auto bg restrictions. 1306 */ 1307 static final String KEY_BG_CURRENT_DRAIN_AUTO_RESTRICT_ABUSIVE_APPS_ENABLED = 1308 DEVICE_CONFIG_SUBNAMESPACE_PREFIX 1309 + "current_drain_auto_restrict_abusive_apps_enabled"; 1310 1311 /** 1312 * The types of battery drain we're checking on each app; if the sum of the battery drain 1313 * exceeds the threshold, it'll be moved to restricted standby bucket; the type here 1314 * must be one of, or combination of {@link #BATTERY_USAGE_TYPE_BACKGROUND}, 1315 * {@link #BATTERY_USAGE_TYPE_FOREGROUND_SERVICE} and {@link #BATTERY_USAGE_TYPE_CACHED}. 1316 */ 1317 static final String KEY_BG_CURRENT_DRAIN_TYPES_TO_RESTRICTED_BUCKET = 1318 DEVICE_CONFIG_SUBNAMESPACE_PREFIX + "current_drain_types_to_restricted_bucket"; 1319 1320 /** 1321 * The types of battery drain we're checking on each app; if the sum of the battery drain 1322 * exceeds the threshold, it'll be moved to background restricted level; the type here 1323 * must be one of, or combination of {@link #BATTERY_USAGE_TYPE_BACKGROUND}, 1324 * {@link #BATTERY_USAGE_TYPE_FOREGROUND_SERVICE} and {@link #BATTERY_USAGE_TYPE_CACHED}. 1325 */ 1326 static final String KEY_BG_CURRENT_DRAIN_TYPES_TO_BG_RESTRICTED = 1327 DEVICE_CONFIG_SUBNAMESPACE_PREFIX + "current_drain_types_to_bg_restricted"; 1328 1329 /** 1330 * The power usage components we're monitoring. 1331 */ 1332 static final String KEY_BG_CURRENT_DRAIN_POWER_COMPONENTS = 1333 DEVICE_CONFIG_SUBNAMESPACE_PREFIX + "current_drain_power_components"; 1334 1335 /** 1336 * The types of state where we'll exempt its battery usage when it's in that state. 1337 * The state here must be one or a combination of STATE_TYPE_* in BaseAppStateTracker. 1338 */ 1339 static final String KEY_BG_CURRENT_DRAIN_EXEMPTED_TYPES = 1340 DEVICE_CONFIG_SUBNAMESPACE_PREFIX + "current_drain_exempted_types"; 1341 1342 /** 1343 * The behavior when an app has the permission ACCESS_BACKGROUND_LOCATION granted, 1344 * whether or not the system will use a higher threshold towards its background battery 1345 * usage because of it. 1346 */ 1347 static final String KEY_BG_CURRENT_DRAIN_HIGH_THRESHOLD_BY_BG_LOCATION = 1348 DEVICE_CONFIG_SUBNAMESPACE_PREFIX + "current_drain_high_threshold_by_bg_location"; 1349 1350 /** 1351 * Whether or not the battery usage of the offending app should fulfill the 1st threshold 1352 * before taking actions for the 2nd threshold. 1353 */ 1354 static final String KEY_BG_CURRENT_DRAIN_DECOUPLE_THRESHOLDS = 1355 DEVICE_CONFIG_SUBNAMESPACE_PREFIX + "current_drain_decouple_thresholds"; 1356 1357 /** 1358 * Default value to the {@link #INDEX_REGULAR_CURRENT_DRAIN_THRESHOLD} of 1359 * the {@link #mBgCurrentDrainRestrictedBucketThreshold}. 1360 */ 1361 final float mDefaultBgCurrentDrainRestrictedBucket; 1362 1363 /** 1364 * Default value to the {@link #INDEX_REGULAR_CURRENT_DRAIN_THRESHOLD} of 1365 * the {@link #mBgCurrentDrainBgRestrictedThreshold}. 1366 */ 1367 final float mDefaultBgCurrentDrainBgRestrictedThreshold; 1368 1369 /** 1370 * Default value to {@link #mBgCurrentDrainWindowMs}. 1371 */ 1372 final long mDefaultBgCurrentDrainWindowMs; 1373 1374 /** 1375 * Default value to {@link #mBgCurrentDrainInteractionGracePeriodMs}. 1376 */ 1377 final long mDefaultBgCurrentDrainInteractionGracePeriodMs; 1378 1379 /** 1380 * Default value to the {@link #INDEX_HIGH_CURRENT_DRAIN_THRESHOLD} of 1381 * the {@link #mBgCurrentDrainRestrictedBucketThreshold}. 1382 */ 1383 final float mDefaultBgCurrentDrainRestrictedBucketHighThreshold; 1384 1385 /** 1386 * Default value to the {@link #INDEX_HIGH_CURRENT_DRAIN_THRESHOLD} of 1387 * the {@link #mBgCurrentDrainBgRestrictedThreshold}. 1388 */ 1389 final float mDefaultBgCurrentDrainBgRestrictedHighThreshold; 1390 1391 /** 1392 * Default value to {@link #mBgCurrentDrainMediaPlaybackMinDuration}. 1393 */ 1394 final long mDefaultBgCurrentDrainMediaPlaybackMinDuration; 1395 1396 /** 1397 * Default value to {@link #mBgCurrentDrainLocationMinDuration}. 1398 */ 1399 final long mDefaultBgCurrentDrainLocationMinDuration; 1400 1401 /** 1402 * Default value to {@link #mBgCurrentDrainEventDurationBasedThresholdEnabled}. 1403 */ 1404 final boolean mDefaultBgCurrentDrainEventDurationBasedThresholdEnabled; 1405 1406 /** 1407 * Default value to {@link #mBgCurrentDrainAutoRestrictAbusiveAppsEnabled}. 1408 */ 1409 final boolean mDefaultBgCurrentDrainAutoRestrictAbusiveAppsEnabled; 1410 1411 /** 1412 * Default value to {@link #mBgCurrentDrainRestrictedBucketTypes}. 1413 */ 1414 final int mDefaultCurrentDrainTypesToRestrictedBucket; 1415 1416 /** 1417 * Default value to {@link #mBgCurrentDrainBgRestrictedTypes}. 1418 */ 1419 final int mDefaultBgCurrentDrainTypesToBgRestricted; 1420 1421 /** 1422 * Default value to {@link #mBgCurrentDrainPowerComponents}. 1423 **/ 1424 @BatteryConsumer.PowerComponent 1425 static final int DEFAULT_BG_CURRENT_DRAIN_POWER_COMPONENTS = POWER_COMPONENT_ANY; 1426 1427 final int mDefaultBgCurrentDrainPowerComponent; 1428 1429 /** 1430 * Default value to {@link #mBgCurrentDrainExemptedTypes}. 1431 **/ 1432 final int mDefaultBgCurrentDrainExemptedTypes; 1433 1434 /** 1435 * Default value to {@link #mBgCurrentDrainHighThresholdByBgLocation}. 1436 */ 1437 final boolean mDefaultBgCurrentDrainHighThresholdByBgLocation; 1438 1439 /** 1440 * Default value to {@link #mBgCurrentDrainDecoupleThresholds}. 1441 */ 1442 static final boolean DEFAULT_BG_CURRENT_DRAIN_DECOUPLE_THRESHOLD = true; 1443 1444 /** 1445 * The index to {@link #mBgCurrentDrainRestrictedBucketThreshold} 1446 * and {@link #mBgCurrentDrainBgRestrictedThreshold}. 1447 */ 1448 static final int INDEX_REGULAR_CURRENT_DRAIN_THRESHOLD = 0; 1449 static final int INDEX_HIGH_CURRENT_DRAIN_THRESHOLD = 1; 1450 1451 /** 1452 * @see #KEY_BG_CURRENT_DRAIN_THRESHOLD_TO_RESTRICTED_BUCKET. 1453 * @see #KEY_BG_CURRENT_DRAIN_HIGH_THRESHOLD_TO_RESTRICTED_BUCKET. 1454 */ 1455 volatile float[] mBgCurrentDrainRestrictedBucketThreshold = new float[2]; 1456 1457 /** 1458 * @see #KEY_BG_CURRENT_DRAIN_THRESHOLD_TO_BG_RESTRICTED. 1459 * @see #KEY_BG_CURRENT_DRAIN_HIGH_THRESHOLD_TO_BG_RESTRICTED. 1460 */ 1461 volatile float[] mBgCurrentDrainBgRestrictedThreshold = new float[2]; 1462 1463 /** 1464 * @see #KEY_BG_CURRENT_DRAIN_WINDOW. 1465 */ 1466 volatile long mBgCurrentDrainWindowMs; 1467 1468 /** 1469 * @see #KEY_BG_CURRENT_DRAIN_INTERACTION_GRACE_PERIOD. 1470 */ 1471 volatile long mBgCurrentDrainInteractionGracePeriodMs; 1472 1473 /** 1474 * @see #KEY_BG_CURRENT_DRAIN_MEDIA_PLAYBACK_MIN_DURATION. 1475 */ 1476 volatile long mBgCurrentDrainMediaPlaybackMinDuration; 1477 1478 /** 1479 * @see #KEY_BG_CURRENT_DRAIN_LOCATION_MIN_DURATION. 1480 */ 1481 volatile long mBgCurrentDrainLocationMinDuration; 1482 1483 /** 1484 * @see #KEY_BG_CURRENT_DRAIN_EVENT_DURATION_BASED_THRESHOLD_ENABLED. 1485 */ 1486 volatile boolean mBgCurrentDrainEventDurationBasedThresholdEnabled; 1487 1488 /** 1489 * @see #KEY_BG_CURRENT_DRAIN_AUTO_RESTRICT_ABUSIVE_APPS_ENABLED. 1490 */ 1491 volatile boolean mBgCurrentDrainAutoRestrictAbusiveAppsEnabled; 1492 1493 /** 1494 * @see #KEY_BG_CURRENT_DRAIN_TYPES_TO_RESTRICTED_BUCKET. 1495 */ 1496 volatile int mBgCurrentDrainRestrictedBucketTypes; 1497 1498 /** 1499 * @see #KEY_BG_CURRENT_DRAIN_TYPES_TO_BG_RESTRICTED. 1500 */ 1501 volatile int mBgCurrentDrainBgRestrictedTypes; 1502 1503 /** 1504 * @see #KEY_BG_CURRENT_DRAIN_POWER_COMPONENTS. 1505 */ 1506 @BatteryConsumer.PowerComponent 1507 volatile int mBgCurrentDrainPowerComponents; 1508 1509 volatile Dimensions[] mBatteryDimensions; 1510 1511 /** 1512 * @see #KEY_BG_CURRENT_DRAIN_EXEMPTED_TYPES. 1513 */ 1514 volatile int mBgCurrentDrainExemptedTypes; 1515 1516 /** 1517 * @see #KEY_BG_CURRENT_DRAIN_HIGH_THRESHOLD_BY_BG_LOCATION. 1518 */ 1519 volatile boolean mBgCurrentDrainHighThresholdByBgLocation; 1520 1521 /** 1522 * @see #KEY_BG_CURRENT_DRAIN_DECOUPLE_THRESHOLDS. 1523 */ 1524 volatile boolean mBgCurrentDrainDecoupleThresholds; 1525 1526 /** 1527 * The capacity of the battery when fully charged in mAh. 1528 */ 1529 private int mBatteryFullChargeMah; 1530 1531 /** 1532 * List of the packages with significant background battery usage, key is the UID of 1533 * the package and value is the pair of {timestamp[], battery usage snapshot[]} 1534 * when the UID is found guilty and should be moved to the next level of restriction. 1535 */ 1536 @GuardedBy("mLock") 1537 private final SparseArray<Pair<long[], ImmutableBatteryUsage[]>> mHighBgBatteryPackages = 1538 new SparseArray<>(); 1539 1540 /** 1541 * The timestamp of the last interaction, key is the UID. 1542 */ 1543 @GuardedBy("mLock") 1544 private final SparseLongArray mLastInteractionTime = new SparseLongArray(); 1545 1546 @NonNull 1547 private final Object mLock; 1548 1549 private static final int TIME_STAMP_INDEX_RESTRICTED_BUCKET = 0; 1550 private static final int TIME_STAMP_INDEX_BG_RESTRICTED = 1; 1551 private static final int TIME_STAMP_INDEX_LAST = 2; 1552 AppBatteryPolicy(@onNull Injector injector, @NonNull AppBatteryTracker tracker)1553 AppBatteryPolicy(@NonNull Injector injector, @NonNull AppBatteryTracker tracker) { 1554 super(injector, tracker, KEY_BG_CURRENT_DRAIN_MONITOR_ENABLED, 1555 tracker.mContext.getResources() 1556 .getBoolean(R.bool.config_bg_current_drain_monitor_enabled)); 1557 mLock = tracker.mLock; 1558 final Resources resources = tracker.mContext.getResources(); 1559 float[] val = getFloatArray(resources.obtainTypedArray( 1560 R.array.config_bg_current_drain_threshold_to_restricted_bucket)); 1561 mDefaultBgCurrentDrainRestrictedBucket = 1562 isLowRamDeviceStatic() ? val[1] : val[0]; 1563 val = getFloatArray(resources.obtainTypedArray( 1564 R.array.config_bg_current_drain_threshold_to_bg_restricted)); 1565 mDefaultBgCurrentDrainBgRestrictedThreshold = 1566 isLowRamDeviceStatic() ? val[1] : val[0]; 1567 mDefaultBgCurrentDrainWindowMs = resources.getInteger( 1568 R.integer.config_bg_current_drain_window) * 1_000; 1569 mDefaultBgCurrentDrainInteractionGracePeriodMs = mDefaultBgCurrentDrainWindowMs; 1570 val = getFloatArray(resources.obtainTypedArray( 1571 R.array.config_bg_current_drain_high_threshold_to_restricted_bucket)); 1572 mDefaultBgCurrentDrainRestrictedBucketHighThreshold = 1573 isLowRamDeviceStatic() ? val[1] : val[0]; 1574 val = getFloatArray(resources.obtainTypedArray( 1575 R.array.config_bg_current_drain_high_threshold_to_bg_restricted)); 1576 mDefaultBgCurrentDrainBgRestrictedHighThreshold = 1577 isLowRamDeviceStatic() ? val[1] : val[0]; 1578 mDefaultBgCurrentDrainMediaPlaybackMinDuration = resources.getInteger( 1579 R.integer.config_bg_current_drain_media_playback_min_duration) * 1_000; 1580 mDefaultBgCurrentDrainLocationMinDuration = resources.getInteger( 1581 R.integer.config_bg_current_drain_location_min_duration) * 1_000; 1582 mDefaultBgCurrentDrainEventDurationBasedThresholdEnabled = resources.getBoolean( 1583 R.bool.config_bg_current_drain_event_duration_based_threshold_enabled); 1584 mDefaultBgCurrentDrainAutoRestrictAbusiveAppsEnabled = resources.getBoolean( 1585 R.bool.config_bg_current_drain_auto_restrict_abusive_apps); 1586 mDefaultCurrentDrainTypesToRestrictedBucket = resources.getInteger( 1587 R.integer.config_bg_current_drain_types_to_restricted_bucket); 1588 mDefaultBgCurrentDrainTypesToBgRestricted = resources.getInteger( 1589 R.integer.config_bg_current_drain_types_to_bg_restricted); 1590 mDefaultBgCurrentDrainPowerComponent = resources.getInteger( 1591 R.integer.config_bg_current_drain_power_components); 1592 mDefaultBgCurrentDrainExemptedTypes = resources.getInteger( 1593 R.integer.config_bg_current_drain_exempted_types); 1594 mDefaultBgCurrentDrainHighThresholdByBgLocation = resources.getBoolean( 1595 R.bool.config_bg_current_drain_high_threshold_by_bg_location); 1596 mBgCurrentDrainRestrictedBucketThreshold[0] = 1597 mDefaultBgCurrentDrainRestrictedBucket; 1598 mBgCurrentDrainRestrictedBucketThreshold[1] = 1599 mDefaultBgCurrentDrainRestrictedBucketHighThreshold; 1600 mBgCurrentDrainBgRestrictedThreshold[0] = 1601 mDefaultBgCurrentDrainBgRestrictedThreshold; 1602 mBgCurrentDrainBgRestrictedThreshold[1] = 1603 mDefaultBgCurrentDrainBgRestrictedHighThreshold; 1604 mBgCurrentDrainWindowMs = mDefaultBgCurrentDrainWindowMs; 1605 mBgCurrentDrainInteractionGracePeriodMs = 1606 mDefaultBgCurrentDrainInteractionGracePeriodMs; 1607 mBgCurrentDrainMediaPlaybackMinDuration = 1608 mDefaultBgCurrentDrainMediaPlaybackMinDuration; 1609 mBgCurrentDrainLocationMinDuration = mDefaultBgCurrentDrainLocationMinDuration; 1610 } 1611 getFloatArray(TypedArray array)1612 static float[] getFloatArray(TypedArray array) { 1613 int length = array.length(); 1614 float[] floatArray = new float[length]; 1615 for (int i = 0; i < length; i++) { 1616 floatArray[i] = array.getFloat(i, Float.NaN); 1617 } 1618 array.recycle(); 1619 return floatArray; 1620 } 1621 1622 @Override onPropertiesChanged(String name)1623 public void onPropertiesChanged(String name) { 1624 switch (name) { 1625 case KEY_BG_CURRENT_DRAIN_THRESHOLD_TO_RESTRICTED_BUCKET: 1626 case KEY_BG_CURRENT_DRAIN_THRESHOLD_TO_BG_RESTRICTED: 1627 case KEY_BG_CURRENT_DRAIN_HIGH_THRESHOLD_BY_BG_LOCATION: 1628 case KEY_BG_CURRENT_DRAIN_HIGH_THRESHOLD_TO_RESTRICTED_BUCKET: 1629 case KEY_BG_CURRENT_DRAIN_HIGH_THRESHOLD_TO_BG_RESTRICTED: 1630 case KEY_BG_CURRENT_DRAIN_TYPES_TO_RESTRICTED_BUCKET: 1631 case KEY_BG_CURRENT_DRAIN_TYPES_TO_BG_RESTRICTED: 1632 case KEY_BG_CURRENT_DRAIN_POWER_COMPONENTS: 1633 updateCurrentDrainThreshold(); 1634 break; 1635 case KEY_BG_CURRENT_DRAIN_AUTO_RESTRICT_ABUSIVE_APPS_ENABLED: 1636 updateBgCurrentDrainAutoRestrictAbusiveAppsEnabled(); 1637 break; 1638 case KEY_BG_CURRENT_DRAIN_WINDOW: 1639 updateCurrentDrainWindow(); 1640 break; 1641 case KEY_BG_CURRENT_DRAIN_INTERACTION_GRACE_PERIOD: 1642 updateCurrentDrainInteractionGracePeriod(); 1643 break; 1644 case KEY_BG_CURRENT_DRAIN_MEDIA_PLAYBACK_MIN_DURATION: 1645 updateCurrentDrainMediaPlaybackMinDuration(); 1646 break; 1647 case KEY_BG_CURRENT_DRAIN_LOCATION_MIN_DURATION: 1648 updateCurrentDrainLocationMinDuration(); 1649 break; 1650 case KEY_BG_CURRENT_DRAIN_EVENT_DURATION_BASED_THRESHOLD_ENABLED: 1651 updateCurrentDrainEventDurationBasedThresholdEnabled(); 1652 break; 1653 case KEY_BG_CURRENT_DRAIN_EXEMPTED_TYPES: 1654 updateCurrentDrainExemptedTypes(); 1655 break; 1656 case KEY_BG_CURRENT_DRAIN_DECOUPLE_THRESHOLDS: 1657 updateCurrentDrainDecoupleThresholds(); 1658 break; 1659 default: 1660 super.onPropertiesChanged(name); 1661 break; 1662 } 1663 } 1664 updateTrackerEnabled()1665 void updateTrackerEnabled() { 1666 if (mBatteryFullChargeMah > 0) { 1667 super.updateTrackerEnabled(); 1668 } else { 1669 mTrackerEnabled = false; 1670 onTrackerEnabled(false); 1671 } 1672 } 1673 onTrackerEnabled(boolean enabled)1674 public void onTrackerEnabled(boolean enabled) { 1675 mTracker.onCurrentDrainMonitorEnabled(enabled); 1676 } 1677 updateCurrentDrainThreshold()1678 private void updateCurrentDrainThreshold() { 1679 mBgCurrentDrainRestrictedBucketThreshold[INDEX_REGULAR_CURRENT_DRAIN_THRESHOLD] = 1680 DeviceConfig.getFloat(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, 1681 KEY_BG_CURRENT_DRAIN_THRESHOLD_TO_RESTRICTED_BUCKET, 1682 mDefaultBgCurrentDrainRestrictedBucket); 1683 mBgCurrentDrainRestrictedBucketThreshold[INDEX_HIGH_CURRENT_DRAIN_THRESHOLD] = 1684 DeviceConfig.getFloat(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, 1685 KEY_BG_CURRENT_DRAIN_HIGH_THRESHOLD_TO_RESTRICTED_BUCKET, 1686 mDefaultBgCurrentDrainRestrictedBucketHighThreshold); 1687 mBgCurrentDrainBgRestrictedThreshold[INDEX_REGULAR_CURRENT_DRAIN_THRESHOLD] = 1688 DeviceConfig.getFloat(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, 1689 KEY_BG_CURRENT_DRAIN_THRESHOLD_TO_BG_RESTRICTED, 1690 mDefaultBgCurrentDrainBgRestrictedThreshold); 1691 mBgCurrentDrainBgRestrictedThreshold[INDEX_HIGH_CURRENT_DRAIN_THRESHOLD] = 1692 DeviceConfig.getFloat(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, 1693 KEY_BG_CURRENT_DRAIN_HIGH_THRESHOLD_TO_BG_RESTRICTED, 1694 mDefaultBgCurrentDrainBgRestrictedHighThreshold); 1695 mBgCurrentDrainRestrictedBucketTypes = 1696 DeviceConfig.getInt(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, 1697 KEY_BG_CURRENT_DRAIN_TYPES_TO_RESTRICTED_BUCKET, 1698 mDefaultCurrentDrainTypesToRestrictedBucket); 1699 mBgCurrentDrainBgRestrictedTypes = 1700 DeviceConfig.getInt(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, 1701 KEY_BG_CURRENT_DRAIN_TYPES_TO_BG_RESTRICTED, 1702 mDefaultBgCurrentDrainTypesToBgRestricted); 1703 mBgCurrentDrainPowerComponents = 1704 DeviceConfig.getInt(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, 1705 KEY_BG_CURRENT_DRAIN_POWER_COMPONENTS, 1706 mDefaultBgCurrentDrainPowerComponent); 1707 if (mBgCurrentDrainPowerComponents == DEFAULT_BG_CURRENT_DRAIN_POWER_COMPONENTS) { 1708 mBatteryDimensions = BatteryUsage.BATT_DIMENS; 1709 } else { 1710 mBatteryDimensions = new Dimensions[BatteryUsage.BATTERY_USAGE_COUNT]; 1711 for (int i = 0; i < BatteryUsage.BATTERY_USAGE_COUNT; i++) { 1712 mBatteryDimensions[i] = new Dimensions(mBgCurrentDrainPowerComponents, i); 1713 } 1714 } 1715 mBgCurrentDrainHighThresholdByBgLocation = 1716 DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, 1717 KEY_BG_CURRENT_DRAIN_HIGH_THRESHOLD_BY_BG_LOCATION, 1718 mDefaultBgCurrentDrainHighThresholdByBgLocation); 1719 } 1720 updateCurrentDrainWindow()1721 private void updateCurrentDrainWindow() { 1722 mBgCurrentDrainWindowMs = DeviceConfig.getLong( 1723 DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, 1724 KEY_BG_CURRENT_DRAIN_WINDOW, 1725 mDefaultBgCurrentDrainWindowMs); 1726 } 1727 updateCurrentDrainInteractionGracePeriod()1728 private void updateCurrentDrainInteractionGracePeriod() { 1729 mBgCurrentDrainInteractionGracePeriodMs = DeviceConfig.getLong( 1730 DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, 1731 KEY_BG_CURRENT_DRAIN_INTERACTION_GRACE_PERIOD, 1732 mDefaultBgCurrentDrainInteractionGracePeriodMs); 1733 } 1734 updateCurrentDrainMediaPlaybackMinDuration()1735 private void updateCurrentDrainMediaPlaybackMinDuration() { 1736 mBgCurrentDrainMediaPlaybackMinDuration = DeviceConfig.getLong( 1737 DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, 1738 KEY_BG_CURRENT_DRAIN_MEDIA_PLAYBACK_MIN_DURATION, 1739 mDefaultBgCurrentDrainMediaPlaybackMinDuration); 1740 } 1741 updateCurrentDrainLocationMinDuration()1742 private void updateCurrentDrainLocationMinDuration() { 1743 mBgCurrentDrainLocationMinDuration = DeviceConfig.getLong( 1744 DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, 1745 KEY_BG_CURRENT_DRAIN_LOCATION_MIN_DURATION, 1746 mDefaultBgCurrentDrainLocationMinDuration); 1747 } 1748 updateCurrentDrainEventDurationBasedThresholdEnabled()1749 private void updateCurrentDrainEventDurationBasedThresholdEnabled() { 1750 mBgCurrentDrainEventDurationBasedThresholdEnabled = DeviceConfig.getBoolean( 1751 DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, 1752 KEY_BG_CURRENT_DRAIN_EVENT_DURATION_BASED_THRESHOLD_ENABLED, 1753 mDefaultBgCurrentDrainEventDurationBasedThresholdEnabled); 1754 } 1755 updateCurrentDrainExemptedTypes()1756 private void updateCurrentDrainExemptedTypes() { 1757 mBgCurrentDrainExemptedTypes = DeviceConfig.getInt( 1758 DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, 1759 KEY_BG_CURRENT_DRAIN_EXEMPTED_TYPES, 1760 mDefaultBgCurrentDrainExemptedTypes); 1761 } 1762 updateCurrentDrainDecoupleThresholds()1763 private void updateCurrentDrainDecoupleThresholds() { 1764 mBgCurrentDrainDecoupleThresholds = DeviceConfig.getBoolean( 1765 DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, 1766 KEY_BG_CURRENT_DRAIN_DECOUPLE_THRESHOLDS, 1767 DEFAULT_BG_CURRENT_DRAIN_DECOUPLE_THRESHOLD); 1768 } 1769 updateBgCurrentDrainAutoRestrictAbusiveAppsEnabled()1770 private void updateBgCurrentDrainAutoRestrictAbusiveAppsEnabled() { 1771 mBgCurrentDrainAutoRestrictAbusiveAppsEnabled = DeviceConfig.getBoolean( 1772 DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, 1773 KEY_BG_CURRENT_DRAIN_AUTO_RESTRICT_ABUSIVE_APPS_ENABLED, 1774 mDefaultBgCurrentDrainAutoRestrictAbusiveAppsEnabled); 1775 } 1776 1777 @Override onSystemReady()1778 public void onSystemReady() { 1779 mBatteryFullChargeMah = 1780 mInjector.getBatteryManagerInternal().getBatteryFullCharge() / 1000; 1781 super.onSystemReady(); 1782 updateCurrentDrainThreshold(); 1783 updateCurrentDrainWindow(); 1784 updateCurrentDrainInteractionGracePeriod(); 1785 updateCurrentDrainMediaPlaybackMinDuration(); 1786 updateCurrentDrainLocationMinDuration(); 1787 updateCurrentDrainEventDurationBasedThresholdEnabled(); 1788 updateCurrentDrainExemptedTypes(); 1789 updateCurrentDrainDecoupleThresholds(); 1790 updateBgCurrentDrainAutoRestrictAbusiveAppsEnabled(); 1791 } 1792 1793 @Override 1794 @RestrictionLevel getProposedRestrictionLevel(String packageName, int uid, @RestrictionLevel int maxLevel)1795 public int getProposedRestrictionLevel(String packageName, int uid, 1796 @RestrictionLevel int maxLevel) { 1797 if (maxLevel <= RESTRICTION_LEVEL_ADAPTIVE_BUCKET) { 1798 return RESTRICTION_LEVEL_UNKNOWN; 1799 } 1800 synchronized (mLock) { 1801 final Pair<long[], ImmutableBatteryUsage[]> pair = mHighBgBatteryPackages.get(uid); 1802 if (pair != null) { 1803 final long lastInteractionTime = mLastInteractionTime.get(uid, 0L); 1804 final long[] ts = pair.first; 1805 final boolean noInteractionRecently = ts[TIME_STAMP_INDEX_RESTRICTED_BUCKET] 1806 > (lastInteractionTime + mBgCurrentDrainInteractionGracePeriodMs); 1807 final boolean canRestrict = 1808 mTracker.mAppRestrictionController.isAutoRestrictAbusiveAppEnabled() 1809 && mBgCurrentDrainAutoRestrictAbusiveAppsEnabled; 1810 final int restrictedLevel = noInteractionRecently && canRestrict 1811 ? RESTRICTION_LEVEL_RESTRICTED_BUCKET 1812 : RESTRICTION_LEVEL_ADAPTIVE_BUCKET; 1813 if (maxLevel > RESTRICTION_LEVEL_BACKGROUND_RESTRICTED) { 1814 return ts[TIME_STAMP_INDEX_BG_RESTRICTED] > 0 1815 ? RESTRICTION_LEVEL_BACKGROUND_RESTRICTED : restrictedLevel; 1816 } else if (maxLevel == RESTRICTION_LEVEL_BACKGROUND_RESTRICTED) { 1817 return restrictedLevel; 1818 } 1819 } 1820 return RESTRICTION_LEVEL_ADAPTIVE_BUCKET; 1821 } 1822 } 1823 calcPercentage(final int uid, final double[] usage, double[] percentage)1824 double[] calcPercentage(final int uid, final double[] usage, double[] percentage) { 1825 final BatteryUsage debugUsage = uid > 0 ? mTracker.mDebugUidPercentages.get(uid) : null; 1826 final double[] forced = debugUsage != null ? debugUsage.getPercentage() : null; 1827 for (int i = 0; i < usage.length; i++) { 1828 percentage[i] = forced != null ? forced[i] : usage[i] / mBatteryFullChargeMah * 100; 1829 } 1830 return percentage; 1831 } 1832 sumPercentageOfTypes(double[] percentage, int types)1833 private double sumPercentageOfTypes(double[] percentage, int types) { 1834 double result = 0.0d; 1835 for (int type = Integer.highestOneBit(types); type != 0; 1836 type = Integer.highestOneBit(types)) { 1837 final int index = Integer.numberOfTrailingZeros(type); 1838 result += percentage[index]; 1839 types &= ~type; 1840 } 1841 return result; 1842 } 1843 batteryUsageTypesToString(int types)1844 private static String batteryUsageTypesToString(int types) { 1845 final StringBuilder sb = new StringBuilder("["); 1846 boolean needDelimiter = false; 1847 for (int type = Integer.highestOneBit(types); type != 0; 1848 type = Integer.highestOneBit(types)) { 1849 if (needDelimiter) { 1850 sb.append('|'); 1851 } 1852 needDelimiter = true; 1853 switch (type) { 1854 case BATTERY_USAGE_TYPE_UNSPECIFIED: 1855 sb.append("UNSPECIFIED"); 1856 break; 1857 case BATTERY_USAGE_TYPE_FOREGROUND: 1858 sb.append("FOREGROUND"); 1859 break; 1860 case BATTERY_USAGE_TYPE_BACKGROUND: 1861 sb.append("BACKGROUND"); 1862 break; 1863 case BATTERY_USAGE_TYPE_FOREGROUND_SERVICE: 1864 sb.append("FOREGROUND_SERVICE"); 1865 break; 1866 case BATTERY_USAGE_TYPE_CACHED: 1867 sb.append("CACHED"); 1868 break; 1869 default: 1870 return "[UNKNOWN(" + Integer.toHexString(types) + ")]"; 1871 } 1872 types &= ~type; 1873 } 1874 sb.append("]"); 1875 return sb.toString(); 1876 } 1877 handleUidBatteryUsage(final int uid, final ImmutableBatteryUsage usage)1878 void handleUidBatteryUsage(final int uid, final ImmutableBatteryUsage usage) { 1879 final @ReasonCode int reason = shouldExemptUid(uid); 1880 if (reason != REASON_DENIED) { 1881 if (DEBUG_BACKGROUND_BATTERY_TRACKER_VERBOSE && !BATTERY_USAGE_NONE.equals(usage)) { 1882 Slog.i(TAG, "Exempting battery usage in " + UserHandle.formatUid(uid) 1883 + " " + PowerExemptionManager.reasonCodeToString(reason)); 1884 } 1885 return; 1886 } 1887 boolean notifyController = false; 1888 boolean excessive = false; 1889 int index = 0; 1890 final double rbPercentage = sumPercentageOfTypes(usage.getPercentage(), 1891 mBgCurrentDrainRestrictedBucketTypes); 1892 final double brPercentage = sumPercentageOfTypes(usage.getPercentage(), 1893 mBgCurrentDrainBgRestrictedTypes); 1894 synchronized (mLock) { 1895 final int curLevel = mTracker.mAppRestrictionController.getRestrictionLevel(uid); 1896 if (curLevel >= RESTRICTION_LEVEL_BACKGROUND_RESTRICTED) { 1897 // We're already in the background restricted level, nothing more we could do. 1898 return; 1899 } 1900 final long lastInteractionTime = mLastInteractionTime.get(uid, 0L); 1901 final long now = SystemClock.elapsedRealtime(); 1902 final int thresholdIndex = getCurrentDrainThresholdIndex(uid, now, 1903 mBgCurrentDrainWindowMs); 1904 index = mHighBgBatteryPackages.indexOfKey(uid); 1905 final boolean decoupleThresholds = mBgCurrentDrainDecoupleThresholds; 1906 final double rbThreshold = mBgCurrentDrainRestrictedBucketThreshold[thresholdIndex]; 1907 final double brThreshold = mBgCurrentDrainBgRestrictedThreshold[thresholdIndex]; 1908 if (index < 0) { 1909 long[] ts = null; 1910 ImmutableBatteryUsage[] usages = null; 1911 if (rbPercentage >= rbThreshold) { 1912 if (now > lastInteractionTime + mBgCurrentDrainInteractionGracePeriodMs) { 1913 // New findings to us, track it and let the controller know. 1914 ts = new long[TIME_STAMP_INDEX_LAST]; 1915 ts[TIME_STAMP_INDEX_RESTRICTED_BUCKET] = now; 1916 usages = new ImmutableBatteryUsage[TIME_STAMP_INDEX_LAST]; 1917 usages[TIME_STAMP_INDEX_RESTRICTED_BUCKET] = usage; 1918 mHighBgBatteryPackages.put(uid, Pair.create(ts, usages)); 1919 // It's beeen long enough since last interaction with this app. 1920 notifyController = true; 1921 } 1922 excessive = true; 1923 } 1924 if (decoupleThresholds && brPercentage >= brThreshold) { 1925 if (ts == null) { 1926 ts = new long[TIME_STAMP_INDEX_LAST]; 1927 usages = new ImmutableBatteryUsage[TIME_STAMP_INDEX_LAST]; 1928 mHighBgBatteryPackages.put(uid, Pair.create(ts, usages)); 1929 } 1930 ts[TIME_STAMP_INDEX_BG_RESTRICTED] = now; 1931 usages[TIME_STAMP_INDEX_BG_RESTRICTED] = usage; 1932 notifyController = excessive = true; 1933 } 1934 } else { 1935 final Pair<long[], ImmutableBatteryUsage[]> pair = 1936 mHighBgBatteryPackages.valueAt(index); 1937 final long[] ts = pair.first; 1938 final long lastRestrictBucketTs = ts[TIME_STAMP_INDEX_RESTRICTED_BUCKET]; 1939 if (rbPercentage >= rbThreshold) { 1940 if (now > lastInteractionTime + mBgCurrentDrainInteractionGracePeriodMs) { 1941 if (lastRestrictBucketTs == 0) { 1942 ts[TIME_STAMP_INDEX_RESTRICTED_BUCKET] = now; 1943 pair.second[TIME_STAMP_INDEX_RESTRICTED_BUCKET] = usage; 1944 } 1945 // It's been long enough since last interaction with this app. 1946 notifyController = true; 1947 } 1948 excessive = true; 1949 } else { 1950 // It's actually back to normal, but we don't untrack it until 1951 // explicit user interactions, because the restriction could be the cause 1952 // of going back to normal. 1953 } 1954 if (brPercentage >= brThreshold) { 1955 // If either 1956 // a) It's configured to goto threshold 2 directly without threshold 1; 1957 // b) It's already in the restricted standby bucket, but still seeing 1958 // high current drains, and it's been a while since it's restricted; 1959 // tell the controller. 1960 notifyController = decoupleThresholds 1961 || (curLevel == RESTRICTION_LEVEL_RESTRICTED_BUCKET 1962 && (now > lastRestrictBucketTs + mBgCurrentDrainWindowMs)); 1963 if (notifyController) { 1964 ts[TIME_STAMP_INDEX_BG_RESTRICTED] = now; 1965 pair.second[TIME_STAMP_INDEX_BG_RESTRICTED] = usage; 1966 } 1967 excessive = true; 1968 } else { 1969 // Reset the track now - if it's already background restricted, it requires 1970 // user consent to unrestrict it; or if it's in restricted bucket level, 1971 // resetting this won't lift it from that level. 1972 ts[TIME_STAMP_INDEX_BG_RESTRICTED] = 0; 1973 pair.second[TIME_STAMP_INDEX_BG_RESTRICTED] = null; 1974 // Now need to notify the controller. 1975 } 1976 } 1977 } 1978 1979 if (excessive) { 1980 if (DEBUG_BACKGROUND_BATTERY_TRACKER_VERBOSE) { 1981 Slog.i(TAG, "Excessive background current drain " + uid + " " 1982 + usage + " (" + usage.percentageToString() + " ) over " 1983 + TimeUtils.formatDuration(mBgCurrentDrainWindowMs)); 1984 } 1985 if (notifyController) { 1986 mTracker.mAppRestrictionController.refreshAppRestrictionLevelForUid( 1987 uid, REASON_MAIN_FORCED_BY_SYSTEM, 1988 REASON_SUB_FORCED_SYSTEM_FLAG_ABUSE, true); 1989 } 1990 } else { 1991 if (DEBUG_BACKGROUND_BATTERY_TRACKER_VERBOSE && index >= 0) { 1992 Slog.i(TAG, "Background current drain backs to normal " + uid + " " 1993 + usage + " (" + usage.percentageToString() + " ) over " 1994 + TimeUtils.formatDuration(mBgCurrentDrainWindowMs)); 1995 } 1996 // For now, we're not lifting the restrictions if the bg current drain backs to 1997 // normal util an explicit user interaction. 1998 } 1999 } 2000 getCurrentDrainThresholdIndex(int uid, long now, long window)2001 private int getCurrentDrainThresholdIndex(int uid, long now, long window) { 2002 return (hasMediaPlayback(uid, now, window) || hasLocation(uid, now, window)) 2003 ? INDEX_HIGH_CURRENT_DRAIN_THRESHOLD 2004 : INDEX_REGULAR_CURRENT_DRAIN_THRESHOLD; 2005 } 2006 hasMediaPlayback(int uid, long now, long window)2007 private boolean hasMediaPlayback(int uid, long now, long window) { 2008 return mBgCurrentDrainEventDurationBasedThresholdEnabled 2009 && mTracker.mAppRestrictionController.getCompositeMediaPlaybackDurations( 2010 uid, now, window) >= mBgCurrentDrainMediaPlaybackMinDuration; 2011 } 2012 hasLocation(int uid, long now, long window)2013 private boolean hasLocation(int uid, long now, long window) { 2014 if (!mBgCurrentDrainHighThresholdByBgLocation) { 2015 return false; 2016 } 2017 if (mTracker.mInjector.checkPermission(ACCESS_BACKGROUND_LOCATION, 2018 Process.INVALID_PID, uid) == PERMISSION_GRANTED) { 2019 return true; 2020 } 2021 if (!mBgCurrentDrainEventDurationBasedThresholdEnabled) { 2022 return false; 2023 } 2024 final long since = Math.max(0, now - window); 2025 final AppRestrictionController controller = mTracker.mAppRestrictionController; 2026 final long locationDuration = controller.getForegroundServiceTotalDurationsSince( 2027 uid, since, now, ServiceInfo.FOREGROUND_SERVICE_TYPE_LOCATION); 2028 return locationDuration >= mBgCurrentDrainLocationMinDuration; 2029 } 2030 onUserInteractionStarted(String packageName, int uid)2031 void onUserInteractionStarted(String packageName, int uid) { 2032 boolean changed = false; 2033 synchronized (mLock) { 2034 mLastInteractionTime.put(uid, SystemClock.elapsedRealtime()); 2035 final int curLevel = mTracker.mAppRestrictionController.getRestrictionLevel( 2036 uid, packageName); 2037 if (curLevel == RESTRICTION_LEVEL_BACKGROUND_RESTRICTED) { 2038 // It's a sticky state, user interaction won't change it, still track it. 2039 } else { 2040 // Remove the given UID from our tracking list, as user interacted with it. 2041 final int index = mHighBgBatteryPackages.indexOfKey(uid); 2042 if (index >= 0) { 2043 mHighBgBatteryPackages.removeAt(index); 2044 changed = true; 2045 } 2046 } 2047 } 2048 if (changed) { 2049 // Request to refresh the app restriction level. 2050 mTracker.mAppRestrictionController.refreshAppRestrictionLevelForUid(uid, 2051 REASON_MAIN_USAGE, REASON_SUB_USAGE_USER_INTERACTION, true); 2052 } 2053 } 2054 onBackgroundRestrictionChanged(int uid, String pkgName, boolean restricted)2055 void onBackgroundRestrictionChanged(int uid, String pkgName, boolean restricted) { 2056 if (restricted) { 2057 return; 2058 } 2059 synchronized (mLock) { 2060 // User has explicitly removed it from background restricted level, 2061 // clear the timestamp of the background-restricted 2062 final Pair<long[], ImmutableBatteryUsage[]> pair = mHighBgBatteryPackages.get(uid); 2063 if (pair != null) { 2064 pair.first[TIME_STAMP_INDEX_BG_RESTRICTED] = 0; 2065 pair.second[TIME_STAMP_INDEX_BG_RESTRICTED] = null; 2066 } 2067 } 2068 } 2069 2070 @VisibleForTesting reset()2071 void reset() { 2072 mHighBgBatteryPackages.clear(); 2073 mLastInteractionTime.clear(); 2074 mTracker.reset(); 2075 } 2076 2077 @GuardedBy("mLock") onUserRemovedLocked(final @UserIdInt int userId)2078 void onUserRemovedLocked(final @UserIdInt int userId) { 2079 for (int i = mHighBgBatteryPackages.size() - 1; i >= 0; i--) { 2080 if (UserHandle.getUserId(mHighBgBatteryPackages.keyAt(i)) == userId) { 2081 mHighBgBatteryPackages.removeAt(i); 2082 } 2083 } 2084 for (int i = mLastInteractionTime.size() - 1; i >= 0; i--) { 2085 if (UserHandle.getUserId(mLastInteractionTime.keyAt(i)) == userId) { 2086 mLastInteractionTime.removeAt(i); 2087 } 2088 } 2089 } 2090 2091 @GuardedBy("mLock") onUidRemovedLocked(final int uid)2092 void onUidRemovedLocked(final int uid) { 2093 mHighBgBatteryPackages.remove(uid); 2094 mLastInteractionTime.delete(uid); 2095 } 2096 2097 @Override dump(PrintWriter pw, String prefix)2098 void dump(PrintWriter pw, String prefix) { 2099 pw.print(prefix); 2100 pw.println("APP BATTERY TRACKER POLICY SETTINGS:"); 2101 final String indent = " "; 2102 prefix = indent + prefix; 2103 super.dump(pw, prefix); 2104 if (isEnabled()) { 2105 pw.print(prefix); 2106 pw.print(KEY_BG_CURRENT_DRAIN_THRESHOLD_TO_RESTRICTED_BUCKET); 2107 pw.print('='); 2108 pw.println(mBgCurrentDrainRestrictedBucketThreshold[ 2109 INDEX_REGULAR_CURRENT_DRAIN_THRESHOLD]); 2110 pw.print(prefix); 2111 pw.print(KEY_BG_CURRENT_DRAIN_HIGH_THRESHOLD_TO_RESTRICTED_BUCKET); 2112 pw.print('='); 2113 pw.println(mBgCurrentDrainRestrictedBucketThreshold[ 2114 INDEX_HIGH_CURRENT_DRAIN_THRESHOLD]); 2115 pw.print(prefix); 2116 pw.print(KEY_BG_CURRENT_DRAIN_THRESHOLD_TO_BG_RESTRICTED); 2117 pw.print('='); 2118 pw.println(mBgCurrentDrainBgRestrictedThreshold[ 2119 INDEX_REGULAR_CURRENT_DRAIN_THRESHOLD]); 2120 pw.print(prefix); 2121 pw.print(KEY_BG_CURRENT_DRAIN_HIGH_THRESHOLD_TO_BG_RESTRICTED); 2122 pw.print('='); 2123 pw.println(mBgCurrentDrainBgRestrictedThreshold[ 2124 INDEX_HIGH_CURRENT_DRAIN_THRESHOLD]); 2125 pw.print(prefix); 2126 pw.print(KEY_BG_CURRENT_DRAIN_WINDOW); 2127 pw.print('='); 2128 pw.println(mBgCurrentDrainWindowMs); 2129 pw.print(prefix); 2130 pw.print(KEY_BG_CURRENT_DRAIN_INTERACTION_GRACE_PERIOD); 2131 pw.print('='); 2132 pw.println(mBgCurrentDrainInteractionGracePeriodMs); 2133 pw.print(prefix); 2134 pw.print(KEY_BG_CURRENT_DRAIN_MEDIA_PLAYBACK_MIN_DURATION); 2135 pw.print('='); 2136 pw.println(mBgCurrentDrainMediaPlaybackMinDuration); 2137 pw.print(prefix); 2138 pw.print(KEY_BG_CURRENT_DRAIN_LOCATION_MIN_DURATION); 2139 pw.print('='); 2140 pw.println(mBgCurrentDrainLocationMinDuration); 2141 pw.print(prefix); 2142 pw.print(KEY_BG_CURRENT_DRAIN_EVENT_DURATION_BASED_THRESHOLD_ENABLED); 2143 pw.print('='); 2144 pw.println(mBgCurrentDrainEventDurationBasedThresholdEnabled); 2145 pw.print(prefix); 2146 pw.print(KEY_BG_CURRENT_DRAIN_AUTO_RESTRICT_ABUSIVE_APPS_ENABLED); 2147 pw.print('='); 2148 pw.println(mBgCurrentDrainAutoRestrictAbusiveAppsEnabled); 2149 pw.print(prefix); 2150 pw.print(KEY_BG_CURRENT_DRAIN_TYPES_TO_RESTRICTED_BUCKET); 2151 pw.print('='); 2152 pw.println(batteryUsageTypesToString(mBgCurrentDrainRestrictedBucketTypes)); 2153 pw.print(prefix); 2154 pw.print(KEY_BG_CURRENT_DRAIN_TYPES_TO_BG_RESTRICTED); 2155 pw.print('='); 2156 pw.println(batteryUsageTypesToString(mBgCurrentDrainBgRestrictedTypes)); 2157 pw.print(prefix); 2158 pw.print(KEY_BG_CURRENT_DRAIN_POWER_COMPONENTS); 2159 pw.print('='); 2160 pw.println(mBgCurrentDrainPowerComponents); 2161 pw.print(prefix); 2162 pw.print(KEY_BG_CURRENT_DRAIN_EXEMPTED_TYPES); 2163 pw.print('='); 2164 pw.println(BaseAppStateTracker.stateTypesToString(mBgCurrentDrainExemptedTypes)); 2165 pw.print(prefix); 2166 pw.print(KEY_BG_CURRENT_DRAIN_HIGH_THRESHOLD_BY_BG_LOCATION); 2167 pw.print('='); 2168 pw.println(mBgCurrentDrainHighThresholdByBgLocation); 2169 pw.print(prefix); 2170 pw.print("Full charge capacity="); 2171 pw.print(mBatteryFullChargeMah); 2172 pw.println(" mAh"); 2173 2174 pw.print(prefix); 2175 pw.println("Excessive current drain detected:"); 2176 synchronized (mLock) { 2177 final int size = mHighBgBatteryPackages.size(); 2178 prefix = indent + prefix; 2179 if (size > 0) { 2180 final long now = SystemClock.elapsedRealtime(); 2181 for (int i = 0; i < size; i++) { 2182 final int uid = mHighBgBatteryPackages.keyAt(i); 2183 final Pair<long[], ImmutableBatteryUsage[]> pair = 2184 mHighBgBatteryPackages.valueAt(i); 2185 final long[] ts = pair.first; 2186 final ImmutableBatteryUsage[] usages = pair.second; 2187 final int thresholdIndex = getCurrentDrainThresholdIndex(uid, now, 2188 mBgCurrentDrainWindowMs); 2189 pw.format("%s%s: (threshold=%4.2f%%/%4.2f%%) %s / %s\n", 2190 prefix, 2191 UserHandle.formatUid(uid), 2192 mBgCurrentDrainRestrictedBucketThreshold[thresholdIndex], 2193 mBgCurrentDrainBgRestrictedThreshold[thresholdIndex], 2194 formatHighBgBatteryRecord( 2195 ts[TIME_STAMP_INDEX_RESTRICTED_BUCKET], now, 2196 usages[TIME_STAMP_INDEX_RESTRICTED_BUCKET]), 2197 formatHighBgBatteryRecord( 2198 ts[TIME_STAMP_INDEX_BG_RESTRICTED], now, 2199 usages[TIME_STAMP_INDEX_BG_RESTRICTED]) 2200 ); 2201 } 2202 } else { 2203 pw.print(prefix); 2204 pw.println("(none)"); 2205 } 2206 } 2207 } 2208 } 2209 formatHighBgBatteryRecord(long ts, long now, ImmutableBatteryUsage usage)2210 private String formatHighBgBatteryRecord(long ts, long now, ImmutableBatteryUsage usage) { 2211 if (ts > 0 && usage != null) { 2212 return String.format("%s %s (%s)", 2213 formatTime(ts, now), usage.toString(), usage.percentageToString()); 2214 } else { 2215 return "0"; 2216 } 2217 } 2218 } 2219 } 2220