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