Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 210fe70a authored by Jing Ji's avatar Jing Ji Committed by Android (Google) Code Review
Browse files

Merge "Track the battery usage in different dimensions in AppBatteryTracker"

parents 98dbecb4 e1217fdd
Loading
Loading
Loading
Loading
+13 −7
Original line number Diff line number Diff line
@@ -31,6 +31,7 @@ import static com.android.internal.app.procstats.ProcessStats.ADJ_MEM_FACTOR_MOD
import static com.android.internal.app.procstats.ProcessStats.ADJ_MEM_FACTOR_NORMAL;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.am.AppBatteryTracker.BatteryUsage.BATTERY_USAGE_COUNT;
import static com.android.server.am.LowMemDetector.ADJ_MEM_FACTOR_NOTHING;

import android.app.ActivityManager;
@@ -3256,12 +3257,12 @@ final class ActivityManagerShellCommand extends ShellCommand {
            return -1;
        }
        if (arg == null) {
            batteryTracker.mDebugUidPercentages.clear();
            batteryTracker.clearDebugUidPercentage();
            return 0;
        }
        String[] pairs = arg.split(",");
        int[] uids = new int[pairs.length];
        double[] values = new double[pairs.length];
        double[][] values = new double[pairs.length][];
        try {
            for (int i = 0; i < pairs.length; i++) {
                String[] pair = pairs[i].split("=");
@@ -3270,16 +3271,21 @@ final class ActivityManagerShellCommand extends ShellCommand {
                    return -1;
                }
                uids[i] = Integer.parseInt(pair[0]);
                values[i] = Double.parseDouble(pair[1]);
                final String[] vals = pair[1].split(":");
                if (vals.length != BATTERY_USAGE_COUNT) {
                    getErrPrintWriter().println("Malformed input");
                    return -1;
                }
                values[i] = new double[vals.length];
                for (int j = 0; j < vals.length; j++) {
                    values[i][j] = Double.parseDouble(vals[j]);
                }
            }
        } catch (NumberFormatException e) {
            getErrPrintWriter().println("Malformed input");
            return -1;
        }
        batteryTracker.mDebugUidPercentages.clear();
        for (int i = 0; i < pairs.length; i++) {
            batteryTracker.mDebugUidPercentages.put(uids[i], values[i]);
        }
        batteryTracker.setDebugUidPercentage(uids, values);
        return 0;
    }

+59 −38
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ package com.android.server.am;

import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.am.AppBatteryTracker.BATTERY_USAGE_NONE;
import static com.android.server.am.AppRestrictionController.DEVICE_CONFIG_SUBNAMESPACE_PREFIX;
import static com.android.server.am.BaseAppStateDurationsTracker.EVENT_NUM;

