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

Commit e5167ca6 authored by Dianne Hackborn's avatar Dianne Hackborn
Browse files

Reduce wake lock noise in battery history.

When the work source of a wake lock was changed, this would
cause the old wake lock to be released in battery stats before
the new one was acquired (the power manager would correctly
keep holding the associated wake lock).  This resulted in a
pointless entry in the battery history showing the last wake
lock being released and a new one acquired.

This change adds a new path in to battery stats to report
when a wake lock has changed, allowing it to acquire the
new wake locks first before the old ones, so it can't drop
down to zero wake locks.  This also provides better timing
information, as the same current time can be used for both
operations.

In addition, added a new kind of history entry for the
current time, so you can tell when in actual world clock
time the battery data is happening.

Change-Id: Ibbf2eed83bb93f31f60267889b7bc5b9e71e355f
parent 30df0be2
Loading
Loading
Loading
Loading
+48 −22
Original line number Diff line number Diff line
@@ -343,8 +343,9 @@ public abstract class BatteryStats implements Parcelable {
        }

        public class Pid {
            public long mWakeSum;
            public long mWakeStart;
            public int mWakeNesting;
            public long mWakeSumMs;
            public long mWakeStartMs;
        }

        /**
@@ -515,7 +516,8 @@ public abstract class BatteryStats implements Parcelable {
        public static final byte CMD_UPDATE = 0;        // These can be written as deltas
        public static final byte CMD_NULL = -1;
        public static final byte CMD_START = 4;
        public static final byte CMD_OVERFLOW = 5;
        public static final byte CMD_CURRENT_TIME = 5;
        public static final byte CMD_OVERFLOW = 6;

        public byte cmd = CMD_NULL;
        
@@ -610,6 +612,9 @@ public abstract class BatteryStats implements Parcelable {
        public int eventCode;
        public HistoryTag eventTag;

        // Only set for CMD_CURRENT_TIME.
        public long currentTime;

        // Meta-data when reading.
        public int numReadInts;

@@ -637,29 +642,28 @@ public abstract class BatteryStats implements Parcelable {
                    | ((((int)batteryLevel)<<8)&0xff00)
                    | ((((int)batteryStatus)<<16)&0xf0000)
                    | ((((int)batteryHealth)<<20)&0xf00000)
                    | ((((int)batteryPlugType)<<24)&0xf000000);
                    | ((((int)batteryPlugType)<<24)&0xf000000)
                    | (wakelockTag != null ? 0x10000000 : 0)
                    | (wakeReasonTag != null ? 0x20000000 : 0)
                    | (eventCode != EVENT_NONE ? 0x40000000 : 0);
            dest.writeInt(bat);
            bat = (((int)batteryTemperature)&0xffff)
                    | ((((int)batteryVoltage)<<16)&0xffff0000);
            dest.writeInt(bat);
            dest.writeInt(states);
            if (wakelockTag != null) {
                dest.writeInt(1);
                wakelockTag.writeToParcel(dest, flags);
            } else {
                dest.writeInt(0);
            }
            if (wakeReasonTag != null) {
                dest.writeInt(1);
                wakeReasonTag.writeToParcel(dest, flags);
            } else {
                dest.writeInt(0);
            }
            dest.writeInt(eventCode);
            if (eventCode != EVENT_NONE) {
                dest.writeInt(eventCode);
                eventTag.writeToParcel(dest, flags);
            }
            if (cmd == CMD_CURRENT_TIME) {
                dest.writeLong(currentTime);
            }
        }

        public void readFromParcel(Parcel src) {
@@ -670,26 +674,34 @@ public abstract class BatteryStats implements Parcelable {
            batteryStatus = (byte)((bat>>16)&0xf);
            batteryHealth = (byte)((bat>>20)&0xf);
            batteryPlugType = (byte)((bat>>24)&0xf);
            bat = src.readInt();
            batteryTemperature = (short)(bat&0xffff);
            batteryVoltage = (char)((bat>>16)&0xffff);
            int bat2 = src.readInt();
            batteryTemperature = (short)(bat2&0xffff);
            batteryVoltage = (char)((bat2>>16)&0xffff);
            states = src.readInt();
            if (src.readInt() != 0) {
            if ((bat&0x10000000) != 0) {
                wakelockTag = localWakelockTag;
                wakelockTag.readFromParcel(src);
            } else {
                wakelockTag = null;
            }
            if (src.readInt() != 0) {
            if ((bat&0x20000000) != 0) {
                wakeReasonTag = localWakeReasonTag;
                wakeReasonTag.readFromParcel(src);
            } else {
                wakeReasonTag = null;
            }
            if ((bat&0x40000000) != 0) {
                eventCode = src.readInt();
            if (eventCode != EVENT_NONE) {
                eventTag = localEventTag;
                eventTag.readFromParcel(src);
            } else {
                eventCode = EVENT_NONE;
                eventTag = null;
            }
            if (cmd == CMD_CURRENT_TIME) {
                currentTime = src.readLong();
            } else {
                currentTime = 0;
            }
            numReadInts += (src.dataPosition()-start)/4;
        }
@@ -749,6 +761,7 @@ public abstract class BatteryStats implements Parcelable {
            } else {
                eventTag = null;
            }
            currentTime = o.currentTime;
        }

        public boolean sameNonEvent(HistoryItem o) {
@@ -758,7 +771,8 @@ public abstract class BatteryStats implements Parcelable {
                    && batteryPlugType == o.batteryPlugType
                    && batteryTemperature == o.batteryTemperature
                    && batteryVoltage == o.batteryVoltage
                    && states == o.states;
                    && states == o.states
                    && currentTime == o.currentTime;
        }

        public boolean same(HistoryItem o) {
@@ -2788,6 +2802,18 @@ public abstract class BatteryStats implements Parcelable {
                    pw.print(":");
                }
                pw.println("START");
            } else if (rec.cmd == HistoryItem.CMD_CURRENT_TIME) {
                if (checkin) {
                    pw.print(":");
                }
                pw.print("TIME:");
                if (checkin) {
                    pw.println(rec.currentTime);
                } else {
                    pw.print(" ");
                    pw.println(DateFormat.format("yyyy-MM-dd-HH-mm-ss",
                            rec.currentTime).toString());
                }
            } else if (rec.cmd == HistoryItem.CMD_OVERFLOW) {
                if (checkin) {
                    pw.print(":");
@@ -2941,10 +2967,10 @@ public abstract class BatteryStats implements Parcelable {
                    }
                }
                pw.println();
            }
                oldState = rec.states;
            }
        }
    }

    private void printSizeValue(PrintWriter pw, long size) {
        float result = size;
@@ -3059,8 +3085,8 @@ public abstract class BatteryStats implements Parcelable {
                            pw.println("Per-PID Stats:");
                            didPid = true;
                        }
                        long time = pid.mWakeSum + (pid.mWakeStart != 0
                                ? (nowRealtime - pid.mWakeStart) : 0);
                        long time = pid.mWakeSumMs + (pid.mWakeNesting > 0
                                ? (nowRealtime - pid.mWakeStartMs) : 0);
                        pw.print("  PID "); pw.print(pids.keyAt(j));
                                pw.print(" wake time: ");
                                TimeUtils.formatDuration(time, pw);
+3 −0
Original line number Diff line number Diff line
@@ -41,6 +41,9 @@ interface IBatteryStats {

    void noteStartWakelockFromSource(in WorkSource ws, int pid, String name, String historyName,
            int type, boolean unimportantForLogging);
    void noteChangeWakelockFromSource(in WorkSource ws, int pid, String name, int type,
            in WorkSource newWs, int newPid, String newName,
            String newHistoryName, int newType, boolean newUnimportantForLogging);
    void noteStopWakelockFromSource(in WorkSource ws, int pid, String name, int type);

    void noteVibratorOn(int uid, long durationMillis);
+56 −26
Original line number Diff line number Diff line
@@ -87,7 +87,7 @@ public final class BatteryStatsImpl extends BatteryStats {
    private static final int MAGIC = 0xBA757475; // 'BATSTATS'

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

    // Maximum number of items we will record in the history.
    private static final int MAX_HISTORY_ITEMS = 2000;
@@ -2274,9 +2274,8 @@ public final class BatteryStatsImpl extends BatteryStats {
    }

    public void noteStartWakeLocked(int uid, int pid, String name, String historyName, int type,
            boolean unimportantForLogging) {
            boolean unimportantForLogging, long elapsedRealtime) {
        uid = mapUid(uid);
        final long elapsedRealtime = SystemClock.elapsedRealtime();
        if (type == WAKE_TYPE_PARTIAL) {
            // Only care about partial wake locks, since full wake locks
            // will be canceled when the user puts the screen to sleep.
@@ -2308,9 +2307,8 @@ public final class BatteryStatsImpl extends BatteryStats {
        }
    }

    public void noteStopWakeLocked(int uid, int pid, String name, int type) {
    public void noteStopWakeLocked(int uid, int pid, String name, int type, long elapsedRealtime) {
        uid = mapUid(uid);
        final long elapsedRealtime = SystemClock.elapsedRealtime();
        if (type == WAKE_TYPE_PARTIAL) {
            mWakeLockNesting--;
            if (mWakeLockNesting == 0) {
@@ -2328,16 +2326,37 @@ public final class BatteryStatsImpl extends BatteryStats {

    public void noteStartWakeFromSourceLocked(WorkSource ws, int pid, String name,
            String historyName, int type, boolean unimportantForLogging) {
        int N = ws.size();
        final long elapsedRealtime = SystemClock.elapsedRealtime();
        final int N = ws.size();
        for (int i=0; i<N; i++) {
            noteStartWakeLocked(ws.get(i), pid, name, historyName, type, unimportantForLogging);
            noteStartWakeLocked(ws.get(i), pid, name, historyName, type, unimportantForLogging,
                    elapsedRealtime);
        }
    }

    public void noteChangeWakelockFromSourceLocked(WorkSource ws, int pid, String name, int type,
            WorkSource newWs, int newPid, String newName,
            String newHistoryName, int newType, boolean newUnimportantForLogging) {
        final long elapsedRealtime = SystemClock.elapsedRealtime();
        // For correct semantics, we start the need worksources first, so that we won't
        // make inappropriate history items as if all wake locks went away and new ones
        // appeared.  This is okay because tracking of wake locks allows nesting.
        final int NN = ws.size();
        for (int i=0; i<NN; i++) {
            noteStartWakeLocked(newWs.get(i), newPid, newName, newHistoryName, newType,
                    newUnimportantForLogging, elapsedRealtime);
        }
        final int NO = ws.size();
        for (int i=0; i<NO; i++) {
            noteStopWakeLocked(ws.get(i), pid, name, type, elapsedRealtime);
        }
    }

    public void noteStopWakeFromSourceLocked(WorkSource ws, int pid, String name, int type) {
        int N = ws.size();
        final long elapsedRealtime = SystemClock.elapsedRealtime();
        final int N = ws.size();
        for (int i=0; i<N; i++) {
            noteStopWakeLocked(ws.get(i), pid, name, type);
            noteStopWakeLocked(ws.get(i), pid, name, type, elapsedRealtime);
        }
    }

@@ -2466,7 +2485,7 @@ public final class BatteryStatsImpl extends BatteryStats {
        if (u != null) {
            Uid.Pid p = u.mPids.get(pid);
            if (p != null) {
                return p.mWakeSum + (p.mWakeStart != 0 ? (realtime - p.mWakeStart) : 0);
                return p.mWakeSumMs + (p.mWakeNesting > 0 ? (realtime - p.mWakeStartMs) : 0);
            }
        }
        return 0;
@@ -2562,7 +2581,7 @@ public final class BatteryStatsImpl extends BatteryStats {

            // Fake a wake lock, so we consider the device waked as long
            // as the screen is on.
            noteStartWakeLocked(-1, -1, "screen", null, WAKE_TYPE_PARTIAL, false);
            noteStartWakeLocked(-1, -1, "screen", null, WAKE_TYPE_PARTIAL, false, elapsedRealtime);

            // Update discharge amounts.
            if (mOnBatteryInternal) {
@@ -2584,7 +2603,7 @@ public final class BatteryStatsImpl extends BatteryStats {
                mScreenBrightnessTimer[mScreenBrightnessBin].stopRunningLocked(elapsedRealtime);
            }

            noteStopWakeLocked(-1, -1, "screen", WAKE_TYPE_PARTIAL);
            noteStopWakeLocked(-1, -1, "screen", WAKE_TYPE_PARTIAL, elapsedRealtime);

            updateTimeBasesLocked(mOnBatteryTimeBase.isRunning(), true,
                    SystemClock.uptimeMillis() * 1000, elapsedRealtime * 1000);
@@ -3999,10 +4018,12 @@ public final class BatteryStatsImpl extends BatteryStats {
                mProcessStats.clear();
            }
            if (mPids.size() > 0) {
                for (int i=0; !active && i<mPids.size(); i++) {
                for (int i=mPids.size()-1; i>=0; i--) {
                    Pid pid = mPids.valueAt(i);
                    if (pid.mWakeStart != 0) {
                    if (pid.mWakeNesting > 0) {
                        active = true;
                    } else {
                        mPids.removeAt(i);
                    }
                }
            }
@@ -4024,8 +4045,6 @@ public final class BatteryStatsImpl extends BatteryStats {
                mPackageStats.clear();
            }

            mPids.clear();

            if (!active) {
                if (mWifiRunningTimer != null) {
                    mWifiRunningTimer.detach();
@@ -4067,6 +4086,7 @@ public final class BatteryStatsImpl extends BatteryStats {
                        mNetworkPacketActivityCounters[i].detach();
                    }
                }
                mPids.clear();
            }

            return !active;
@@ -5304,8 +5324,8 @@ public final class BatteryStatsImpl extends BatteryStats {
            }
            if (pid >= 0 && type == WAKE_TYPE_PARTIAL) {
                Pid p = getPidStatsLocked(pid);
                if (p.mWakeStart == 0) {
                    p.mWakeStart = elapsedRealtimeMs;
                if (p.mWakeNesting++ == 0) {
                    p.mWakeStartMs = elapsedRealtimeMs;
                }
            }
        }
@@ -5317,9 +5337,11 @@ public final class BatteryStatsImpl extends BatteryStats {
            }
            if (pid >= 0 && type == WAKE_TYPE_PARTIAL) {
                Pid p = mPids.get(pid);
                if (p != null && p.mWakeStart != 0) {
                    p.mWakeSum += elapsedRealtimeMs - p.mWakeStart;
                    p.mWakeStart = 0;
                if (p != null && p.mWakeNesting > 0) {
                    if (p.mWakeNesting-- == 1) {
                        p.mWakeSumMs += elapsedRealtimeMs - p.mWakeStartMs;
                        p.mWakeStartMs = 0;
                    }
                }
            }
        }
@@ -5765,6 +5787,9 @@ public final class BatteryStatsImpl extends BatteryStats {
            mHistoryCur.states &= ~HistoryItem.STATE_BATTERY_PLUGGED_FLAG;
            if (DEBUG_HISTORY) Slog.v(TAG, "Battery unplugged to: "
                    + Integer.toHexString(mHistoryCur.states));
            mHistoryCur.currentTime = System.currentTimeMillis();
            addHistoryBufferLocked(mSecRealtime, HistoryItem.CMD_CURRENT_TIME);
            mHistoryCur.currentTime = 0;
            addHistoryRecordLocked(mSecRealtime);
            mDischargeCurrentLevel = mDischargeUnplugLevel = level;
            if (mScreenOn) {
@@ -6414,11 +6439,16 @@ public final class BatteryStatsImpl extends BatteryStats {
            Slog.e("BatteryStats", "Error reading battery statistics", e);
        }

        if (mHistoryBuffer.dataPosition() > 0) {
            long now = SystemClock.elapsedRealtime();
            if (USE_OLD_HISTORY) {
                addHistoryRecordLocked(now, HistoryItem.CMD_START);
            }
            addHistoryBufferLocked(now, HistoryItem.CMD_START);
            mHistoryCur.currentTime = System.currentTimeMillis();
            addHistoryBufferLocked(now, HistoryItem.CMD_CURRENT_TIME);
            mHistoryCur.currentTime = 0;
        }
    }

    public int describeContents() {
+19 −11
Original line number Diff line number Diff line
@@ -426,8 +426,10 @@ class AlarmManagerService extends SystemService {
        final Pair<String, ComponentName> mTarget;
        final BroadcastStats mBroadcastStats;
        final FilterStats mFilterStats;
        final int mAlarmType;

        InFlight(AlarmManagerService service, PendingIntent pendingIntent, WorkSource workSource) {
        InFlight(AlarmManagerService service, PendingIntent pendingIntent, WorkSource workSource,
                int alarmType) {
            mPendingIntent = pendingIntent;
            mWorkSource = workSource;
            Intent intent = pendingIntent.getIntent();
@@ -441,6 +443,7 @@ class AlarmManagerService extends SystemService {
                mBroadcastStats.filterStats.put(mTarget, fs);
            }
            mFilterStats = fs;
            mAlarmType = alarmType;
        }
    }

@@ -1280,17 +1283,12 @@ class AlarmManagerService extends SystemService {
                            
                            // we have an active broadcast so stay awake.
                            if (mBroadcastRefCount == 0) {
                                setWakelockWorkSource(alarm.operation, alarm.workSource);
                                mWakeLock.setUnimportantForLogging(
                                        alarm.operation == mTimeTickSender);
                                mWakeLock.setHistoryTag(alarm.operation.getTag(
                                        alarm.type == ELAPSED_REALTIME_WAKEUP
                                                || alarm.type == RTC_WAKEUP
                                                ? "*walarm*:" : "*alarm*:"));
                                setWakelockWorkSource(alarm.operation, alarm.workSource,
                                        alarm.type, true);
                                mWakeLock.acquire();
                            }
                            final InFlight inflight = new InFlight(AlarmManagerService.this,
                                    alarm.operation, alarm.workSource);
                                    alarm.operation, alarm.workSource, alarm.type);
                            mInFlight.add(inflight);
                            mBroadcastRefCount++;

@@ -1345,9 +1343,17 @@ class AlarmManagerService extends SystemService {
     * @param pi PendingIntent to attribute blame to if ws is null.
     * @param ws WorkSource to attribute blame.
     */
    void setWakelockWorkSource(PendingIntent pi, WorkSource ws) {
    void setWakelockWorkSource(PendingIntent pi, WorkSource ws, int type, boolean first) {
        try {
            mWakeLock.setUnimportantForLogging(pi == mTimeTickSender);
            if (ws != null) {
                if (first) {
                    mWakeLock.setHistoryTag(pi.getTag(
                            type == ELAPSED_REALTIME_WAKEUP || type == RTC_WAKEUP
                                    ? "*walarm*:" : "*alarm*:"));
                } else {
                    mWakeLock.setHistoryTag(null);
                }
                mWakeLock.setWorkSource(ws);
                return;
            }
@@ -1355,6 +1361,7 @@ class AlarmManagerService extends SystemService {
            final int uid = ActivityManagerNative.getDefault()
                    .getUidForIntentSender(pi.getTarget());
            if (uid >= 0) {
                mWakeLock.setHistoryTag(null);
                mWakeLock.setWorkSource(new WorkSource(uid));
                return;
            }
@@ -1579,7 +1586,8 @@ class AlarmManagerService extends SystemService {
                    // the next of our alarms is now in flight.  reattribute the wakelock.
                    if (mInFlight.size() > 0) {
                        InFlight inFlight = mInFlight.get(0);
                        setWakelockWorkSource(inFlight.mPendingIntent, inFlight.mWorkSource);
                        setWakelockWorkSource(inFlight.mPendingIntent, inFlight.mWorkSource,
                                inFlight.mAlarmType, false);
                    } else {
                        // should never happen
                        mLog.w("Alarm wakelock still held but sent queue empty");
+14 −2
Original line number Diff line number Diff line
@@ -29,6 +29,7 @@ import android.os.IBinder;
import android.os.Parcel;
import android.os.Process;
import android.os.ServiceManager;
import android.os.SystemClock;
import android.os.UserHandle;
import android.os.WorkSource;
import android.telephony.SignalStrength;
@@ -133,14 +134,15 @@ public final class BatteryStatsService extends IBatteryStats.Stub {
            boolean unimportantForLogging) {
        enforceCallingPermission();
        synchronized (mStats) {
            mStats.noteStartWakeLocked(uid, pid, name, historyName, type, unimportantForLogging);
            mStats.noteStartWakeLocked(uid, pid, name, historyName, type, unimportantForLogging,
                    SystemClock.elapsedRealtime());
        }
    }

    public void noteStopWakelock(int uid, int pid, String name, int type) {
        enforceCallingPermission();
        synchronized (mStats) {
            mStats.noteStopWakeLocked(uid, pid, name, type);
            mStats.noteStopWakeLocked(uid, pid, name, type, SystemClock.elapsedRealtime());
        }
    }

@@ -153,6 +155,16 @@ public final class BatteryStatsService extends IBatteryStats.Stub {
        }
    }

    public void noteChangeWakelockFromSource(WorkSource ws, int pid, String name, int type,
            WorkSource newWs, int newPid, String newName,
            String newHistoryName, int newType, boolean newUnimportantForLogging) {
        enforceCallingPermission();
        synchronized (mStats) {
            mStats.noteChangeWakelockFromSourceLocked(ws, pid, name, type,
                    newWs, newPid, newName, newHistoryName, newType, newUnimportantForLogging);
        }
    }

    public void noteStopWakelockFromSource(WorkSource ws, int pid, String name, int type) {
        enforceCallingPermission();
        synchronized (mStats) {
Loading