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