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

Commit 6776849d authored by Amith Yamasani's avatar Amith Yamasani
Browse files

Report app standby state to batterystats

Also reduce idle checks to the target user if possible.
Optimized calls to some internal methods

Bug: 21639147
Change-Id: If1faf26f862e5c4ca905f2603a4ba52a8d1af954
parent 4039f657
Loading
Loading
Loading
Loading
+8 −3
Original line number Original line Diff line number Diff line
@@ -1177,8 +1177,13 @@ public abstract class BatteryStats implements Parcelable {
        public static final int EVENT_ALARM = 0x000e;
        public static final int EVENT_ALARM = 0x000e;
        // Record that we have decided we need to collect new stats data.
        // Record that we have decided we need to collect new stats data.
        public static final int EVENT_COLLECT_EXTERNAL_STATS = 0x000f;
        public static final int EVENT_COLLECT_EXTERNAL_STATS = 0x000f;
        // Event for a package becoming inactive due to being unused for a period of time.
        public static final int EVENT_PACKAGE_INACTIVE = 0x0010;
        // Event for a package becoming active due to an interaction.
        public static final int EVENT_PACKAGE_ACTIVE = 0x0011;

        // Number of event types.
        // Number of event types.
        public static final int EVENT_COUNT = 0x0010;
        public static final int EVENT_COUNT = 0x0012;
        // Mask to extract out only the type part of the event.
        // Mask to extract out only the type part of the event.
        public static final int EVENT_TYPE_MASK = ~(EVENT_FLAG_START|EVENT_FLAG_FINISH);
        public static final int EVENT_TYPE_MASK = ~(EVENT_FLAG_START|EVENT_FLAG_FINISH);


@@ -1835,12 +1840,12 @@ public abstract class BatteryStats implements Parcelable {


    public static final String[] HISTORY_EVENT_NAMES = new String[] {
    public static final String[] HISTORY_EVENT_NAMES = new String[] {
            "null", "proc", "fg", "top", "sync", "wake_lock_in", "job", "user", "userfg", "conn",
            "null", "proc", "fg", "top", "sync", "wake_lock_in", "job", "user", "userfg", "conn",
            "motion", "active", "pkginst", "pkgunin", "alarm", "stats"
            "motion", "active", "pkginst", "pkgunin", "alarm", "stats", "inactive", "active"
    };
    };


    public static final String[] HISTORY_EVENT_CHECKIN_NAMES = new String[] {
    public static final String[] HISTORY_EVENT_CHECKIN_NAMES = new String[] {
            "Enl", "Epr", "Efg", "Etp", "Esy", "Ewl", "Ejb", "Eur", "Euf", "Ecn",
            "Enl", "Epr", "Efg", "Etp", "Esy", "Ewl", "Ejb", "Eur", "Euf", "Ecn",
            "Esm", "Eac", "Epi", "Epu", "Eal", "Est"
            "Esm", "Eac", "Epi", "Epu", "Eal", "Est", "Eai", "Eaa"
    };
    };


    /**
    /**
+33 −16
Original line number Original line Diff line number Diff line
@@ -27,34 +27,27 @@ import com.android.internal.util.IndentingPrintWriter;
 */
 */
public class AppIdleHistory {
public class AppIdleHistory {


    private SparseArray<ArrayMap<String,byte[]>> idleHistory = new SparseArray<>();
    private SparseArray<ArrayMap<String,byte[]>> mIdleHistory = new SparseArray<>();
    private long lastPeriod = 0;
    private long lastPeriod = 0;
    private static final long ONE_MINUTE = 60 * 1000;
    private static final long ONE_MINUTE = 60 * 1000;
    private static final int HISTORY_SIZE = 100;
    private static final int HISTORY_SIZE = 100;
    private static final int FLAG_LAST_STATE = 2;
    private static final int FLAG_LAST_STATE = 2;
    private static final int FLAG_PARTIAL_ACTIVE = 1;
    private static final int FLAG_PARTIAL_ACTIVE = 1;
    private static final long PERIOD_DURATION = UsageStatsService.DEBUG ? ONE_MINUTE
    private static final long PERIOD_DURATION = UsageStatsService.COMPRESS_TIME ? ONE_MINUTE
            : 60 * ONE_MINUTE;
            : 60 * ONE_MINUTE;


    public void addEntry(String packageName, int userId, boolean idle, long timeNow) {
    public void addEntry(String packageName, int userId, boolean idle, long timeNow) {
        ArrayMap<String, byte[]> userHistory = idleHistory.get(userId);
        ArrayMap<String, byte[]> userHistory = getUserHistory(userId);
        if (userHistory == null) {
        byte[] packageHistory = getPackageHistory(userHistory, packageName);
            userHistory = new ArrayMap<>();

            idleHistory.put(userId, userHistory);
        }
        byte[] packageHistory = userHistory.get(packageName);
        if (packageHistory == null) {
            packageHistory = new byte[HISTORY_SIZE];
            userHistory.put(packageName, packageHistory);
        }
        long thisPeriod = timeNow / PERIOD_DURATION;
        long thisPeriod = timeNow / PERIOD_DURATION;
        // Has the period switched over? Slide all users' package histories
        // Has the period switched over? Slide all users' package histories
        if (lastPeriod != 0 && lastPeriod < thisPeriod
        if (lastPeriod != 0 && lastPeriod < thisPeriod
                && (thisPeriod - lastPeriod) < HISTORY_SIZE - 1) {
                && (thisPeriod - lastPeriod) < HISTORY_SIZE - 1) {
            int diff = (int) (thisPeriod - lastPeriod);
            int diff = (int) (thisPeriod - lastPeriod);
            final int NUSERS = idleHistory.size();
            final int NUSERS = mIdleHistory.size();
            for (int u = 0; u < NUSERS; u++) {
            for (int u = 0; u < NUSERS; u++) {
                userHistory = idleHistory.valueAt(u);
                userHistory = mIdleHistory.valueAt(u);
                for (byte[] history : userHistory.values()) {
                for (byte[] history : userHistory.values()) {
                    // Shift left
                    // Shift left
                    System.arraycopy(history, diff, history, 0, HISTORY_SIZE - diff);
                    System.arraycopy(history, diff, history, 0, HISTORY_SIZE - diff);
@@ -74,12 +67,36 @@ public class AppIdleHistory {
        }
        }
    }
    }


    private ArrayMap<String, byte[]> getUserHistory(int userId) {
        ArrayMap<String, byte[]> userHistory = mIdleHistory.get(userId);
        if (userHistory == null) {
            userHistory = new ArrayMap<>();
            mIdleHistory.put(userId, userHistory);
        }
        return userHistory;
    }

    private byte[] getPackageHistory(ArrayMap<String, byte[]> userHistory, String packageName) {
        byte[] packageHistory = userHistory.get(packageName);
        if (packageHistory == null) {
            packageHistory = new byte[HISTORY_SIZE];
            userHistory.put(packageName, packageHistory);
        }
        return packageHistory;
    }

    public void removeUser(int userId) {
    public void removeUser(int userId) {
        idleHistory.remove(userId);
        mIdleHistory.remove(userId);
    }

    public boolean isIdle(int userId, String packageName) {
        ArrayMap<String, byte[]> userHistory = getUserHistory(userId);
        byte[] packageHistory = getPackageHistory(userHistory, packageName);
        return (packageHistory[HISTORY_SIZE - 1] & FLAG_LAST_STATE) == 0;
    }
    }


    public void dump(IndentingPrintWriter idpw, int userId) {
    public void dump(IndentingPrintWriter idpw, int userId) {
        ArrayMap<String, byte[]> userHistory = idleHistory.get(userId);
        ArrayMap<String, byte[]> userHistory = mIdleHistory.get(userId);
        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++) {
+73 −30
Original line number Original line Diff line number Diff line
@@ -43,6 +43,7 @@ import android.database.ContentObserver;
import android.hardware.display.DisplayManager;
import android.hardware.display.DisplayManager;
import android.net.Uri;
import android.net.Uri;
import android.os.BatteryManager;
import android.os.BatteryManager;
import android.os.BatteryStats;
import android.os.Binder;
import android.os.Binder;
import android.os.Environment;
import android.os.Environment;
import android.os.Handler;
import android.os.Handler;
@@ -65,6 +66,7 @@ import android.util.SparseArray;
import android.view.Display;
import android.view.Display;


import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.app.IBatteryStats;
import com.android.internal.os.BackgroundThread;
import com.android.internal.os.BackgroundThread;
import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.IndentingPrintWriter;
import com.android.server.DeviceIdleController;
import com.android.server.DeviceIdleController;
@@ -91,7 +93,7 @@ public class UsageStatsService extends SystemService implements
    static final String TAG = "UsageStatsService";
    static final String TAG = "UsageStatsService";


    static final boolean DEBUG = false;
    static final boolean DEBUG = false;
    private static final boolean COMPRESS_TIME = false;
    static final boolean COMPRESS_TIME = false;


    private static final long TEN_SECONDS = 10 * 1000;
    private static final long TEN_SECONDS = 10 * 1000;
    private static final long ONE_MINUTE = 60 * 1000;
    private static final long ONE_MINUTE = 60 * 1000;
@@ -128,6 +130,7 @@ public class UsageStatsService extends SystemService implements
    IDeviceIdleController mDeviceIdleController;
    IDeviceIdleController mDeviceIdleController;
    private DisplayManager mDisplayManager;
    private DisplayManager mDisplayManager;
    private PowerManager mPowerManager;
    private PowerManager mPowerManager;
    private IBatteryStats mBatteryStats;


    private final SparseArray<UserUsageStatsService> mUserState = new SparseArray<>();
    private final SparseArray<UserUsageStatsService> mUserState = new SparseArray<>();
    private File mUsageStatsDir;
    private File mUsageStatsDir;
@@ -200,6 +203,8 @@ public class UsageStatsService extends SystemService implements
            mAppWidgetManager = getContext().getSystemService(AppWidgetManager.class);
            mAppWidgetManager = getContext().getSystemService(AppWidgetManager.class);
            mDeviceIdleController = IDeviceIdleController.Stub.asInterface(
            mDeviceIdleController = IDeviceIdleController.Stub.asInterface(
                    ServiceManager.getService(DeviceIdleController.SERVICE_NAME));
                    ServiceManager.getService(DeviceIdleController.SERVICE_NAME));
            mBatteryStats = IBatteryStats.Stub.asInterface(
                    ServiceManager.getService(BatteryStats.SERVICE_NAME));
            mDisplayManager = (DisplayManager) getContext().getSystemService(
            mDisplayManager = (DisplayManager) getContext().getSystemService(
                    Context.DISPLAY_SERVICE);
                    Context.DISPLAY_SERVICE);
            mPowerManager = getContext().getSystemService(PowerManager.class);
            mPowerManager = getContext().getSystemService(PowerManager.class);
@@ -228,7 +233,7 @@ public class UsageStatsService extends SystemService implements
                }
                }
            } else if (Intent.ACTION_USER_STARTED.equals(intent.getAction())) {
            } else if (Intent.ACTION_USER_STARTED.equals(intent.getAction())) {
                if (userId >=0) {
                if (userId >=0) {
                    postCheckIdleStates();
                    postCheckIdleStates(userId);
                }
                }
            }
            }
        }
        }
@@ -307,7 +312,7 @@ public class UsageStatsService extends SystemService implements
                    mLastAppIdleParoledTime = checkAndGetTimeLocked();
                    mLastAppIdleParoledTime = checkAndGetTimeLocked();
                    postNextParoleTimeout();
                    postNextParoleTimeout();
                }
                }
                postCheckIdleStates();
                postCheckIdleStates(UserHandle.USER_ALL);
            }
            }
        }
        }
    }
    }
