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

Commit a1cae835 authored by Treehugger Robot's avatar Treehugger Robot Committed by Gerrit Code Review
Browse files

Merge "Route KernelWakelockReader's userspace native wakelock stats collection...

Merge "Route KernelWakelockReader's userspace native wakelock stats collection to SystemSuspend (ISuspendControl::getWakeLockStats())"
parents 170b0973 759af327
Loading
Loading
Loading
Loading
+1 −0
Original line number Original line Diff line number Diff line
@@ -687,6 +687,7 @@ java_defaults {


    static_libs: [
    static_libs: [
        "apex_aidl_interface-java",
        "apex_aidl_interface-java",
        "suspend_control_aidl_interface-java",
        "framework-protos",
        "framework-protos",
        "game-driver-protos",
        "game-driver-protos",
        "android.hidl.base-V1.0-java",
        "android.hidl.base-V1.0-java",
+80 −11
Original line number Original line Diff line number Diff line
@@ -16,8 +16,13 @@
package com.android.internal.os;
package com.android.internal.os;


import android.os.Process;
import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.ServiceManager.ServiceNotFoundException;
import android.os.StrictMode;
import android.os.StrictMode;
import android.os.SystemClock;
import android.os.SystemClock;
import android.system.suspend.ISuspendControlService;
import android.system.suspend.WakeLockInfo;
import android.util.Slog;
import android.util.Slog;


import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.annotations.VisibleForTesting;
@@ -58,6 +63,7 @@ public class KernelWakelockReader {


    private final String[] mProcWakelocksName = new String[3];
    private final String[] mProcWakelocksName = new String[3];
    private final long[] mProcWakelocksData = new long[3];
    private final long[] mProcWakelocksData = new long[3];
    private ISuspendControlService mSuspendControlService = null;


    /**
    /**
     * Reads kernel wakelock stats and updates the staleStats with the new information.
     * Reads kernel wakelock stats and updates the staleStats with the new information.
@@ -117,7 +123,52 @@ public class KernelWakelockReader {
                }
                }
            }
            }
        }
        }
        return parseProcWakelocks(buffer, len, wakeup_sources, staleStats);

        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.
     * @param staleStats Existing object to update.
     * @return the updated stats.
     */
    @VisibleForTesting
    public KernelWakelockStats getNativeWakelockStats(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));
            } else {
                KernelWakelockStats.Entry kwlStats = staleStats.get(info.name);
                kwlStats.mCount = (int) info.activeCount;
                kwlStats.mTotalTime = info.totalTime;
                kwlStats.mVersion = sKernelWakelockUpdateVersion;
            }
        }

        return staleStats;
    }
    }


    /**
    /**
@@ -138,7 +189,6 @@ public class KernelWakelockReader {
        startIndex = endIndex = i + 1;
        startIndex = endIndex = i + 1;


        synchronized(this) {
        synchronized(this) {
            sKernelWakelockUpdateVersion++;
            while (endIndex < len) {
            while (endIndex < len) {
                for (endIndex=startIndex;
                for (endIndex=startIndex;
                        endIndex < len && wlBuffer[endIndex] != '\n' && wlBuffer[endIndex] != '\0';
                        endIndex < len && wlBuffer[endIndex] != '\n' && wlBuffer[endIndex] != '\0';
@@ -199,16 +249,35 @@ public class KernelWakelockReader {
                startIndex = endIndex + 1;
                startIndex = endIndex + 1;
            }
            }


            // Don't report old data.
            return staleStats;
        }
    }

    /**
     * Increments sKernelWakelockUpdateVersion and updates the version in staleStats.
     * @param staleStats Existing object to update.
     * @return the updated stats.
     */
    @VisibleForTesting
    public KernelWakelockStats updateVersion(KernelWakelockStats staleStats) {
        sKernelWakelockUpdateVersion++;
        staleStats.kernelWakelockVersion = sKernelWakelockUpdateVersion;
        return staleStats;
    }

    /**
     * Removes old stats from staleStats.
     * @param staleStats Existing object to update.
     * @return the updated stats.
     */
    @VisibleForTesting
    public KernelWakelockStats removeOldStats(final KernelWakelockStats staleStats) {
        Iterator<KernelWakelockStats.Entry> itr = staleStats.values().iterator();
        Iterator<KernelWakelockStats.Entry> itr = staleStats.values().iterator();
        while (itr.hasNext()) {
        while (itr.hasNext()) {
            if (itr.next().mVersion != sKernelWakelockUpdateVersion) {
            if (itr.next().mVersion != sKernelWakelockUpdateVersion) {
                itr.remove();
                itr.remove();
            }
            }
        }
        }

            staleStats.kernelWakelockVersion = sKernelWakelockUpdateVersion;
        return staleStats;
        return staleStats;
    }
    }
}
}
}
+273 −4
Original line number Original line Diff line number Diff line
@@ -13,14 +13,17 @@
 * License for the specific language governing permissions and limitations under
 * License for the specific language governing permissions and limitations under
 * the License.
 * the License.
 */
 */

