Merge "Keep oom_adj score low for top started EJs." into tm-dev

This commit is contained in:
Kweku Adams
2022-03-25 14:48:55 +00:00
committed by Android (Google) Code Review
6 changed files with 216 additions and 2 deletions

View File

@@ -2894,6 +2894,12 @@ public final class ActiveServices {
s.isNotAppComponentUsage = true;
}
if (s.app != null && s.app.mState != null
&& s.app.mState.getCurProcState() <= PROCESS_STATE_TOP
&& (flags & Context.BIND_ALMOST_PERCEPTIBLE) != 0) {
s.lastTopAlmostPerceptibleBindRequestUptimeMs = SystemClock.uptimeMillis();
}
if (s.app != null) {
updateServiceClientActivitiesLocked(s.app.mServices, c, true);
}
@@ -4798,6 +4804,10 @@ public final class ActiveServices {
if ((c.flags & Context.BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS) != 0) {
s.updateIsAllowedBgActivityStartsByBinding();
}
// And for almost perceptible exceptions.
if ((c.flags & Context.BIND_ALMOST_PERCEPTIBLE) != 0) {
psr.updateHasTopStartedAlmostPerceptibleServices();
}
if (s.app != null) {
updateServiceClientActivitiesLocked(s.app.mServices, c, true);
}

View File

@@ -108,6 +108,8 @@ final class ActivityManagerConstants extends ContentObserver {
static final String KEY_PROCESS_START_ASYNC = "process_start_async";
static final String KEY_MEMORY_INFO_THROTTLE_TIME = "memory_info_throttle_time";
static final String KEY_TOP_TO_FGS_GRACE_DURATION = "top_to_fgs_grace_duration";
static final String KEY_TOP_TO_ALMOST_PERCEPTIBLE_GRACE_DURATION =
"top_to_almost_perceptible_grace_duration";
static final String KEY_PENDINGINTENT_WARNING_THRESHOLD = "pendingintent_warning_threshold";
static final String KEY_MIN_CRASH_INTERVAL = "min_crash_interval";
static final String KEY_PROCESS_CRASH_COUNT_RESET_INTERVAL =
@@ -170,6 +172,7 @@ final class ActivityManagerConstants extends ContentObserver {
private static final boolean DEFAULT_PROCESS_START_ASYNC = true;
private static final long DEFAULT_MEMORY_INFO_THROTTLE_TIME = 5*60*1000;
private static final long DEFAULT_TOP_TO_FGS_GRACE_DURATION = 15 * 1000;
private static final long DEFAULT_TOP_TO_ALMOST_PERCEPTIBLE_GRACE_DURATION = 15 * 1000;
private static final int DEFAULT_PENDINGINTENT_WARNING_THRESHOLD = 2000;
private static final int DEFAULT_MIN_CRASH_INTERVAL = 2 * 60 * 1000;
private static final int DEFAULT_MAX_PHANTOM_PROCESSES = 32;
@@ -223,6 +226,8 @@ final class ActivityManagerConstants extends ContentObserver {
private static final int DEFAULT_SERVICE_START_FOREGROUND_ANR_DELAY_MS = 10 * 1000;
private static final long DEFAULT_SERVICE_BIND_ALMOST_PERCEPTIBLE_TIMEOUT_MS = 15 * 1000;
// Flag stored in the DeviceConfig API.
/**
* Maximum number of cached processes.
@@ -321,6 +326,9 @@ final class ActivityManagerConstants extends ContentObserver {
private static final String KEY_SERVICE_START_FOREGROUND_ANR_DELAY_MS =
"service_start_foreground_anr_delay_ms";
private static final String KEY_SERVICE_BIND_ALMOST_PERCEPTIBLE_TIMEOUT_MS =
"service_bind_almost_perceptible_timeout_ms";
// Maximum number of cached processes we will allow.
public int MAX_CACHED_PROCESSES = DEFAULT_MAX_CACHED_PROCESSES;
@@ -463,6 +471,13 @@ final class ActivityManagerConstants extends ContentObserver {
// this long.
public long TOP_TO_FGS_GRACE_DURATION = DEFAULT_TOP_TO_FGS_GRACE_DURATION;
/**
* Allow app just leaving TOP with an already running ALMOST_PERCEPTIBLE service to stay in
* a higher adj value for this long.
*/
public long TOP_TO_ALMOST_PERCEPTIBLE_GRACE_DURATION =
DEFAULT_TOP_TO_ALMOST_PERCEPTIBLE_GRACE_DURATION;
/**
* The minimum time we allow between crashes, for us to consider this
* application to be bad and stop its services and reject broadcasts.
@@ -653,6 +668,13 @@ final class ActivityManagerConstants extends ContentObserver {
volatile int mServiceStartForegroundAnrDelayMs =
DEFAULT_SERVICE_START_FOREGROUND_ANR_DELAY_MS;
/**
* How long the grace period is from starting an almost perceptible service to a successful
* binding before we stop considering it an almost perceptible service.
*/
volatile long mServiceBindAlmostPerceptibleTimeoutMs =
DEFAULT_SERVICE_BIND_ALMOST_PERCEPTIBLE_TIMEOUT_MS;
/**
* Defines component aliases. Format
* ComponentName ":" ComponentName ( "," ComponentName ":" ComponentName )*
@@ -942,6 +964,9 @@ final class ActivityManagerConstants extends ContentObserver {
case KEY_SERVICE_START_FOREGROUND_ANR_DELAY_MS:
updateServiceStartForegroundAnrDealyMs();
break;
case KEY_SERVICE_BIND_ALMOST_PERCEPTIBLE_TIMEOUT_MS:
updateServiceBindAlmostPerceptibleTimeoutMs();
break;
case KEY_NO_KILL_CACHED_PROCESSES_UNTIL_BOOT_COMPLETED:
updateNoKillCachedProcessesUntilBootCompleted();
break;
@@ -1170,6 +1195,9 @@ final class ActivityManagerConstants extends ContentObserver {
DEFAULT_MEMORY_INFO_THROTTLE_TIME);
TOP_TO_FGS_GRACE_DURATION = mParser.getDurationMillis(KEY_TOP_TO_FGS_GRACE_DURATION,
DEFAULT_TOP_TO_FGS_GRACE_DURATION);
TOP_TO_ALMOST_PERCEPTIBLE_GRACE_DURATION = mParser.getDurationMillis(
KEY_TOP_TO_ALMOST_PERCEPTIBLE_GRACE_DURATION,
DEFAULT_TOP_TO_ALMOST_PERCEPTIBLE_GRACE_DURATION);
MIN_CRASH_INTERVAL = mParser.getInt(KEY_MIN_CRASH_INTERVAL,
DEFAULT_MIN_CRASH_INTERVAL);
PENDINGINTENT_WARNING_THRESHOLD = mParser.getInt(KEY_PENDINGINTENT_WARNING_THRESHOLD,
@@ -1432,6 +1460,14 @@ final class ActivityManagerConstants extends ContentObserver {
DEFAULT_SERVICE_START_FOREGROUND_ANR_DELAY_MS);
}
private void updateServiceBindAlmostPerceptibleTimeoutMs() {
mServiceBindAlmostPerceptibleTimeoutMs = DeviceConfig.getLong(
DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
KEY_SERVICE_BIND_ALMOST_PERCEPTIBLE_TIMEOUT_MS,
DEFAULT_SERVICE_BIND_ALMOST_PERCEPTIBLE_TIMEOUT_MS);
}
private long[] parseLongArray(@NonNull String key, @NonNull long[] def) {
final String val = DeviceConfig.getString(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
key, null);
@@ -1647,6 +1683,8 @@ final class ActivityManagerConstants extends ContentObserver {
pw.println(MEMORY_INFO_THROTTLE_TIME);
pw.print(" "); pw.print(KEY_TOP_TO_FGS_GRACE_DURATION); pw.print("=");
pw.println(TOP_TO_FGS_GRACE_DURATION);
pw.print(" "); pw.print(KEY_TOP_TO_ALMOST_PERCEPTIBLE_GRACE_DURATION); pw.print("=");
pw.println(TOP_TO_ALMOST_PERCEPTIBLE_GRACE_DURATION);
pw.print(" "); pw.print(KEY_MIN_CRASH_INTERVAL); pw.print("=");
pw.println(MIN_CRASH_INTERVAL);
pw.print(" "); pw.print(KEY_PROCESS_CRASH_COUNT_RESET_INTERVAL); pw.print("=");
@@ -1716,6 +1754,8 @@ final class ActivityManagerConstants extends ContentObserver {
pw.print("="); pw.println(mServiceStartForegroundTimeoutMs);
pw.print(" "); pw.print(KEY_SERVICE_START_FOREGROUND_ANR_DELAY_MS);
pw.print("="); pw.println(mServiceStartForegroundAnrDelayMs);
pw.print(" "); pw.print(KEY_SERVICE_BIND_ALMOST_PERCEPTIBLE_TIMEOUT_MS);
pw.print("="); pw.println(mServiceBindAlmostPerceptibleTimeoutMs);
pw.println();
if (mOverrideMaxCachedProcesses >= 0) {

View File

@@ -1674,6 +1674,24 @@ public class OomAdjuster {
}
}
// If the app was recently in the foreground and has expedited jobs running,
// allow it to get a higher rank in memory for some time, compared to other EJS and even
// foreground services so that it can finish performing any persistence/processing of
// in-memory state.
if (psr.hasTopStartedAlmostPerceptibleServices()
&& adj > ProcessList.PERCEPTIBLE_RECENT_FOREGROUND_APP_ADJ
&& (state.getLastTopTime()
+ mConstants.TOP_TO_ALMOST_PERCEPTIBLE_GRACE_DURATION > now
|| state.getSetProcState() <= PROCESS_STATE_TOP)) {
adj = ProcessList.PERCEPTIBLE_RECENT_FOREGROUND_APP_ADJ;
// This shall henceforth be called the "EJ" exemption, despite utilizing the
// ALMOST_PERCEPTIBLE flag to work.
state.setAdjType("top-ej-act");
if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise to recent fg for EJ: " + app);
}
}
if (adj > ProcessList.PERCEPTIBLE_APP_ADJ
|| procState > PROCESS_STATE_TRANSIENT_BACKGROUND) {
if (state.getForcingToImportant() != null) {

View File

@@ -19,6 +19,7 @@ package com.android.server.am;
import android.app.ActivityManager;
import android.content.Context;
import android.os.IBinder;
import android.os.SystemClock;
import android.util.ArrayMap;
import android.util.ArraySet;
@@ -41,6 +42,18 @@ final class ProcessServiceRecord {
*/
private boolean mHasForegroundServices;
/**
* Running any services that are almost perceptible (started with
* {@link Context#BIND_ALMOST_PERCEPTIBLE} while the app was on TOP)?
*/
private boolean mHasTopStartedAlmostPerceptibleServices;
/**
* The latest value of {@link ServiceRecord#lastTopAlmostPerceptibleBindRequestUptimeMs} among
* the currently running services.
*/
private long mLastTopStartedAlmostPerceptibleBindRequestUptimeMs;
/**
* Service that applied current connectionGroup/Importance.
*/
@@ -146,6 +159,46 @@ final class ProcessServiceRecord {
mRepFgServiceTypes = foregroundServiceTypes;
}
void updateHasTopStartedAlmostPerceptibleServices() {
mHasTopStartedAlmostPerceptibleServices = false;
mLastTopStartedAlmostPerceptibleBindRequestUptimeMs = 0;
for (int s = mServices.size() - 1; s >= 0; --s) {
final ServiceRecord sr = mServices.valueAt(s);
mLastTopStartedAlmostPerceptibleBindRequestUptimeMs = Math.max(
mLastTopStartedAlmostPerceptibleBindRequestUptimeMs,
sr.lastTopAlmostPerceptibleBindRequestUptimeMs);
if (!mHasTopStartedAlmostPerceptibleServices && isAlmostPerceptible(sr)) {
mHasTopStartedAlmostPerceptibleServices = true;
}
}
}
private boolean isAlmostPerceptible(ServiceRecord record) {
if (record.lastTopAlmostPerceptibleBindRequestUptimeMs <= 0) {
return false;
}
final ArrayMap<IBinder, ArrayList<ConnectionRecord>> serviceConnections =
record.getConnections();
for (int m = serviceConnections.size() - 1; m >= 0; --m) {
final ArrayList<ConnectionRecord> clist = serviceConnections.valueAt(m);
for (int c = clist.size() - 1; c >= 0; --c) {
final ConnectionRecord cr = clist.get(c);
if ((cr.flags & Context.BIND_ALMOST_PERCEPTIBLE) != 0) {
return true;
}
}
}
return false;
}
boolean hasTopStartedAlmostPerceptibleServices() {
return mHasTopStartedAlmostPerceptibleServices
|| (mLastTopStartedAlmostPerceptibleBindRequestUptimeMs > 0
&& SystemClock.uptimeMillis() - mLastTopStartedAlmostPerceptibleBindRequestUptimeMs
< mService.mConstants.mServiceBindAlmostPerceptibleTimeoutMs);
}
ServiceRecord getConnectionService() {
return mConnectionService;
}
@@ -243,6 +296,14 @@ final class ProcessServiceRecord {
if (added && record.serviceInfo != null) {
mApp.getWindowProcessController().onServiceStarted(record.serviceInfo);
}
if (record.lastTopAlmostPerceptibleBindRequestUptimeMs > 0) {
mLastTopStartedAlmostPerceptibleBindRequestUptimeMs = Math.max(
mLastTopStartedAlmostPerceptibleBindRequestUptimeMs,
record.lastTopAlmostPerceptibleBindRequestUptimeMs);
if (!mHasTopStartedAlmostPerceptibleServices) {
mHasTopStartedAlmostPerceptibleServices = isAlmostPerceptible(record);
}
}
return added;
}
@@ -253,7 +314,11 @@ final class ProcessServiceRecord {
* @return true if the service was removed, false otherwise.
*/
boolean stopService(ServiceRecord record) {
return mServices.remove(record);
final boolean removed = mServices.remove(record);
if (record.lastTopAlmostPerceptibleBindRequestUptimeMs > 0) {
updateHasTopStartedAlmostPerceptibleServices();
}
return removed;
}
/**
@@ -261,6 +326,7 @@ final class ProcessServiceRecord {
*/
void stopAllServices() {
mServices.clear();
updateHasTopStartedAlmostPerceptibleServices();
}
/**
@@ -408,6 +474,13 @@ final class ProcessServiceRecord {
pw.print(prefix); pw.print("mHasForegroundServices="); pw.print(mHasForegroundServices);
pw.print(" forcingToImportant="); pw.println(mApp.mState.getForcingToImportant());
}
if (mHasTopStartedAlmostPerceptibleServices
|| mLastTopStartedAlmostPerceptibleBindRequestUptimeMs > 0) {
pw.print(prefix); pw.print("mHasTopStartedAlmostPerceptibleServices=");
pw.print(mHasTopStartedAlmostPerceptibleServices);
pw.print(" mLastTopStartedAlmostPerceptibleBindRequestUptimeMs=");
pw.println(mLastTopStartedAlmostPerceptibleBindRequestUptimeMs);
}
if (mHasClientActivities || mHasAboveClient || mTreatLikeActivity) {
pw.print(prefix); pw.print("hasClientActivities="); pw.print(mHasClientActivities);
pw.print(" hasAboveClient="); pw.print(mHasAboveClient);

View File

@@ -24,6 +24,7 @@ import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_FOREGROUND_
import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.IApplicationThread;
import android.app.Notification;
@@ -141,6 +142,12 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN
int pendingConnectionGroup; // To be filled in to ProcessRecord once it connects
int pendingConnectionImportance; // To be filled in to ProcessRecord once it connects
/**
* The last time (in uptime timebase) a bind request was made with BIND_ALMOST_PERCEPTIBLE for
* this service while on TOP.
*/
long lastTopAlmostPerceptibleBindRequestUptimeMs;
// any current binding to this service has BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS flag?
private boolean mIsAllowedBgActivityStartsByBinding;
// is this service currently allowed to start activities from background by providing
@@ -713,6 +720,7 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN
}
}
@NonNull
ArrayMap<IBinder, ArrayList<ConnectionRecord>> getConnections() {
return connections;
}

View File

@@ -63,6 +63,7 @@ import static com.android.server.am.ProcessList.UNKNOWN_ADJ;
import static com.android.server.am.ProcessList.VISIBLE_APP_ADJ;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertTrue;
import static org.mockito.AdditionalAnswers.answer;
import static org.mockito.Mockito.any;
@@ -444,7 +445,7 @@ public class MockingOomAdjusterTests {
@SuppressWarnings("GuardedBy")
@Test
public void testUpdateOomAdj_DoOne_PerceptibleRecent() {
public void testUpdateOomAdj_DoOne_PerceptibleRecent_FgService() {
ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
app.mServices.setHasForegroundServices(true, 0);
@@ -456,6 +457,70 @@ public class MockingOomAdjusterTests {
PERCEPTIBLE_RECENT_FOREGROUND_APP_ADJ, SCHED_GROUP_DEFAULT);
}
@SuppressWarnings("GuardedBy")
@Test
public void testUpdateOomAdj_DoOne_PerceptibleRecent_AlmostPerceptibleService() {
// Grace period allows the adjustment.
{
ProcessRecord system = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, true));
long nowUptime = SystemClock.uptimeMillis();
app.mState.setLastTopTime(nowUptime);
// Simulate the system starting and binding to a service in the app.
ServiceRecord s = bindService(app, system,
null, Context.BIND_ALMOST_PERCEPTIBLE, mock(IBinder.class));
s.lastTopAlmostPerceptibleBindRequestUptimeMs = nowUptime;
s.getConnections().clear();
app.mServices.updateHasTopStartedAlmostPerceptibleServices();
sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
sService.mOomAdjuster.updateOomAdjLocked(app, OomAdjuster.OOM_ADJ_REASON_NONE);
assertEquals(PERCEPTIBLE_RECENT_FOREGROUND_APP_ADJ, app.mState.getSetAdj());
}
// Out of grace period but valid binding allows the adjustment.
{
ProcessRecord system = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, true));
long nowUptime = SystemClock.uptimeMillis();
app.mState.setLastTopTime(nowUptime);
// Simulate the system starting and binding to a service in the app.
ServiceRecord s = bindService(app, system,
null, Context.BIND_ALMOST_PERCEPTIBLE, mock(IBinder.class));
s.lastTopAlmostPerceptibleBindRequestUptimeMs =
nowUptime - 2 * sService.mConstants.mServiceBindAlmostPerceptibleTimeoutMs;
app.mServices.updateHasTopStartedAlmostPerceptibleServices();
sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
sService.mOomAdjuster.updateOomAdjLocked(app, OomAdjuster.OOM_ADJ_REASON_NONE);
assertEquals(PERCEPTIBLE_RECENT_FOREGROUND_APP_ADJ, app.mState.getSetAdj());
}
// Out of grace period and no valid binding so no adjustment.
{
ProcessRecord system = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, true));
long nowUptime = SystemClock.uptimeMillis();
app.mState.setLastTopTime(nowUptime);
// Simulate the system starting and binding to a service in the app.
ServiceRecord s = bindService(app, system,
null, Context.BIND_ALMOST_PERCEPTIBLE, mock(IBinder.class));
s.lastTopAlmostPerceptibleBindRequestUptimeMs =
nowUptime - 2 * sService.mConstants.mServiceBindAlmostPerceptibleTimeoutMs;
s.getConnections().clear();
app.mServices.updateHasTopStartedAlmostPerceptibleServices();
sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
sService.mOomAdjuster.updateOomAdjLocked(app, OomAdjuster.OOM_ADJ_REASON_NONE);
assertNotEquals(PERCEPTIBLE_RECENT_FOREGROUND_APP_ADJ, app.mState.getSetAdj());
}
}
@SuppressWarnings("GuardedBy")
@Test
public void testUpdateOomAdj_DoOne_Toast() {