Merge "While-idle alarm timeout & EBS"

This commit is contained in:
Makoto Onuki
2018-02-02 23:42:56 +00:00
committed by Android (Google) Code Review
6 changed files with 363 additions and 141 deletions

View File

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

View File

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

View File

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

View File

@@ -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,18 +898,23 @@ 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);
if (userId == removedUserId) {
mForegroundUids.removeAt(i);
}
}
cleanUpArrayForUser(mActiveUids, removedUserId);
cleanUpArrayForUser(mForegroundUids, removedUserId);
mExemptedPackages.remove(removedUserId);
}
}
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);
}
}
}
/**
* Called by device idle controller to update the power save whitelists.
*/
@@ -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) {
@@ -981,6 +1038,22 @@ 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.
*
@@ -988,7 +1061,7 @@ public class ForceAppStandbyTracker {
* 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,

View File

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

View File

@@ -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;
@@ -455,6 +460,88 @@ public class ForceAppStandbyTrackerTest {
assertTrue(instance.isUidTempPowerSaveWhitelisted(UID_10_2));
}
@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();
@@ -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));