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

Commit 3e013e85 authored by Jeff Sharkey's avatar Jeff Sharkey
Browse files

Track foreground activities in battery stats.

To help correlate battery usage against actual foreground app usage,
start tracking time on a per UID basis.  It uses the nesting feature
of StopwatchTimer to track multiple PIDs inside the same UID.

Improves units on docs, and persists foreground CPU time with a
consistent ordering.  Reports foreground activities time and
foreground CPU time.

Change-Id: I95d12963923e3fd421730f6fbfc842dfd8d3a055
parent 58b98d39
Loading
Loading
Loading
Loading
+55 −16
Original line number Diff line number Diff line
@@ -97,6 +97,11 @@ public abstract class BatteryStats implements Parcelable {
     */
    public static final int VIBRATOR_ON = 9;

    /**
     * A constant indicating a foreground activity timer
     */
    public static final int FOREGROUND_ACTIVITY = 10;

    /**
     * Include all of the data in the stats, including previously saved data.
     */
@@ -125,7 +130,7 @@ public abstract class BatteryStats implements Parcelable {
    /**
     * Bump the version on this if the checkin format changes.
     */
    private static final int BATTERY_STATS_CHECKIN_VERSION = 5;
    private static final int BATTERY_STATS_CHECKIN_VERSION = 6;
    
    private static final long BYTES_PER_KB = 1024;
    private static final long BYTES_PER_MB = 1048576; // 1024^2
@@ -137,6 +142,7 @@ public abstract class BatteryStats implements Parcelable {
    private static final String PROCESS_DATA = "pr";
    private static final String SENSOR_DATA = "sr";
    private static final String VIBRATOR_DATA = "vib";
    private static final String FOREGROUND_DATA = "fg";
    private static final String WAKELOCK_DATA = "wl";
    private static final String KERNEL_WAKELOCK_DATA = "kwl";
    private static final String NETWORK_DATA = "nt";
@@ -276,6 +282,8 @@ public abstract class BatteryStats implements Parcelable {
        public abstract void noteAudioTurnedOffLocked();
        public abstract void noteVideoTurnedOnLocked();
        public abstract void noteVideoTurnedOffLocked();
        public abstract void noteActivityResumedLocked();
        public abstract void noteActivityPausedLocked();
        public abstract long getWifiRunningTime(long batteryRealtime, int which);
        public abstract long getFullWifiLockTime(long batteryRealtime, int which);
        public abstract long getWifiScanTime(long batteryRealtime, int which);
@@ -283,6 +291,7 @@ public abstract class BatteryStats implements Parcelable {
                                                  int which);
        public abstract long getAudioTurnedOnTime(long batteryRealtime, int which);
        public abstract long getVideoTurnedOnTime(long batteryRealtime, int which);
        public abstract Timer getForegroundActivityTimer();
        public abstract Timer getVibratorOnTimer();

        /**
@@ -1417,22 +1426,31 @@ public abstract class BatteryStats implements Parcelable {
                }
            }

            Timer fgTimer = u.getForegroundActivityTimer();
            if (fgTimer != null) {
                // Convert from microseconds to milliseconds with rounding
                long totalTime = (fgTimer.getTotalTimeLocked(batteryRealtime, which) + 500) / 1000;
                int count = fgTimer.getCountLocked(which);
                if (totalTime != 0) {
                    dumpLine(pw, uid, category, FOREGROUND_DATA, totalTime, count);
                }
            }

            Map<String, ? extends BatteryStats.Uid.Proc> processStats = u.getProcessStats();
            if (processStats.size() > 0) {
                for (Map.Entry<String, ? extends BatteryStats.Uid.Proc> ent
                        : processStats.entrySet()) {
                    Uid.Proc ps = ent.getValue();

                    long userTime = ps.getUserTime(which);
                    long systemTime = ps.getSystemTime(which);
                    int starts = ps.getStarts(which);
                    final long userMillis = ps.getUserTime(which) * 10;
                    final long systemMillis = ps.getSystemTime(which) * 10;
                    final long foregroundMillis = ps.getForegroundTime(which) * 10;
                    final long starts = ps.getStarts(which);

                    if (userTime != 0 || systemTime != 0 || starts != 0) {
                        dumpLine(pw, uid, category, PROCESS_DATA, 
                                ent.getKey(), // proc
                                userTime * 10, // cpu time in ms
                                systemTime * 10, // user time in ms
                                starts); // process starts
                    if (userMillis != 0 || systemMillis != 0 || foregroundMillis != 0
                            || starts != 0) {
                        dumpLine(pw, uid, category, PROCESS_DATA, ent.getKey(), userMillis,
                                systemMillis, foregroundMillis, starts);
                    }
                }
            }
@@ -1961,6 +1979,24 @@ public abstract class BatteryStats implements Parcelable {
                }
            }

            Timer fgTimer = u.getForegroundActivityTimer();
            if (fgTimer != null) {
                // Convert from microseconds to milliseconds with rounding
                long totalTime = (fgTimer.getTotalTimeLocked(batteryRealtime, which) + 500) / 1000;
                int count = fgTimer.getCountLocked(which);
                if (totalTime != 0) {
                    sb.setLength(0);
                    sb.append(prefix);
                    sb.append("    Foreground activities: ");
                    formatTimeMs(sb, totalTime);
                    sb.append("realtime (");
                    sb.append(count);
                    sb.append(" times)");
                    pw.println(sb.toString());
                    uidActivity = true;
                }
            }

            Map<String, ? extends BatteryStats.Uid.Proc> processStats = u.getProcessStats();
            if (processStats.size() > 0) {
                for (Map.Entry<String, ? extends BatteryStats.Uid.Proc> ent
@@ -1968,23 +2004,26 @@ public abstract class BatteryStats implements Parcelable {
                    Uid.Proc ps = ent.getValue();
                    long userTime;
                    long systemTime;
                    long foregroundTime;
                    int starts;
                    int numExcessive;

                    userTime = ps.getUserTime(which);
                    systemTime = ps.getSystemTime(which);
                    foregroundTime = ps.getForegroundTime(which);
                    starts = ps.getStarts(which);
                    numExcessive = which == STATS_SINCE_CHARGED
                            ? ps.countExcessivePowers() : 0;

                    if (userTime != 0 || systemTime != 0 || starts != 0
                    if (userTime != 0 || systemTime != 0 || foregroundTime != 0 || starts != 0
                            || numExcessive != 0) {
                        sb.setLength(0);
                        sb.append(prefix); sb.append("    Proc ");
                                sb.append(ent.getKey()); sb.append(":\n");
                        sb.append(prefix); sb.append("      CPU: ");
                                formatTime(sb, userTime); sb.append("usr + ");
                                formatTime(sb, systemTime); sb.append("krn");
                                formatTime(sb, systemTime); sb.append("krn ; ");
                                formatTime(sb, foregroundTime); sb.append("fg");
                        if (starts != 0) {
                            sb.append("\n"); sb.append(prefix); sb.append("      ");
                                    sb.append(starts); sb.append(" proc starts");
+86 −20
Original line number Diff line number Diff line
@@ -83,7 +83,7 @@ public final class BatteryStatsImpl extends BatteryStats {
    private static final int MAGIC = 0xBA757475; // 'BATSTATS'

    // Current on-disk Parcel version
    private static final int VERSION = 64 + (USE_OLD_HISTORY ? 1000 : 0);
    private static final int VERSION = 65 + (USE_OLD_HISTORY ? 1000 : 0);

    // Maximum number of items we will record in the history.
    private static final int MAX_HISTORY_ITEMS = 2000;
@@ -2240,6 +2240,14 @@ public final class BatteryStatsImpl extends BatteryStats {
        getUidStatsLocked(uid).noteVideoTurnedOffLocked();
    }

    public void noteActivityResumedLocked(int uid) {
        getUidStatsLocked(uid).noteActivityResumedLocked();
    }

    public void noteActivityPausedLocked(int uid) {
        getUidStatsLocked(uid).noteActivityPausedLocked();
    }

    public void noteVibratorOnLocked(int uid, long durationMillis) {
        getUidStatsLocked(uid).noteVibratorOnLocked(durationMillis);
    }
@@ -2541,6 +2549,8 @@ public final class BatteryStatsImpl extends BatteryStats {
        boolean mVideoTurnedOn;
        StopwatchTimer mVideoTurnedOnTimer;

        StopwatchTimer mForegroundActivityTimer;

        BatchTimer mVibratorOnTimer;

        Counter[] mUserActivityCounters;
@@ -2776,6 +2786,27 @@ public final class BatteryStatsImpl extends BatteryStats {
            }
        }

        public StopwatchTimer createForegroundActivityTimerLocked() {
            if (mForegroundActivityTimer == null) {
                mForegroundActivityTimer = new StopwatchTimer(
                        Uid.this, FOREGROUND_ACTIVITY, null, mUnpluggables);
            }
            return mForegroundActivityTimer;
        }

        @Override
        public void noteActivityResumedLocked() {
            // We always start, since we want multiple foreground PIDs to nest
            createForegroundActivityTimerLocked().startRunningLocked(BatteryStatsImpl.this);
        }

        @Override
        public void noteActivityPausedLocked() {
            if (mForegroundActivityTimer != null) {
                mForegroundActivityTimer.stopRunningLocked(BatteryStatsImpl.this);
            }
        }

        public BatchTimer createVibratorOnTimerLocked() {
            if (mVibratorOnTimer == null) {
                mVibratorOnTimer = new BatchTimer(Uid.this, VIBRATOR_ON,
@@ -2843,6 +2874,11 @@ public final class BatteryStatsImpl extends BatteryStats {
            return mVideoTurnedOnTimer.getTotalTimeLocked(batteryRealtime, which);
        }

        @Override
        public Timer getForegroundActivityTimer() {
            return mForegroundActivityTimer;
        }

        @Override
        public Timer getVibratorOnTimer() {
            return mVibratorOnTimer;
@@ -2919,6 +2955,9 @@ public final class BatteryStatsImpl extends BatteryStats {
                active |= !mVideoTurnedOnTimer.reset(BatteryStatsImpl.this, false);
                active |= mVideoTurnedOn;
            }
            if (mForegroundActivityTimer != null) {
                active |= !mForegroundActivityTimer.reset(BatteryStatsImpl.this, false);
            }
            if (mVibratorOnTimer != null) {
                if (mVibratorOnTimer.reset(BatteryStatsImpl.this, false)) {
                    mVibratorOnTimer.detach();
@@ -3018,6 +3057,10 @@ public final class BatteryStatsImpl extends BatteryStats {
                    mVideoTurnedOnTimer.detach();
                    mVideoTurnedOnTimer = null;
                }
                if (mForegroundActivityTimer != null) {
                    mForegroundActivityTimer.detach();
                    mForegroundActivityTimer = null;
                }
                if (mUserActivityCounters != null) {
                    for (int i=0; i<NUM_USER_ACTIVITY_TYPES; i++) {
                        mUserActivityCounters[i].detach();
@@ -3099,6 +3142,12 @@ public final class BatteryStatsImpl extends BatteryStats {
            } else {
                out.writeInt(0);
            }
            if (mForegroundActivityTimer != null) {
                out.writeInt(1);
                mForegroundActivityTimer.writeToParcel(out, batteryRealtime);
            } else {
                out.writeInt(0);
            }
            if (mVibratorOnTimer != null) {
                out.writeInt(1);
                mVibratorOnTimer.writeToParcel(out, batteryRealtime);
@@ -3203,6 +3252,12 @@ public final class BatteryStatsImpl extends BatteryStats {
            } else {
                mVideoTurnedOnTimer = null;
            }
            if (in.readInt() != 0) {
                mForegroundActivityTimer = new StopwatchTimer(
                        Uid.this, FOREGROUND_ACTIVITY, null, mUnpluggables, in);
            } else {
                mForegroundActivityTimer = null;
            }
            if (in.readInt() != 0) {
                mVibratorOnTimer = new BatchTimer(Uid.this, VIBRATOR_ON,
                        mUnpluggables, BatteryStatsImpl.this.mOnBatteryInternal, in);
@@ -3372,14 +3427,14 @@ public final class BatteryStatsImpl extends BatteryStats {
            long mSystemTime;

            /**
             * Number of times the process has been started.
             * Amount of time the process was running in the foreground.
             */
            int mStarts;
            long mForegroundTime;

            /**
             * Amount of time the process was running in the foreground.
             * Number of times the process has been started.
             */
            long mForegroundTime;
            int mStarts;

            /**
             * The amount of user time loaded from a previous save.
@@ -3392,14 +3447,14 @@ public final class BatteryStatsImpl extends BatteryStats {
            long mLoadedSystemTime;

            /**
             * The number of times the process has started from a previous save.
             * The amount of foreground time loaded from a previous save.
             */
            int mLoadedStarts;
            long mLoadedForegroundTime;

            /**
             * The amount of foreground time loaded from a previous save.
             * The number of times the process has started from a previous save.
             */
            long mLoadedForegroundTime;
            int mLoadedStarts;

            /**
             * The amount of user time loaded from the previous run.
@@ -3412,14 +3467,14 @@ public final class BatteryStatsImpl extends BatteryStats {
            long mLastSystemTime;

            /**
             * The number of times the process has started from the previous run.
             * The amount of foreground time loaded from the previous run
             */
            int mLastStarts;
            long mLastForegroundTime;

            /**
             * The amount of foreground time loaded from the previous run
             * The number of times the process has started from the previous run.
             */
            long mLastForegroundTime;
            int mLastStarts;

            /**
             * The amount of user time when last unplugged.
@@ -3432,14 +3487,14 @@ public final class BatteryStatsImpl extends BatteryStats {
            long mUnpluggedSystemTime;

            /**
             * The number of times the process has started before unplugged.
             * The amount of foreground time since unplugged.
             */
            int mUnpluggedStarts;
            long mUnpluggedForegroundTime;

            /**
             * The amount of foreground time since unplugged.
             * The number of times the process has started before unplugged.
             */
            long mUnpluggedForegroundTime;
            int mUnpluggedStarts;

            SamplingCounter[] mSpeedBins;

@@ -3453,8 +3508,8 @@ public final class BatteryStatsImpl extends BatteryStats {
            public void unplug(long elapsedRealtime, long batteryUptime, long batteryRealtime) {
                mUnpluggedUserTime = mUserTime;
                mUnpluggedSystemTime = mSystemTime;
                mUnpluggedStarts = mStarts;
                mUnpluggedForegroundTime = mForegroundTime;
                mUnpluggedStarts = mStarts;
            }

            public void plug(long elapsedRealtime, long batteryUptime, long batteryRealtime) {
@@ -5361,6 +5416,9 @@ public final class BatteryStatsImpl extends BatteryStats {
            if (in.readInt() != 0) {
                u.createVideoTurnedOnTimerLocked().readSummaryFromParcelLocked(in);
            }
            if (in.readInt() != 0) {
                u.createForegroundActivityTimerLocked().readSummaryFromParcelLocked(in);
            }
            if (in.readInt() != 0) {
                u.createVibratorOnTimerLocked().readSummaryFromParcelLocked(in);
            }
@@ -5415,6 +5473,7 @@ public final class BatteryStatsImpl extends BatteryStats {
                Uid.Proc p = u.getProcessStatsLocked(procName);
                p.mUserTime = p.mLoadedUserTime = in.readLong();
                p.mSystemTime = p.mLoadedSystemTime = in.readLong();
                p.mForegroundTime = p.mLoadedForegroundTime = in.readLong();
                p.mStarts = p.mLoadedStarts = in.readInt();
                int NSB = in.readInt();
                if (NSB > 100) {
@@ -5564,6 +5623,12 @@ public final class BatteryStatsImpl extends BatteryStats {
            } else {
                out.writeInt(0);
            }
            if (u.mForegroundActivityTimer != null) {
                out.writeInt(1);
                u.mForegroundActivityTimer.writeSummaryFromParcelLocked(out, NOWREAL);
            } else {
                out.writeInt(0);
            }
            if (u.mVibratorOnTimer != null) {
                out.writeInt(1);
                u.mVibratorOnTimer.writeSummaryFromParcelLocked(out, NOWREAL);
@@ -5633,6 +5698,7 @@ public final class BatteryStatsImpl extends BatteryStats {
                    Uid.Proc ps = ent.getValue();
                    out.writeLong(ps.mUserTime);
                    out.writeLong(ps.mSystemTime);
                    out.writeLong(ps.mForegroundTime);
                    out.writeInt(ps.mStarts);
                    final int N = ps.mSpeedBins.length;
                    out.writeInt(N);
+7 −3
Original line number Diff line number Diff line
@@ -518,6 +518,10 @@ public class ProcessStats {
        return pids;
    }

    /**
     * Returns the total time (in clock ticks, or 1/100 sec) spent executing in
     * both user and system code.
     */
    public long getCpuTimeForPid(int pid) {
        final String statFile = "/proc/" + pid + "/stat";
        final long[] statsData = mSinglePidStatsData;
@@ -531,9 +535,9 @@ public class ProcessStats {
    }

    /**
     * Returns the times spent at each CPU speed, since the last call to this method. If this
     * is the first time, it will return 1 for each value.
     * @return relative times spent at different speed steps.
     * Returns the delta time (in clock ticks, or 1/100 sec) spent at each CPU
     * speed, since the last call to this method. If this is the first call, it
     * will return 1 for each value.
     */
    public long[] getLastCpuSpeedTimes() {
        if (mCpuSpeedTimes == null) {
+12 −5
Original line number Diff line number Diff line
@@ -2340,13 +2340,19 @@ public final class ActivityManagerService extends ActivityManagerNative
        }
    }
    void updateUsageStats(ActivityRecord resumedComponent, boolean resumed) {
        if (DEBUG_SWITCH) Slog.d(TAG, "updateUsageStats: comp=" + resumedComponent + "res="
                + resumed);
    void updateUsageStats(ActivityRecord component, boolean resumed) {
        if (DEBUG_SWITCH) Slog.d(TAG, "updateUsageStats: comp=" + component + "res=" + resumed);
        final BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
        if (resumed) {
            mUsageStatsService.noteResumeComponent(resumedComponent.realActivity);
            mUsageStatsService.noteResumeComponent(component.realActivity);
            synchronized (stats) {
                stats.noteActivityResumedLocked(component.app.uid);
            }
        } else {
            mUsageStatsService.notePauseComponent(resumedComponent.realActivity);
            mUsageStatsService.notePauseComponent(component.realActivity);
            synchronized (stats) {
                stats.noteActivityPausedLocked(component.app.uid);
            }
        }
    }
@@ -2542,6 +2548,7 @@ public final class ActivityManagerService extends ActivityManagerNative
            mPendingProcessChanges.clear();
            if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG, "*** Delivering " + N + " process changes");
        }
        int i = mProcessObservers.beginBroadcast();
        while (i > 0) {
            i--;