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