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

Commit 61d5fd7f authored by Amith Yamasani's avatar Amith Yamasani
Browse files

Reduce screen on delay during UsageStats rollover

Decoupled the app idle book-keeping from usage stats lock, by
introducing an mAppIdleLock. This is used for all state related
to app idle. In some cases, the locks will be nested, with
mLock being acquired first and then mAppIdleLock.

This should fix the situation where a rollover, which writes to
disk and could take several seconds when the system is swamped,
like when the device just came out of idle and the screen was
turned on (like this run-on sentence), causes calls from other
services for app-idle status to be blocked. This was resulting
in a long time to turn on the screen.

Also fixed a dump indentation issue.

Bug: 34627115
Bug: 34961340
Test: Manual, force into idle, increased rollover frequency,
      and tested screen on time.

Change-Id: Ie8b44e6f07f82d8a31f1b733a403dd9b6dc310f6
parent 2140cd64
Loading
Loading
Loading
Loading
+25 −25
Original line number Original line Diff line number Diff line
@@ -45,12 +45,12 @@ public class AppIdleHistoryTests extends AndroidTestCase {
        final int userId = 0;
        final int userId = 0;
        AppIdleHistory aih = new AppIdleHistory(mStorageDir, 0);
        AppIdleHistory aih = new AppIdleHistory(mStorageDir, 0);


        aih.updateDisplayLocked(true, /* elapsedRealtime= */ 1000);
        aih.updateDisplay(true, /* elapsedRealtime= */ 1000);
        aih.updateDisplayLocked(false, /* elapsedRealtime= */ 2000);
        aih.updateDisplay(false, /* elapsedRealtime= */ 2000);
        // Screen On time file should be written right away
        // Screen On time file should be written right away
        assertTrue(aih.getScreenOnTimeFile().exists());
        assertTrue(aih.getScreenOnTimeFile().exists());


        aih.writeAppIdleTimesLocked(userId);
        aih.writeAppIdleTimes(userId);
        // stats file should be written now
        // stats file should be written now
        assertTrue(new File(new File(mStorageDir, "users/" + userId),
        assertTrue(new File(new File(mStorageDir, "users/" + userId),
                AppIdleHistory.APP_IDLE_FILENAME).exists());
                AppIdleHistory.APP_IDLE_FILENAME).exists());
@@ -58,43 +58,43 @@ public class AppIdleHistoryTests extends AndroidTestCase {


    public void testScreenOnTime() {
    public void testScreenOnTime() {
        AppIdleHistory aih = new AppIdleHistory(mStorageDir, 1000);
        AppIdleHistory aih = new AppIdleHistory(mStorageDir, 1000);
        aih.updateDisplayLocked(false, 2000);
        aih.updateDisplay(false, 2000);
        assertEquals(aih.getScreenOnTimeLocked(2000), 0);
        assertEquals(aih.getScreenOnTime(2000), 0);
        aih.updateDisplayLocked(true, 3000);
        aih.updateDisplay(true, 3000);
        assertEquals(aih.getScreenOnTimeLocked(4000), 1000);
        assertEquals(aih.getScreenOnTime(4000), 1000);
        assertEquals(aih.getScreenOnTimeLocked(5000), 2000);
        assertEquals(aih.getScreenOnTime(5000), 2000);
        aih.updateDisplayLocked(false, 6000);
        aih.updateDisplay(false, 6000);
        // Screen on time should not keep progressing with screen is off
        // Screen on time should not keep progressing with screen is off
        assertEquals(aih.getScreenOnTimeLocked(7000), 3000);
        assertEquals(aih.getScreenOnTime(7000), 3000);
        assertEquals(aih.getScreenOnTimeLocked(8000), 3000);
        assertEquals(aih.getScreenOnTime(8000), 3000);
        aih.writeAppIdleDurationsLocked();
        aih.writeAppIdleDurations();


        // Check if the screen on time is persisted across instantiations
        // Check if the screen on time is persisted across instantiations
        AppIdleHistory aih2 = new AppIdleHistory(mStorageDir, 0);
        AppIdleHistory aih2 = new AppIdleHistory(mStorageDir, 0);
        assertEquals(aih2.getScreenOnTimeLocked(11000), 3000);
        assertEquals(aih2.getScreenOnTime(11000), 3000);
        aih2.updateDisplayLocked(true, 4000);
        aih2.updateDisplay(true, 4000);
        aih2.updateDisplayLocked(false, 5000);
        aih2.updateDisplay(false, 5000);
        assertEquals(aih2.getScreenOnTimeLocked(13000), 4000);
        assertEquals(aih2.getScreenOnTime(13000), 4000);
    }
    }


    public void testPackageEvents() {
    public void testPackageEvents() {
        AppIdleHistory aih = new AppIdleHistory(mStorageDir, 1000);
        AppIdleHistory aih = new AppIdleHistory(mStorageDir, 1000);
        aih.setThresholds(4000, 1000);
        aih.setThresholds(4000, 1000);
        aih.updateDisplayLocked(true, 1000);
        aih.updateDisplay(true, 1000);
        // App is not-idle by default
        // App is not-idle by default
        assertFalse(aih.isIdleLocked(PACKAGE_1, 0, 1500));
        assertFalse(aih.isIdle(PACKAGE_1, 0, 1500));
        // Still not idle
        // Still not idle
        assertFalse(aih.isIdleLocked(PACKAGE_1, 0, 3000));
        assertFalse(aih.isIdle(PACKAGE_1, 0, 3000));
        // Idle now
        // Idle now
        assertTrue(aih.isIdleLocked(PACKAGE_1, 0, 8000));
        assertTrue(aih.isIdle(PACKAGE_1, 0, 8000));
        // Not idle
        // Not idle
        assertFalse(aih.isIdleLocked(PACKAGE_2, 0, 9000));
        assertFalse(aih.isIdle(PACKAGE_2, 0, 9000));


        // Screen off
        // Screen off
        aih.updateDisplayLocked(false, 9100);
        aih.updateDisplay(false, 9100);
        // Still idle after 10 seconds because screen hasn't been on long enough
        // Still idle after 10 seconds because screen hasn't been on long enough
        assertFalse(aih.isIdleLocked(PACKAGE_2, 0, 20000));
        assertFalse(aih.isIdle(PACKAGE_2, 0, 20000));
        aih.updateDisplayLocked(true, 21000);
        aih.updateDisplay(true, 21000);
        assertTrue(aih.isIdleLocked(PACKAGE_2, 0, 23000));
        assertTrue(aih.isIdle(PACKAGE_2, 0, 23000));
    }
    }
}
}
 No newline at end of file