@@ -32,6 +33,8 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.server.am.AppBatteryExemptionTracker.AppBatteryExemptionPolicy;
import com.android.server.am.AppBatteryExemptionTracker.UidBatteryStates;
import com.android.server.am.AppBatteryTracker.AppBatteryPolicy;
import com.android.server.am.AppBatteryTracker.BatteryUsage;
import com.android.server.am.AppBatteryTracker.ImmutableBatteryUsage;
import com.android.server.am.BaseAppStateDurationsTracker.EventListener;
import com.android.server.am.BaseAppStateTimeEvents.BaseTimeEvent;
import com.android.server.am.BaseAppStateTracker.Injector;
@@ -97,7 +100,8 @@ final class AppBatteryExemptionTracker
        if (!mInjector.getPolicy().isEnabled()) {
            return;
        }
        final double batteryUsage = mAppRestrictionController.getUidBatteryUsage(uid);
        final ImmutableBatteryUsage batteryUsage = mAppRestrictionController
                .getUidBatteryUsage(uid);
        synchronized (mLock) {
            UidBatteryStates pkg = mPkgEvents.get(uid, DEFAULT_NAME);
            if (pkg == null) {
@@ -120,22 +124,23 @@ final class AppBatteryExemptionTracker
     * @return The to-be-exempted battery usage of the given UID in the given duration; it could
     *         be considered as "exempted" due to various use cases, i.e. media playback.
     */
    double getUidBatteryExemptedUsageSince(int uid, long since, long now) {
    ImmutableBatteryUsage getUidBatteryExemptedUsageSince(int uid, long since, long now) {
        if (!mInjector.getPolicy().isEnabled()) {
            return 0.0d;
            return BATTERY_USAGE_NONE;
        }
        Pair<Double, Double> result;
        Pair<ImmutableBatteryUsage, ImmutableBatteryUsage> result;
        synchronized (mLock) {
            final UidBatteryStates pkg = mPkgEvents.get(uid, DEFAULT_NAME);
            if (pkg == null) {
                return 0.0d;
                return BATTERY_USAGE_NONE;
            }
            result = pkg.getBatteryUsageSince(since, now);
        }
        if (result.second > 0.0d) {
        if (!result.second.isEmpty()) {
            // We have an open event (just start, no stop), get the battery usage till now.
            final double batteryUsage = mAppRestrictionController.getUidBatteryUsage(uid);
            return result.first + batteryUsage - result.second;
            final ImmutableBatteryUsage batteryUsage = mAppRestrictionController
                    .getUidBatteryUsage(uid);
            return result.first.mutate().add(batteryUsage).subtract(result.second).unmutate();
        }
        return result.first;
    }
@@ -156,7 +161,7 @@ final class AppBatteryExemptionTracker
         * @param batteryUsage The background current drain since the system boots.
         * @param eventType One of EVENT_TYPE_* defined in the class BaseAppStateDurationsTracker.
         */
        void addEvent(boolean start, long now, double batteryUsage, int eventType) {
        void addEvent(boolean start, long now, ImmutableBatteryUsage batteryUsage, int eventType) {
            if (start) {
                addEvent(start, new UidStateEventWithBattery(start, now, batteryUsage, null),
                        eventType);
@@ -169,7 +174,8 @@ final class AppBatteryExemptionTracker
                    return;
                }
                addEvent(start, new UidStateEventWithBattery(start, now,
                        batteryUsage - last.getBatteryUsage(), last), eventType);
                        batteryUsage.mutate().subtract(last.getBatteryUsage()).unmutate(), last),
                        eventType);
            }
        }

@@ -183,34 +189,37 @@ final class AppBatteryExemptionTracker
         *         the second value is the battery usage since the system boots, if there is
         *         an open event(just start, no stop) at the end of the duration.
         */
        Pair<Double, Double> getBatteryUsageSince(long since, long now, int eventType) {
        Pair<ImmutableBatteryUsage, ImmutableBatteryUsage> getBatteryUsageSince(long since,
                long now, int eventType) {
            return getBatteryUsageSince(since, now, mEvents[eventType]);
        }

        private Pair<Double, Double> getBatteryUsageSince(long since, long now,
                LinkedList<UidStateEventWithBattery> events) {
        private Pair<ImmutableBatteryUsage, ImmutableBatteryUsage> getBatteryUsageSince(long since,
                long now, LinkedList<UidStateEventWithBattery> events) {
            if (events == null || events.size() == 0) {
                return Pair.create(0.0d, 0.0d);
                return Pair.create(BATTERY_USAGE_NONE, BATTERY_USAGE_NONE);
            }
            double batteryUsage = 0.0d;
            final BatteryUsage batteryUsage = new BatteryUsage();
            UidStateEventWithBattery lastEvent = null;
            for (UidStateEventWithBattery event : events) {
                lastEvent = event;
                if (event.getTimestamp() < since || event.isStart()) {
                    continue;
                }
                batteryUsage += event.getBatteryUsage(since, Math.min(now, event.getTimestamp()));
                batteryUsage.add(event.getBatteryUsage(since, Math.min(now, event.getTimestamp())));
                if (now <= event.getTimestamp()) {
                    break;
                }
            }
            return Pair.create(batteryUsage, lastEvent.isStart() ? lastEvent.getBatteryUsage() : 0);
            return Pair.create(batteryUsage.unmutate(), lastEvent.isStart()
                    ? lastEvent.getBatteryUsage() : BATTERY_USAGE_NONE);
        }

        /**
         * @return The aggregated battery usage amongst all the event types we're tracking.
         */
        Pair<Double, Double> getBatteryUsageSince(long since, long now) {
        Pair<ImmutableBatteryUsage, ImmutableBatteryUsage> getBatteryUsageSince(long since,
                long now) {
            LinkedList<UidStateEventWithBattery> result = new LinkedList<>();
            for (int i = 0; i < mEvents.length; i++) {
                result = add(result, mEvents[i]);
@@ -236,7 +245,7 @@ final class AppBatteryExemptionTracker
            UidStateEventWithBattery l = itl.next(), r = itr.next();
            LinkedList<UidStateEventWithBattery> dest = new LinkedList<>();
            boolean actl = false, actr = false, overlapping = false;
            double batteryUsage = 0.0d;
            final BatteryUsage batteryUsage = new BatteryUsage();
            long recentActTs = 0, overlappingDuration = 0;
            for (long lts = l.getTimestamp(), rts = r.getTimestamp();
                    lts != Long.MAX_VALUE || rts != Long.MAX_VALUE;) {
@@ -245,8 +254,8 @@ final class AppBatteryExemptionTracker
                if (lts == rts) {
                    earliest = l;
                    // we'll deal with the double counting problem later.
                    batteryUsage += actl ? l.getBatteryUsage() : 0.0d;
                    batteryUsage += actr ? r.getBatteryUsage() : 0.0d;
                    if (actl) batteryUsage.add(l.getBatteryUsage());
                    if (actr) batteryUsage.add(r.getBatteryUsage());
                    overlappingDuration += overlapping && (actl || actr)
                            ? (lts - recentActTs) : 0;
                    actl = !actl;
@@ -255,13 +264,13 @@ final class AppBatteryExemptionTracker
                    rts = itr.hasNext() ? (r = itr.next()).getTimestamp() : Long.MAX_VALUE;
                } else if (lts < rts) {
                    earliest = l;
                    batteryUsage += actl ? l.getBatteryUsage() : 0.0d;
                    if (actl) batteryUsage.add(l.getBatteryUsage());
                    overlappingDuration += overlapping && actl ? (lts - recentActTs) : 0;
                    actl = !actl;
                    lts = itl.hasNext() ? (l = itl.next()).getTimestamp() : Long.MAX_VALUE;
                } else {
                    earliest = r;
                    batteryUsage += actr ? r.getBatteryUsage() : 0.0d;
                    if (actr) batteryUsage.add(r.getBatteryUsage());
                    overlappingDuration += overlapping && actr ? (rts - recentActTs) : 0;
                    actr = !actr;
                    rts = itr.hasNext() ? (r = itr.next()).getTimestamp() : Long.MAX_VALUE;
@@ -281,12 +290,12 @@ final class AppBatteryExemptionTracker
                        final long durationWithOverlapping = duration + overlappingDuration;
                        // Get the proportional batteryUsage.
                        if (durationWithOverlapping != 0) {
                            batteryUsage *= duration * 1.0d / durationWithOverlapping;
                            batteryUsage.scale(duration * 1.0d / durationWithOverlapping);
                            event.update(lastEvent, new ImmutableBatteryUsage(batteryUsage));
                        } else {
                            batteryUsage = 0.0d;
                            event.update(lastEvent, BATTERY_USAGE_NONE);
                        }
                        event.update(lastEvent, batteryUsage);
                        batteryUsage = 0.0d;
                        batteryUsage.setTo(BATTERY_USAGE_NONE);
                        overlappingDuration = 0;
                    }
                    dest.add(event);
@@ -322,14 +331,15 @@ final class AppBatteryExemptionTracker
         * the system boots if the {@link #mIsStart} is true, but will be the delta of the bg
         * battery usage since the start event if the {@link #mIsStart} is false.
         */
        private double mBatteryUsage;
        private @NonNull ImmutableBatteryUsage mBatteryUsage;

        /**
         * The peer event of this pair (a pair of start/stop events).
         */
        private @Nullable UidStateEventWithBattery mPeer;

        UidStateEventWithBattery(boolean isStart, long now, double batteryUsage,
        UidStateEventWithBattery(boolean isStart, long now,
                @NonNull ImmutableBatteryUsage batteryUsage,
                @Nullable UidStateEventWithBattery peer) {
            super(now);
            mIsStart = isStart;
@@ -355,15 +365,19 @@ final class AppBatteryExemptionTracker
            }
            if (mPeer != null) {
                // Reduce the bg battery usage proportionally.
                final double batteryUsage = mPeer.getBatteryUsage();
                final ImmutableBatteryUsage batteryUsage = mPeer.getBatteryUsage();
                mPeer.mBatteryUsage = mPeer.getBatteryUsage(timestamp, mPeer.mTimestamp);
                // Update the battery data of the start event too.
                mBatteryUsage += batteryUsage - mPeer.mBatteryUsage;
                mBatteryUsage = mBatteryUsage.mutate()
                        .add(batteryUsage)
                        .subtract(mPeer.mBatteryUsage)
                        .unmutate();
            }
            mTimestamp = timestamp;
        }

        void update(@NonNull UidStateEventWithBattery peer, double batteryUsage) {
        void update(@NonNull UidStateEventWithBattery peer,
                @NonNull ImmutableBatteryUsage batteryUsage) {
            mPeer = peer;
            peer.mPeer = this;
            mBatteryUsage = batteryUsage;
@@ -373,18 +387,19 @@ final class AppBatteryExemptionTracker
            return mIsStart;
        }

        double getBatteryUsage(long start, long end) {
        @NonNull ImmutableBatteryUsage getBatteryUsage(long start, long end) {
            if (mIsStart || start >= mTimestamp || end <= start) {
                return 0.0d;
                return BATTERY_USAGE_NONE;
            }
            start = Math.max(start, mPeer.mTimestamp);
            end = Math.min(end, mTimestamp);
            final long totalDur = mTimestamp - mPeer.mTimestamp;
            final long inputDur = end - start;
            return totalDur != 0 ? mBatteryUsage * (1.0d * inputDur) / totalDur : 0.0d;
            return totalDur != 0 ? (totalDur == inputDur ? mBatteryUsage : mBatteryUsage.mutate()
                    .scale((1.0d * inputDur) / totalDur).unmutate()) : BATTERY_USAGE_NONE;
        }

        double getBatteryUsage() {
        @NonNull ImmutableBatteryUsage getBatteryUsage() {
            return mBatteryUsage;
        }

@@ -404,14 +419,20 @@ final class AppBatteryExemptionTracker
            final UidStateEventWithBattery otherEvent = (UidStateEventWithBattery) other;
            return otherEvent.mIsStart == mIsStart
                    && otherEvent.mTimestamp == mTimestamp
                    && Double.compare(otherEvent.mBatteryUsage, mBatteryUsage) == 0;
                    && mBatteryUsage.equals(otherEvent.mBatteryUsage);
        }

        @Override
        public String toString() {
            return "UidStateEventWithBattery(" + mIsStart + ", " + mTimestamp
                    + ", " + mBatteryUsage + ")";
        }

        @Override
        public int hashCode() {
            return (Boolean.hashCode(mIsStart) * 31
                    + Long.hashCode(mTimestamp)) * 31
                    + Double.hashCode(mBatteryUsage);
                    + mBatteryUsage.hashCode();
        }
    }

+495 −94

File changed.

Preview size limit exceeded, changes collapsed.

+4 −3
Original line number Diff line number Diff line
@@ -142,6 +142,7 @@ import com.android.internal.util.function.TriConsumer;
import com.android.server.AppStateTracker;
import com.android.server.LocalServices;
import com.android.server.SystemConfig;
import com.android.server.am.AppBatteryTracker.ImmutableBatteryUsage;
import com.android.server.apphibernation.AppHibernationManagerInternal;
import com.android.server.pm.UserManagerInternal;
import com.android.server.usage.AppStandbyInternal;
@@ -1076,7 +1077,7 @@ public final class AppRestrictionController {
     * @return The to-be-exempted battery usage of the given UID in the given duration; it could
     *         be considered as "exempted" due to various use cases, i.e. media playback.
     */
    double getUidBatteryExemptedUsageSince(int uid, long since, long now) {
    ImmutableBatteryUsage getUidBatteryExemptedUsageSince(int uid, long since, long now) {
        return mInjector.getAppBatteryExemptionTracker()
                .getUidBatteryExemptedUsageSince(uid, since, now);
    }
@@ -1084,7 +1085,7 @@ public final class AppRestrictionController {
    /**
     * @return The total battery usage of the given UID since the system boots.
     */
    double getUidBatteryUsage(int uid) {
    @NonNull ImmutableBatteryUsage getUidBatteryUsage(int uid) {
        return mInjector.getUidBatteryUsageProvider().getUidBatteryUsage(uid);
    }

@@ -1092,7 +1093,7 @@ public final class AppRestrictionController {
        /**
         * @return The total battery usage of the given UID since the system boots.
         */
        double getUidBatteryUsage(int uid);
        @NonNull ImmutableBatteryUsage getUidBatteryUsage(int uid);
    }

    void dump(PrintWriter pw, String prefix) {
+15 −10
Original line number Diff line number Diff line
@@ -46,9 +46,10 @@ import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_NONE;
import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;

import static com.android.internal.notification.SystemNotificationChannels.ABUSIVE_BACKGROUND_APPS;
import static com.android.server.am.AppBatteryTracker.BATT_DIMEN_BG;
import static com.android.server.am.AppBatteryTracker.BATT_DIMEN_FG;
import static com.android.server.am.AppBatteryTracker.BATT_DIMEN_FGS;
import static com.android.server.am.AppBatteryTracker.BatteryUsage.BATTERY_USAGE_INDEX_BACKGROUND;
import static com.android.server.am.AppBatteryTracker.BatteryUsage.BATTERY_USAGE_INDEX_FOREGROUND;
import static com.android.server.am.AppBatteryTracker.BatteryUsage.BATTERY_USAGE_INDEX_FOREGROUND_SERVICE;
import static com.android.server.am.AppBatteryTracker.BatteryUsage.BATT_DIMENS;
import static com.android.server.am.AppRestrictionController.STOCK_PM_FLAGS;

import static org.junit.Assert.assertEquals;
@@ -113,6 +114,7 @@ import com.android.server.am.AppBatteryExemptionTracker.AppBatteryExemptionPolic
import com.android.server.am.AppBatteryExemptionTracker.UidBatteryStates;
import com.android.server.am.AppBatteryExemptionTracker.UidStateEventWithBattery;
import com.android.server.am.AppBatteryTracker.AppBatteryPolicy;
import com.android.server.am.AppBatteryTracker.ImmutableBatteryUsage;
import com.android.server.am.AppBindServiceEventsTracker.AppBindServiceEventsPolicy;
import com.android.server.am.AppBroadcastEventsTracker.AppBroadcastEventsPolicy;
import com.android.server.am.AppFGSTracker.AppFGSPolicy;
@@ -566,7 +568,7 @@ public final class BackgroundRestrictionTest {
                    DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
                    AppBatteryPolicy.KEY_BG_CURRENT_DRAIN_THRESHOLD_TO_RESTRICTED_BUCKET,
                    DeviceConfig::getFloat,
                    AppBatteryPolicy.DEFAULT_BG_CURRENT_DRAIN_BG_RESTRICTED_THRESHOLD);
                    AppBatteryPolicy.DEFAULT_BG_CURRENT_DRAIN_RESTRICTED_BUCKET_THRESHOLD);
            bgCurrentDrainRestrictedBucketThreshold.set(restrictBucketThreshold);

            bgCurrentDrainBgRestrictedThreshold = new DeviceConfigSession<>(
@@ -1294,7 +1296,7 @@ public final class BackgroundRestrictionTest {
                    DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
                    AppBatteryPolicy.KEY_BG_CURRENT_DRAIN_THRESHOLD_TO_RESTRICTED_BUCKET,
                    DeviceConfig::getFloat,
                    AppBatteryPolicy.DEFAULT_BG_CURRENT_DRAIN_BG_RESTRICTED_THRESHOLD);
                    AppBatteryPolicy.DEFAULT_BG_CURRENT_DRAIN_RESTRICTED_BUCKET_THRESHOLD);
            bgCurrentDrainRestrictedBucketThreshold.set(restrictBucketThreshold);

            bgCurrentDrainBgRestrictedThreshold = new DeviceConfigSession<>(
@@ -1932,9 +1934,12 @@ public final class BackgroundRestrictionTest {
    private UidBatteryConsumer mockUidBatteryConsumer(int uid, double bg, double fgs, double fg) {
        UidBatteryConsumer uidConsumer = mock(UidBatteryConsumer.class);
        doReturn(uid).when(uidConsumer).getUid();
        doReturn(bg).when(uidConsumer).getConsumedPower(eq(BATT_DIMEN_BG));
        doReturn(fgs).when(uidConsumer).getConsumedPower(eq(BATT_DIMEN_FGS));
        doReturn(fg).when(uidConsumer).getConsumedPower(eq(BATT_DIMEN_FG));
        doReturn(bg).when(uidConsumer).getConsumedPower(
                eq(BATT_DIMENS[BATTERY_USAGE_INDEX_BACKGROUND]));
        doReturn(fgs).when(uidConsumer).getConsumedPower(
                eq(BATT_DIMENS[BATTERY_USAGE_INDEX_FOREGROUND_SERVICE]));
        doReturn(fg).when(uidConsumer).getConsumedPower(
                eq(BATT_DIMENS[BATTERY_USAGE_INDEX_FOREGROUND]));
        return uidConsumer;
    }

@@ -2234,8 +2239,8 @@ public final class BackgroundRestrictionTest {
            boolean[] isStart, long[] timestamps, double[] batteryUsage) {
        final LinkedList<UidStateEventWithBattery> result = new LinkedList<>();
        for (int i = 0; i < isStart.length; i++) {
            result.add(new UidStateEventWithBattery(
                    isStart[i], timestamps[i], batteryUsage[i], null));
            result.add(new UidStateEventWithBattery(isStart[i], timestamps[i],
                        new ImmutableBatteryUsage(0.0d, 0.0d, batteryUsage[i], 0.0d), null));
        }
        return result;
    }