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

Commit f166d19e authored by Kalesh Singh's avatar Kalesh Singh
Browse files

Get wakelock stats from SystemSuspend

Read wakelock stats from SystemSuspend if possible else fallback to
/d/wakeup_source, /proc/wakelocks.

Bug: 128923994
Test: KernelWakelockReaderTest

Change-Id: I859092d53d7697a4940f9369480e203181f0c370
parent f4b0318d
Loading
Loading
Loading
Loading
+73 −62
Original line number Diff line number Diff line
@@ -27,6 +27,7 @@ import android.util.Slog;

import com.android.internal.annotations.VisibleForTesting;

import java.io.File;
import java.io.FileInputStream;
import java.util.Iterator;

@@ -38,6 +39,7 @@ public class KernelWakelockReader {
    private static int sKernelWakelockUpdateVersion = 0;
    private static final String sWakelockFile = "/proc/wakelocks";
    private static final String sWakeupSourceFile = "/d/wakeup_sources";
    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
@@ -71,6 +73,32 @@ public class KernelWakelockReader {
     * @return the updated data.
     */
    public final KernelWakelockStats readKernelWakelockStats(KernelWakelockStats staleStats) {
        boolean useSystemSuspend = (new File(sSysClassWakeupDir)).exists();

        if (useSystemSuspend) {
            WakeLockInfo[] wlStats = null;
            if (mSuspendControlService == null) {
                try {
                    mSuspendControlService = ISuspendControlService.Stub.asInterface(
                        ServiceManager.getServiceOrThrow("suspend_control"));
                } catch (ServiceNotFoundException e) {
                    Slog.wtf(TAG, "Required service suspend_control not available", e);
                    return null;
                }
            }

            try {
                wlStats = mSuspendControlService.getWakeLockStats();
                updateVersion(staleStats);
                updateWakelockStats(wlStats, staleStats);
            } catch (RemoteException e) {
                Slog.wtf(TAG, "Failed to obtain wakelock stats from ISuspendControlService", e);
                return null;
            }

            return removeOldStats(staleStats);

        } else {
            byte[] buffer = new byte[32*1024];
            int len = 0;
            boolean wakeup_sources;
@@ -125,45 +153,28 @@ public class KernelWakelockReader {
            }

            updateVersion(staleStats);

            parseProcWakelocks(buffer, len, wakeup_sources, staleStats);

        if (mSuspendControlService == null) {
            try {
                mSuspendControlService = ISuspendControlService.Stub.asInterface(
                    ServiceManager.getServiceOrThrow("suspend_control"));
            } catch (ServiceNotFoundException e) {
                Slog.wtf(TAG, "Required service suspend_control not available", e);
            }
        }

        try {
            WakeLockInfo[] wlStats = mSuspendControlService.getWakeLockStats();
            getNativeWakelockStats(wlStats, staleStats);
        } catch (RemoteException e) {
            Slog.wtf(TAG, "Failed to obtain wakelock stats from ISuspendControlService", e);
        }

            return removeOldStats(staleStats);
        }
    }

    /**
     * Reads native wakelock stats from SystemSuspend and updates staleStats with the new
     * information.
     * Updates statleStats with stats from  SystemSuspend.
     * @param staleStats Existing object to update.
     * @return the updated stats.
     */
    @VisibleForTesting
    public KernelWakelockStats getNativeWakelockStats(WakeLockInfo[] wlStats,
    public KernelWakelockStats updateWakelockStats(WakeLockInfo[] wlStats,
                                                      final KernelWakelockStats staleStats) {
        for (WakeLockInfo info : wlStats) {
            if (!staleStats.containsKey(info.name)) {
                staleStats.put(info.name, new KernelWakelockStats.Entry((int) info.activeCount,
                        info.totalTime, sKernelWakelockUpdateVersion));
                        info.totalTime * 1000 /* ms to us */, sKernelWakelockUpdateVersion));
            } else {
                KernelWakelockStats.Entry kwlStats = staleStats.get(info.name);
                kwlStats.mCount = (int) info.activeCount;
                kwlStats.mTotalTime = info.totalTime;
                // Convert milliseconds to microseconds
                kwlStats.mTotalTime = info.totalTime * 1000;
                kwlStats.mVersion = sKernelWakelockUpdateVersion;
            }
        }
+16 −161
Original line number Diff line number Diff line
@@ -68,12 +68,7 @@ public class KernelWakelockReaderTest extends TestCase {
    private WakeLockInfo createWakeLockInfo(String name, int activeCount, long totalTime) {
        WakeLockInfo info = new WakeLockInfo();
        info.name = name;
        info.pid = 1;
        info.activeCount = activeCount;
        info.isActive = true;
        info.activeSince = 0;
        info.lastChange = 0;
        info.maxTime = 0;
        info.totalTime = totalTime;
        return info;
    }
@@ -89,7 +84,7 @@ public class KernelWakelockReaderTest extends TestCase {
                                                        byte[] buffer, WakeLockInfo[] wlStats) {
        mReader.updateVersion(staleStats);
        mReader.parseProcWakelocks(buffer, buffer.length, true, staleStats);
        mReader.getNativeWakelockStats(wlStats, staleStats);
        mReader.updateWakelockStats(wlStats, staleStats);
        return mReader.removeOldStats(staleStats);
    }

@@ -101,7 +96,7 @@ public class KernelWakelockReaderTest extends TestCase {
        mReader = new KernelWakelockReader();
    }

// ------------------------- Kernel Wakelock Stats Test ------------------------
// ------------------------- Legacy Wakelock Stats Test ------------------------
    @SmallTest
    public void testParseEmptyFile() throws Exception {
        KernelWakelockStats staleStats = mReader.parseProcWakelocks(new byte[0], 0, true,
@@ -196,10 +191,10 @@ public class KernelWakelockReaderTest extends TestCase {
        assertFalse(staleStats.containsKey("Fakelock"));
    }

// -------------------- Native (SystemSuspend) Wakelock Stats Test -------------------
// -------------------- SystemSuspend Wakelock Stats Test -------------------
    @SmallTest
    public void testEmptyWakeLockInfoList() {
        KernelWakelockStats staleStats = mReader.getNativeWakelockStats(new WakeLockInfo[0],
        KernelWakelockStats staleStats = mReader.updateWakelockStats(new WakeLockInfo[0],
                new KernelWakelockStats());

        assertTrue(staleStats.isEmpty());
@@ -208,9 +203,9 @@ public class KernelWakelockReaderTest extends TestCase {
    @SmallTest
    public void testOneWakeLockInfo() {
        WakeLockInfo[] wlStats = new WakeLockInfo[1];
        wlStats[0] = createWakeLockInfo("WakeLock", 20, 10000);
        wlStats[0] = createWakeLockInfo("WakeLock", 20, 1000);   // Milliseconds

        KernelWakelockStats staleStats = mReader.getNativeWakelockStats(wlStats,
        KernelWakelockStats staleStats = mReader.updateWakelockStats(wlStats,
                new KernelWakelockStats());

        assertEquals(1, staleStats.size());
@@ -219,16 +214,16 @@ public class KernelWakelockReaderTest extends TestCase {

        KernelWakelockStats.Entry entry = staleStats.get("WakeLock");
        assertEquals(20, entry.mCount);
        assertEquals(10000, entry.mTotalTime);
        assertEquals(1000 * 1000, entry.mTotalTime);   // Microseconds
    }

    @SmallTest
    public void testTwoWakeLockInfos() {
        WakeLockInfo[] wlStats = new WakeLockInfo[2];
        wlStats[0] = createWakeLockInfo("WakeLock1", 10, 1000);
        wlStats[1] = createWakeLockInfo("WakeLock2", 20, 2000);
        wlStats[0] = createWakeLockInfo("WakeLock1", 10, 1000); // Milliseconds
        wlStats[1] = createWakeLockInfo("WakeLock2", 20, 2000); // Milliseconds

        KernelWakelockStats staleStats = mReader.getNativeWakelockStats(wlStats,
        KernelWakelockStats staleStats = mReader.updateWakelockStats(wlStats,
                new KernelWakelockStats());

        assertEquals(2, staleStats.size());
@@ -238,17 +233,17 @@ public class KernelWakelockReaderTest extends TestCase {

        KernelWakelockStats.Entry entry1 = staleStats.get("WakeLock1");
        assertEquals(10, entry1.mCount);
        assertEquals(1000, entry1.mTotalTime);
        assertEquals(1000 * 1000, entry1.mTotalTime); // Microseconds

        KernelWakelockStats.Entry entry2 = staleStats.get("WakeLock2");
        assertEquals(20, entry2.mCount);
        assertEquals(2000, entry2.mTotalTime);
        assertEquals(2000 * 1000, entry2.mTotalTime); // Microseconds
    }

    @SmallTest
    public void testWakeLockInfosBecomeStale() {
        WakeLockInfo[] wlStats = new WakeLockInfo[1];
        wlStats[0] = createWakeLockInfo("WakeLock1", 10, 1000);
        wlStats[0] = createWakeLockInfo("WakeLock1", 10, 1000); // Milliseconds

        KernelWakelockStats staleStats = new KernelWakelockStats();

@@ -259,9 +254,9 @@ public class KernelWakelockReaderTest extends TestCase {
        assertTrue(staleStats.containsKey("WakeLock1"));
        KernelWakelockStats.Entry entry = staleStats.get("WakeLock1");
        assertEquals(10, entry.mCount);
        assertEquals(1000, entry.mTotalTime);
        assertEquals(1000 * 1000, entry.mTotalTime);  // Microseconds

        wlStats[0] = createWakeLockInfo("WakeLock2", 20, 2000);
        wlStats[0] = createWakeLockInfo("WakeLock2", 20, 2000); // Milliseconds

        readKernelWakelockStats(staleStats, new byte[0], wlStats);

@@ -271,146 +266,6 @@ public class KernelWakelockReaderTest extends TestCase {
        assertTrue(staleStats.containsKey("WakeLock2"));
        entry = staleStats.get("WakeLock2");
        assertEquals(20, entry.mCount);
        assertEquals(2000, entry.mTotalTime);
    }

// -------------------- Aggregate  Wakelock Stats Tests --------------------
    @SmallTest
    public void testAggregateStatsEmpty() throws Exception {
        KernelWakelockStats staleStats = new KernelWakelockStats();

        byte[] buffer = new byte[0];
        WakeLockInfo[] wlStats = new WakeLockInfo[0];

        readKernelWakelockStats(staleStats, buffer, wlStats);

        assertTrue(staleStats.isEmpty());
    }

    @SmallTest
    public void testAggregateStatsNoNativeWakelocks() throws Exception {
        KernelWakelockStats staleStats = new KernelWakelockStats();

        byte[] buffer = new ProcFileBuilder()
                .addLine("Wakelock", 34, 123) // Milliseconds
                .getBytes();
        WakeLockInfo[] wlStats = new WakeLockInfo[0];

        readKernelWakelockStats(staleStats, buffer, wlStats);

        assertEquals(1, staleStats.size());

        assertTrue(staleStats.containsKey("Wakelock"));

        KernelWakelockStats.Entry entry = staleStats.get("Wakelock");
        assertEquals(34, entry.mCount);
        assertEquals(1000 * 123, entry.mTotalTime);  // Microseconds
    }

    @SmallTest
    public void testAggregateStatsNoKernelWakelocks() throws Exception {
        KernelWakelockStats staleStats = new KernelWakelockStats();

        byte[] buffer = new byte[0];
        WakeLockInfo[] wlStats = new WakeLockInfo[1];
        wlStats[0] = createWakeLockInfo("WakeLock", 10, 1000);

        readKernelWakelockStats(staleStats, buffer, wlStats);

        assertEquals(1, staleStats.size());

        assertTrue(staleStats.containsKey("WakeLock"));

        KernelWakelockStats.Entry entry = staleStats.get("WakeLock");
        assertEquals(10, entry.mCount);
        assertEquals(1000, entry.mTotalTime);
    }

    @SmallTest
    public void testAggregateStatsBothKernelAndNativeWakelocks() throws Exception {
        KernelWakelockStats staleStats = new KernelWakelockStats();

        byte[] buffer = new ProcFileBuilder()
                .addLine("WakeLock1", 34, 123)  // Milliseconds
                .getBytes();
        WakeLockInfo[] wlStats = new WakeLockInfo[1];
        wlStats[0] = createWakeLockInfo("WakeLock2", 10, 1000);

        readKernelWakelockStats(staleStats, buffer, wlStats);

        assertEquals(2, staleStats.size());

        assertTrue(staleStats.containsKey("WakeLock1"));
        KernelWakelockStats.Entry entry1 = staleStats.get("WakeLock1");
        assertEquals(34, entry1.mCount);
        assertEquals(123 * 1000, entry1.mTotalTime);  // Microseconds

        assertTrue(staleStats.containsKey("WakeLock2"));
        KernelWakelockStats.Entry entry2 = staleStats.get("WakeLock2");
        assertEquals(10, entry2.mCount);
        assertEquals(1000, entry2.mTotalTime);
    }

    @SmallTest
    public void testAggregateStatsUpdate() throws Exception {
        KernelWakelockStats staleStats = new KernelWakelockStats();

        byte[] buffer = new ProcFileBuilder()
                .addLine("WakeLock1", 34, 123)  // Milliseconds
                .addLine("WakeLock2", 46, 345)  // Milliseconds
                .getBytes();
        WakeLockInfo[] wlStats = new WakeLockInfo[2];
        wlStats[0] = createWakeLockInfo("WakeLock3", 10, 1000);
        wlStats[1] = createWakeLockInfo("WakeLock4", 20, 2000);

        readKernelWakelockStats(staleStats, buffer, wlStats);

        assertEquals(4, staleStats.size());

        assertTrue(staleStats.containsKey("WakeLock1"));
        assertTrue(staleStats.containsKey("WakeLock2"));
        assertTrue(staleStats.containsKey("WakeLock3"));
        assertTrue(staleStats.containsKey("WakeLock4"));

        KernelWakelockStats.Entry entry1 = staleStats.get("WakeLock1");
        assertEquals(34, entry1.mCount);
        assertEquals(123 * 1000, entry1.mTotalTime); // Microseconds

        KernelWakelockStats.Entry entry2 = staleStats.get("WakeLock2");
        assertEquals(46, entry2.mCount);
        assertEquals(345 * 1000, entry2.mTotalTime); // Microseconds

        KernelWakelockStats.Entry entry3 = staleStats.get("WakeLock3");
        assertEquals(10, entry3.mCount);
        assertEquals(1000, entry3.mTotalTime);

        KernelWakelockStats.Entry entry4 = staleStats.get("WakeLock4");
        assertEquals(20, entry4.mCount);
        assertEquals(2000, entry4.mTotalTime);

        buffer = new ProcFileBuilder()
                .addLine("WakeLock1", 45, 789)  // Milliseconds
                .addLine("WakeLock1", 56, 123)  // Milliseconds
                .getBytes();
        wlStats = new WakeLockInfo[1];
        wlStats[0] = createWakeLockInfo("WakeLock4", 40, 4000);

        readKernelWakelockStats(staleStats, buffer, wlStats);

        assertEquals(2, staleStats.size());

        assertTrue(staleStats.containsKey("WakeLock1"));
        assertTrue(staleStats.containsKey("WakeLock4"));

        assertFalse(staleStats.containsKey("WakeLock2"));
        assertFalse(staleStats.containsKey("WakeLock3"));

        entry1 = staleStats.get("WakeLock1");
        assertEquals(45 + 56, entry1.mCount);
        assertEquals((789 + 123) * 1000, entry1.mTotalTime);  // Microseconds

        entry2 = staleStats.get("WakeLock4");
        assertEquals(40, entry2.mCount);
        assertEquals(4000, entry4.mTotalTime);
        assertEquals(2000 * 1000, entry.mTotalTime); // Micro seconds
    }
}