Kill process if it's cached & idle and in forced-app-standby mode

This behavior could be turned OFF via the flag kill_fas_cached_idle
in device_config.

Bug: 152573287
Test: atest FrameworksServicesTests:ActivityManagerTest
Test: atest FrameworksMockingServicesTests:AppStateTrackerTest
Change-Id: Ifa6950582fbf6a24595b36163810f3c7e9345394
This commit is contained in:
Jing Ji
2021-05-05 20:51:01 -07:00
parent 610ec38145
commit 6cf25139a0
12 changed files with 400 additions and 27 deletions

View File

@@ -25,19 +25,29 @@ public interface AppStateTracker {
String TAG = "AppStateTracker";
/**
* Register a {@link ServiceStateListener} to listen for forced-app-standby changes that should
* affect services.
* Register a {@link ForcedAppStandbyListener} to listen for forced-app-standby changes that
* should affect services etc.
*/
void addServiceStateListener(@NonNull ServiceStateListener listener);
void addForcedAppStandbyListener(@NonNull ForcedAppStandbyListener listener);
/**
* A listener to listen to forced-app-standby changes that should affect services.
* @return {code true} if the given UID/package has been in forced app standby mode.
*/
interface ServiceStateListener {
boolean isAppInForcedAppStandby(int uid, @NonNull String packageName);
/**
* A listener to listen to forced-app-standby changes that should affect services etc.
*/
interface ForcedAppStandbyListener {
/**
* Called when an app goes into forced app standby and its foreground
* services need to be removed from that state.
* Called when an app goes in/out of forced app standby.
*/
void stopForegroundServicesForUidPackage(int uid, String packageName);
void updateForceAppStandbyForUidPackage(int uid, String packageName, boolean standby);
/**
* Called when all apps' forced-app-standby states need to be re-evaluated, due to
* enable/disable certain feature flags.
*/
void updateForcedAppStandbyForAllApps();
}
}

View File

@@ -60,8 +60,10 @@ import com.android.server.usage.AppStandbyInternal.AppIdleStateChangeListener;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.Set;
/**
* Class to keep track of the information related to "force app standby", which includes:
@@ -160,16 +162,46 @@ public class AppStateTrackerImpl implements AppStateTracker {
@GuardedBy("mLock")
boolean mForcedAppStandbyEnabled;
/**
* A lock-free set of (uid, packageName) pairs in forced app standby mode.
*
* <p>
* It's bascially shadowing the {@link #mRunAnyRestrictedPackages} together with
* the {@link #mForcedAppStandbyEnabled} and the {@link #mForceAllAppsStandby} - mutations on
* them would result in copy-on-write.
*
* Note: when {@link #mForcedAppStandbyEnabled} is {@code false}, it'll be set to an empty set.
* when {@link #mForceAllAppsStandby} is {@code true}, it'll be set to null;
* </p>
*/
volatile Set<Pair<Integer, String>> mForcedAppStandbyUidPackages = Collections.emptySet();
@Override
public void addServiceStateListener(@NonNull ServiceStateListener listener) {
public void addForcedAppStandbyListener(@NonNull ForcedAppStandbyListener listener) {
addListener(new Listener() {
@Override
public void stopForegroundServicesForUidPackage(int uid, String packageName) {
listener.stopForegroundServicesForUidPackage(uid, packageName);
public void updateForceAppStandbyForUidPackage(int uid, String packageName,
boolean standby) {
listener.updateForceAppStandbyForUidPackage(uid, packageName, standby);
}
@Override
public void updateForcedAppStandbyForAllApps() {
listener.updateForcedAppStandbyForAllApps();
}
});
}
@Override
public boolean isAppInForcedAppStandby(int uid, @NonNull String packageName) {
final Set<Pair<Integer, String>> fasUidPkgs = mForcedAppStandbyUidPackages;
if (fasUidPkgs == null) {
// Meaning the mForceAllAppsStandby is true.
return true;
}
return fasUidPkgs.contains(Pair.create(uid, packageName));
}
interface Stats {
int UID_FG_STATE_CHANGED = 0;
int UID_ACTIVE_STATE_CHANGED = 1;
@@ -233,6 +265,7 @@ public class AppStateTrackerImpl implements AppStateTracker {
return;
}
mForcedAppStandbyEnabled = enabled;
updateForcedAppStandbyUidPackagesLocked();
if (DEBUG) {
Slog.d(TAG, "Forced app standby feature flag changed: "
+ mForcedAppStandbyEnabled);
@@ -277,7 +310,11 @@ public class AppStateTrackerImpl implements AppStateTracker {
if (!sender.isRunAnyInBackgroundAppOpsAllowed(uid, packageName)) {
Slog.v(TAG, "Package " + packageName + "/" + uid
+ " toggled into fg service restriction");
stopForegroundServicesForUidPackage(uid, packageName);
updateForceAppStandbyForUidPackage(uid, packageName, true);
} else {
Slog.v(TAG, "Package " + packageName + "/" + uid
+ " toggled out of fg service restriction");
updateForceAppStandbyForUidPackage(uid, packageName, false);
}
}
@@ -342,6 +379,7 @@ public class AppStateTrackerImpl implements AppStateTracker {
private void onForceAllAppsStandbyChanged(AppStateTrackerImpl sender) {
updateAllJobs();
updateAllAlarms();
updateForcedAppStandbyForAllApps();
}
/**
@@ -366,10 +404,17 @@ public class AppStateTrackerImpl implements AppStateTracker {
}
/**
* Called when an app goes into forced app standby and its foreground
* services need to be removed from that state.
* Called when an app goes in/out of forced app standby.
*/
public void stopForegroundServicesForUidPackage(int uid, String packageName) {
public void updateForceAppStandbyForUidPackage(int uid, String packageName,
boolean standby) {
}
/**
* Called when all apps' forced-app-standby states need to be re-evaluated due to changes of
* feature flags such as {@link #mForcedAppStandbyEnabled} or {@link #mForceAllAppsStandby}.
*/
public void updateForcedAppStandbyForAllApps() {
}
/**
@@ -438,9 +483,12 @@ public class AppStateTrackerImpl implements AppStateTracker {
final int uid = intent.getIntExtra(Intent.EXTRA_UID, -1);
// No need to notify for state change as all the alarms and jobs should be
// removed too.
mExemptedBucketPackages.remove(userId, pkgName);
mRunAnyRestrictedPackages.remove(Pair.create(uid, pkgName));
mActiveUids.delete(uid);
synchronized (mLock) {
mExemptedBucketPackages.remove(userId, pkgName);
mRunAnyRestrictedPackages.remove(Pair.create(uid, pkgName));
updateForcedAppStandbyUidPackagesLocked();
mActiveUids.delete(uid);
}
}
break;
}
@@ -580,6 +628,29 @@ public class AppStateTrackerImpl implements AppStateTracker {
}
}
}
updateForcedAppStandbyUidPackagesLocked();
}
/**
* Update the {@link #mForcedAppStandbyUidPackages} upon mutations on
* {@link #mRunAnyRestrictedPackages}, {@link #mForcedAppStandbyEnabled} or
* {@link #mForceAllAppsStandby}.
*/
@GuardedBy("mLock")
private void updateForcedAppStandbyUidPackagesLocked() {
if (!mForcedAppStandbyEnabled) {
mForcedAppStandbyUidPackages = Collections.emptySet();
return;
}
if (mForceAllAppsStandby) {
mForcedAppStandbyUidPackages = null;
return;
}
Set<Pair<Integer, String>> fasUidPkgs = new ArraySet<>();
for (int i = 0, size = mRunAnyRestrictedPackages.size(); i < size; i++) {
fasUidPkgs.add(mRunAnyRestrictedPackages.valueAt(i));
}
mForcedAppStandbyUidPackages = Collections.unmodifiableSet(fasUidPkgs);
}
private void updateForceAllAppStandbyState() {
@@ -601,6 +672,7 @@ public class AppStateTrackerImpl implements AppStateTracker {
return;
}
mForceAllAppsStandby = enable;
updateForcedAppStandbyUidPackagesLocked();
mHandler.notifyForceAllAppsStandbyChanged();
}
@@ -645,6 +717,7 @@ public class AppStateTrackerImpl implements AppStateTracker {
} else {
mRunAnyRestrictedPackages.removeAt(index);
}
updateForcedAppStandbyUidPackagesLocked();
return true;
}
@@ -896,6 +969,7 @@ public class AppStateTrackerImpl implements AppStateTracker {
if (unblockAlarms) {
l.unblockAllUnrestrictedAlarms();
}
l.updateForcedAppStandbyForAllApps();
}
mStatLogger.logDurationStat(
Stats.FORCE_APP_STANDBY_FEATURE_FLAG_CHANGED, start);
@@ -966,6 +1040,7 @@ public class AppStateTrackerImpl implements AppStateTracker {
mRunAnyRestrictedPackages.removeAt(i);
}
}
updateForcedAppStandbyUidPackagesLocked();
cleanUpArrayForUser(mActiveUids, removedUserId);
mExemptedBucketPackages.remove(removedUserId);
}

View File

@@ -325,6 +325,15 @@ public final class ApplicationExitInfo implements Parcelable {
*/
public static final int SUBREASON_ISOLATED_NOT_NEEDED = 17;
/**
* The process was killed because it's in forced-app-standby state, and it's cached and
* its uid state is idle; this would be set only when the reason is {@link #REASON_OTHER}.
*
* For internal use only.
* @hide
*/
public static final int SUBREASON_CACHED_IDLE_FORCED_APP_STANDBY = 18;
// If there is any OEM code which involves additional app kill reasons, it should
// be categorized in {@link #REASON_OTHER}, with subreason code starting from 1000.

View File

@@ -213,10 +213,15 @@ enum AppExitSubReasonCode {
* The process was killed because it's isolated and was in a cached state.
*/
SUBREASON_ISOLATED_NOT_NEEDED = 17;
/**
* The process was killed because it's in forced-app-standby state, and it's cached and
* its uid state is idle; this would be set only when the reason is {@link #REASON_OTHER}.
*/
SUBREASON_CACHED_IDLE_FORCED_APP_STANDBY = 18;
}
/**
* The relative importance level that the system places on a process.
/** * The relative importance level that the system places on a process.
* Keep sync with the definitions in
* {@link android.app.ActivityManager.RunningAppProcessInfo}
*/

View File

@@ -309,11 +309,23 @@ public final class ActiveServices {
* Watch for apps being put into forced app standby, so we can step their fg
* services down.
*/
class ForcedStandbyListener implements AppStateTracker.ServiceStateListener {
class ForcedStandbyListener implements AppStateTracker.ForcedAppStandbyListener {
@Override
public void stopForegroundServicesForUidPackage(final int uid, final String packageName) {
public void updateForceAppStandbyForUidPackage(int uid, String packageName,
boolean standby) {
synchronized (mAm) {
stopAllForegroundServicesLocked(uid, packageName);
if (standby) {
stopAllForegroundServicesLocked(uid, packageName);
}
mAm.mProcessList.updateForceAppStandbyForUidPackageLocked(
uid, packageName, standby);
}
}
@Override
public void updateForcedAppStandbyForAllApps() {
synchronized (mAm) {
mAm.mProcessList.updateForcedAppStandbyForAllAppsLocked();
}
}
}
@@ -499,7 +511,7 @@ public final class ActiveServices {
void systemServicesReady() {
AppStateTracker ast = LocalServices.getService(AppStateTracker.class);
ast.addServiceStateListener(new ForcedStandbyListener());
ast.addForcedAppStandbyListener(new ForcedStandbyListener());
mAppWidgetManagerInternal = LocalServices.getService(AppWidgetManagerInternal.class);
setAllowListWhileInUsePermissionInFgs();
}

View File

@@ -52,7 +52,8 @@ final class ActivityManagerConstants extends ContentObserver {
private static final String TAG = "ActivityManagerConstants";
// Key names stored in the settings value.
private static final String KEY_BACKGROUND_SETTLE_TIME = "background_settle_time";
static final String KEY_BACKGROUND_SETTLE_TIME = "background_settle_time";
private static final String KEY_FGSERVICE_MIN_SHOWN_TIME
= "fgservice_min_shown_time";
private static final String KEY_FGSERVICE_MIN_REPORT_TIME
@@ -108,9 +109,9 @@ final class ActivityManagerConstants extends ContentObserver {
static final String KEY_FG_TO_BG_FGS_GRACE_DURATION = "fg_to_bg_fgs_grace_duration";
static final String KEY_FGS_START_FOREGROUND_TIMEOUT = "fgs_start_foreground_timeout";
static final String KEY_FGS_ATOM_SAMPLE_RATE = "fgs_atom_sample_rate";
static final String KEY_KILL_FAS_CACHED_IDLE = "kill_fas_cached_idle";
private static final int DEFAULT_MAX_CACHED_PROCESSES = 32;
private static final long DEFAULT_BACKGROUND_SETTLE_TIME = 60*1000;
private static final long DEFAULT_FGSERVICE_MIN_SHOWN_TIME = 2*1000;
private static final long DEFAULT_FGSERVICE_MIN_REPORT_TIME = 3*1000;
private static final long DEFAULT_FGSERVICE_SCREEN_ON_BEFORE_TIME = 1*1000;
@@ -151,6 +152,10 @@ final class ActivityManagerConstants extends ContentObserver {
private static final long DEFAULT_FG_TO_BG_FGS_GRACE_DURATION = 5 * 1000;
private static final int DEFAULT_FGS_START_FOREGROUND_TIMEOUT_MS = 10 * 1000;
private static final float DEFAULT_FGS_ATOM_SAMPLE_RATE = 1; // 100 %
static final long DEFAULT_BACKGROUND_SETTLE_TIME = 60 * 1000;
static final boolean DEFAULT_KILL_FAS_CACHED_IDLE = true;
/**
* Same as {@link TEMPORARY_ALLOW_LIST_TYPE_FOREGROUND_SERVICE_NOT_ALLOWED}
*/
@@ -482,6 +487,12 @@ final class ActivityManagerConstants extends ContentObserver {
*/
volatile float mFgsAtomSampleRate = DEFAULT_FGS_ATOM_SAMPLE_RATE;
/**
* Whether or not to kill apps in force-app-standby state and it's cached, its UID state is
* idle.
*/
volatile boolean mKillForceAppStandByAndCachedIdle = DEFAULT_KILL_FAS_CACHED_IDLE;
private final ActivityManagerService mService;
private ContentResolver mResolver;
private final KeyValueListParser mParser = new KeyValueListParser(',');
@@ -687,6 +698,9 @@ final class ActivityManagerConstants extends ContentObserver {
case KEY_FGS_ATOM_SAMPLE_RATE:
updateFgsAtomSamplePercent();
break;
case KEY_KILL_FAS_CACHED_IDLE:
updateKillFasCachedIdle();
break;
default:
break;
}
@@ -1019,6 +1033,13 @@ final class ActivityManagerConstants extends ContentObserver {
DEFAULT_FGS_ATOM_SAMPLE_RATE);
}
private void updateKillFasCachedIdle() {
mKillForceAppStandByAndCachedIdle = DeviceConfig.getBoolean(
DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
KEY_KILL_FAS_CACHED_IDLE,
DEFAULT_KILL_FAS_CACHED_IDLE);
}
private void updateImperceptibleKillExemptions() {
IMPERCEPTIBLE_KILL_EXEMPT_PACKAGES.clear();
IMPERCEPTIBLE_KILL_EXEMPT_PACKAGES.addAll(mDefaultImperceptibleKillExemptPackages);

View File

@@ -14267,6 +14267,10 @@ public class ActivityManagerService extends IActivityManager.Stub
final int capability = uidRec != null ? uidRec.getSetCapability() : 0;
final boolean ephemeral = uidRec != null ? uidRec.isEphemeral() : isEphemeralLocked(uid);
if (uidRec != null && uidRec.isIdle() && (change & UidRecord.CHANGE_IDLE) != 0) {
mProcessList.killAppIfForceStandbyAndCachedIdleLocked(uidRec);
}
if (uidRec != null && !uidRec.isIdle() && (change & UidRecord.CHANGE_GONE) != 0) {
// If this uid is going away, and we haven't yet reported it is gone,
// then do so now.

View File

@@ -2863,6 +2863,8 @@ public class OomAdjuster {
+ " target=" + state.getAdjTarget() + " capability=" + item.capability);
}
mProcessList.killAppIfForceStandbyAndCachedIdleLocked(app);
return success;
}

View File

@@ -125,6 +125,7 @@ import com.android.internal.os.Zygote;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.FrameworkStatsLog;
import com.android.internal.util.MemInfoReader;
import com.android.server.AppStateTracker;
import com.android.server.LocalServices;
import com.android.server.ServiceThread;
import com.android.server.SystemConfig;
@@ -2333,6 +2334,12 @@ public final class ProcessList {
allowlistedAppDataInfoMap = null;
}
AppStateTracker ast = LocalServices.getService(AppStateTracker.class);
if (ast != null) {
app.mState.setForcedAppStandby(ast.isAppInForcedAppStandby(
app.info.uid, app.info.packageName));
}
final Process.ProcessStartResult startResult;
if (hostingRecord.usesWebviewZygote()) {
startResult = startWebView(entryPoint,
@@ -4959,6 +4966,54 @@ public final class ProcessList {
return true;
}
@GuardedBy("mService")
void updateForceAppStandbyForUidPackageLocked(int uid, String packageName, boolean standby) {
final UidRecord uidRec = getUidRecordLOSP(uid);
if (uidRec != null) {
uidRec.forEachProcess(app -> {
if (TextUtils.equals(app.info.packageName, packageName)) {
app.mState.setForcedAppStandby(standby);
killAppIfForceStandbyAndCachedIdleLocked(app);
}
});
}
}
@GuardedBy("mService")
void updateForcedAppStandbyForAllAppsLocked() {
if (!mService.mConstants.mKillForceAppStandByAndCachedIdle) {
return;
}
final AppStateTracker ast = LocalServices.getService(AppStateTracker.class);
for (int i = mLruProcesses.size() - 1; i >= 0; i--) {
final ProcessRecord app = mLruProcesses.get(i);
final boolean standby = ast.isAppInForcedAppStandby(
app.info.uid, app.info.packageName);
app.mState.setForcedAppStandby(standby);
if (standby) {
killAppIfForceStandbyAndCachedIdleLocked(app);
}
}
}
@GuardedBy("mService")
void killAppIfForceStandbyAndCachedIdleLocked(ProcessRecord app) {
final UidRecord uidRec = app.getUidRecord();
if (mService.mConstants.mKillForceAppStandByAndCachedIdle
&& uidRec != null && uidRec.isIdle()
&& app.isCached() && app.mState.isForcedAppStandby()) {
app.killLocked("cached idle & forced-app-standby",
ApplicationExitInfo.REASON_OTHER,
ApplicationExitInfo.SUBREASON_CACHED_IDLE_FORCED_APP_STANDBY,
true);
}
}
@GuardedBy("mService")
void killAppIfForceStandbyAndCachedIdleLocked(UidRecord uidRec) {
uidRec.forEachProcess(app -> killAppIfForceStandbyAndCachedIdleLocked(app));
}
/**
* Called by ActivityManagerService when a process died.
*/

View File

@@ -341,6 +341,12 @@ final class ProcessStateRecord {
@GuardedBy("mService")
private @ReasonCode int mAllowStartFgs = REASON_DENIED;
/**
* Whether or not this process has been in forced-app-standby state.
*/
@GuardedBy("mService")
private boolean mForcedAppStandby;
/**
* Debugging: primary thing impacting oom_adj.
*/
@@ -1275,6 +1281,16 @@ final class ProcessStateRecord {
return mAllowStartFgs;
}
@GuardedBy("mService")
void setForcedAppStandby(boolean standby) {
mForcedAppStandby = standby;
}
@GuardedBy("mService")
boolean isForcedAppStandby() {
return mForcedAppStandby;
}
@GuardedBy("mService")
void updateLastInvisibleTime(boolean hasVisibleActivities) {
if (hasVisibleActivities) {
@@ -1337,7 +1353,8 @@ final class ProcessStateRecord {
pw.print(" pendingUiClean="); pw.println(mApp.mProfile.hasPendingUiClean());
}
pw.print(prefix); pw.print("cached="); pw.print(mCached);
pw.print(" empty="); pw.println(mEmpty);
pw.print(" empty="); pw.print(mEmpty);
pw.print(" forcedAppStandby="); pw.println(mForcedAppStandby);
if (mServiceB) {
pw.print(prefix); pw.print("serviceb="); pw.print(mServiceB);
pw.print(" serviceHighRam="); pw.println(mServiceHighRam);

View File

@@ -1003,6 +1003,8 @@ public class AppStateTrackerTest {
verify(l, times(0)).updateAllJobs();
verify(l, times(0)).updateJobsForUid(anyInt(), anyBoolean());
verify(l, times(1)).updateJobsForUidPackage(eq(UID_10_2), eq(PACKAGE_2), anyBoolean());
verify(l, times(1)).updateForceAppStandbyForUidPackage(eq(UID_10_2), eq(PACKAGE_2),
eq(true));
verify(l, times(0)).updateAllAlarms();
verify(l, times(0)).updateAlarmsForUid(anyInt());
@@ -1017,6 +1019,8 @@ public class AppStateTrackerTest {
verify(l, times(0)).updateAllJobs();
verify(l, times(0)).updateJobsForUid(anyInt(), anyBoolean());
verify(l, times(1)).updateJobsForUidPackage(eq(UID_10_2), eq(PACKAGE_2), anyBoolean());
verify(l, times(1)).updateForceAppStandbyForUidPackage(eq(UID_10_2), eq(PACKAGE_2),
eq(false));
verify(l, times(0)).updateAllAlarms();
verify(l, times(0)).updateAlarmsForUid(anyInt());
@@ -1030,6 +1034,7 @@ public class AppStateTrackerTest {
verify(l, times(0)).updateAllJobs();
verify(l, times(0)).updateJobsForUid(anyInt(), anyBoolean());
verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean());
verify(l, times(0)).updateForceAppStandbyForUidPackage(anyInt(), anyString(), anyBoolean());
verify(l, times(0)).updateAllAlarms();
verify(l, times(0)).updateAlarmsForUid(anyInt());
@@ -1047,6 +1052,8 @@ public class AppStateTrackerTest {
verify(l, times(1)).updateAllJobs();
verify(l, times(0)).updateJobsForUid(anyInt(), anyBoolean());
verify(l, times(1)).updateJobsForUidPackage(eq(UID_10_2), eq(PACKAGE_2), anyBoolean());
verify(l, times(1)).updateForceAppStandbyForUidPackage(eq(UID_10_2), eq(PACKAGE_2),
eq(true));
verify(l, times(1)).updateAllAlarms();
verify(l, times(0)).updateAlarmsForUid(anyInt());
@@ -1063,6 +1070,7 @@ public class AppStateTrackerTest {
verify(l, times(1)).updateAllJobs();
verify(l, times(0)).updateJobsForUid(anyInt(), anyBoolean());
verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean());
verify(l, times(0)).updateForceAppStandbyForUidPackage(anyInt(), anyString(), anyBoolean());
verify(l, times(1)).updateAllAlarms();
verify(l, times(0)).updateAlarmsForUid(anyInt());
@@ -1081,6 +1089,7 @@ public class AppStateTrackerTest {
verify(l, times(1)).updateAllJobs();
verify(l, times(0)).updateJobsForUid(anyInt(), anyBoolean());
verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean());
verify(l, times(0)).updateForceAppStandbyForUidPackage(anyInt(), anyString(), anyBoolean());
verify(l, times(1)).updateAllAlarms();
verify(l, times(0)).updateAlarmsForUid(anyInt());
@@ -1095,6 +1104,7 @@ public class AppStateTrackerTest {
verify(l, times(1)).updateAllJobs();
verify(l, times(0)).updateJobsForUid(anyInt(), anyBoolean());
verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean());
verify(l, times(0)).updateForceAppStandbyForUidPackage(anyInt(), anyString(), anyBoolean());
verify(l, times(1)).updateAllAlarms();
verify(l, times(0)).updateAlarmsForUid(anyInt());
@@ -1111,6 +1121,7 @@ public class AppStateTrackerTest {
verify(l, times(1)).updateAllJobs();
verify(l, times(0)).updateJobsForUid(anyInt(), anyBoolean());
verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean());
verify(l, times(0)).updateForceAppStandbyForUidPackage(anyInt(), anyString(), anyBoolean());
verify(l, times(0)).updateAllAlarms();
verify(l, times(0)).updateAlarmsForUid(anyInt());
@@ -1126,6 +1137,7 @@ public class AppStateTrackerTest {
verify(l, times(1)).updateAllJobs();
verify(l, times(0)).updateJobsForUid(anyInt(), anyBoolean());
verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean());
verify(l, times(0)).updateForceAppStandbyForUidPackage(anyInt(), anyString(), anyBoolean());
verify(l, times(0)).updateAllAlarms();
verify(l, times(0)).updateAlarmsForUid(anyInt());
@@ -1142,6 +1154,7 @@ public class AppStateTrackerTest {
verify(l, times(1)).updateAllJobs();
verify(l, times(0)).updateJobsForUid(anyInt(), anyBoolean());
verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean());
verify(l, times(0)).updateForceAppStandbyForUidPackage(anyInt(), anyString(), anyBoolean());
verify(l, times(1)).updateAllAlarms();
verify(l, times(0)).updateAlarmsForUid(anyInt());
@@ -1158,6 +1171,7 @@ public class AppStateTrackerTest {
verify(l, times(2)).updateAllJobs();
verify(l, times(0)).updateJobsForUid(anyInt(), anyBoolean());
verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean());
verify(l, times(0)).updateForceAppStandbyForUidPackage(anyInt(), anyString(), anyBoolean());
verify(l, times(1)).updateAllAlarms();
verify(l, times(0)).updateAlarmsForUid(anyInt());
@@ -1172,6 +1186,7 @@ public class AppStateTrackerTest {
verify(l, times(1)).updateAllJobs();
verify(l, times(0)).updateJobsForUid(anyInt(), anyBoolean());
verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean());
verify(l, times(0)).updateForceAppStandbyForUidPackage(anyInt(), anyString(), anyBoolean());
verify(l, times(1)).updateAllAlarms();
verify(l, times(0)).updateAlarmsForUid(anyInt());
@@ -1188,6 +1203,7 @@ public class AppStateTrackerTest {
verify(l, times(1)).updateAllJobs();
verify(l, times(0)).updateJobsForUid(anyInt(), anyBoolean());
verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean());
verify(l, times(0)).updateForceAppStandbyForUidPackage(anyInt(), anyString(), anyBoolean());
verify(l, times(0)).updateAllAlarms();
verify(l, times(0)).updateAlarmsForUid(anyInt());
@@ -1203,6 +1219,7 @@ public class AppStateTrackerTest {
verify(l, times(1)).updateAllJobs();
verify(l, times(0)).updateJobsForUid(anyInt(), anyBoolean());
verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean());
verify(l, times(0)).updateForceAppStandbyForUidPackage(anyInt(), anyString(), anyBoolean());
verify(l, times(0)).updateAllAlarms();
verify(l, times(0)).updateAlarmsForUid(anyInt());
@@ -1225,6 +1242,7 @@ public class AppStateTrackerTest {
verify(l, times(0)).updateAllJobs();
verify(l, times(1)).updateJobsForUid(eq(UID_10_1), anyBoolean());
verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean());
verify(l, times(0)).updateForceAppStandbyForUidPackage(anyInt(), anyString(), anyBoolean());
verify(l, times(0)).updateAllAlarms();
verify(l, times(1)).updateAlarmsForUid(eq(UID_10_1));
@@ -1240,6 +1258,7 @@ public class AppStateTrackerTest {
verify(l, times(0)).updateAllJobs();
verify(l, times(1)).updateJobsForUid(eq(UID_10_1), anyBoolean());
verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean());
verify(l, times(0)).updateForceAppStandbyForUidPackage(anyInt(), anyString(), anyBoolean());
verify(l, times(0)).updateAllAlarms();
verify(l, times(1)).updateAlarmsForUid(eq(UID_10_1));
@@ -1255,6 +1274,7 @@ public class AppStateTrackerTest {
verify(l, times(0)).updateAllJobs();
verify(l, times(1)).updateJobsForUid(eq(UID_10_1), anyBoolean());
verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean());
verify(l, times(0)).updateForceAppStandbyForUidPackage(anyInt(), anyString(), anyBoolean());
verify(l, times(0)).updateAllAlarms();
verify(l, times(1)).updateAlarmsForUid(eq(UID_10_1));
@@ -1270,6 +1290,7 @@ public class AppStateTrackerTest {
verify(l, times(0)).updateAllJobs();
verify(l, times(1)).updateJobsForUid(eq(UID_10_1), anyBoolean());
verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean());
verify(l, times(0)).updateForceAppStandbyForUidPackage(anyInt(), anyString(), anyBoolean());
verify(l, times(0)).updateAllAlarms();
verify(l, times(1)).updateAlarmsForUid(eq(UID_10_1));
@@ -1286,6 +1307,7 @@ public class AppStateTrackerTest {
verify(l, times(1)).updateAllJobs();
verify(l, times(0)).updateJobsForUid(eq(UID_10_1), anyBoolean());
verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean());
verify(l, times(0)).updateForceAppStandbyForUidPackage(anyInt(), anyString(), anyBoolean());
verify(l, times(1)).updateAllAlarms();
verify(l, times(0)).updateAlarmsForUid(eq(UID_10_1));
@@ -1301,6 +1323,7 @@ public class AppStateTrackerTest {
verify(l, times(0)).updateAllJobs();
verify(l, times(1)).updateJobsForUid(eq(UID_10_1), anyBoolean());
verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean());
verify(l, times(0)).updateForceAppStandbyForUidPackage(anyInt(), anyString(), anyBoolean());
verify(l, times(0)).updateAllAlarms();
verify(l, times(1)).updateAlarmsForUid(eq(UID_10_1));
@@ -1316,6 +1339,7 @@ public class AppStateTrackerTest {
verify(l, times(0)).updateAllJobs();
verify(l, times(1)).updateJobsForUid(eq(UID_10_1), anyBoolean());
verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean());
verify(l, times(0)).updateForceAppStandbyForUidPackage(anyInt(), anyString(), anyBoolean());
verify(l, times(0)).updateAllAlarms();
verify(l, times(1)).updateAlarmsForUid(eq(UID_10_1));
@@ -1331,6 +1355,7 @@ public class AppStateTrackerTest {
verify(l, times(0)).updateAllJobs();
verify(l, times(1)).updateJobsForUid(eq(UID_10_1), anyBoolean());
verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean());
verify(l, times(0)).updateForceAppStandbyForUidPackage(anyInt(), anyString(), anyBoolean());
verify(l, times(0)).updateAllAlarms();
verify(l, times(1)).updateAlarmsForUid(eq(UID_10_1));
@@ -1346,6 +1371,7 @@ public class AppStateTrackerTest {
verify(l, times(0)).updateAllJobs();
verify(l, times(1)).updateJobsForUid(eq(UID_10_1), anyBoolean());
verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean());
verify(l, times(0)).updateForceAppStandbyForUidPackage(anyInt(), anyString(), anyBoolean());
verify(l, times(0)).updateAllAlarms();
verify(l, times(1)).updateAlarmsForUid(eq(UID_10_1));

View File

@@ -52,6 +52,7 @@ import android.server.wm.settings.SettingsSession;
import android.support.test.uiautomator.UiDevice;
import android.test.suitebuilder.annotation.LargeTest;
import android.text.TextUtils;
import android.util.KeyValueListParser;
import android.util.Log;
import androidx.test.InstrumentationRegistry;
@@ -417,6 +418,142 @@ public class ActivityManagerTest {
return false;
}
@LargeTest
@Test
public void testKillAppIfFasCachedIdle() throws Exception {
final long shortTimeoutMs = 5_000;
final long backgroundSettleMs = 10_000;
final PackageManager pm = mContext.getPackageManager();
final int uid = pm.getPackageUid(TEST_APP, 0);
final MyUidImportanceListener uidListener1 = new MyUidImportanceListener(uid);
final MyUidImportanceListener uidListener2 = new MyUidImportanceListener(uid);
SettingsSession<String> amConstantsSettings = null;
DeviceConfigSession<Boolean> killForceAppStandByAndCachedIdle = null;
final ActivityManager am = mContext.getSystemService(ActivityManager.class);
final CountDownLatch[] latchHolder = new CountDownLatch[1];
final H handler = new H(Looper.getMainLooper(), latchHolder);
final Messenger messenger = new Messenger(handler);
try {
am.addOnUidImportanceListener(uidListener1,
RunningAppProcessInfo.IMPORTANCE_FOREGROUND_SERVICE);
am.addOnUidImportanceListener(uidListener2, RunningAppProcessInfo.IMPORTANCE_GONE);
toggleScreenOn(true);
killForceAppStandByAndCachedIdle = new DeviceConfigSession<>(
DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
ActivityManagerConstants.KEY_KILL_FAS_CACHED_IDLE,
DeviceConfig::getBoolean,
ActivityManagerConstants.DEFAULT_KILL_FAS_CACHED_IDLE);
killForceAppStandByAndCachedIdle.set(true);
amConstantsSettings = new SettingsSession<>(
Settings.Global.getUriFor(Settings.Global.ACTIVITY_MANAGER_CONSTANTS),
Settings.Global::getString, Settings.Global::putString);
final KeyValueListParser parser = new KeyValueListParser(',');
long currentBackgroundSettleMs =
ActivityManagerConstants.DEFAULT_BACKGROUND_SETTLE_TIME;
try {
parser.setString(amConstantsSettings.get());
currentBackgroundSettleMs = parser.getLong(
ActivityManagerConstants.KEY_BACKGROUND_SETTLE_TIME,
ActivityManagerConstants.DEFAULT_BACKGROUND_SETTLE_TIME);
} catch (IllegalArgumentException e) {
}
// Drain queue to make sure the existing UID_IDLE_MSG has been processed.
Thread.sleep(currentBackgroundSettleMs);
amConstantsSettings.set(
ActivityManagerConstants.KEY_BACKGROUND_SETTLE_TIME + "=" + backgroundSettleMs);
runShellCommand("cmd appops set " + TEST_APP + " RUN_ANY_IN_BACKGROUND allow");
final Intent intent = new Intent(ACTION_FGS_STATS_TEST);
final ComponentName cn = ComponentName.unflattenFromString(
TEST_APP + "/" + TEST_FGS_CLASS);
final Bundle bundle = new Bundle();
intent.setComponent(cn);
bundle.putBinder(EXTRA_MESSENGER, messenger.getBinder());
intent.putExtras(bundle);
// Start the FGS.
latchHolder[0] = new CountDownLatch(1);
mContext.startForegroundService(intent);
assertTrue("Timed out to start fg service", uidListener1.waitFor(
RunningAppProcessInfo.IMPORTANCE_FOREGROUND_SERVICE, shortTimeoutMs));
assertTrue("Timed out to get the remote messenger", latchHolder[0].await(
shortTimeoutMs, TimeUnit.MILLISECONDS));
assertFalse("FGS shouldn't be killed", uidListener2.waitFor(
RunningAppProcessInfo.IMPORTANCE_GONE, backgroundSettleMs + shortTimeoutMs));
// Stop the FGS, it shouldn't be killed because it's not in FAS state.
latchHolder[0] = new CountDownLatch(1);
handler.sendRemoteMessage(H.MSG_STOP_FOREGROUND, 0, 0, null);
assertTrue("Timed out to wait for stop fg", latchHolder[0].await(
shortTimeoutMs, TimeUnit.MILLISECONDS));
assertFalse("FGS shouldn't be killed", uidListener2.waitFor(
RunningAppProcessInfo.IMPORTANCE_GONE, backgroundSettleMs + shortTimeoutMs));
// Set the FAS state.
runShellCommand("cmd appops set " + TEST_APP + " RUN_ANY_IN_BACKGROUND deny");
// Now it should've been killed.
assertTrue("Should have been killed", uidListener2.waitFor(
RunningAppProcessInfo.IMPORTANCE_GONE, backgroundSettleMs + shortTimeoutMs));
// Start the FGS.
// Temporarily allow RUN_ANY_IN_BACKGROUND to start FGS.
runShellCommand("cmd appops set " + TEST_APP + " RUN_ANY_IN_BACKGROUND allow");
latchHolder[0] = new CountDownLatch(1);
mContext.startForegroundService(intent);
assertTrue("Timed out to start fg service", uidListener1.waitFor(
RunningAppProcessInfo.IMPORTANCE_FOREGROUND_SERVICE, shortTimeoutMs));
assertTrue("Timed out to get the remote messenger", latchHolder[0].await(
shortTimeoutMs, TimeUnit.MILLISECONDS));
runShellCommand("cmd appops set " + TEST_APP + " RUN_ANY_IN_BACKGROUND deny");
// It shouldn't be killed since it's not cached.
assertFalse("FGS shouldn't be killed", uidListener2.waitFor(
RunningAppProcessInfo.IMPORTANCE_GONE, backgroundSettleMs + shortTimeoutMs));
// Stop the FGS, it should get killed because it's cached & uid idle & in FAS state.
latchHolder[0] = new CountDownLatch(1);
handler.sendRemoteMessage(H.MSG_STOP_FOREGROUND, 0, 0, null);
assertTrue("Timed out to wait for stop fg", latchHolder[0].await(
shortTimeoutMs, TimeUnit.MILLISECONDS));
assertTrue("Should have been killed", uidListener2.waitFor(
RunningAppProcessInfo.IMPORTANCE_GONE, backgroundSettleMs + shortTimeoutMs));
// Disable this FAS cached idle kill feature.
killForceAppStandByAndCachedIdle.set(false);
// Start the FGS.
// Temporarily allow RUN_ANY_IN_BACKGROUND to start FGS.
runShellCommand("cmd appops set " + TEST_APP + " RUN_ANY_IN_BACKGROUND allow");
latchHolder[0] = new CountDownLatch(1);
mContext.startForegroundService(intent);
assertTrue("Timed out to start fg service", uidListener1.waitFor(
RunningAppProcessInfo.IMPORTANCE_FOREGROUND_SERVICE, shortTimeoutMs));
assertTrue("Timed out to get the remote messenger", latchHolder[0].await(
shortTimeoutMs, TimeUnit.MILLISECONDS));
runShellCommand("cmd appops set " + TEST_APP + " RUN_ANY_IN_BACKGROUND deny");
assertFalse("FGS shouldn't be killed", uidListener2.waitFor(
RunningAppProcessInfo.IMPORTANCE_GONE, backgroundSettleMs + shortTimeoutMs));
// Stop the FGS, it shouldn't be killed because the feature has been turned off.
latchHolder[0] = new CountDownLatch(1);
handler.sendRemoteMessage(H.MSG_STOP_FOREGROUND, 0, 0, null);
assertTrue("Timed out to wait for stop fg", latchHolder[0].await(
shortTimeoutMs, TimeUnit.MILLISECONDS));
assertFalse("FGS shouldn't be killed", uidListener2.waitFor(
RunningAppProcessInfo.IMPORTANCE_GONE, backgroundSettleMs + shortTimeoutMs));
} finally {
runShellCommand("cmd appops set " + TEST_APP + " RUN_ANY_IN_BACKGROUND default");
if (amConstantsSettings != null) {
amConstantsSettings.close();
}
if (killForceAppStandByAndCachedIdle != null) {
killForceAppStandByAndCachedIdle.close();
}
am.removeOnUidImportanceListener(uidListener1);
am.removeOnUidImportanceListener(uidListener2);
}
}
/**
* Make sure the screen state.
*/