Merge "Keep warming services out of cached adj"
This commit is contained in:
committed by
Android (Google) Code Review
commit
60d9339b3b
@@ -4386,4 +4386,6 @@
|
||||
0.333
|
||||
</item>
|
||||
|
||||
<!-- Component names of the services which will keep critical code path warm -->
|
||||
<string-array name="config_keep_warming_services" translatable="false" />
|
||||
</resources>
|
||||
|
||||
@@ -4058,4 +4058,5 @@
|
||||
<java-symbol type="integer" name="config_defaultBinderHeavyHitterAutoSamplerBatchSize" />
|
||||
<java-symbol type="dimen" name="config_defaultBinderHeavyHitterAutoSamplerThreshold" />
|
||||
|
||||
<java-symbol type="array" name="config_keep_warming_services" />
|
||||
</resources>
|
||||
|
||||
@@ -19,6 +19,7 @@ package com.android.server.am;
|
||||
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_POWER_QUICK;
|
||||
|
||||
import android.app.ActivityThread;
|
||||
import android.content.ComponentName;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.database.ContentObserver;
|
||||
@@ -336,6 +337,11 @@ final class ActivityManagerConstants extends ContentObserver {
|
||||
*/
|
||||
public int PENDINGINTENT_WARNING_THRESHOLD = DEFAULT_PENDINGINTENT_WARNING_THRESHOLD;
|
||||
|
||||
/**
|
||||
* Component names of the services which will keep critical code path of the host warm
|
||||
*/
|
||||
public final ArraySet<ComponentName> KEEP_WARMING_SERVICES = new ArraySet<ComponentName>();
|
||||
|
||||
private List<String> mDefaultImperceptibleKillExemptPackages;
|
||||
private List<Integer> mDefaultImperceptibleKillExemptProcStates;
|
||||
|
||||
@@ -496,6 +502,10 @@ final class ActivityManagerConstants extends ContentObserver {
|
||||
BINDER_HEAVY_HITTER_AUTO_SAMPLER_BATCHSIZE = mDefaultBinderHeavyHitterAutoSamplerBatchSize;
|
||||
BINDER_HEAVY_HITTER_AUTO_SAMPLER_THRESHOLD = mDefaultBinderHeavyHitterAutoSamplerThreshold;
|
||||
service.scheduleUpdateBinderHeavyHitterWatcherConfig();
|
||||
KEEP_WARMING_SERVICES.addAll(Arrays.stream(
|
||||
context.getResources().getStringArray(
|
||||
com.android.internal.R.array.config_keep_warming_services))
|
||||
.map(ComponentName::unflattenFromString).collect(Collectors.toSet()));
|
||||
}
|
||||
|
||||
public void start(ContentResolver resolver) {
|
||||
|
||||
@@ -76,7 +76,11 @@ import android.app.ApplicationExitInfo;
|
||||
import android.app.usage.UsageEvents;
|
||||
import android.compat.annotation.ChangeId;
|
||||
import android.compat.annotation.EnabledAfter;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.pm.ServiceInfo;
|
||||
import android.os.Debug;
|
||||
import android.os.Handler;
|
||||
@@ -265,6 +269,43 @@ public final class OomAdjuster {
|
||||
|
||||
void initSettings() {
|
||||
mCachedAppOptimizer.init();
|
||||
if (mService.mConstants.KEEP_WARMING_SERVICES.size() > 0) {
|
||||
final IntentFilter filter = new IntentFilter(Intent.ACTION_USER_SWITCHED);
|
||||
mService.mContext.registerReceiverForAllUsers(new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
synchronized (mService) {
|
||||
handleUserSwitchedLocked();
|
||||
}
|
||||
}
|
||||
}, filter, null, mService.mHandler);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the keep-warming service flags upon user switches
|
||||
*/
|
||||
@VisibleForTesting
|
||||
@GuardedBy("mService")
|
||||
void handleUserSwitchedLocked() {
|
||||
final ArraySet<ComponentName> warmServices = mService.mConstants.KEEP_WARMING_SERVICES;
|
||||
final ArrayList<ProcessRecord> processes = mProcessList.mLruProcesses;
|
||||
for (int i = processes.size() - 1; i >= 0; i--) {
|
||||
final ProcessRecord app = processes.get(i);
|
||||
boolean includeWarmPkg = false;
|
||||
for (int j = warmServices.size() - 1; j >= 0; j--) {
|
||||
if (app.pkgList.containsKey(warmServices.valueAt(j).getPackageName())) {
|
||||
includeWarmPkg = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!includeWarmPkg) {
|
||||
continue;
|
||||
}
|
||||
for (int j = app.numberOfRunningServices() - 1; j >= 0; j--) {
|
||||
app.getRunningServiceAt(j).updateKeepWarmLocked();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1470,7 +1511,7 @@ public final class OomAdjuster {
|
||||
"Raise procstate to started service: " + app);
|
||||
}
|
||||
}
|
||||
if (app.hasShownUi && !app.getCachedIsHomeProcess()) {
|
||||
if (!s.mKeepWarming && app.hasShownUi && !app.getCachedIsHomeProcess()) {
|
||||
// If this process has shown some UI, let it immediately
|
||||
// go to the LRU list because it may be pretty heavy with
|
||||
// UI stuff. We'll tag it with a label just to help
|
||||
@@ -1479,7 +1520,8 @@ public final class OomAdjuster {
|
||||
app.adjType = "cch-started-ui-services";
|
||||
}
|
||||
} else {
|
||||
if (now < (s.lastActivity + mConstants.MAX_SERVICE_INACTIVITY)) {
|
||||
if (s.mKeepWarming
|
||||
|| now < (s.lastActivity + mConstants.MAX_SERVICE_INACTIVITY)) {
|
||||
// This service has seen some activity within
|
||||
// recent memory, so we will keep its process ahead
|
||||
// of the background processes.
|
||||
|
||||
@@ -43,6 +43,7 @@ import android.util.TimeUtils;
|
||||
import android.util.proto.ProtoOutputStream;
|
||||
import android.util.proto.ProtoUtils;
|
||||
|
||||
import com.android.internal.annotations.GuardedBy;
|
||||
import com.android.internal.app.procstats.ServiceState;
|
||||
import com.android.internal.os.BatteryStatsImpl;
|
||||
import com.android.server.LocalServices;
|
||||
@@ -149,6 +150,8 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN
|
||||
|
||||
private int lastStartId; // identifier of most recent start request.
|
||||
|
||||
boolean mKeepWarming; // Whether or not it'll keep critical code path of the host warm
|
||||
|
||||
static class StartItem {
|
||||
final ServiceRecord sr;
|
||||
final boolean taskRemoved;
|
||||
@@ -517,6 +520,7 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN
|
||||
lastActivity = SystemClock.uptimeMillis();
|
||||
userId = UserHandle.getUserId(appInfo.uid);
|
||||
createdFromFg = callerIsFg;
|
||||
updateKeepWarmLocked();
|
||||
}
|
||||
|
||||
public ServiceState getTracker() {
|
||||
@@ -735,6 +739,14 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN
|
||||
}
|
||||
}
|
||||
|
||||
@GuardedBy("ams")
|
||||
void updateKeepWarmLocked() {
|
||||
mKeepWarming = ams.mConstants.KEEP_WARMING_SERVICES.contains(name)
|
||||
&& (ams.mUserController.getCurrentUserId() == userId
|
||||
|| ams.isSingleton(processName, appInfo, instanceName.getClassName(),
|
||||
serviceInfo.flags));
|
||||
}
|
||||
|
||||
public AppBindRecord retrieveAppBindingLocked(Intent intent,
|
||||
ProcessRecord app) {
|
||||
Intent.FilterComparison filter = new Intent.FilterComparison(intent);
|
||||
|
||||
@@ -84,6 +84,7 @@ import android.os.Build;
|
||||
import android.os.IBinder;
|
||||
import android.os.PowerManagerInternal;
|
||||
import android.os.SystemClock;
|
||||
import android.os.UserHandle;
|
||||
import android.platform.test.annotations.Presubmit;
|
||||
import android.util.ArrayMap;
|
||||
import android.util.ArraySet;
|
||||
@@ -130,6 +131,7 @@ public class MockingOomAdjusterTests {
|
||||
private static final int MOCKAPP5_UID = MOCKAPP_UID + 4;
|
||||
private static final String MOCKAPP5_PROCESSNAME = "test #5";
|
||||
private static final String MOCKAPP5_PACKAGENAME = "com.android.test.test5";
|
||||
private static final int MOCKAPP2_UID_OTHER = MOCKAPP2_UID + UserHandle.PER_USER_RANGE;
|
||||
private static Context sContext;
|
||||
private static PackageManagerInternal sPackageManagerInternal;
|
||||
private static ActivityManagerService sService;
|
||||
@@ -168,6 +170,8 @@ public class MockingOomAdjusterTests {
|
||||
mock(SparseArray.class));
|
||||
setFieldValue(ActivityManagerService.class, sService, "mOomAdjProfiler",
|
||||
mock(OomAdjProfiler.class));
|
||||
setFieldValue(ActivityManagerService.class, sService, "mUserController",
|
||||
mock(UserController.class));
|
||||
doReturn(new ActivityManagerService.ProcessChangeItem()).when(sService)
|
||||
.enqueueProcessChangeItemLocked(anyInt(), anyInt());
|
||||
sService.mOomAdjuster = new OomAdjuster(sService, sService.mProcessList,
|
||||
@@ -1621,6 +1625,117 @@ public class MockingOomAdjusterTests {
|
||||
assertEquals(SERVICE_ADJ, app.setAdj);
|
||||
}
|
||||
|
||||
@SuppressWarnings("GuardedBy")
|
||||
@Test
|
||||
public void testUpdateOomAdj_DoAll_Service_KeepWarmingList() {
|
||||
final ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
|
||||
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
|
||||
final ProcessRecord app2 = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID_OTHER,
|
||||
MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
|
||||
final int userOwner = 0;
|
||||
final int userOther = 1;
|
||||
final int cachedAdj1 = CACHED_APP_MIN_ADJ + ProcessList.CACHED_APP_IMPORTANCE_LEVELS;
|
||||
final int cachedAdj2 = cachedAdj1 + ProcessList.CACHED_APP_IMPORTANCE_LEVELS * 2;
|
||||
doReturn(userOwner).when(sService.mUserController).getCurrentUserId();
|
||||
|
||||
final ArrayList<ProcessRecord> lru = sService.mProcessList.mLruProcesses;
|
||||
lru.clear();
|
||||
lru.add(app2);
|
||||
lru.add(app);
|
||||
|
||||
final ComponentName cn = ComponentName.unflattenFromString(
|
||||
MOCKAPP_PACKAGENAME + "/.TestService");
|
||||
final ComponentName cn2 = ComponentName.unflattenFromString(
|
||||
MOCKAPP2_PACKAGENAME + "/.TestService");
|
||||
final long now = SystemClock.uptimeMillis();
|
||||
|
||||
sService.mConstants.KEEP_WARMING_SERVICES.clear();
|
||||
final ServiceInfo si = mock(ServiceInfo.class);
|
||||
si.applicationInfo = mock(ApplicationInfo.class);
|
||||
ServiceRecord s = spy(new ServiceRecord(sService, null, cn, cn, null, 0, null,
|
||||
si, false, null));
|
||||
doReturn(new ArrayMap<IBinder, ArrayList<ConnectionRecord>>()).when(s).getConnections();
|
||||
s.startRequested = true;
|
||||
s.lastActivity = now;
|
||||
|
||||
app.setCached(false);
|
||||
app.startService(s);
|
||||
app.hasShownUi = true;
|
||||
|
||||
final ServiceInfo si2 = mock(ServiceInfo.class);
|
||||
si2.applicationInfo = mock(ApplicationInfo.class);
|
||||
si2.applicationInfo.uid = MOCKAPP2_UID_OTHER;
|
||||
ServiceRecord s2 = spy(new ServiceRecord(sService, null, cn2, cn2, null, 0, null,
|
||||
si2, false, null));
|
||||
doReturn(new ArrayMap<IBinder, ArrayList<ConnectionRecord>>()).when(s2).getConnections();
|
||||
s2.startRequested = true;
|
||||
s2.lastActivity = now - sService.mConstants.MAX_SERVICE_INACTIVITY - 1;
|
||||
|
||||
app2.setCached(false);
|
||||
app2.startService(s2);
|
||||
app2.hasShownUi = false;
|
||||
|
||||
sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
|
||||
sService.mOomAdjuster.updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_NONE);
|
||||
|
||||
assertProcStates(app, true, PROCESS_STATE_SERVICE, cachedAdj1, "cch-started-ui-services");
|
||||
assertProcStates(app2, true, PROCESS_STATE_SERVICE, cachedAdj2, "cch-started-services");
|
||||
|
||||
app.setProcState = PROCESS_STATE_NONEXISTENT;
|
||||
app.adjType = null;
|
||||
app.setAdj = UNKNOWN_ADJ;
|
||||
app.hasShownUi = false;
|
||||
sService.mOomAdjuster.updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_NONE);
|
||||
|
||||
assertProcStates(app, false, PROCESS_STATE_SERVICE, SERVICE_ADJ, "started-services");
|
||||
|
||||
app.setCached(false);
|
||||
app.setProcState = PROCESS_STATE_NONEXISTENT;
|
||||
app.adjType = null;
|
||||
app.setAdj = UNKNOWN_ADJ;
|
||||
s.lastActivity = now - sService.mConstants.MAX_SERVICE_INACTIVITY - 1;
|
||||
sService.mOomAdjuster.updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_NONE);
|
||||
|
||||
assertProcStates(app, true, PROCESS_STATE_SERVICE, cachedAdj1, "cch-started-services");
|
||||
|
||||
app.stopService(s);
|
||||
app.setProcState = PROCESS_STATE_NONEXISTENT;
|
||||
app.adjType = null;
|
||||
app.setAdj = UNKNOWN_ADJ;
|
||||
app.hasShownUi = true;
|
||||
sService.mConstants.KEEP_WARMING_SERVICES.add(cn);
|
||||
sService.mConstants.KEEP_WARMING_SERVICES.add(cn2);
|
||||
s = spy(new ServiceRecord(sService, null, cn, cn, null, 0, null,
|
||||
si, false, null));
|
||||
doReturn(new ArrayMap<IBinder, ArrayList<ConnectionRecord>>()).when(s).getConnections();
|
||||
s.startRequested = true;
|
||||
s.lastActivity = now;
|
||||
|
||||
app.startService(s);
|
||||
sService.mOomAdjuster.updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_NONE);
|
||||
|
||||
assertProcStates(app, false, PROCESS_STATE_SERVICE, SERVICE_ADJ, "started-services");
|
||||
assertProcStates(app2, true, PROCESS_STATE_SERVICE, cachedAdj1, "cch-started-services");
|
||||
|
||||
app.setCached(true);
|
||||
app.setProcState = PROCESS_STATE_NONEXISTENT;
|
||||
app.adjType = null;
|
||||
app.setAdj = UNKNOWN_ADJ;
|
||||
app.hasShownUi = false;
|
||||
s.lastActivity = now - sService.mConstants.MAX_SERVICE_INACTIVITY - 1;
|
||||
sService.mOomAdjuster.updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_NONE);
|
||||
|
||||
assertProcStates(app, false, PROCESS_STATE_SERVICE, SERVICE_ADJ, "started-services");
|
||||
assertProcStates(app2, true, PROCESS_STATE_SERVICE, cachedAdj1, "cch-started-services");
|
||||
|
||||
doReturn(userOther).when(sService.mUserController).getCurrentUserId();
|
||||
sService.mOomAdjuster.handleUserSwitchedLocked();
|
||||
|
||||
sService.mOomAdjuster.updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_NONE);
|
||||
assertProcStates(app, true, PROCESS_STATE_SERVICE, cachedAdj1, "cch-started-services");
|
||||
assertProcStates(app2, false, PROCESS_STATE_SERVICE, SERVICE_ADJ, "started-services");
|
||||
}
|
||||
|
||||
private ProcessRecord makeDefaultProcessRecord(int pid, int uid, String processName,
|
||||
String packageName, boolean hasShownUi) {
|
||||
long now = SystemClock.uptimeMillis();
|
||||
@@ -1747,4 +1862,12 @@ public class MockingOomAdjusterTests {
|
||||
assertEquals(expectedAdj, app.setAdj);
|
||||
assertEquals(expectedSchedGroup, app.setSchedGroup);
|
||||
}
|
||||
|
||||
private void assertProcStates(ProcessRecord app, boolean expectedCached,
|
||||
int expectedProcState, int expectedAdj, String expectedAdjType) {
|
||||
assertEquals(expectedCached, app.isCached());
|
||||
assertEquals(expectedProcState, app.setProcState);
|
||||
assertEquals(expectedAdj, app.setAdj);
|
||||
assertEquals(expectedAdjType, app.adjType);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user