@@ -332,22 +337,25 @@ public class UsageStatsService extends SystemService implements
        mHandler.sendEmptyMessageDelayed(MSG_PAROLE_END_TIMEOUT, DEFAULT_PAROLE_DURATION);
        mHandler.sendEmptyMessageDelayed(MSG_PAROLE_END_TIMEOUT, DEFAULT_PAROLE_DURATION);
    }
    }


    void postCheckIdleStates() {
    void postCheckIdleStates(int userId) {
        mHandler.removeMessages(MSG_CHECK_IDLE_STATES);
        mHandler.sendMessage(mHandler.obtainMessage(MSG_CHECK_IDLE_STATES, userId, 0));
        mHandler.sendEmptyMessage(MSG_CHECK_IDLE_STATES);
    }
    }


    /** Check all running users' apps to see if they enter an idle state. */
    /** Check all running users' or specified user's apps to see if they enter an idle state. */
    void checkIdleStates() {
    void checkIdleStates(int checkUserId) {
        final int[] runningUsers;
        final int[] userIds;
        try {
        try {
            runningUsers = ActivityManagerNative.getDefault().getRunningUserIds();
            if (checkUserId == UserHandle.USER_ALL) {
                userIds = ActivityManagerNative.getDefault().getRunningUserIds();
            } else {
                userIds = new int[] { checkUserId };
            }
        } catch (RemoteException re) {
        } catch (RemoteException re) {
            return;
            return;
        }
        }


        for (int i = 0; i < runningUsers.length; i++) {
        for (int i = 0; i < userIds.length; i++) {
            final int userId = runningUsers[i];
            final int userId = userIds[i];
            List<PackageInfo> packages =
            List<PackageInfo> packages =
                    getContext().getPackageManager().getInstalledPackages(
                    getContext().getPackageManager().getInstalledPackages(
                            PackageManager.GET_DISABLED_COMPONENTS
                            PackageManager.GET_DISABLED_COMPONENTS
@@ -355,17 +363,22 @@ public class UsageStatsService extends SystemService implements
                            userId);
                            userId);
            synchronized (mLock) {
            synchronized (mLock) {
                final long timeNow = checkAndGetTimeLocked();
                final long timeNow = checkAndGetTimeLocked();
                final long screenOnTime = getScreenOnTimeLocked(timeNow);
                UserUsageStatsService service = getUserDataAndInitializeIfNeededLocked(userId,
                        timeNow);
                final int packageCount = packages.size();
                final int packageCount = packages.size();
                for (int p = 0; p < packageCount; p++) {
                for (int p = 0; p < packageCount; p++) {
                    final String packageName = packages.get(p).packageName;
                    final String packageName = packages.get(p).packageName;
                    final boolean isIdle = isAppIdleFiltered(packageName, userId, timeNow);
                    final boolean isIdle = isAppIdleFiltered(packageName, userId, service, timeNow,
                            screenOnTime);
                    mHandler.sendMessage(mHandler.obtainMessage(MSG_INFORM_LISTENERS,
                    mHandler.sendMessage(mHandler.obtainMessage(MSG_INFORM_LISTENERS,
                            userId, isIdle ? 1 : 0, packageName));
                            userId, isIdle ? 1 : 0, packageName));
                    mAppIdleHistory.addEntry(packageName, userId, isIdle, timeNow);
                    mAppIdleHistory.addEntry(packageName, userId, isIdle, timeNow);
                }
                }
            }
            }
        }
        }
        mHandler.sendEmptyMessageDelayed(MSG_CHECK_IDLE_STATES, mCheckIdleIntervalMillis);
        mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_CHECK_IDLE_STATES, checkUserId, 0),
                mCheckIdleIntervalMillis);
    }
    }


    /** Check if it's been a while since last parole and let idle apps do some work */
    /** Check if it's been a while since last parole and let idle apps do some work */
