diff options
| author | 2018-02-02 23:42:56 +0000 | |
|---|---|---|
| committer | 2018-02-02 23:42:56 +0000 | |
| commit | a938cfa7a4e63c6d940aa614d8e00f69f4b4ca52 (patch) | |
| tree | 1419511f0b825081957eae8ae9819e07649be13f | |
| parent | 353952fa2a8d3965e32c5e11eb0a9f992de69117 (diff) | |
| parent | adb50d8c50f2ed071bc7d166dfa73ba408f5ec41 (diff) | |
Merge "While-idle alarm timeout & EBS"
6 files changed, 362 insertions, 140 deletions
diff --git a/core/proto/android/server/alarmmanagerservice.proto b/core/proto/android/server/alarmmanagerservice.proto index aa2663fa2cc4..0342c9c89527 100644 --- a/core/proto/android/server/alarmmanagerservice.proto +++ b/core/proto/android/server/alarmmanagerservice.proto @@ -27,6 +27,7 @@ package com.android.server; option java_multiple_files = true; +// next ID: 43 message AlarmManagerServiceProto { option (.android.msg_privacy).dest = DEST_AUTOMATIC; @@ -114,7 +115,14 @@ message AlarmManagerServiceProto { optional int32 uid = 1; // In the 'elapsed' timebase. optional int64 time_ms = 2; + + // Time when the next while-idle is allowed, in the 'elapsed' timebase. + optional int64 next_allowed_ms = 3; } + + // Whether the short or long while-idle timeout should be used for each UID. + repeated int32 use_allow_while_idle_short_time = 42; + // For each uid, this is the last time we dispatched an "allow while idle" // alarm, used to determine the earliest we can dispatch the next such alarm. repeated LastAllowWhileIdleDispatch last_allow_while_idle_dispatch_times = 36; diff --git a/core/proto/android/server/forceappstandbytracker.proto b/core/proto/android/server/forceappstandbytracker.proto index 43c869c76705..5296e4764f0c 100644 --- a/core/proto/android/server/forceappstandbytracker.proto +++ b/core/proto/android/server/forceappstandbytracker.proto @@ -24,14 +24,19 @@ package com.android.server; option java_multiple_files = true; // Dump from com.android.server.ForceAppStandbyTracker. +// +// Next ID: 12 message ForceAppStandbyTrackerProto { option (.android.msg_privacy).dest = DEST_AUTOMATIC; // Whether all apps are forced standby or not. optional bool force_all_apps_standby = 1; + // UIDs currently active. + repeated int32 active_uids = 2; + // UIDs currently in the foreground. - repeated int32 foreground_uids = 2; + repeated int32 foreground_uids = 11; // App ids that are in power-save whitelist. repeated int32 power_save_whitelist_app_ids = 3; diff --git a/services/core/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java index 30dfee86403f..f49cd6745e79 100644 --- a/services/core/java/com/android/server/AlarmManagerService.java +++ b/services/core/java/com/android/server/AlarmManagerService.java @@ -1840,14 +1840,6 @@ class AlarmManagerService extends SystemService { if (!blocked) { pw.println(" none"); } - pw.print(" mUseAllowWhileIdleShortTime: ["); - for (int i = 0; i < mUseAllowWhileIdleShortTime.size(); i++) { - if (mUseAllowWhileIdleShortTime.valueAt(i)) { - UserHandle.formatUid(pw, mUseAllowWhileIdleShortTime.keyAt(i)); - pw.print(" "); - } - } - pw.println("]"); pw.println(" mLastAlarmDeliveredForPackage:"); for (int i = 0; i < mLastAlarmDeliveredForPackage.size(); i++) { @@ -1913,14 +1905,32 @@ class AlarmManagerService extends SystemService { if (mLastAllowWhileIdleDispatch.size() > 0) { pw.println(" Last allow while idle dispatch times:"); for (int i=0; i<mLastAllowWhileIdleDispatch.size(); i++) { - pw.print(" UID "); - UserHandle.formatUid(pw, mLastAllowWhileIdleDispatch.keyAt(i)); + pw.print(" UID "); + final int uid = mLastAllowWhileIdleDispatch.keyAt(i); + UserHandle.formatUid(pw, uid); pw.print(": "); - TimeUtils.formatDuration(mLastAllowWhileIdleDispatch.valueAt(i), - nowELAPSED, pw); + final long lastTime = mLastAllowWhileIdleDispatch.valueAt(i); + TimeUtils.formatDuration(lastTime, nowELAPSED, pw); + + final long minInterval = getWhileIdleMinIntervalLocked(uid); + pw.print(" Next allowed:"); + TimeUtils.formatDuration(lastTime + minInterval, nowELAPSED, pw); + pw.print(" ("); + TimeUtils.formatDuration(minInterval, 0, pw); + pw.print(")"); + pw.println(); } } + + pw.print(" mUseAllowWhileIdleShortTime: ["); + for (int i = 0; i < mUseAllowWhileIdleShortTime.size(); i++) { + if (mUseAllowWhileIdleShortTime.valueAt(i)) { + UserHandle.formatUid(pw, mUseAllowWhileIdleShortTime.keyAt(i)); + pw.print(" "); + } + } + pw.println("]"); pw.println(); if (mLog.dump(pw, " Recent problems", " ")) { @@ -2181,13 +2191,23 @@ class AlarmManagerService extends SystemService { for (int i = 0; i < mLastAllowWhileIdleDispatch.size(); ++i) { final long token = proto.start( AlarmManagerServiceProto.LAST_ALLOW_WHILE_IDLE_DISPATCH_TIMES); - proto.write(AlarmManagerServiceProto.LastAllowWhileIdleDispatch.UID, - mLastAllowWhileIdleDispatch.keyAt(i)); - proto.write(AlarmManagerServiceProto.LastAllowWhileIdleDispatch.TIME_MS, - mLastAllowWhileIdleDispatch.valueAt(i)); + final int uid = mLastAllowWhileIdleDispatch.keyAt(i); + final long lastTime = mLastAllowWhileIdleDispatch.valueAt(i); + + proto.write(AlarmManagerServiceProto.LastAllowWhileIdleDispatch.UID, uid); + proto.write(AlarmManagerServiceProto.LastAllowWhileIdleDispatch.TIME_MS, lastTime); + proto.write(AlarmManagerServiceProto.LastAllowWhileIdleDispatch.NEXT_ALLOWED_MS, + lastTime + getWhileIdleMinIntervalLocked(uid)); proto.end(token); } + for (int i = 0; i < mUseAllowWhileIdleShortTime.size(); i++) { + if (mUseAllowWhileIdleShortTime.valueAt(i)) { + proto.write(AlarmManagerServiceProto.USE_ALLOW_WHILE_IDLE_SHORT_TIME, + mUseAllowWhileIdleShortTime.keyAt(i)); + } + } + mLog.writeToProto(proto, AlarmManagerServiceProto.RECENT_PROBLEMS); final FilterStats[] topFilters = new FilterStats[10]; @@ -2866,6 +2886,23 @@ class AlarmManagerService extends SystemService { private native int setKernelTime(long nativeData, long millis); private native int setKernelTimezone(long nativeData, int minuteswest); + private long getWhileIdleMinIntervalLocked(int uid) { + final boolean dozing = mPendingIdleUntil != null; + final boolean ebs = mForceAppStandbyTracker.isForceAllAppsStandbyEnabled(); + if (!dozing && !ebs) { + return mConstants.ALLOW_WHILE_IDLE_SHORT_TIME; + } + if (dozing) { + return mConstants.ALLOW_WHILE_IDLE_LONG_TIME; + } + if (mUseAllowWhileIdleShortTime.get(uid)) { + // if the last allow-while-idle went off while uid was fg, or the uid + // recently came into fg, don't block the alarm for long. + return mConstants.ALLOW_WHILE_IDLE_SHORT_TIME; + } + return mConstants.ALLOW_WHILE_IDLE_LONG_TIME; + } + boolean triggerAlarmsLocked(ArrayList<Alarm> triggerList, final long nowELAPSED, final long nowRTC) { boolean hasWakeup = false; @@ -2891,20 +2928,7 @@ class AlarmManagerService extends SystemService { // If this is an ALLOW_WHILE_IDLE alarm, we constrain how frequently the app can // schedule such alarms. final long lastTime = mLastAllowWhileIdleDispatch.get(alarm.creatorUid, 0); - final boolean dozing = mPendingIdleUntil != null; - final boolean ebs = mForceAppStandbyTracker.isForceAllAppsStandbyEnabled(); - final long minTime; - if (!dozing && !ebs) { - minTime = lastTime + mConstants.ALLOW_WHILE_IDLE_SHORT_TIME; - } else if (dozing) { - minTime = lastTime + mConstants.ALLOW_WHILE_IDLE_LONG_TIME; - } else if (mUseAllowWhileIdleShortTime.get(alarm.creatorUid)) { - // if the last allow-while-idle went off while uid was fg, or the uid - // recently came into fg, don't block the alarm for long. - minTime = lastTime + mConstants.ALLOW_WHILE_IDLE_SHORT_TIME; - } else { - minTime = lastTime + mConstants.ALLOW_WHILE_IDLE_LONG_TIME; - } + final long minTime = lastTime + getWhileIdleMinIntervalLocked(alarm.creatorUid); if (nowELAPSED < minTime) { // Whoops, it hasn't been long enough since the last ALLOW_WHILE_IDLE // alarm went off for this app. Reschedule the alarm to be in the @@ -3641,6 +3665,7 @@ class AlarmManagerService extends SystemService { } else if (Intent.ACTION_UID_REMOVED.equals(action)) { if (uid >= 0) { mLastAllowWhileIdleDispatch.delete(uid); + mUseAllowWhileIdleShortTime.delete(uid); } } else { if (Intent.ACTION_PACKAGE_REMOVED.equals(action) @@ -3693,7 +3718,6 @@ class AlarmManagerService extends SystemService { @Override public void onUidGone(int uid, boolean disabled) { synchronized (mLock) { - mUseAllowWhileIdleShortTime.delete(uid); if (disabled) { removeForStoppedLocked(uid); } @@ -3701,9 +3725,6 @@ class AlarmManagerService extends SystemService { } @Override public void onUidActive(int uid) { - synchronized (mLock) { - mUseAllowWhileIdleShortTime.put(uid, true); - } } @Override public void onUidIdle(int uid, boolean disabled) { @@ -3766,6 +3787,18 @@ class AlarmManagerService extends SystemService { sendPendingBackgroundAlarmsLocked(uid, packageName); } } + + @Override + public void onUidForeground(int uid, boolean foreground) { + synchronized (mLock) { + if (foreground) { + mUseAllowWhileIdleShortTime.put(uid, true); + + // Note we don't have to drain the pending while-idle alarms here, because + // this event should coincide with unblockAlarmsForUid(). + } + } + } }; private final BroadcastStats getStatsLocked(PendingIntent pi) { @@ -4026,7 +4059,7 @@ class AlarmManagerService extends SystemService { if (allowWhileIdle) { // Record the last time this uid handled an ALLOW_WHILE_IDLE alarm. mLastAllowWhileIdleDispatch.put(alarm.creatorUid, nowELAPSED); - if (mForceAppStandbyTracker.isInForeground(alarm.creatorUid)) { + if (mForceAppStandbyTracker.isUidInForeground(alarm.creatorUid)) { mUseAllowWhileIdleShortTime.put(alarm.creatorUid, true); } else { mUseAllowWhileIdleShortTime.put(alarm.creatorUid, false); diff --git a/services/core/java/com/android/server/ForceAppStandbyTracker.java b/services/core/java/com/android/server/ForceAppStandbyTracker.java index 7604044583db..339101fa79bb 100644 --- a/services/core/java/com/android/server/ForceAppStandbyTracker.java +++ b/services/core/java/com/android/server/ForceAppStandbyTracker.java @@ -54,6 +54,7 @@ import com.android.internal.app.IAppOpsCallback; import com.android.internal.app.IAppOpsService; import com.android.internal.util.ArrayUtils; import com.android.internal.util.Preconditions; +import com.android.server.DeviceIdleController.LocalService; import com.android.server.ForceAppStandbyTrackerProto.ExemptedPackage; import com.android.server.ForceAppStandbyTrackerProto.RunAnyInBackgroundRestrictedPackages; @@ -64,18 +65,15 @@ import java.util.List; /** * Class to keep track of the information related to "force app standby", which includes: * - OP_RUN_ANY_IN_BACKGROUND for each package - * - UID foreground state + * - UID foreground/active state * - User+system power save whitelist * - Temporary power save whitelist * - Global "force all apps standby" mode enforced by battery saver. * - * TODO: In general, we can reduce the number of callbacks by checking all signals before sending - * each callback. For example, even when an UID comes into the foreground, if it wasn't - * originally restricted, then there's no need to send an event. - * Doing this would be error-prone, so we punt it for now, but we should revisit it later. + * TODO: Make it a LocalService. * * Test: - * atest $ANDROID_BUILD_TOP/frameworks/base/services/tests/servicestests/src/com/android/server/ForceAppStandbyTrackerTest.java + atest $ANDROID_BUILD_TOP/frameworks/base/services/tests/servicestests/src/com/android/server/ForceAppStandbyTrackerTest.java */ public class ForceAppStandbyTracker { private static final String TAG = "ForceAppStandbyTracker"; @@ -108,6 +106,11 @@ public class ForceAppStandbyTracker { @GuardedBy("mLock") final ArraySet<Pair<Integer, String>> mRunAnyRestrictedPackages = new ArraySet<>(); + /** UIDs that are active. */ + @GuardedBy("mLock") + final SparseBooleanArray mActiveUids = new SparseBooleanArray(); + + /** UIDs that are in the foreground. */ @GuardedBy("mLock") final SparseBooleanArray mForegroundUids = new SparseBooleanArray(); @@ -160,18 +163,20 @@ public class ForceAppStandbyTracker { boolean mForcedAppStandbyEnabled; interface Stats { - int UID_STATE_CHANGED = 0; - int RUN_ANY_CHANGED = 1; - int ALL_UNWHITELISTED = 2; - int ALL_WHITELIST_CHANGED = 3; - int TEMP_WHITELIST_CHANGED = 4; - int EXEMPT_CHANGED = 5; - int FORCE_ALL_CHANGED = 6; - int FORCE_APP_STANDBY_FEATURE_FLAG_CHANGED = 7; + int UID_FG_STATE_CHANGED = 0; + int UID_ACTIVE_STATE_CHANGED = 1; + int RUN_ANY_CHANGED = 2; + int ALL_UNWHITELISTED = 3; + int ALL_WHITELIST_CHANGED = 4; + int TEMP_WHITELIST_CHANGED = 5; + int EXEMPT_CHANGED = 6; + int FORCE_ALL_CHANGED = 7; + int FORCE_APP_STANDBY_FEATURE_FLAG_CHANGED = 8; } private final StatLogger mStatLogger = new StatLogger(new String[] { - "UID_STATE_CHANGED", + "UID_FG_STATE_CHANGED", + "UID_ACTIVE_STATE_CHANGED", "RUN_ANY_CHANGED", "ALL_UNWHITELISTED", "ALL_WHITELIST_CHANGED", @@ -260,9 +265,16 @@ public class ForceAppStandbyTracker { * This is called when the foreground state changed for a UID. */ private void onUidForegroundStateChanged(ForceAppStandbyTracker sender, int uid) { + onUidForeground(uid, sender.isUidInForeground(uid)); + } + + /** + * This is called when the active/idle state changed for a UID. + */ + private void onUidActiveStateChanged(ForceAppStandbyTracker sender, int uid) { updateJobsForUid(uid); - if (sender.isInForeground(uid)) { + if (sender.isUidActive(uid)) { unblockAlarmsForUid(uid); } } @@ -355,6 +367,14 @@ public class ForceAppStandbyTracker { */ public void unblockAlarmsForUidPackage(int uid, String packageName) { } + + /** + * Called when a UID comes into the foreground or the background. + * + * @see #isUidInForeground(int) + */ + public void onUidForeground(int uid, boolean foreground) { + } } @VisibleForTesting @@ -404,8 +424,10 @@ public class ForceAppStandbyTracker { try { mIActivityManager.registerUidObserver(new UidObserver(), - ActivityManager.UID_OBSERVER_GONE | ActivityManager.UID_OBSERVER_IDLE - | ActivityManager.UID_OBSERVER_ACTIVE, + ActivityManager.UID_OBSERVER_GONE + | ActivityManager.UID_OBSERVER_IDLE + | ActivityManager.UID_OBSERVER_ACTIVE + | ActivityManager.UID_OBSERVER_PROCSTATE, ActivityManager.PROCESS_STATE_UNKNOWN, null); mAppOpsService.startWatchingMode(TARGET_OP, null, new AppOpsWatcher()); @@ -563,65 +585,77 @@ public class ForceAppStandbyTracker { return true; } - /** - * Puts a UID to {@link #mForegroundUids}. - */ - void uidToForeground(int uid) { - synchronized (mLock) { - if (UserHandle.isCore(uid)) { - return; - } - // TODO This can be optimized by calling indexOfKey and sharing the index for get and - // put. - if (mForegroundUids.get(uid)) { - return; - } - mForegroundUids.put(uid, true); - mHandler.notifyUidForegroundStateChanged(uid); + private static boolean addUidToArray(SparseBooleanArray array, int uid) { + if (UserHandle.isCore(uid)) { + return false; + } + if (array.get(uid)) { + return false; } + array.put(uid, true); + return true; } - /** - * Sets false for a UID {@link #mForegroundUids}, or remove it when {@code remove} is true. - */ - void uidToBackground(int uid, boolean remove) { - synchronized (mLock) { - if (UserHandle.isCore(uid)) { - return; - } - // TODO This can be optimized by calling indexOfKey and sharing the index for get and - // put. - if (!mForegroundUids.get(uid)) { - return; - } - if (remove) { - mForegroundUids.delete(uid); - } else { - mForegroundUids.put(uid, false); - } - mHandler.notifyUidForegroundStateChanged(uid); + private static boolean removeUidFromArray(SparseBooleanArray array, int uid, boolean remove) { + if (UserHandle.isCore(uid)) { + return false; } + if (!array.get(uid)) { + return false; + } + if (remove) { + array.delete(uid); + } else { + array.put(uid, false); + } + return true; } private final class UidObserver extends IUidObserver.Stub { @Override public void onUidStateChanged(int uid, int procState, long procStateSeq) { + synchronized (mLock) { + if (procState > ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND) { + if (removeUidFromArray(mForegroundUids, uid, false)) { + mHandler.notifyUidForegroundStateChanged(uid); + } + } else { + if (addUidToArray(mForegroundUids, uid)) { + mHandler.notifyUidForegroundStateChanged(uid); + } + } + } } @Override public void onUidGone(int uid, boolean disabled) { - uidToBackground(uid, /*remove=*/ true); + removeUid(uid, true); } @Override public void onUidActive(int uid) { - uidToForeground(uid); + synchronized (mLock) { + if (addUidToArray(mActiveUids, uid)) { + mHandler.notifyUidActiveStateChanged(uid); + } + } } @Override public void onUidIdle(int uid, boolean disabled) { // Just to avoid excessive memcpy, don't remove from the array in this case. - uidToBackground(uid, /*remove=*/ false); + removeUid(uid, false); + } + + private void removeUid(int uid, boolean remove) { + synchronized (mLock) { + if (removeUidFromArray(mActiveUids, uid, remove)) { + mHandler.notifyUidActiveStateChanged(uid); + } + if (removeUidFromArray(mForegroundUids, uid, remove)) { + mHandler.notifyUidForegroundStateChanged(uid); + } + } } @Override @@ -695,22 +729,27 @@ public class ForceAppStandbyTracker { } private class MyHandler extends Handler { - private static final int MSG_UID_STATE_CHANGED = 1; - private static final int MSG_RUN_ANY_CHANGED = 2; - private static final int MSG_ALL_UNWHITELISTED = 3; - private static final int MSG_ALL_WHITELIST_CHANGED = 4; - private static final int MSG_TEMP_WHITELIST_CHANGED = 5; - private static final int MSG_FORCE_ALL_CHANGED = 6; - private static final int MSG_USER_REMOVED = 7; - private static final int MSG_FORCE_APP_STANDBY_FEATURE_FLAG_CHANGED = 8; - private static final int MSG_EXEMPT_CHANGED = 9; + private static final int MSG_UID_ACTIVE_STATE_CHANGED = 0; + private static final int MSG_UID_FG_STATE_CHANGED = 1; + private static final int MSG_RUN_ANY_CHANGED = 3; + private static final int MSG_ALL_UNWHITELISTED = 4; + private static final int MSG_ALL_WHITELIST_CHANGED = 5; + private static final int MSG_TEMP_WHITELIST_CHANGED = 6; + private static final int MSG_FORCE_ALL_CHANGED = 7; + private static final int MSG_USER_REMOVED = 8; + private static final int MSG_FORCE_APP_STANDBY_FEATURE_FLAG_CHANGED = 9; + private static final int MSG_EXEMPT_CHANGED = 10; public MyHandler(Looper looper) { super(looper); } + public void notifyUidActiveStateChanged(int uid) { + obtainMessage(MSG_UID_ACTIVE_STATE_CHANGED, uid, 0).sendToTarget(); + } + public void notifyUidForegroundStateChanged(int uid) { - obtainMessage(MSG_UID_STATE_CHANGED, uid, 0).sendToTarget(); + obtainMessage(MSG_UID_FG_STATE_CHANGED, uid, 0).sendToTarget(); } public void notifyRunAnyAppOpsChanged(int uid, @NonNull String packageName) { @@ -718,26 +757,32 @@ public class ForceAppStandbyTracker { } public void notifyAllUnwhitelisted() { + removeMessages(MSG_ALL_UNWHITELISTED); obtainMessage(MSG_ALL_UNWHITELISTED).sendToTarget(); } public void notifyAllWhitelistChanged() { + removeMessages(MSG_ALL_WHITELIST_CHANGED); obtainMessage(MSG_ALL_WHITELIST_CHANGED).sendToTarget(); } public void notifyTempWhitelistChanged() { + removeMessages(MSG_TEMP_WHITELIST_CHANGED); obtainMessage(MSG_TEMP_WHITELIST_CHANGED).sendToTarget(); } public void notifyForceAllAppsStandbyChanged() { + removeMessages(MSG_FORCE_ALL_CHANGED); obtainMessage(MSG_FORCE_ALL_CHANGED).sendToTarget(); } public void notifyForcedAppStandbyFeatureFlagChanged() { + removeMessages(MSG_FORCE_APP_STANDBY_FEATURE_FLAG_CHANGED); obtainMessage(MSG_FORCE_APP_STANDBY_FEATURE_FLAG_CHANGED).sendToTarget(); } public void notifyExemptChanged() { + removeMessages(MSG_EXEMPT_CHANGED); obtainMessage(MSG_EXEMPT_CHANGED).sendToTarget(); } @@ -763,11 +808,18 @@ public class ForceAppStandbyTracker { long start = mStatLogger.getTime(); switch (msg.what) { - case MSG_UID_STATE_CHANGED: + case MSG_UID_ACTIVE_STATE_CHANGED: + for (Listener l : cloneListeners()) { + l.onUidActiveStateChanged(sender, msg.arg1); + } + mStatLogger.logDurationStat(Stats.UID_ACTIVE_STATE_CHANGED, start); + return; + + case MSG_UID_FG_STATE_CHANGED: for (Listener l : cloneListeners()) { l.onUidForegroundStateChanged(sender, msg.arg1); } - mStatLogger.logDurationStat(Stats.UID_STATE_CHANGED, start); + mStatLogger.logDurationStat(Stats.UID_FG_STATE_CHANGED, start); return; case MSG_RUN_ANY_CHANGED: @@ -846,15 +898,20 @@ public class ForceAppStandbyTracker { mRunAnyRestrictedPackages.removeAt(i); } } - for (int i = mForegroundUids.size() - 1; i >= 0; i--) { - final int uid = mForegroundUids.keyAt(i); - final int userId = UserHandle.getUserId(uid); + cleanUpArrayForUser(mActiveUids, removedUserId); + cleanUpArrayForUser(mForegroundUids, removedUserId); + mExemptedPackages.remove(removedUserId); + } + } - if (userId == removedUserId) { - mForegroundUids.removeAt(i); - } + private void cleanUpArrayForUser(SparseBooleanArray array, int removedUserId) { + for (int i = array.size() - 1; i >= 0; i--) { + final int uid = array.keyAt(i); + final int userId = UserHandle.getUserId(uid); + + if (userId == removedUserId) { + array.removeAt(i); } - mExemptedPackages.remove(removedUserId); } } @@ -954,7 +1011,7 @@ public class ForceAppStandbyTracker { */ private boolean isRestricted(int uid, @NonNull String packageName, boolean useTempWhitelistToo, boolean exemptOnBatterySaver) { - if (isInForeground(uid)) { + if (isUidActive(uid)) { return false; } synchronized (mLock) { @@ -982,13 +1039,29 @@ public class ForceAppStandbyTracker { } /** + * @return whether a UID is in active or not. + * + * Note this information is based on the UID proc state callback, meaning it's updated + * asynchronously and may subtly be stale. If the fresh data is needed, use + * {@link ActivityManagerInternal#getUidProcessState} instead. + */ + public boolean isUidActive(int uid) { + if (UserHandle.isCore(uid)) { + return true; + } + synchronized (mLock) { + return mActiveUids.get(uid); + } + } + + /** * @return whether a UID is in the foreground or not. * * Note this information is based on the UID proc state callback, meaning it's updated * asynchronously and may subtly be stale. If the fresh data is needed, use * {@link ActivityManagerInternal#getUidProcessState} instead. */ - public boolean isInForeground(int uid) { + public boolean isUidInForeground(int uid) { if (UserHandle.isCore(uid)) { return true; } @@ -1062,17 +1135,12 @@ public class ForceAppStandbyTracker { pw.println(mIsPluggedIn); pw.print(indent); - pw.print("Foreground uids: ["); + pw.print("Active uids: "); + dumpUids(pw, mActiveUids); - String sep = ""; - for (int i = 0; i < mForegroundUids.size(); i++) { - if (mForegroundUids.valueAt(i)) { - pw.print(sep); - pw.print(UserHandle.formatUid(mForegroundUids.keyAt(i))); - sep = " "; - } - } - pw.println("]"); + pw.print(indent); + pw.print("Foreground uids: "); + dumpUids(pw, mForegroundUids); pw.print(indent); pw.print("Whitelist appids: "); @@ -1114,6 +1182,20 @@ public class ForceAppStandbyTracker { } } + private void dumpUids(PrintWriter pw, SparseBooleanArray array) { + pw.print("["); + + String sep = ""; + for (int i = 0; i < array.size(); i++) { + if (array.valueAt(i)) { + pw.print(sep); + pw.print(UserHandle.formatUid(array.keyAt(i))); + sep = " "; + } + } + pw.println("]"); + } + public void dumpProto(ProtoOutputStream proto, long fieldId) { synchronized (mLock) { final long token = proto.start(fieldId); @@ -1125,6 +1207,13 @@ public class ForceAppStandbyTracker { mForceAllAppStandbyForSmallBattery); proto.write(ForceAppStandbyTrackerProto.IS_PLUGGED_IN, mIsPluggedIn); + for (int i = 0; i < mActiveUids.size(); i++) { + if (mActiveUids.valueAt(i)) { + proto.write(ForceAppStandbyTrackerProto.ACTIVE_UIDS, + mActiveUids.keyAt(i)); + } + } + for (int i = 0; i < mForegroundUids.size(); i++) { if (mForegroundUids.valueAt(i)) { proto.write(ForceAppStandbyTrackerProto.FOREGROUND_UIDS, diff --git a/services/core/java/com/android/server/job/controllers/BackgroundJobsController.java b/services/core/java/com/android/server/job/controllers/BackgroundJobsController.java index 2e4567ac1dff..5eb77000a4f1 100644 --- a/services/core/java/com/android/server/job/controllers/BackgroundJobsController.java +++ b/services/core/java/com/android/server/job/controllers/BackgroundJobsController.java @@ -92,7 +92,7 @@ public final class BackgroundJobsController extends StateController { jobStatus.printUniqueId(pw); pw.print(" from "); UserHandle.formatUid(pw, uid); - pw.print(mForceAppStandbyTracker.isInForeground(uid) ? " foreground" : " background"); + pw.print(mForceAppStandbyTracker.isUidActive(uid) ? " active" : " idle"); if (mForceAppStandbyTracker.isUidPowerSaveWhitelisted(uid) || mForceAppStandbyTracker.isUidTempPowerSaveWhitelisted(uid)) { pw.print(", whitelisted"); @@ -136,7 +136,7 @@ public final class BackgroundJobsController extends StateController { proto.write(TrackedJob.SOURCE_PACKAGE_NAME, sourcePkg); proto.write(TrackedJob.IS_IN_FOREGROUND, - mForceAppStandbyTracker.isInForeground(sourceUid)); + mForceAppStandbyTracker.isUidActive(sourceUid)); proto.write(TrackedJob.IS_WHITELISTED, mForceAppStandbyTracker.isUidPowerSaveWhitelisted(sourceUid) || mForceAppStandbyTracker.isUidTempPowerSaveWhitelisted(sourceUid)); diff --git a/services/tests/servicestests/src/com/android/server/ForceAppStandbyTrackerTest.java b/services/tests/servicestests/src/com/android/server/ForceAppStandbyTrackerTest.java index a16f118007da..2c50f2272187 100644 --- a/services/tests/servicestests/src/com/android/server/ForceAppStandbyTrackerTest.java +++ b/services/tests/servicestests/src/com/android/server/ForceAppStandbyTrackerTest.java @@ -54,7 +54,6 @@ import android.os.PowerSaveState; import android.os.Process; import android.os.RemoteException; import android.os.UserHandle; -import android.provider.Settings; import android.provider.Settings.Global; import android.support.test.filters.SmallTest; import android.support.test.runner.AndroidJUnit4; @@ -64,7 +63,6 @@ import android.util.Pair; import com.android.internal.app.IAppOpsCallback; import com.android.internal.app.IAppOpsService; -import com.android.internal.util.test.FakeSettingsProvider; import com.android.server.ForceAppStandbyTracker.Listener; import org.junit.Before; @@ -83,6 +81,12 @@ import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.function.Consumer; +/** + * Tests for {@link ForceAppStandbyTracker} + * + * Run with: + atest $ANDROID_BUILD_TOP/frameworks/base/services/tests/servicestests/src/com/android/server/ForceAppStandbyTrackerTest.java + */ @SmallTest @RunWith(AndroidJUnit4.class) public class ForceAppStandbyTrackerTest { @@ -236,7 +240,8 @@ public class ForceAppStandbyTrackerTest { verify(mMockIActivityManager).registerUidObserver( uidObserverArgumentCaptor.capture(), eq(ActivityManager.UID_OBSERVER_GONE | ActivityManager.UID_OBSERVER_IDLE - | ActivityManager.UID_OBSERVER_ACTIVE), + | ActivityManager.UID_OBSERVER_ACTIVE + | ActivityManager.UID_OBSERVER_PROCSTATE), eq(ActivityManager.PROCESS_STATE_UNKNOWN), isNull()); verify(mMockIAppOpsService).startWatchingMode( @@ -333,23 +338,23 @@ public class ForceAppStandbyTrackerTest { mPowerSaveMode = true; mPowerSaveObserver.accept(getPowerSaveState()); - assertFalse(instance.isInForeground(UID_1)); - assertFalse(instance.isInForeground(UID_2)); - assertTrue(instance.isInForeground(Process.SYSTEM_UID)); + assertFalse(instance.isUidActive(UID_1)); + assertFalse(instance.isUidActive(UID_2)); + assertTrue(instance.isUidActive(Process.SYSTEM_UID)); mIUidObserver.onUidActive(UID_1); areRestricted(instance, UID_1, PACKAGE_1, NONE); areRestricted(instance, UID_2, PACKAGE_2, JOBS_AND_ALARMS); areRestricted(instance, Process.SYSTEM_UID, PACKAGE_SYSTEM, NONE); - assertTrue(instance.isInForeground(UID_1)); - assertFalse(instance.isInForeground(UID_2)); + assertTrue(instance.isUidActive(UID_1)); + assertFalse(instance.isUidActive(UID_2)); mIUidObserver.onUidGone(UID_1, /*disable=*/ false); areRestricted(instance, UID_1, PACKAGE_1, JOBS_AND_ALARMS); areRestricted(instance, UID_2, PACKAGE_2, JOBS_AND_ALARMS); areRestricted(instance, Process.SYSTEM_UID, PACKAGE_SYSTEM, NONE); - assertFalse(instance.isInForeground(UID_1)); - assertFalse(instance.isInForeground(UID_2)); + assertFalse(instance.isUidActive(UID_1)); + assertFalse(instance.isUidActive(UID_2)); mIUidObserver.onUidActive(UID_1); areRestricted(instance, UID_1, PACKAGE_1, NONE); @@ -360,8 +365,8 @@ public class ForceAppStandbyTrackerTest { areRestricted(instance, UID_1, PACKAGE_1, JOBS_AND_ALARMS); areRestricted(instance, UID_2, PACKAGE_2, JOBS_AND_ALARMS); areRestricted(instance, Process.SYSTEM_UID, PACKAGE_SYSTEM, NONE); - assertFalse(instance.isInForeground(UID_1)); - assertFalse(instance.isInForeground(UID_2)); + assertFalse(instance.isUidActive(UID_1)); + assertFalse(instance.isUidActive(UID_2)); // Toggle the app ops. mPowerSaveMode = false; @@ -456,6 +461,88 @@ public class ForceAppStandbyTrackerTest { } @Test + public void testUidStateForeground() throws Exception { + final ForceAppStandbyTrackerTestable instance = newInstance(); + callStart(instance); + + mIUidObserver.onUidActive(UID_1); + + assertTrue(instance.isUidActive(UID_1)); + assertFalse(instance.isUidActive(UID_2)); + assertTrue(instance.isUidActive(Process.SYSTEM_UID)); + + assertFalse(instance.isUidInForeground(UID_1)); + assertFalse(instance.isUidInForeground(UID_2)); + assertTrue(instance.isUidInForeground(Process.SYSTEM_UID)); + + + mIUidObserver.onUidStateChanged(UID_2, + ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE, 0); + + assertTrue(instance.isUidActive(UID_1)); + assertFalse(instance.isUidActive(UID_2)); + assertTrue(instance.isUidActive(Process.SYSTEM_UID)); + + assertFalse(instance.isUidInForeground(UID_1)); + assertTrue(instance.isUidInForeground(UID_2)); + assertTrue(instance.isUidInForeground(Process.SYSTEM_UID)); + + + mIUidObserver.onUidStateChanged(UID_1, + ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE, 0); + + assertTrue(instance.isUidActive(UID_1)); + assertFalse(instance.isUidActive(UID_2)); + assertTrue(instance.isUidActive(Process.SYSTEM_UID)); + + assertTrue(instance.isUidInForeground(UID_1)); + assertTrue(instance.isUidInForeground(UID_2)); + assertTrue(instance.isUidInForeground(Process.SYSTEM_UID)); + + mIUidObserver.onUidGone(UID_1, true); + + assertFalse(instance.isUidActive(UID_1)); + assertFalse(instance.isUidActive(UID_2)); + assertTrue(instance.isUidActive(Process.SYSTEM_UID)); + + assertFalse(instance.isUidInForeground(UID_1)); + assertTrue(instance.isUidInForeground(UID_2)); + assertTrue(instance.isUidInForeground(Process.SYSTEM_UID)); + + mIUidObserver.onUidIdle(UID_2, true); + + assertFalse(instance.isUidActive(UID_1)); + assertFalse(instance.isUidActive(UID_2)); + assertTrue(instance.isUidActive(Process.SYSTEM_UID)); + + assertFalse(instance.isUidInForeground(UID_1)); + assertFalse(instance.isUidInForeground(UID_2)); + assertTrue(instance.isUidInForeground(Process.SYSTEM_UID)); + + mIUidObserver.onUidStateChanged(UID_1, + ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND, 0); + + assertFalse(instance.isUidActive(UID_1)); + assertFalse(instance.isUidActive(UID_2)); + assertTrue(instance.isUidActive(Process.SYSTEM_UID)); + + assertTrue(instance.isUidInForeground(UID_1)); + assertFalse(instance.isUidInForeground(UID_2)); + assertTrue(instance.isUidInForeground(Process.SYSTEM_UID)); + + mIUidObserver.onUidStateChanged(UID_1, + ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND, 0); + + assertFalse(instance.isUidActive(UID_1)); + assertFalse(instance.isUidActive(UID_2)); + assertTrue(instance.isUidActive(Process.SYSTEM_UID)); + + assertFalse(instance.isUidInForeground(UID_1)); + assertFalse(instance.isUidInForeground(UID_2)); + assertTrue(instance.isUidInForeground(Process.SYSTEM_UID)); + } + + @Test public void testExempt() throws Exception { final ForceAppStandbyTrackerTestable instance = newInstance(); callStart(instance); @@ -953,8 +1040,8 @@ public class ForceAppStandbyTrackerTest { setAppOps(UID_2, PACKAGE_2, true); setAppOps(UID_10_2, PACKAGE_2, true); - assertTrue(instance.isInForeground(UID_1)); - assertTrue(instance.isInForeground(UID_10_1)); + assertTrue(instance.isUidActive(UID_1)); + assertTrue(instance.isUidActive(UID_10_1)); assertFalse(instance.isRunAnyInBackgroundAppOpsAllowed(UID_2, PACKAGE_2)); assertFalse(instance.isRunAnyInBackgroundAppOpsAllowed(UID_10_2, PACKAGE_2)); @@ -965,8 +1052,8 @@ public class ForceAppStandbyTrackerTest { waitUntilMainHandlerDrain(); - assertTrue(instance.isInForeground(UID_1)); - assertFalse(instance.isInForeground(UID_10_1)); + assertTrue(instance.isUidActive(UID_1)); + assertFalse(instance.isUidActive(UID_10_1)); assertFalse(instance.isRunAnyInBackgroundAppOpsAllowed(UID_2, PACKAGE_2)); assertTrue(instance.isRunAnyInBackgroundAppOpsAllowed(UID_10_2, PACKAGE_2)); |