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

Commit 36c552ec authored by Dmitri Plotnikov's avatar Dmitri Plotnikov Committed by Android (Google) Code Review
Browse files

Merge "Preserve active kernel wakelocks across batterystats reset"

parents 49cb8910 0b2d4b49
Loading
Loading
Loading
Loading
+40 −24
Original line number Diff line number Diff line
@@ -251,9 +251,10 @@ public class BatteryStatsImpl extends BatteryStats {
    private static final LongCounter[] ZERO_LONG_COUNTER_ARRAY =
            new LongCounter[]{ZERO_LONG_COUNTER};
    private final KernelWakelockReader mKernelWakelockReader = new KernelWakelockReader();
    private final KernelWakelockStats mTmpWakelockStats = new KernelWakelockStats();
    @VisibleForTesting
    protected KernelWakelockReader mKernelWakelockReader;
    @VisibleForTesting
    protected KernelCpuUidUserSysTimeReader mCpuUidUserSysTimeReader;
    @VisibleForTesting
@@ -1763,6 +1764,7 @@ public class BatteryStatsImpl extends BatteryStats {
        mCpuUidFreqTimeReader = new KernelCpuUidFreqTimeReader(true, clock);
        mCpuUidActiveTimeReader = new KernelCpuUidActiveTimeReader(true, clock);
        mCpuUidClusterTimeReader = new KernelCpuUidClusterTimeReader(true, clock);
        mKernelWakelockReader = new KernelWakelockReader();
    }
    /**
@@ -2675,19 +2677,18 @@ public class BatteryStatsImpl extends BatteryStats {
         * The reported count from /proc/wakelocks when unplug() was last
         * called.
         */
        int mUnpluggedReportedCount;
        int mBaseReportedCount;
        /**
         * The most recent reported total_time from /proc/wakelocks.
         */
        long mCurrentReportedTotalTimeUs;
        /**
         * The reported total_time from /proc/wakelocks when unplug() was last
         * called.
         */
        long mUnpluggedReportedTotalTimeUs;
        long mBaseReportedTotalTimeUs;
        /**
         * Whether we are currently in a discharge cycle.
@@ -2708,9 +2709,9 @@ public class BatteryStatsImpl extends BatteryStats {
        public SamplingTimer(Clock clock, TimeBase timeBase, Parcel in) {
            super(clock, 0, timeBase, in);
            mCurrentReportedCount = in.readInt();
            mUnpluggedReportedCount = in.readInt();
            mBaseReportedCount = in.readInt();
            mCurrentReportedTotalTimeUs = in.readLong();
            mUnpluggedReportedTotalTimeUs = in.readLong();
            mBaseReportedTotalTimeUs = in.readLong();
            mTrackingReportedValues = in.readInt() == 1;
            mTimeBaseRunning = timeBase.isRunning();
        }
@@ -2736,8 +2737,8 @@ public class BatteryStatsImpl extends BatteryStats {
        public void endSample(long elapsedRealtimeUs) {
            mTotalTimeUs = computeRunTimeLocked(0 /* unused by us */, elapsedRealtimeUs);
            mCount = computeCurrentCountLocked();
            mUnpluggedReportedTotalTimeUs = mCurrentReportedTotalTimeUs = 0;
            mUnpluggedReportedCount = mCurrentReportedCount = 0;
            mBaseReportedTotalTimeUs = mCurrentReportedTotalTimeUs = 0;
            mBaseReportedCount = mCurrentReportedCount = 0;
            mTrackingReportedValues = false;
        }