package com.android.internal.os;
package com.android.internal.os;


import android.support.test.filters.SmallTest;
import androidx.test.filters.SmallTest;


import junit.framework.TestCase;
import junit.framework.TestCase;


import java.nio.charset.Charset;
import java.nio.charset.Charset;


import android.system.suspend.WakeLockInfo;

public class KernelWakelockReaderTest extends TestCase {
public class KernelWakelockReaderTest extends TestCase {
    /**
    /**
     * Helper class that builds the mock Kernel module file /d/wakeup_sources.
     * Helper class that builds the mock Kernel module file /d/wakeup_sources.
@@ -57,6 +60,39 @@ public class KernelWakelockReaderTest extends TestCase {
        }
        }
    }
    }


    /**
     * Helper method to create WakeLockInfo object.
     * @param totalTime is time in microseconds.
     * @return the created WakeLockInfo object.
     */
    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;
    }

    /**
     * Helper method for KernelWakeLockReader::readKernelWakelockStats(...)
     * @param staleStats existing stats to update.
     * @param buffer representation of mock kernel module file /d/wakeup_sources.
     * @param wlStats mock WakeLockInfo list returned from ISuspendControlService.
     * @return the updated stats.
     */
    private KernelWakelockStats readKernelWakelockStats(KernelWakelockStats staleStats,
                                                        byte[] buffer, WakeLockInfo[] wlStats) {
        mReader.updateVersion(staleStats);
        mReader.parseProcWakelocks(buffer, buffer.length, true, staleStats);
        mReader.getNativeWakelockStats(wlStats, staleStats);
        return mReader.removeOldStats(staleStats);
    }

    private KernelWakelockReader mReader;
    private KernelWakelockReader mReader;


    @Override
    @Override
@@ -65,18 +101,22 @@ public class KernelWakelockReaderTest extends TestCase {
        mReader = new KernelWakelockReader();
        mReader = new KernelWakelockReader();
    }
    }


// ------------------------- Kernel Wakelock Stats Test ------------------------
    @SmallTest
    @SmallTest
    public void testParseEmptyFile() throws Exception {
    public void testParseEmptyFile() throws Exception {
        KernelWakelockStats staleStats = mReader.parseProcWakelocks(new byte[0], 0, true,
        KernelWakelockStats staleStats = mReader.parseProcWakelocks(new byte[0], 0, true,
                new KernelWakelockStats());
                new KernelWakelockStats());

        assertTrue(staleStats.isEmpty());
        assertTrue(staleStats.isEmpty());
    }
    }


    @SmallTest
    @SmallTest
    public void testOnlyHeader() throws Exception {
    public void testOnlyHeader() throws Exception {
        byte[] buffer = new ProcFileBuilder().getBytes();
        byte[] buffer = new ProcFileBuilder().getBytes();

        KernelWakelockStats staleStats = mReader.parseProcWakelocks(buffer, buffer.length, true,
        KernelWakelockStats staleStats = mReader.parseProcWakelocks(buffer, buffer.length, true,
                new KernelWakelockStats());
                new KernelWakelockStats());

        assertTrue(staleStats.isEmpty());
        assertTrue(staleStats.isEmpty());
    }
    }


