• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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