@@ -386,6 +399,20 @@ public class UsageStatsService extends SystemService implements
        }
        }
    }
    }


    private void notifyBatteryStats(String packageName, int userId, boolean idle) {
        try {
            int uid = AppGlobals.getPackageManager().getPackageUid(packageName, userId);
            if (idle) {
                mBatteryStats.noteEvent(BatteryStats.HistoryItem.EVENT_PACKAGE_INACTIVE,
                        packageName, uid);
            } else {
                mBatteryStats.noteEvent(BatteryStats.HistoryItem.EVENT_PACKAGE_ACTIVE,
                        packageName, uid);
            }
        } catch (RemoteException re) {
        }
    }

    void updateDisplayLocked() {
    void updateDisplayLocked() {
        boolean screenOn = mDisplayManager.getDisplay(Display.DEFAULT_DISPLAY).getState()
        boolean screenOn = mDisplayManager.getDisplay(Display.DEFAULT_DISPLAY).getState()
                == Display.STATE_ON;
                == Display.STATE_ON;
@@ -545,7 +572,7 @@ public class UsageStatsService extends SystemService implements
            final long lastUsedTime = service.getSystemLastUsedTime(event.mPackage);
            final long lastUsedTime = service.getSystemLastUsedTime(event.mPackage);
            final boolean previouslyIdle = hasPassedIdleTimeoutLocked(beginIdleTime,
            final boolean previouslyIdle = hasPassedIdleTimeoutLocked(beginIdleTime,
                    lastUsedTime, screenOnTime, timeNow);
                    lastUsedTime, screenOnTime, timeNow);
            service.reportEvent(event, getScreenOnTimeLocked(timeNow));
            service.reportEvent(event, screenOnTime);
            // Inform listeners if necessary
            // Inform listeners if necessary
            if ((event.mEventType == Event.MOVE_TO_FOREGROUND
            if ((event.mEventType == Event.MOVE_TO_FOREGROUND
                    || event.mEventType == Event.MOVE_TO_BACKGROUND
                    || event.mEventType == Event.MOVE_TO_BACKGROUND
@@ -555,6 +582,7 @@ public class UsageStatsService extends SystemService implements
                    // Slog.d(TAG, "Informing listeners of out-of-idle " + event.mPackage);
                    // Slog.d(TAG, "Informing listeners of out-of-idle " + event.mPackage);
                    mHandler.sendMessage(mHandler.obtainMessage(MSG_INFORM_LISTENERS, userId,
                    mHandler.sendMessage(mHandler.obtainMessage(MSG_INFORM_LISTENERS, userId,
                            /* idle = */ 0, event.mPackage));
                            /* idle = */ 0, event.mPackage));
                    notifyBatteryStats(event.mPackage, userId, false);
                    mAppIdleHistory.addEntry(event.mPackage, userId, false, timeNow);
                    mAppIdleHistory.addEntry(event.mPackage, userId, false, timeNow);
                }
                }
            }
            }
@@ -586,6 +614,9 @@ public class UsageStatsService extends SystemService implements
                // Slog.d(TAG, "Informing listeners of out-of-idle " + event.mPackage);
                // Slog.d(TAG, "Informing listeners of out-of-idle " + event.mPackage);
                mHandler.sendMessage(mHandler.obtainMessage(MSG_INFORM_LISTENERS, userId,
                mHandler.sendMessage(mHandler.obtainMessage(MSG_INFORM_LISTENERS, userId,
                        /* idle = */ idle ? 1 : 0, packageName));
                        /* idle = */ idle ? 1 : 0, packageName));
                if (!idle) {
                    notifyBatteryStats(packageName, userId, idle);
                }
                mAppIdleHistory.addEntry(packageName, userId, idle, timeNow);
                mAppIdleHistory.addEntry(packageName, userId, idle, timeNow);
            }
            }
        }
        }