+43 −44
Original line number Original line Diff line number Diff line
@@ -18,7 +18,6 @@ package com.android.server.usage;


import android.os.Environment;
import android.os.Environment;
import android.os.SystemClock;
import android.os.SystemClock;
import android.os.UserHandle;
import android.util.ArrayMap;
import android.util.ArrayMap;
import android.util.AtomicFile;
import android.util.AtomicFile;
import android.util.Slog;
import android.util.Slog;
@@ -101,7 +100,7 @@ public class AppIdleHistory {
        mElapsedSnapshot = elapsedRealtime;
        mElapsedSnapshot = elapsedRealtime;
        mScreenOnSnapshot = elapsedRealtime;
        mScreenOnSnapshot = elapsedRealtime;
        mStorageDir = storageDir;
        mStorageDir = storageDir;
        readScreenOnTimeLocked();
        readScreenOnTime();
    }
    }


    public void setThresholds(long elapsedTimeThreshold, long screenOnTimeThreshold) {
    public void setThresholds(long elapsedTimeThreshold, long screenOnTimeThreshold) {
@@ -109,7 +108,7 @@ public class AppIdleHistory {
        mScreenOnTimeThreshold = screenOnTimeThreshold;
        mScreenOnTimeThreshold = screenOnTimeThreshold;
    }
    }


    public void updateDisplayLocked(boolean screenOn, long elapsedRealtime) {
    public void updateDisplay(boolean screenOn, long elapsedRealtime) {
        if (screenOn == mScreenOn) return;
        if (screenOn == mScreenOn) return;


        mScreenOn = screenOn;
        mScreenOn = screenOn;
@@ -122,7 +121,7 @@ public class AppIdleHistory {
        }
        }
    }
    }


    public long getScreenOnTimeLocked(long elapsedRealtime) {
    public long getScreenOnTime(long elapsedRealtime) {
        long screenOnTime = mScreenOnDuration;
        long screenOnTime = mScreenOnDuration;
        if (mScreenOn) {
        if (mScreenOn) {
            screenOnTime += elapsedRealtime - mScreenOnSnapshot;
            screenOnTime += elapsedRealtime - mScreenOnSnapshot;
@@ -135,7 +134,7 @@ public class AppIdleHistory {
        return new File(mStorageDir, "screen_on_time");
        return new File(mStorageDir, "screen_on_time");
    }
    }


    private void readScreenOnTimeLocked() {
    private void readScreenOnTime() {
        File screenOnTimeFile = getScreenOnTimeFile();
        File screenOnTimeFile = getScreenOnTimeFile();
        if (screenOnTimeFile.exists()) {
        if (screenOnTimeFile.exists()) {
            try {
            try {
@@ -146,11 +145,11 @@ public class AppIdleHistory {
            } catch (IOException | NumberFormatException e) {
            } catch (IOException | NumberFormatException e) {
            }
            }
        } else {
        } else {
            writeScreenOnTimeLocked();
            writeScreenOnTime();
        }
        }
    }
    }


    private void writeScreenOnTimeLocked() {
    private void writeScreenOnTime() {
        AtomicFile screenOnTimeFile = new AtomicFile(getScreenOnTimeFile());
        AtomicFile screenOnTimeFile = new AtomicFile(getScreenOnTimeFile());
        FileOutputStream fos = null;
        FileOutputStream fos = null;
        try {
        try {
@@ -166,30 +165,30 @@ public class AppIdleHistory {
    /**
    /**
     * To be called periodically to keep track of elapsed time when app idle times are written
     * To be called periodically to keep track of elapsed time when app idle times are written
     */
     */
    public void writeAppIdleDurationsLocked() {
    public void writeAppIdleDurations() {
        final long elapsedRealtime = SystemClock.elapsedRealtime();
        final long elapsedRealtime = SystemClock.elapsedRealtime();
        // Only bump up and snapshot the elapsed time. Don't change screen on duration.
        // Only bump up and snapshot the elapsed time. Don't change screen on duration.
        mElapsedDuration += elapsedRealtime - mElapsedSnapshot;
        mElapsedDuration += elapsedRealtime - mElapsedSnapshot;
        mElapsedSnapshot = elapsedRealtime;
        mElapsedSnapshot = elapsedRealtime;
        writeScreenOnTimeLocked();
        writeScreenOnTime();
    }
    }


    public void reportUsageLocked(String packageName, int userId, long elapsedRealtime) {
    public void reportUsage(String packageName, int userId, long elapsedRealtime) {
        ArrayMap<String, PackageHistory> userHistory = getUserHistoryLocked(userId);
        ArrayMap<String, PackageHistory> userHistory = getUserHistory(userId);
        PackageHistory packageHistory = getPackageHistoryLocked(userHistory, packageName,
        PackageHistory packageHistory = getPackageHistory(userHistory, packageName,
                elapsedRealtime);
                elapsedRealtime);


        shiftHistoryToNow(userHistory, elapsedRealtime);
        shiftHistoryToNow(userHistory, elapsedRealtime);


        packageHistory.lastUsedElapsedTime = mElapsedDuration
        packageHistory.lastUsedElapsedTime = mElapsedDuration
                + (elapsedRealtime - mElapsedSnapshot);
                + (elapsedRealtime - mElapsedSnapshot);
        packageHistory.lastUsedScreenTime = getScreenOnTimeLocked(elapsedRealtime);
        packageHistory.lastUsedScreenTime = getScreenOnTime(elapsedRealtime);
        packageHistory.recent[HISTORY_SIZE - 1] = FLAG_LAST_STATE | FLAG_PARTIAL_ACTIVE;
        packageHistory.recent[HISTORY_SIZE - 1] = FLAG_LAST_STATE | FLAG_PARTIAL_ACTIVE;
    }
    }


    public void setIdle(String packageName, int userId, long elapsedRealtime) {
    public void setIdle(String packageName, int userId, long elapsedRealtime) {
        ArrayMap<String, PackageHistory> userHistory = getUserHistoryLocked(userId);
        ArrayMap<String, PackageHistory> userHistory = getUserHistory(userId);
        PackageHistory packageHistory = getPackageHistoryLocked(userHistory, packageName,
        PackageHistory packageHistory = getPackageHistory(userHistory, packageName,
                elapsedRealtime);
                elapsedRealtime);


        shiftHistoryToNow(userHistory, elapsedRealtime);
        shiftHistoryToNow(userHistory, elapsedRealtime);
@@ -222,23 +221,23 @@ public class AppIdleHistory {
        mLastPeriod = thisPeriod;
        mLastPeriod = thisPeriod;
    }
    }


    private ArrayMap<String, PackageHistory> getUserHistoryLocked(int userId) {
    private ArrayMap<String, PackageHistory> getUserHistory(int userId) {
        ArrayMap<String, PackageHistory> userHistory = mIdleHistory.get(userId);
        ArrayMap<String, PackageHistory> userHistory = mIdleHistory.get(userId);
        if (userHistory == null) {
        if (userHistory == null) {
            userHistory = new ArrayMap<>();
            userHistory = new ArrayMap<>();
            mIdleHistory.put(userId, userHistory);
            mIdleHistory.put(userId, userHistory);
            readAppIdleTimesLocked(userId, userHistory);
            readAppIdleTimes(userId, userHistory);
        }
        }
        return userHistory;
        return userHistory;
    }
    }


    private PackageHistory getPackageHistoryLocked(ArrayMap<String, PackageHistory> userHistory,
    private PackageHistory getPackageHistory(ArrayMap<String, PackageHistory> userHistory,
            String packageName, long elapsedRealtime) {
            String packageName, long elapsedRealtime) {
        PackageHistory packageHistory = userHistory.get(packageName);
        PackageHistory packageHistory = userHistory.get(packageName);
        if (packageHistory == null) {
        if (packageHistory == null) {
            packageHistory = new PackageHistory();
            packageHistory = new PackageHistory();
            packageHistory.lastUsedElapsedTime = getElapsedTimeLocked(elapsedRealtime);
            packageHistory.lastUsedElapsedTime = getElapsedTime(elapsedRealtime);
            packageHistory.lastUsedScreenTime = getScreenOnTimeLocked(elapsedRealtime);
            packageHistory.lastUsedScreenTime = getScreenOnTime(elapsedRealtime);
            userHistory.put(packageName, packageHistory);
            userHistory.put(packageName, packageHistory);
        }
        }
        return packageHistory;
        return packageHistory;
@@ -248,41 +247,41 @@ public class AppIdleHistory {
        mIdleHistory.remove(userId);
        mIdleHistory.remove(userId);
    }
    }


    public boolean isIdleLocked(String packageName, int userId, long elapsedRealtime) {
    public boolean isIdle(String packageName, int userId, long elapsedRealtime) {
        ArrayMap<String, PackageHistory> userHistory = getUserHistoryLocked(userId);
        ArrayMap<String, PackageHistory> userHistory = getUserHistory(userId);
        PackageHistory packageHistory =
        PackageHistory packageHistory =
                getPackageHistoryLocked(userHistory, packageName, elapsedRealtime);
                getPackageHistory(userHistory, packageName, elapsedRealtime);
        if (packageHistory == null) {
        if (packageHistory == null) {
            return false; // Default to not idle
            return false; // Default to not idle
        } else {
        } else {
            return hasPassedThresholdsLocked(packageHistory, elapsedRealtime);
            return hasPassedThresholds(packageHistory, elapsedRealtime);
        }
        }
    }
    }


    private long getElapsedTimeLocked(long elapsedRealtime) {
    private long getElapsedTime(long elapsedRealtime) {
        return (elapsedRealtime - mElapsedSnapshot + mElapsedDuration);
        return (elapsedRealtime - mElapsedSnapshot + mElapsedDuration);
    }
    }


    public void setIdleLocked(String packageName, int userId, boolean idle, long elapsedRealtime) {
    public void setIdle(String packageName, int userId, boolean idle, long elapsedRealtime) {
        ArrayMap<String, PackageHistory> userHistory = getUserHistoryLocked(userId);
        ArrayMap<String, PackageHistory> userHistory = getUserHistory(userId);
        PackageHistory packageHistory = getPackageHistoryLocked(userHistory, packageName,
        PackageHistory packageHistory = getPackageHistory(userHistory, packageName,
                elapsedRealtime);
                elapsedRealtime);
        packageHistory.lastUsedElapsedTime = getElapsedTimeLocked(elapsedRealtime)
        packageHistory.lastUsedElapsedTime = getElapsedTime(elapsedRealtime)
                - mElapsedTimeThreshold;
                - mElapsedTimeThreshold;
        packageHistory.lastUsedScreenTime = getScreenOnTimeLocked(elapsedRealtime)
        packageHistory.lastUsedScreenTime = getScreenOnTime(elapsedRealtime)
                - (idle ? mScreenOnTimeThreshold : 0) - 1000 /* just a second more */;
                - (idle ? mScreenOnTimeThreshold : 0) - 1000 /* just a second more */;
    }
    }


    public void clearUsageLocked(String packageName, int userId) {
    public void clearUsage(String packageName, int userId) {
        ArrayMap<String, PackageHistory> userHistory = getUserHistoryLocked(userId);
        ArrayMap<String, PackageHistory> userHistory = getUserHistory(userId);
        userHistory.remove(packageName);
        userHistory.remove(packageName);
    }
    }


    private boolean hasPassedThresholdsLocked(PackageHistory packageHistory, long elapsedRealtime) {
    private boolean hasPassedThresholds(PackageHistory packageHistory, long elapsedRealtime) {
        return (packageHistory.lastUsedScreenTime
        return (packageHistory.lastUsedScreenTime
                    <= getScreenOnTimeLocked(elapsedRealtime) - mScreenOnTimeThreshold)
                    <= getScreenOnTime(elapsedRealtime) - mScreenOnTimeThreshold)
                && (packageHistory.lastUsedElapsedTime
                && (packageHistory.lastUsedElapsedTime
                        <= getElapsedTimeLocked(elapsedRealtime) - mElapsedTimeThreshold);
                        <= getElapsedTime(elapsedRealtime) - mElapsedTimeThreshold);
    }
    }


    private File getUserFile(int userId) {
    private File getUserFile(int userId) {
@@ -290,7 +289,7 @@ public class AppIdleHistory {
                Integer.toString(userId)), APP_IDLE_FILENAME);
                Integer.toString(userId)), APP_IDLE_FILENAME);
    }
    }


    private void readAppIdleTimesLocked(int userId, ArrayMap<String, PackageHistory> userHistory) {
    private void readAppIdleTimes(int userId, ArrayMap<String, PackageHistory> userHistory) {
        FileInputStream fis = null;
        FileInputStream fis = null;
        try {
        try {
            AtomicFile appIdleFile = new AtomicFile(getUserFile(userId));
            AtomicFile appIdleFile = new AtomicFile(getUserFile(userId));
@@ -332,7 +331,7 @@ public class AppIdleHistory {
        }
        }
    }
    }


    public void writeAppIdleTimesLocked(int userId) {
    public void writeAppIdleTimes(int userId) {
        FileOutputStream fos = null;
        FileOutputStream fos = null;
        AtomicFile appIdleFile = new AtomicFile(getUserFile(userId));
        AtomicFile appIdleFile = new AtomicFile(getUserFile(userId));
        try {
        try {
@@ -346,7 +345,7 @@ public class AppIdleHistory {


            xml.startTag(null, TAG_PACKAGES);
            xml.startTag(null, TAG_PACKAGES);


            ArrayMap<String,PackageHistory> userHistory = getUserHistoryLocked(userId);
            ArrayMap<String,PackageHistory> userHistory = getUserHistory(userId);
            final int N = userHistory.size();
            final int N = userHistory.size();
            for (int i = 0; i < N; i++) {
            for (int i = 0; i < N; i++) {
                String packageName = userHistory.keyAt(i);
                String packageName = userHistory.keyAt(i);
@@ -374,8 +373,8 @@ public class AppIdleHistory {
        idpw.increaseIndent();
        idpw.increaseIndent();
        ArrayMap<String, PackageHistory> userHistory = mIdleHistory.get(userId);
        ArrayMap<String, PackageHistory> userHistory = mIdleHistory.get(userId);
        final long elapsedRealtime = SystemClock.elapsedRealtime();
        final long elapsedRealtime = SystemClock.elapsedRealtime();
        final long totalElapsedTime = getElapsedTimeLocked(elapsedRealtime);
        final long totalElapsedTime = getElapsedTime(elapsedRealtime);
        final long screenOnTime = getScreenOnTimeLocked(elapsedRealtime);
        final long screenOnTime = getScreenOnTime(elapsedRealtime);
        if (userHistory == null) return;
        if (userHistory == null) return;
        final int P = userHistory.size();
        final int P = userHistory.size();
        for (int p = 0; p < P; p++) {
        for (int p = 0; p < P; p++) {
@@ -386,15 +385,15 @@ public class AppIdleHistory {
            TimeUtils.formatDuration(totalElapsedTime - packageHistory.lastUsedElapsedTime, idpw);
            TimeUtils.formatDuration(totalElapsedTime - packageHistory.lastUsedElapsedTime, idpw);
            idpw.print(" lastUsedScreenOn=");
            idpw.print(" lastUsedScreenOn=");
            TimeUtils.formatDuration(screenOnTime - packageHistory.lastUsedScreenTime, idpw);
            TimeUtils.formatDuration(screenOnTime - packageHistory.lastUsedScreenTime, idpw);
            idpw.print(" idle=" + (isIdleLocked(packageName, userId, elapsedRealtime) ? "y" : "n"));
            idpw.print(" idle=" + (isIdle(packageName, userId, elapsedRealtime) ? "y" : "n"));
            idpw.println();
            idpw.println();
        }
        }
        idpw.println();
        idpw.println();
        idpw.print("totalElapsedTime=");
        idpw.print("totalElapsedTime=");
        TimeUtils.formatDuration(getElapsedTimeLocked(elapsedRealtime), idpw);
        TimeUtils.formatDuration(getElapsedTime(elapsedRealtime), idpw);
        idpw.println();
        idpw.println();
        idpw.print("totalScreenOnTime=");
        idpw.print("totalScreenOnTime=");
        TimeUtils.formatDuration(getScreenOnTimeLocked(elapsedRealtime), idpw);
        TimeUtils.formatDuration(getScreenOnTime(elapsedRealtime), idpw);
        idpw.println();
        idpw.println();
        idpw.decreaseIndent();
        idpw.decreaseIndent();
    }
    }
@@ -410,7 +409,7 @@ public class AppIdleHistory {
            for (int i = 0; i < HISTORY_SIZE; i++) {
            for (int i = 0; i < HISTORY_SIZE; i++) {
                idpw.print(history[i] == 0 ? '.' : 'A');
                idpw.print(history[i] == 0 ? '.' : 'A');
            }
            }
            idpw.print(" idle=" + (isIdleLocked(packageName, userId, elapsedRealtime) ? "y" : "n"));
            idpw.print(" idle=" + (isIdle(packageName, userId, elapsedRealtime) ? "y" : "n"));
            idpw.print("  " + packageName);
            idpw.print("  " + packageName);
            idpw.println();
            idpw.println();
        }
        }
+130 −88

File changed.

Preview size limit exceeded, changes collapsed.

+1 −1
Original line number Original line Diff line number Diff line
@@ -529,7 +529,6 @@ class UserUsageStatsService {
        pw.decreaseIndent();
        pw.decreaseIndent();


        pw.println();
        pw.println();
        pw.increaseIndent();
        pw.println("ChooserCounts");
        pw.println("ChooserCounts");
        pw.increaseIndent();
        pw.increaseIndent();
        for (UsageStats usageStats : pkgStats.values()) {
        for (UsageStats usageStats : pkgStats.values()) {
@@ -553,6 +552,7 @@ class UserUsageStatsService {
            }
            }
            pw.println();
            pw.println();
        }
        }
        pw.decreaseIndent();


        pw.println("configurations");
        pw.println("configurations");
        pw.increaseIndent();
        pw.increaseIndent();