Loading services/usage/java/com/android/server/usage/AppIdleHistory.java 0 → 100644 +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 services/usage/java/com/android/server/usage/UsageStatsService.java +21 −8 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading @@ -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; Loading Loading @@ -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<>(); Loading Loading @@ -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); } } } Loading Loading @@ -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); } } } Loading @@ -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); } } } Loading Loading @@ -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"); } } Loading Loading
services/usage/java/com/android/server/usage/AppIdleHistory.java 0 → 100644 +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
services/usage/java/com/android/server/usage/UsageStatsService.java +21 −8 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading @@ -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; Loading Loading @@ -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<>(); Loading Loading @@ -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); } } } Loading Loading @@ -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); } } } Loading @@ -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); } } } Loading Loading @@ -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"); } } Loading