@@ -660,19 +691,20 @@ public class UsageStatsService extends SystemService implements
        }
        }
    }
    }


    private boolean isAppIdleUnfiltered(String packageName, int userId, long timeNow) {
    private boolean isAppIdleUnfiltered(String packageName, UserUsageStatsService userService,
            long timeNow, long screenOnTime) {
        synchronized (mLock) {
        synchronized (mLock) {
            final long screenOnTime = getScreenOnTimeLocked(timeNow);
            long beginIdleTime = userService.getBeginIdleTime(packageName);
            final UserUsageStatsService service =
            long lastUsedTime = userService.getSystemLastUsedTime(packageName);
                    getUserDataAndInitializeIfNeededLocked(userId, timeNow);
            return hasPassedIdleTimeoutLocked(beginIdleTime, lastUsedTime, screenOnTime,
            long beginIdleTime = service.getBeginIdleTime(packageName);
                    timeNow);
            long lastUsedTime = service.getSystemLastUsedTime(packageName);
            return hasPassedIdleTimeoutLocked(beginIdleTime, lastUsedTime, screenOnTime, timeNow);
        }
        }
    }
    }


    /**
    /**
     * @param timestamp when the app was last used in device usage timebase
     * @param beginIdleTime when the app was last used in device usage timebase
     * @param lastUsedTime wallclock time of when the app was last used
     * @param screenOnTime screen-on timebase time
     * @param currentTime current time in device usage timebase
     * @param currentTime current time in device usage timebase
     * @return whether it's been used far enough in the past to be considered inactive
     * @return whether it's been used far enough in the past to be considered inactive
     */
     */