@@ -2762,10 +2763,21 @@ public class BatteryStatsImpl extends BatteryStats {
         * @param count total number of times the event being sampled occurred.
         */
        public void update(long totalTimeUs, int count, long elapsedRealtimeUs) {
            update(totalTimeUs, 0, count, elapsedRealtimeUs);
        }
        /**
         * Updates the current recorded values. See {@link #update(long, int, long)}
         *
         * @param activeTimeUs Time that the currently active wake lock has been held.
         */
        public void update(long totalTimeUs, long activeTimeUs, int count,
                long elapsedRealtimeUs) {
            if (mTimeBaseRunning && !mTrackingReportedValues) {
                // Updating the reported value for the first time.
                mUnpluggedReportedTotalTimeUs = totalTimeUs;
                mUnpluggedReportedCount = count;
                // Updating the reported value for the first time. If the wake lock is currently
                // active, mark the time it was acquired as the base timestamp.
                mBaseReportedTotalTimeUs = totalTimeUs - activeTimeUs;
                mBaseReportedCount = activeTimeUs == 0 ? count : count - 1;
            }
            mTrackingReportedValues = true;
@@ -2800,8 +2812,8 @@ public class BatteryStatsImpl extends BatteryStats {
        public void onTimeStarted(long elapsedRealtimeUs, long baseUptimeUs, long baseRealtimeUs) {
            super.onTimeStarted(elapsedRealtimeUs, baseUptimeUs, baseRealtimeUs);
            if (mTrackingReportedValues) {
                mUnpluggedReportedTotalTimeUs = mCurrentReportedTotalTimeUs;
                mUnpluggedReportedCount = mCurrentReportedCount;
                mBaseReportedTotalTimeUs = mCurrentReportedTotalTimeUs;
                mBaseReportedCount = mCurrentReportedCount;
            }
            mTimeBaseRunning = true;
        }
@@ -2816,30 +2828,30 @@ public class BatteryStatsImpl extends BatteryStats {
        public void logState(Printer pw, String prefix) {
            super.logState(pw, prefix);
            pw.println(prefix + "mCurrentReportedCount=" + mCurrentReportedCount
                    + " mUnpluggedReportedCount=" + mUnpluggedReportedCount
                    + " mBaseReportedCount=" + mBaseReportedCount
                    + " mCurrentReportedTotalTime=" + mCurrentReportedTotalTimeUs
                    + " mUnpluggedReportedTotalTime=" + mUnpluggedReportedTotalTimeUs);
                    + " mBaseReportedTotalTimeUs=" + mBaseReportedTotalTimeUs);
        }
        @Override
        protected long computeRunTimeLocked(long curBatteryRealtime, long elapsedRealtimeUs) {
            return mTotalTimeUs + (mTimeBaseRunning && mTrackingReportedValues
                    ? mCurrentReportedTotalTimeUs - mUnpluggedReportedTotalTimeUs : 0);
                    ? mCurrentReportedTotalTimeUs - mBaseReportedTotalTimeUs : 0);
        }
        @Override
        protected int computeCurrentCountLocked() {
            return mCount + (mTimeBaseRunning && mTrackingReportedValues
                    ? mCurrentReportedCount - mUnpluggedReportedCount : 0);
                    ? mCurrentReportedCount - mBaseReportedCount : 0);
        }
        @Override
        public void writeToParcel(Parcel out, long elapsedRealtimeUs) {
            super.writeToParcel(out, elapsedRealtimeUs);
            out.writeInt(mCurrentReportedCount);
            out.writeInt(mUnpluggedReportedCount);
            out.writeInt(mBaseReportedCount);
            out.writeLong(mCurrentReportedTotalTimeUs);
            out.writeLong(mUnpluggedReportedTotalTimeUs);
            out.writeLong(mBaseReportedTotalTimeUs);
            out.writeInt(mTrackingReportedValues ? 1 : 0);
        }
@@ -2847,8 +2859,8 @@ public class BatteryStatsImpl extends BatteryStats {
        public boolean reset(boolean detachIfReset, long elapsedRealtimeUs) {
            super.reset(detachIfReset, elapsedRealtimeUs);
            mTrackingReportedValues = false;
            mUnpluggedReportedTotalTimeUs = 0;
            mUnpluggedReportedCount = 0;
            mBaseReportedTotalTimeUs = 0;
            mBaseReportedCount = 0;
            return true;
        }
    }
@@ -13398,6 +13410,10 @@ public class BatteryStatsImpl extends BatteryStats {
     * Read and distribute kernel wake lock use across apps.
     */
    public void updateKernelWakelocksLocked(long elapsedRealtimeUs) {
        if (mKernelWakelockReader == null) {
            return;
        }
        final KernelWakelockStats wakelockStats = mKernelWakelockReader.readKernelWakelockStats(
                mTmpWakelockStats);
        if (wakelockStats == null) {
@@ -13416,8 +13432,8 @@ public class BatteryStatsImpl extends BatteryStats {
                mKernelWakelockStats.put(name, kwlt);
            }
            kwlt.update(kws.mTotalTime, kws.mCount, elapsedRealtimeUs);
            kwlt.setUpdateVersion(kws.mVersion);
            kwlt.update(kws.totalTimeUs, kws.activeTimeUs, kws.count, elapsedRealtimeUs);
            kwlt.setUpdateVersion(kws.version);
        }
        int numWakelocksSetStale = 0;
@@ -13471,7 +13487,7 @@ public class BatteryStatsImpl extends BatteryStats {
                Slog.d(TAG, String.format("Added entry %d and updated timer to: "
                        + "mUnpluggedReportedTotalTimeUs %d size %d", bandwidthEntries.keyAt(i),
                        mKernelMemoryStats.get(
                                bandwidthEntries.keyAt(i)).mUnpluggedReportedTotalTimeUs,
                                bandwidthEntries.keyAt(i)).mBaseReportedTotalTimeUs,
                        mKernelMemoryStats.size()));
            }
        }
+53 −42
Original line number Diff line number Diff line
@@ -43,29 +43,30 @@ public class KernelWakelockReader {
    private static final String sSysClassWakeupDir = "/sys/class/wakeup";

    private static final int[] PROC_WAKELOCKS_FORMAT = new int[]{
        Process.PROC_TAB_TERM|Process.PROC_OUT_STRING|                // 0: name
                              Process.PROC_QUOTES,
            Process.PROC_TAB_TERM | Process.PROC_OUT_STRING                 // 0: name
                    | Process.PROC_QUOTES,
            Process.PROC_TAB_TERM | Process.PROC_OUT_LONG,                  // 1: count
            Process.PROC_TAB_TERM,
        Process.PROC_TAB_TERM,
            Process.PROC_TAB_TERM | Process.PROC_OUT_LONG,                  // 3: activeSince
            Process.PROC_TAB_TERM,
            Process.PROC_TAB_TERM | Process.PROC_OUT_LONG,                  // 5: totalTime
    };

    private static final int[] WAKEUP_SOURCES_FORMAT = new int[]{
            Process.PROC_TAB_TERM | Process.PROC_OUT_STRING,                // 0: name
        Process.PROC_TAB_TERM|Process.PROC_COMBINE|
                              Process.PROC_OUT_LONG,                  // 1: count
        Process.PROC_TAB_TERM|Process.PROC_COMBINE,
            Process.PROC_TAB_TERM | Process.PROC_COMBINE
                    | Process.PROC_OUT_LONG,                                // 1: count
            Process.PROC_TAB_TERM | Process.PROC_COMBINE,
            Process.PROC_TAB_TERM | Process.PROC_COMBINE,
            Process.PROC_TAB_TERM | Process.PROC_COMBINE,
            Process.PROC_TAB_TERM | Process.PROC_COMBINE
                    | Process.PROC_OUT_LONG,                                // 5: activeSince
            Process.PROC_TAB_TERM | Process.PROC_COMBINE
                    | Process.PROC_OUT_LONG,                                // 6: totalTime
    };

    private final String[] mProcWakelocksName = new String[3];
    private final long[] mProcWakelocksData = new long[3];
    private final long[] mProcWakelocksData = new long[4];
    private ISuspendControlServiceInternal mSuspendControlService = null;
    private byte[] mKernelWakelockBuffer = new byte[32 * 1024];

@@ -74,7 +75,7 @@ public class KernelWakelockReader {
     * @param staleStats Existing object to update.
     * @return the updated data.
     */
    public final KernelWakelockStats readKernelWakelockStats(KernelWakelockStats staleStats) {
    public KernelWakelockStats readKernelWakelockStats(KernelWakelockStats staleStats) {
        boolean useSystemSuspend = (new File(sSysClassWakeupDir)).exists();

        if (useSystemSuspend) {
@@ -180,14 +181,16 @@ public class KernelWakelockReader {
     */
    private KernelWakelockStats getWakelockStatsFromSystemSuspend(
            final KernelWakelockStats staleStats) {
        WakeLockInfo[] wlStats = null;
        if (mSuspendControlService == null) {
            try {
                mSuspendControlService = waitForSuspendControlService();
            } catch (ServiceNotFoundException e) {
                Slog.wtf(TAG, "Required service suspend_control not available", e);
                return null;
            }
        }

        WakeLockInfo[] wlStats;
        try {
            wlStats = mSuspendControlService.getWakeLockStats();
            updateWakelockStats(wlStats, staleStats);
@@ -210,13 +213,16 @@ public class KernelWakelockReader {
        for (WakeLockInfo info : wlStats) {
            if (!staleStats.containsKey(info.name)) {
                staleStats.put(info.name, new KernelWakelockStats.Entry((int) info.activeCount,
                        info.totalTime * 1000 /* ms to us */, sKernelWakelockUpdateVersion));
                        info.totalTime * 1000 /* ms to us */,
                        info.isActive ? info.activeTime * 1000 : 0,
                        sKernelWakelockUpdateVersion));
            } else {
                KernelWakelockStats.Entry kwlStats = staleStats.get(info.name);
                kwlStats.mCount = (int) info.activeCount;
                kwlStats.count = (int) info.activeCount;
                // Convert milliseconds to microseconds
                kwlStats.mTotalTime = info.totalTime * 1000;
                kwlStats.mVersion = sKernelWakelockUpdateVersion;
                kwlStats.totalTimeUs = info.totalTime * 1000;
                kwlStats.activeTimeUs = info.isActive ? info.activeTime * 1000 : 0;
                kwlStats.version = sKernelWakelockUpdateVersion;
            }
        }

@@ -232,6 +238,7 @@ public class KernelWakelockReader {
        String name;
        int count;
        long totalTime;
        long activeTime;
        int startIndex;
        int endIndex;

@@ -269,25 +276,29 @@ public class KernelWakelockReader {

                if (wakeup_sources) {
                    // convert milliseconds to microseconds
                        totalTime = wlData[2] * 1000;
                    activeTime = wlData[2] * 1000;
                    totalTime = wlData[3] * 1000;
                } else {
                    // convert nanoseconds to microseconds with rounding.
                        totalTime = (wlData[2] + 500) / 1000;
                    activeTime = (wlData[2] + 500) / 1000;
                    totalTime = (wlData[3] + 500) / 1000;
                }

                if (parsed && name.length() > 0) {
                    if (!staleStats.containsKey(name)) {
                        staleStats.put(name, new KernelWakelockStats.Entry(count, totalTime,
                                sKernelWakelockUpdateVersion));
                                activeTime, sKernelWakelockUpdateVersion));
                    } else {
                        KernelWakelockStats.Entry kwlStats = staleStats.get(name);
                        if (kwlStats.mVersion == sKernelWakelockUpdateVersion) {
                            kwlStats.mCount += count;
                            kwlStats.mTotalTime += totalTime;
                        if (kwlStats.version == sKernelWakelockUpdateVersion) {
                            kwlStats.count += count;
                            kwlStats.totalTimeUs += totalTime;
                            kwlStats.activeTimeUs = activeTime;
                        } else {
                            kwlStats.mCount = count;
                            kwlStats.mTotalTime = totalTime;
                            kwlStats.mVersion = sKernelWakelockUpdateVersion;
                            kwlStats.count = count;
                            kwlStats.totalTimeUs = totalTime;
                            kwlStats.activeTimeUs = activeTime;
                            kwlStats.version = sKernelWakelockUpdateVersion;
                        }
                    }
                } else if (!parsed) {
@@ -326,7 +337,7 @@ public class KernelWakelockReader {
    public KernelWakelockStats removeOldStats(final KernelWakelockStats staleStats) {
        Iterator<KernelWakelockStats.Entry> itr = staleStats.values().iterator();
        while (itr.hasNext()) {
            if (itr.next().mVersion != sKernelWakelockUpdateVersion) {
            if (itr.next().version != sKernelWakelockUpdateVersion) {
                itr.remove();
            }
        }
+9 −7
Original line number Diff line number Diff line
@@ -22,14 +22,16 @@ import java.util.HashMap;
 */
public class KernelWakelockStats extends HashMap<String, KernelWakelockStats.Entry> {
    public static class Entry {
        public int mCount;
        public long mTotalTime;
        public int mVersion;
        public int count;
        public long totalTimeUs;
        public long activeTimeUs;
        public int version;

        Entry(int count, long totalTime, int version) {
            mCount = count;
            mTotalTime = totalTime;
            mVersion = version;
        Entry(int count, long totalTimeUs, long activeTimeUs, int version) {
            this.count = count;
            this.totalTimeUs = totalTimeUs;
            this.activeTimeUs = activeTimeUs;
            this.version = version;
        }
    }

+1 −1
Original line number Diff line number Diff line
@@ -1733,7 +1733,7 @@ public class StatsPullAtomService extends SystemService {
            String name = ent.getKey();
            KernelWakelockStats.Entry kws = ent.getValue();
            pulledData.add(FrameworkStatsLog.buildStatsEvent(
                    atomTag, name, kws.mCount, kws.mVersion, kws.mTotalTime));
                    atomTag, name, kws.count, kws.version, kws.totalTimeUs));
        }
        return StatsManager.PULL_SUCCESS;
    }
+51 −1
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@ import static android.os.BatteryStats.Uid.PROCESS_STATE_FOREGROUND_SERVICE;
import static android.os.BatteryStats.Uid.PROCESS_STATE_TOP;

import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;

import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
@@ -55,6 +56,7 @@ import com.android.internal.os.LongArrayMultiStateCounter;
import com.android.internal.os.PowerProfile;

import com.google.common.collect.ImmutableList;
import com.google.common.truth.LongSubject;

import org.junit.Before;
import org.junit.Test;
@@ -77,6 +79,9 @@ public class BatteryStatsImplTest {
    private KernelSingleUidTimeReader mKernelSingleUidTimeReader;
    @Mock
    private PowerProfile mPowerProfile;
    @Mock
    private KernelWakelockReader mKernelWakelockReader;
    private KernelWakelockStats mKernelWakelockStats = new KernelWakelockStats();

    private final MockClock mMockClock = new MockClock();
    private MockBatteryStatsImpl mBatteryStatsImpl;
@@ -89,10 +94,13 @@ public class BatteryStatsImplTest {
        when(mKernelUidCpuFreqTimeReader.readFreqs(any())).thenReturn(CPU_FREQS);
        when(mKernelUidCpuFreqTimeReader.allUidTimesAvailable()).thenReturn(true);
        when(mKernelSingleUidTimeReader.singleUidCpuTimesAvailable()).thenReturn(true);
        when(mKernelWakelockReader.readKernelWakelockStats(
                any(KernelWakelockStats.class))).thenReturn(mKernelWakelockStats);
        mBatteryStatsImpl = new MockBatteryStatsImpl(mMockClock)
                .setPowerProfile(mPowerProfile)
                .setKernelCpuUidFreqTimeReader(mKernelUidCpuFreqTimeReader)
                .setKernelSingleUidTimeReader(mKernelSingleUidTimeReader);
                .setKernelSingleUidTimeReader(mKernelSingleUidTimeReader)
                .setKernelWakelockReader(mKernelWakelockReader);
    }

    @Test
@@ -558,6 +566,48 @@ public class BatteryStatsImplTest {
        assertThat(wakeLock2.totalTimeHeldMs).isEqualTo(4000); // (5000-4000) + (9000-6000)
    }

    @Test
    public void kernelWakelocks() {
        mBatteryStatsImpl.updateTimeBasesLocked(true, Display.STATE_OFF, 0, 0);

        mKernelWakelockStats.put("lock1", new KernelWakelockStats.Entry(42, 1000, 314, 0));
        mKernelWakelockStats.put("lock2", new KernelWakelockStats.Entry(6, 2000, 0, 0));

        mMockClock.realtime = 5000;

        // The fist call makes a snapshot of the initial state of the wakelocks
        mBatteryStatsImpl.updateKernelWakelocksLocked(mMockClock.realtime * 1000);

        assertThat(mBatteryStatsImpl.getKernelWakelockStats()).hasSize(2);

        mMockClock.realtime += 2000;

        assertThatKernelWakelockTotalTime("lock1").isEqualTo(314);  // active
        assertThatKernelWakelockTotalTime("lock2").isEqualTo(0);        // inactive

        mKernelWakelockStats.put("lock1", new KernelWakelockStats.Entry(43, 1100, 414, 0));
        mKernelWakelockStats.put("lock2", new KernelWakelockStats.Entry(6, 2222, 0, 0));

        mMockClock.realtime += 3000;

        // Compute delta from the initial snapshot
        mBatteryStatsImpl.updateKernelWakelocksLocked(mMockClock.realtime * 1000);

        mMockClock.realtime += 4000;

        assertThatKernelWakelockTotalTime("lock1").isEqualTo(414);

        // Wake lock not active. Expect relative total time as reported by Kernel:
        // 2_222 - 2_000 = 222
        assertThatKernelWakelockTotalTime("lock2").isEqualTo(222);
    }

    private LongSubject assertThatKernelWakelockTotalTime(String name) {
        return assertWithMessage("Kernel wakelock " + name + " at " + mMockClock.realtime)
                .that(mBatteryStatsImpl.getKernelWakelockStats().get(name)
                        .getTotalTimeLocked(mMockClock.realtime * 1000, 0));
    }

    @Test
    public void testGetBluetoothBatteryStats() {
        when(mPowerProfile.getAveragePower(
Loading