diff options
8 files changed, 79 insertions, 31 deletions
diff --git a/core/java/android/app/usage/UsageStatsManagerInternal.java b/core/java/android/app/usage/UsageStatsManagerInternal.java index 948ea1e..498ff81 100644 --- a/core/java/android/app/usage/UsageStatsManagerInternal.java +++ b/core/java/android/app/usage/UsageStatsManagerInternal.java @@ -71,10 +71,11 @@ public abstract class UsageStatsManagerInternal { * Could be hours, could be days, who knows? * * @param packageName + * @param uidForAppId The uid of the app, which will be used for its app id * @param userId * @return */ - public abstract boolean isAppIdle(String packageName, int userId); + public abstract boolean isAppIdle(String packageName, int uidForAppId, int userId); /** * Returns all of the uids for a given user where all packages associating with that uid diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index e3b5651..b4d2746 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -368,6 +368,10 @@ public final class ActivityManagerService extends ActivityManagerNative // we will consider it to be doing interaction for usage stats. static final int SERVICE_USAGE_INTERACTION_TIME = 30*60*1000; + // Maximum amount of time we will allow to elapse before re-reporting usage stats + // interaction with foreground processes. + static final long USAGE_STATS_INTERACTION_INTERVAL = 24*60*60*1000L; + // Maximum number of users we allow to be running at a time. static final int MAX_RUNNING_USERS = 3; @@ -18656,7 +18660,8 @@ public final class ActivityManagerService extends ActivityManagerNative } } - private final boolean applyOomAdjLocked(ProcessRecord app, boolean doingAll, long now) { + private final boolean applyOomAdjLocked(ProcessRecord app, boolean doingAll, long now, + long nowElapsed) { boolean success = true; if (app.curRawAdj != app.setRawAdj) { @@ -18760,7 +18765,7 @@ public final class ActivityManagerService extends ActivityManagerNative if (app.setProcState != app.curProcState) { if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Slog.v(TAG_OOM_ADJ, "Proc state change of " + app.processName - + " to " + app.curProcState); + + " to " + app.curProcState); boolean setImportant = app.setProcState < ActivityManager.PROCESS_STATE_SERVICE; boolean curImportant = app.curProcState < ActivityManager.PROCESS_STATE_SERVICE; if (setImportant && !curImportant) { @@ -18771,14 +18776,14 @@ public final class ActivityManagerService extends ActivityManagerNative BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics(); synchronized (stats) { app.lastWakeTime = stats.getProcessWakeTime(app.info.uid, - app.pid, SystemClock.elapsedRealtime()); + app.pid, nowElapsed); } app.lastCpuTime = app.curCpuTime; } // Inform UsageStats of important process state change // Must be called before updating setProcState - maybeUpdateUsageStatsLocked(app); + maybeUpdateUsageStatsLocked(app, nowElapsed); app.setProcState = app.curProcState; if (app.setProcState >= ActivityManager.PROCESS_STATE_HOME) { @@ -18789,6 +18794,11 @@ public final class ActivityManagerService extends ActivityManagerNative } else { app.procStateChanged = true; } + } else if (app.reportedInteraction && (nowElapsed-app.interactionEventTime) + > USAGE_STATS_INTERACTION_INTERVAL) { + // For apps that sit around for a long time in the interactive state, we need + // to report this at least once a day so they don't go idle. + maybeUpdateUsageStatsLocked(app, nowElapsed); } if (changes != 0) { @@ -18883,7 +18893,7 @@ public final class ActivityManagerService extends ActivityManagerNative } } - private void maybeUpdateUsageStatsLocked(ProcessRecord app) { + private void maybeUpdateUsageStatsLocked(ProcessRecord app, long nowElapsed) { if (DEBUG_USAGE_STATS) { Slog.d(TAG, "Checking proc [" + Arrays.toString(app.getPackageList()) + "] state changes: old = " + app.setProcState + ", new = " @@ -18900,19 +18910,20 @@ public final class ActivityManagerService extends ActivityManagerNative isInteraction = true; app.fgInteractionTime = 0; } else if (app.curProcState <= ActivityManager.PROCESS_STATE_TOP_SLEEPING) { - final long now = SystemClock.elapsedRealtime(); if (app.fgInteractionTime == 0) { - app.fgInteractionTime = now; + app.fgInteractionTime = nowElapsed; isInteraction = false; } else { - isInteraction = now > app.fgInteractionTime + SERVICE_USAGE_INTERACTION_TIME; + isInteraction = nowElapsed > app.fgInteractionTime + SERVICE_USAGE_INTERACTION_TIME; } } else { isInteraction = app.curProcState <= ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND; app.fgInteractionTime = 0; } - if (isInteraction && !app.reportedInteraction) { + if (isInteraction && (!app.reportedInteraction + || (nowElapsed-app.interactionEventTime) > USAGE_STATS_INTERACTION_INTERVAL)) { + app.interactionEventTime = nowElapsed; String[] packages = app.getPackageList(); if (packages != null) { for (int i = 0; i < packages.length; i++) { @@ -18922,6 +18933,9 @@ public final class ActivityManagerService extends ActivityManagerNative } } app.reportedInteraction = isInteraction; + if (!isInteraction) { + app.interactionEventTime = 0; + } } private final void setProcessTrackerStateLocked(ProcessRecord proc, int memFactor, long now) { @@ -18944,7 +18958,7 @@ public final class ActivityManagerService extends ActivityManagerNative computeOomAdjLocked(app, cachedAdj, TOP_APP, doingAll, now); - return applyOomAdjLocked(app, doingAll, now); + return applyOomAdjLocked(app, doingAll, now, SystemClock.elapsedRealtime()); } final void updateProcessForegroundLocked(ProcessRecord proc, boolean isForeground, @@ -19036,6 +19050,7 @@ public final class ActivityManagerService extends ActivityManagerNative final ActivityRecord TOP_ACT = resumedAppLocked(); final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null; final long now = SystemClock.uptimeMillis(); + final long nowElapsed = SystemClock.elapsedRealtime(); final long oldTime = now - ProcessList.MAX_EMPTY_TIME; final int N = mLruProcesses.size(); @@ -19162,7 +19177,7 @@ public final class ActivityManagerService extends ActivityManagerNative } } - applyOomAdjLocked(app, true, now); + applyOomAdjLocked(app, true, now, nowElapsed); // Count the number of process types. switch (app.curProcState) { diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java index bd31a21..697b4e2 100644 --- a/services/core/java/com/android/server/am/ProcessRecord.java +++ b/services/core/java/com/android/server/am/ProcessRecord.java @@ -114,6 +114,7 @@ final class ProcessRecord { boolean killed; // True once we know the process has been killed boolean procStateChanged; // Keep track of whether we changed 'setAdj'. boolean reportedInteraction;// Whether we have told usage stats about it being an interaction + long interactionEventTime; // The time we sent the last interaction event long fgInteractionTime; // When we became foreground for interaction purposes String waitingToKill; // Process is waiting to be killed when in the bg, and reason IBinder forcingToForeground;// Token that is forcing this process to be foreground @@ -297,6 +298,10 @@ final class ProcessRecord { if (reportedInteraction || fgInteractionTime != 0) { pw.print(prefix); pw.print("reportedInteraction="); pw.print(reportedInteraction); + if (interactionEventTime != 0) { + pw.print(" time="); + TimeUtils.formatDuration(interactionEventTime, SystemClock.elapsedRealtime(), pw); + } if (fgInteractionTime != 0) { pw.print(" fgInteractionTime="); TimeUtils.formatDuration(fgInteractionTime, SystemClock.elapsedRealtime(), pw); diff --git a/services/core/java/com/android/server/content/AppIdleMonitor.java b/services/core/java/com/android/server/content/AppIdleMonitor.java index fe5c2da..2d768d8 100644 --- a/services/core/java/com/android/server/content/AppIdleMonitor.java +++ b/services/core/java/com/android/server/content/AppIdleMonitor.java @@ -50,8 +50,8 @@ class AppIdleMonitor extends AppIdleStateChangeListener { } } - boolean isAppIdle(String packageName, int userId) { - return !mAppIdleParoleOn && mUsageStats.isAppIdle(packageName, userId); + boolean isAppIdle(String packageName, int uidForAppId, int userId) { + return !mAppIdleParoleOn && mUsageStats.isAppIdle(packageName, uidForAppId, userId); } @Override diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java index b61f90e..3ec0bee 100644 --- a/services/core/java/com/android/server/content/SyncManager.java +++ b/services/core/java/com/android/server/content/SyncManager.java @@ -2623,9 +2623,18 @@ public class SyncManager { continue; } String packageName = getPackageName(op.target); + ApplicationInfo ai = null; + if (packageName != null) { + try { + ai = mContext.getPackageManager().getApplicationInfo(packageName, + PackageManager.GET_UNINSTALLED_PACKAGES + | PackageManager.GET_DISABLED_COMPONENTS); + } catch (NameNotFoundException e) { + } + } // If app is considered idle, then skip for now and backoff - if (packageName != null - && mAppIdleMonitor.isAppIdle(packageName, op.target.userId)) { + if (ai != null + && mAppIdleMonitor.isAppIdle(packageName, ai.uid, op.target.userId)) { increaseBackoffSetting(op); op.appIdle = true; if (isLoggable) { diff --git a/services/core/java/com/android/server/job/controllers/AppIdleController.java b/services/core/java/com/android/server/job/controllers/AppIdleController.java index 02d4f40..6fc02f6 100644 --- a/services/core/java/com/android/server/job/controllers/AppIdleController.java +++ b/services/core/java/com/android/server/job/controllers/AppIdleController.java @@ -67,7 +67,7 @@ public class AppIdleController extends StateController { mTrackedTasks.add(jobStatus); String packageName = jobStatus.job.getService().getPackageName(); final boolean appIdle = !mAppIdleParoleOn && mUsageStatsInternal.isAppIdle(packageName, - jobStatus.getUserId()); + jobStatus.uId, jobStatus.getUserId()); if (DEBUG) { Slog.d(LOG_TAG, "Start tracking, setting idle state of " + packageName + " to " + appIdle); @@ -108,7 +108,7 @@ public class AppIdleController extends StateController { for (JobStatus task : mTrackedTasks) { String packageName = task.job.getService().getPackageName(); final boolean appIdle = !mAppIdleParoleOn && mUsageStatsInternal.isAppIdle(packageName, - task.getUserId()); + task.uId, task.getUserId()); if (DEBUG) { Slog.d(LOG_TAG, "Setting idle state of " + packageName + " to " + appIdle); } diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java index bc8957f..b428322 100644 --- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java +++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java @@ -2229,7 +2229,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { final int userId = UserHandle.getUserId(uid); for (String packageName : packages) { - if (!mUsageStats.isAppIdle(packageName, userId)) { + if (!mUsageStats.isAppIdle(packageName, uid, userId)) { return false; } } diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java index 5ad796f..2b8afba 100644 --- a/services/usage/java/com/android/server/usage/UsageStatsService.java +++ b/services/usage/java/com/android/server/usage/UsageStatsService.java @@ -385,9 +385,11 @@ public class UsageStatsService extends SystemService implements timeNow); 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, service, timeNow, - screenOnTime); + final PackageInfo pi = packages.get(p); + final String packageName = pi.packageName; + final boolean isIdle = isAppIdleFiltered(packageName, + UserHandle.getAppId(pi.applicationInfo.uid), + userId, service, timeNow, screenOnTime); mHandler.sendMessage(mHandler.obtainMessage(MSG_INFORM_LISTENERS, userId, isIdle ? 1 : 0, packageName)); mAppIdleHistory.addEntry(packageName, userId, isIdle, timeNow); @@ -769,10 +771,17 @@ public class UsageStatsService extends SystemService implements if (mAppIdleParoled) { return false; } - return isAppIdleFiltered(packageName, userId, timeNow); + try { + ApplicationInfo ai = getContext().getPackageManager().getApplicationInfo(packageName, + PackageManager.GET_UNINSTALLED_PACKAGES + | PackageManager.GET_DISABLED_COMPONENTS); + return isAppIdleFiltered(packageName, ai.uid, userId, timeNow); + } catch (PackageManager.NameNotFoundException e) { + } + return false; } - boolean isAppIdleFiltered(String packageName, int userId, long timeNow) { + boolean isAppIdleFiltered(String packageName, int uidForAppId, int userId, long timeNow) { final UserUsageStatsService userService; final long screenOnTime; synchronized (mLock) { @@ -782,7 +791,8 @@ public class UsageStatsService extends SystemService implements userService = getUserDataAndInitializeIfNeededLocked(userId, timeNow); screenOnTime = getScreenOnTimeLocked(timeNow); } - return isAppIdleFiltered(packageName, userId, userService, timeNow, screenOnTime); + return isAppIdleFiltered(packageName, UserHandle.getAppId(uidForAppId), userId, + userService, timeNow, screenOnTime); } /** @@ -791,14 +801,22 @@ public class UsageStatsService extends SystemService implements * This happens if the device is plugged in or temporarily allowed to make exceptions. * Called by interface impls. */ - private boolean isAppIdleFiltered(String packageName, int userId, + private boolean isAppIdleFiltered(String packageName, int appId, int userId, UserUsageStatsService userService, long timeNow, long screenOnTime) { if (packageName == null) return false; // If not enabled at all, of course nobody is ever idle. if (!mAppIdleEnabled) { return false; } - if (packageName.equals("android")) return false; + if (appId < Process.FIRST_APPLICATION_UID) { + // System uids never go idle. + return false; + } + if (packageName.equals("android")) { + // Nor does the framework (which should be redundant with the above, but for MR1 we will + // retain this for safety). + return false; + } try { // We allow all whitelisted apps, including those that don't want to be whitelisted // for idle mode, because app idle (aka app standby) is really not as big an issue @@ -865,8 +883,8 @@ public class UsageStatsService extends SystemService implements ApplicationInfo ai = apps.get(i); // Check whether this app is idle. - boolean idle = isAppIdleFiltered(ai.packageName, userId, userService, timeNow, - screenOnTime); + boolean idle = isAppIdleFiltered(ai.packageName, UserHandle.getAppId(ai.uid), + userId, userService, timeNow, screenOnTime); int index = uidStates.indexOfKey(ai.uid); if (index < 0) { @@ -1352,8 +1370,8 @@ public class UsageStatsService extends SystemService implements } @Override - public boolean isAppIdle(String packageName, int userId) { - return UsageStatsService.this.isAppIdleFiltered(packageName, userId, -1); + public boolean isAppIdle(String packageName, int uidForAppId, int userId) { + return UsageStatsService.this.isAppIdleFiltered(packageName, uidForAppId, userId, -1); } @Override |