@@ -696,18 +728,29 @@ public class UsageStatsService extends SystemService implements
        }
        }
    }
    }


    boolean isAppIdleFiltered(String packageName, int userId, long timeNow) {
        final UserUsageStatsService userService;
        final long screenOnTime;
        synchronized (mLock) {
            if (timeNow == -1) {
                timeNow = checkAndGetTimeLocked();
            }
            userService = getUserDataAndInitializeIfNeededLocked(userId, timeNow);
            screenOnTime = getScreenOnTimeLocked(timeNow);
        }
        return isAppIdleFiltered(packageName, userId, userService, timeNow, screenOnTime);
    }

    /**
    /**
     * Checks if an app has been idle for a while and filters out apps that are excluded.
     * Checks if an app has been idle for a while and filters out apps that are excluded.
     * It returns false if the current system state allows all apps to be considered active.
     * It returns false if the current system state allows all apps to be considered active.
     * This happens if the device is plugged in or temporarily allowed to make exceptions.
     * This happens if the device is plugged in or temporarily allowed to make exceptions.
     * Called by interface impls.
     * Called by interface impls.
     */
     */
    boolean isAppIdleFiltered(String packageName, int userId, long timeNow) {
    private boolean isAppIdleFiltered(String packageName, int userId,
            UserUsageStatsService userService, long timeNow, long screenOnTime) {
        if (packageName == null) return false;
        if (packageName == null) return false;
        synchronized (mLock) {
        synchronized (mLock) {
            if (timeNow == -1) {
                timeNow = checkAndGetTimeLocked();
            }
            // Temporary exemption, probably due to device charging or occasional allowance to
            // Temporary exemption, probably due to device charging or occasional allowance to
            // be allowed to sync, etc.
            // be allowed to sync, etc.
            if (mAppIdleParoled) {
            if (mAppIdleParoled) {
@@ -735,7 +778,7 @@ public class UsageStatsService extends SystemService implements
            return false;
            return false;
        }
        }


        return isAppIdleUnfiltered(packageName, userId, timeNow);
        return isAppIdleUnfiltered(packageName, userService, timeNow, screenOnTime);
    }
    }


    void setAppIdle(String packageName, boolean idle, int userId) {
    void setAppIdle(String packageName, boolean idle, int userId) {
@@ -844,7 +887,7 @@ public class UsageStatsService extends SystemService implements
                    break;
                    break;


                case MSG_CHECK_IDLE_STATES:
                case MSG_CHECK_IDLE_STATES:
                    checkIdleStates();
                    checkIdleStates(msg.arg1);
                    break;
                    break;


                case MSG_CHECK_PAROLE_TIMEOUT:
                case MSG_CHECK_PAROLE_TIMEOUT:
@@ -884,7 +927,7 @@ public class UsageStatsService extends SystemService implements
                    UserHandle.USER_OWNER);
                    UserHandle.USER_OWNER);
            mCheckIdleIntervalMillis = Math.min(DEFAULT_CHECK_IDLE_INTERVAL,
            mCheckIdleIntervalMillis = Math.min(DEFAULT_CHECK_IDLE_INTERVAL,
                    mAppIdleDurationMillis / 4);
                    mAppIdleDurationMillis / 4);
            postCheckIdleStates();
            postCheckIdleStates(UserHandle.USER_ALL);
        }
        }
    }
    }