@@ -85,9 +125,12 @@ public class KernelWakelockReaderTest extends TestCase {
        byte[] buffer = new ProcFileBuilder()
        byte[] buffer = new ProcFileBuilder()
                .addLine("Wakelock", 34, 123) // Milliseconds
                .addLine("Wakelock", 34, 123) // Milliseconds
                .getBytes();
                .getBytes();

        KernelWakelockStats staleStats = mReader.parseProcWakelocks(buffer, buffer.length, true,
        KernelWakelockStats staleStats = mReader.parseProcWakelocks(buffer, buffer.length, true,
                new KernelWakelockStats());
                new KernelWakelockStats());

        assertEquals(1, staleStats.size());
        assertEquals(1, staleStats.size());

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


        KernelWakelockStats.Entry entry = staleStats.get("Wakelock");
        KernelWakelockStats.Entry entry = staleStats.get("Wakelock");
@@ -101,9 +144,12 @@ public class KernelWakelockReaderTest extends TestCase {
                .addLine("Wakelock", 1, 10)
                .addLine("Wakelock", 1, 10)
                .addLine("Fakelock", 2, 20)
                .addLine("Fakelock", 2, 20)
                .getBytes();
                .getBytes();

        KernelWakelockStats staleStats = mReader.parseProcWakelocks(buffer, buffer.length, true,
        KernelWakelockStats staleStats = mReader.parseProcWakelocks(buffer, buffer.length, true,
                new KernelWakelockStats());
                new KernelWakelockStats());

        assertEquals(2, staleStats.size());
        assertEquals(2, staleStats.size());

        assertTrue(staleStats.containsKey("Wakelock"));
        assertTrue(staleStats.containsKey("Wakelock"));
        assertTrue(staleStats.containsKey("Fakelock"));
        assertTrue(staleStats.containsKey("Fakelock"));
    }
    }
@@ -114,8 +160,10 @@ public class KernelWakelockReaderTest extends TestCase {
                .addLine("Wakelock", 1, 10) // Milliseconds
                .addLine("Wakelock", 1, 10) // Milliseconds
                .addLine("Wakelock", 1, 10) // Milliseconds
                .addLine("Wakelock", 1, 10) // Milliseconds
                .getBytes();
                .getBytes();

        KernelWakelockStats staleStats = mReader.parseProcWakelocks(buffer, buffer.length, true,
        KernelWakelockStats staleStats = mReader.parseProcWakelocks(buffer, buffer.length, true,
                new KernelWakelockStats());
                new KernelWakelockStats());

        assertEquals(1, staleStats.size());
        assertEquals(1, staleStats.size());
        assertTrue(staleStats.containsKey("Wakelock"));
        assertTrue(staleStats.containsKey("Wakelock"));


@@ -126,12 +174,14 @@ public class KernelWakelockReaderTest extends TestCase {


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

        byte[] buffer = new ProcFileBuilder()
        byte[] buffer = new ProcFileBuilder()
                .addLine("Fakelock", 3, 30)
                .addLine("Fakelock", 3, 30)
                .getBytes();
                .getBytes();
        KernelWakelockStats staleStats = new KernelWakelockStats();


        staleStats = mReader.parseProcWakelocks(buffer, buffer.length, true, staleStats);
        readKernelWakelockStats(staleStats, buffer, new WakeLockInfo[0]);

        assertEquals(1, staleStats.size());
        assertEquals(1, staleStats.size());
        assertTrue(staleStats.containsKey("Fakelock"));
        assertTrue(staleStats.containsKey("Fakelock"));


@@ -139,9 +189,228 @@ public class KernelWakelockReaderTest extends TestCase {
                .addLine("Wakelock", 1, 10)
                .addLine("Wakelock", 1, 10)
                .getBytes();
                .getBytes();


        staleStats = mReader.parseProcWakelocks(buffer, buffer.length, true, staleStats);
        readKernelWakelockStats(staleStats, buffer, new WakeLockInfo[0]);

        assertEquals(1, staleStats.size());
        assertEquals(1, staleStats.size());
        assertTrue(staleStats.containsKey("Wakelock"));
        assertTrue(staleStats.containsKey("Wakelock"));
        assertFalse(staleStats.containsKey("Fakelock"));
        assertFalse(staleStats.containsKey("Fakelock"));
    }
    }

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

        assertTrue(staleStats.isEmpty());
    }

    @SmallTest
    public void testOneWakeLockInfo() {
        WakeLockInfo[] wlStats = new WakeLockInfo[1];
        wlStats[0] = createWakeLockInfo("WakeLock", 20, 10000);

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

        assertEquals(1, staleStats.size());

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

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

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

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

        assertEquals(2, staleStats.size());

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

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

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

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

        KernelWakelockStats staleStats = new KernelWakelockStats();

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

        assertEquals(1, staleStats.size());

        assertTrue(staleStats.containsKey("WakeLock1"));
        KernelWakelockStats.Entry entry = staleStats.get("WakeLock1");
        assertEquals(10, entry.mCount);
        assertEquals(1000, entry.mTotalTime);

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

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

        assertEquals(1, staleStats.size());

        assertFalse(staleStats.containsKey("WakeLock1"));
        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);
    }
}
}