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

Commit 59a5733a authored by Amith Yamasani's avatar Amith Yamasani Committed by Android (Google) Code Review
Browse files

Merge "Track app idle history and dump it" into mnc-dev

parents fc9b0604 0a11e694
Loading
Loading
Loading
Loading
+95 −0
Original line number Diff line number Diff line
/**
 * Copyright (C) 2015 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy
 * of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations
 * under the License.
 */

package com.android.server.usage;

import android.util.ArrayMap;
import android.util.SparseArray;

import com.android.internal.util.IndentingPrintWriter;

/**
 * Keeps track of recent active state changes in apps.
 * Access should be guarded by a lock by the caller.
 */
public class AppIdleHistory {

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

    public void addEntry(String packageName, int userId, boolean idle, long timeNow) {
        ArrayMap<String, byte[]> userHistory = idleHistory.get(userId);
        if (userHistory == null) {
            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;
        // Has the period switched over? Slide all users' package histories
        if (lastPeriod != 0 && lastPeriod < thisPeriod
                && (thisPeriod - lastPeriod) < HISTORY_SIZE - 1) {
            int diff = (int) (thisPeriod - lastPeriod);
            final int NUSERS = idleHistory.size();
            for (int u = 0; u < NUSERS; u++) {
                userHistory = idleHistory.valueAt(u);
                for (byte[] history : userHistory.values()) {
                    // Shift left
                    System.arraycopy(history, diff, history, 0, HISTORY_SIZE - diff);
                    // Replicate last state across the diff
                    for (int i = 0; i < diff; i++) {
                        history[HISTORY_SIZE - i - 1] =
                                (byte) (history[HISTORY_SIZE - diff - 1] & FLAG_LAST_STATE);
                    }
                }
            }
        }
        lastPeriod = thisPeriod;
        if (!idle) {
            packageHistory[HISTORY_SIZE - 1] = FLAG_LAST_STATE | FLAG_PARTIAL_ACTIVE;
        } else {
            packageHistory[HISTORY_SIZE - 1] &= ~FLAG_LAST_STATE;
        }
    }

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

    public void dump(IndentingPrintWriter idpw, int userId) {
        ArrayMap<String, byte[]> userHistory = idleHistory.get(userId);
        if (userHistory == null) return;
        final int P = userHistory.size();
        for (int p = 0; p < P; p++) {
            final String packageName = userHistory.keyAt(p);
            final byte[] history = userHistory.valueAt(p);
            for (int i = 0; i < HISTORY_SIZE; i++) {
                idpw.print(history[i] == 0 ? '.' : 'A');
            }
            idpw.print("  " + packageName);
            idpw.println();
        }
    }
}
 No newline at end of file
+21 −8
Original line number Diff line number Diff line
@@ -64,6 +64,7 @@ import android.util.Slog;
import android.util.SparseArray;
import android.view.Display;

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

    static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);

    private static final long TEN_SECONDS = 10 * 1000;
    private static final long ONE_MINUTE = 60 * 1000;
    private static final long TWENTY_MINUTES = 20 * 60 * 1000;
@@ -97,13 +99,13 @@ public class UsageStatsService extends SystemService implements
    private static final long TIME_CHANGE_THRESHOLD_MILLIS = 2 * 1000; // Two seconds.

    static final long DEFAULT_APP_IDLE_THRESHOLD_MILLIS = DEBUG ? ONE_MINUTE * 4
            : 1L * 24 * 60 * 60 * 1000; // 1 day
    static final long DEFAULT_CHECK_IDLE_INTERVAL = DEBUG ? ONE_MINUTE
            : 8 * 3600 * 1000; // 8 hours
            : 1L * 24 * 60 * ONE_MINUTE; // 1 day
    static final long DEFAULT_CHECK_IDLE_INTERVAL = DEBUG ? ONE_MINUTE / 4
            : 8 * 60 * ONE_MINUTE; // 8 hours
    static final long DEFAULT_PAROLE_INTERVAL = DEBUG ? ONE_MINUTE * 10
            : 24 * 60 * 60 * 1000L; // 24 hours between paroles
    static final long DEFAULT_PAROLE_DURATION = DEBUG ? ONE_MINUTE * 2
            : 10 * 60 * 1000L; // 10 minutes
            : 24 * 60 * ONE_MINUTE; // 24 hours between paroles
    static final long DEFAULT_PAROLE_DURATION = DEBUG ? ONE_MINUTE
            : 10 * ONE_MINUTE; // 10 minutes

    // Handler message types.
    static final int MSG_REPORT_EVENT = 0;
@@ -137,6 +139,9 @@ public class UsageStatsService extends SystemService implements
    long mScreenOnTime;
    long mScreenOnSystemTimeSnapshot;

    @GuardedBy("mLock")
    private AppIdleHistory mAppIdleHistory = new AppIdleHistory();

    private ArrayList<UsageStatsManagerInternal.AppIdleStateChangeListener>
            mPackageAccessListeners = new ArrayList<>();

@@ -346,12 +351,14 @@ public class UsageStatsService extends SystemService implements
                                | PackageManager.GET_UNINSTALLED_PACKAGES,
                            userId);
            synchronized (mLock) {
                final long timeNow = checkAndGetTimeLocked();
                final int packageCount = packages.size();
                for (int p = 0; p < packageCount; p++) {
                    final String packageName = packages.get(p).packageName;
                    final boolean isIdle = isAppIdleFiltered(packageName, userId);
                    mHandler.sendMessage(mHandler.obtainMessage(MSG_INFORM_LISTENERS,
                            userId, isIdle ? 1 : 0, packageName));
                    mAppIdleHistory.addEntry(packageName, userId, isIdle, timeNow);
                }
            }
        }
@@ -541,6 +548,7 @@ public class UsageStatsService extends SystemService implements
                    // Slog.d(TAG, "Informing listeners of out-of-idle " + event.mPackage);
                    mHandler.sendMessage(mHandler.obtainMessage(MSG_INFORM_LISTENERS, userId,
                            /* idle = */ 0, event.mPackage));
                    mAppIdleHistory.addEntry(event.mPackage, userId, false, timeNow);
                }
            }
        }
@@ -567,6 +575,7 @@ public class UsageStatsService extends SystemService implements
                // Slog.d(TAG, "Informing listeners of out-of-idle " + event.mPackage);
                mHandler.sendMessage(mHandler.obtainMessage(MSG_INFORM_LISTENERS, userId,
                        /* idle = */ idle ? 1 : 0, packageName));
                mAppIdleHistory.addEntry(packageName, userId, idle, timeNow);
            }
        }
    }
@@ -768,10 +777,14 @@ public class UsageStatsService extends SystemService implements
                    mUserState.valueAt(i).checkin(idpw, screenOnTime);
                } else {
                    mUserState.valueAt(i).dump(idpw, screenOnTime);
                    idpw.println();
                    if (args.length > 0 && "history".equals(args[0])) {
                        mAppIdleHistory.dump(idpw, mUserState.keyAt(i));
                    }
                }
                idpw.decreaseIndent();
            }
            pw.write("Screen On Timestamp:" + mScreenOnTime + "\n");
            pw.write("Screen On Timebase:" + mScreenOnTime + "\n");
        }
    }