am ffff74ab: Merge "Report app standby state to batterystats" into mnc-dev

* commit 'ffff74abb13ad8c0e25175bd361d570a8e5e1406':
  Report app standby state to batterystats
This commit is contained in:
Amith Yamasani
2015-06-12 18:05:18 +00:00
committed by Android Git Automerger
3 changed files with 114 additions and 49 deletions

View File

@@ -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"
}; };
/** /**

View File

@@ -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++) {

View File

@@ -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);
} }
} }