Merge "Skip resetting the shouldNotFreeze flag while re-evaluating oom adj" into sc-dev

This commit is contained in:
Jing Ji
2021-06-30 22:12:19 +00:00
committed by Android (Google) Code Review
5 changed files with 187 additions and 29 deletions

View File

@@ -212,6 +212,23 @@ public final class CachedAppOptimizer {
}
};
private final OnPropertiesChangedListener mOnNativeBootFlagsChangedListener =
new OnPropertiesChangedListener() {
@Override
public void onPropertiesChanged(Properties properties) {
synchronized (mPhenotypeFlagLock) {
for (String name : properties.getKeyset()) {
if (KEY_FREEZER_DEBOUNCE_TIMEOUT.equals(name)) {
updateFreezerDebounceTimeout();
}
}
}
if (mTestCallback != null) {
mTestCallback.onPropertyChanged();
}
}
};
private final class SettingsContentObserver extends ContentObserver {
SettingsContentObserver() {
super(mAm.mHandler);
@@ -328,6 +345,10 @@ public final class CachedAppOptimizer {
// TODO: initialize flags to default and only update them if values are set in DeviceConfig
DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
ActivityThread.currentApplication().getMainExecutor(), mOnFlagsChangedListener);
DeviceConfig.addOnPropertiesChangedListener(
DeviceConfig.NAMESPACE_ACTIVITY_MANAGER_NATIVE_BOOT,
ActivityThread.currentApplication().getMainExecutor(),
mOnNativeBootFlagsChangedListener);
mAm.mContext.getContentResolver().registerContentObserver(
CACHED_APP_FREEZER_ENABLED_URI, false, mSettingsObserver);
synchronized (mPhenotypeFlagLock) {

View File

@@ -1530,9 +1530,11 @@ public class OomAdjuster {
state.setAdjTarget(null);
state.setEmpty(false);
state.setCached(false);
state.setNoKillOnForcedAppStandbyAndIdle(false);
state.resetAllowStartFgsState();
app.mOptRecord.setShouldNotFreeze(false);
if (!cycleReEval) {
// Don't reset this flag when doing cycles re-evaluation.
app.mOptRecord.setShouldNotFreeze(false);
}
final int appUid = app.info.uid;
final int logUid = mService.mCurOomAdjUid;
@@ -1983,6 +1985,11 @@ public class OomAdjuster {
final boolean clientIsSystem = clientProcState < PROCESS_STATE_TOP;
if (client.mOptRecord.shouldNotFreeze()) {
// Propagate the shouldNotFreeze flag down the bindings.
app.mOptRecord.setShouldNotFreeze(true);
}
if ((cr.flags & Context.BIND_WAIVE_PRIORITY) == 0) {
if (shouldSkipDueToCycle(app, cstate, procState, adj, cycleReEval)) {
continue;
@@ -2019,9 +2026,6 @@ public class OomAdjuster {
// Similar to BIND_WAIVE_PRIORITY, keep it unfrozen.
if (clientAdj < ProcessList.CACHED_APP_MIN_ADJ) {
app.mOptRecord.setShouldNotFreeze(true);
// Similarly, we shouldn't kill it when it's in forced-app-standby
// mode and cached & idle state.
app.mState.setNoKillOnForcedAppStandbyAndIdle(true);
}
// Not doing bind OOM management, so treat
// this guy more like a started service.
@@ -2226,9 +2230,6 @@ public class OomAdjuster {
// unfrozen.
if (clientAdj < ProcessList.CACHED_APP_MIN_ADJ) {
app.mOptRecord.setShouldNotFreeze(true);
// Similarly, we shouldn't kill it when it's in forced-app-standby
// mode and cached & idle state.
app.mState.setNoKillOnForcedAppStandbyAndIdle(true);
}
}
if ((cr.flags&Context.BIND_TREAT_LIKE_ACTIVITY) != 0) {
@@ -2302,6 +2303,10 @@ public class OomAdjuster {
// we are going to consider it empty.
clientProcState = PROCESS_STATE_CACHED_EMPTY;
}
if (client.mOptRecord.shouldNotFreeze()) {
// Propagate the shouldNotFreeze flag down the bindings.
app.mOptRecord.setShouldNotFreeze(true);
}
String adjType = null;
if (adj > clientAdj) {
if (state.hasShownUi() && !state.getCachedIsHomeProcess()

View File

@@ -357,13 +357,6 @@ final class ProcessStateRecord {
@ElapsedRealtimeLong
private long mLastInvisibleTime;
/**
* Whether or not this process could be killed when it's in forced-app-standby mode
* and cached &amp; idle state.
*/
@GuardedBy("mService")
private boolean mNoKillOnForcedAppStandbyAndIdle;
// Below are the cached task info for OomAdjuster only
private static final int VALUE_INVALID = -1;
private static final int VALUE_FALSE = 0;
@@ -1134,16 +1127,6 @@ final class ProcessStateRecord {
return mLastInvisibleTime;
}
@GuardedBy("mService")
void setNoKillOnForcedAppStandbyAndIdle(boolean shouldNotKill) {
mNoKillOnForcedAppStandbyAndIdle = shouldNotKill;
}
@GuardedBy("mService")
boolean shouldNotKillOnForcedAppStandbyAndIdle() {
return mNoKillOnForcedAppStandbyAndIdle;
}
@GuardedBy({"mService", "mProcLock"})
void dump(PrintWriter pw, String prefix, long nowUptime) {
if (mReportedInteraction || mFgInteractionTime != 0) {

View File

@@ -94,6 +94,17 @@ public class ActivityManagerTest {
"com.android.servicestests.apps.simpleservicetestapp.ACTION_FGS_STATS_TEST";
private static final String EXTRA_MESSENGER = "extra_messenger";
private static final String EXTRA_CALLBACK = "callback";
private static final String EXTRA_COMMAND = "command";
private static final String EXTRA_FLAGS = "flags";
private static final String EXTRA_TARGET_PACKAGE = "target_package";
private static final int COMMAND_INVALID = 0;
private static final int COMMAND_EMPTY = 1;
private static final int COMMAND_BIND_SERVICE = 2;
private static final int COMMAND_UNBIND_SERVICE = 3;
private static final int COMMAND_STOP_SELF = 4;
private IActivityManager mService;
private IRemoteCallback mCallback;
private Context mContext;
@@ -333,6 +344,12 @@ public class ActivityManagerTest {
SettingsSession<String> amConstantsSettings = null;
DeviceConfigSession<Long> freezerDebounceTimeout = null;
MyServiceConnection autoConnection = null;
final ActivityManager am = mContext.getSystemService(ActivityManager.class);
final PackageManager pm = mContext.getPackageManager();
final int uid1 = pm.getPackageUid(TEST_APP1, 0);
final int uid2 = pm.getPackageUid(TEST_APP2, 0);
final MyUidImportanceListener uid1Listener = new MyUidImportanceListener(uid1);
final MyUidImportanceListener uid2Listener = new MyUidImportanceListener(uid2);
try {
if (!freezerWasEnabled) {
freezerEnabled = new SettingsSession<>(
@@ -346,7 +363,7 @@ public class ActivityManagerTest {
}
}
freezerDebounceTimeout = new DeviceConfigSession<>(
DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
DeviceConfig.NAMESPACE_ACTIVITY_MANAGER_NATIVE_BOOT,
CachedAppOptimizer.KEY_FREEZER_DEBOUNCE_TIMEOUT,
DeviceConfig::getLong, CachedAppOptimizer.DEFAULT_FREEZER_DEBOUNCE_TIMEOUT);
freezerDebounceTimeout.set(waitFor);
@@ -359,13 +376,20 @@ public class ActivityManagerTest {
amConstantsSettings.set(
ActivityManagerConstants.KEY_MAX_SERVICE_INACTIVITY + "=" + waitFor);
runShellCommand("cmd deviceidle whitelist +" + TEST_APP1);
runShellCommand("cmd deviceidle whitelist +" + TEST_APP2);
am.addOnUidImportanceListener(uid1Listener,
RunningAppProcessInfo.IMPORTANCE_FOREGROUND_SERVICE);
am.addOnUidImportanceListener(uid2Listener, RunningAppProcessInfo.IMPORTANCE_CACHED);
final Intent intent = new Intent();
intent.setClassName(TEST_APP1, TEST_CLASS);
final CountDownLatch latch = new CountDownLatch(1);
CountDownLatch latch = new CountDownLatch(1);
autoConnection = new MyServiceConnection(latch);
mContext.bindService(intent, autoConnection,
Context.BIND_AUTO_CREATE | Context.BIND_ALLOW_OOM_MANAGEMENT);
Context.BIND_AUTO_CREATE | Context.BIND_WAIVE_PRIORITY);
try {
assertTrue("Timeout to bind to service " + intent.getComponent(),
latch.await(AWAIT_TIMEOUT, TimeUnit.MILLISECONDS));
@@ -383,6 +407,37 @@ public class ActivityManagerTest {
// It still shouldn't be frozen, although it's been in cached state.
assertFalse(TEST_APP1 + " shouldn't be frozen now.", isAppFrozen(TEST_APP1));
final CountDownLatch[] latchHolder = new CountDownLatch[1];
final IRemoteCallback callback = new IRemoteCallback.Stub() {
@Override
public void sendResult(Bundle bundle) {
if (bundle != null) {
latchHolder[0].countDown();
}
}
};
// Bind from app1 to app2 without BIND_WAIVE_PRIORITY.
final Bundle extras = new Bundle();
extras.putBinder(EXTRA_CALLBACK, callback.asBinder());
latchHolder[0] = new CountDownLatch(1);
sendCommand(COMMAND_BIND_SERVICE, TEST_APP1, TEST_APP2, extras);
assertTrue("Timed out to bind to " + TEST_APP2, latchHolder[0].await(
waitFor, TimeUnit.MILLISECONDS));
// Stop service in app1
extras.clear();
sendCommand(COMMAND_STOP_SELF, TEST_APP1, TEST_APP1, extras);
assertTrue(TEST_APP2 + " should be in cached", uid2Listener.waitFor(
RunningAppProcessInfo.IMPORTANCE_CACHED, waitFor));
// Wait for the freezer kick in if there is any.
Thread.sleep(waitFor * 4);
// It still shouldn't be frozen, although it's been in cached state.
assertFalse(TEST_APP2 + " shouldn't be frozen now.", isAppFrozen(TEST_APP2));
} finally {
toggleScreenOn(true);
if (amConstantsSettings != null) {
@@ -397,9 +452,26 @@ public class ActivityManagerTest {
if (autoConnection != null) {
mContext.unbindService(autoConnection);
}
am.removeOnUidImportanceListener(uid1Listener);
am.removeOnUidImportanceListener(uid2Listener);
sendCommand(COMMAND_UNBIND_SERVICE, TEST_APP1, TEST_APP2, null);
sendCommand(COMMAND_UNBIND_SERVICE, TEST_APP2, TEST_APP1, null);
runShellCommand("cmd deviceidle whitelist -" + TEST_APP1);
runShellCommand("cmd deviceidle whitelist -" + TEST_APP2);
}
}
private void sendCommand(int command, String sourcePkg, String targetPkg, Bundle extras) {
final Intent intent = new Intent();
intent.setClassName(sourcePkg, TEST_CLASS);
intent.putExtra(EXTRA_COMMAND, command);
intent.putExtra(EXTRA_TARGET_PACKAGE, targetPkg);
if (extras != null) {
intent.putExtras(extras);
}
mContext.startService(intent);
}
private boolean isFreezerEnabled() throws Exception {
final String output = runShellCommand("dumpsys activity settings");
final Matcher matcher = Pattern.compile("\\b" + CachedAppOptimizer.KEY_USE_FREEZER

View File

@@ -16,29 +16,106 @@
package com.android.servicestests.apps.simpleservicetestapp;
import android.app.Service;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.os.IRemoteCallback;
import android.os.Process;
import android.os.RemoteException;
import android.util.ArrayMap;
import android.util.Log;
public class SimpleService extends Service {
private static final String TAG = "SimpleService";
private static final String TEST_CLASS =
"com.android.servicestests.apps.simpleservicetestapp.SimpleService";
private static final String EXTRA_CALLBACK = "callback";
private static final String EXTRA_COMMAND = "command";
private static final String EXTRA_FLAGS = "flags";
private static final String EXTRA_TARGET_PACKAGE = "target_package";
private static final int COMMAND_INVALID = 0;
private static final int COMMAND_EMPTY = 1;
private static final int COMMAND_BIND_SERVICE = 2;
private static final int COMMAND_UNBIND_SERVICE = 3;
private static final int COMMAND_STOP_SELF = 4;
private ArrayMap<String, ServiceConnection> mServiceConnections = new ArrayMap<>();
private final IRemoteCallback.Stub mBinder = new IRemoteCallback.Stub() {
@Override
public void sendResult(Bundle bundle) {
Process.killProcess(Process.myPid());
if (bundle == null) {
Process.killProcess(Process.myPid());
} else {
// No-op for now.
}
}
};
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.i(TAG, "onStartCommand");
int command = intent.getIntExtra(EXTRA_COMMAND, COMMAND_INVALID);
if (command != COMMAND_INVALID) {
final String targetPkg = intent.getStringExtra(EXTRA_TARGET_PACKAGE);
Log.i(TAG, "Received command " + command + " targetPkg=" + targetPkg);
switch (command) {
case COMMAND_BIND_SERVICE:
final Bundle extras = intent.getExtras();
bindToService(targetPkg, intent.getIntExtra(EXTRA_FLAGS, 0),
IRemoteCallback.Stub.asInterface(extras.getBinder(EXTRA_CALLBACK)));
break;
case COMMAND_UNBIND_SERVICE:
unbindService(targetPkg);
break;
case COMMAND_STOP_SELF:
stopSelf();
return START_NOT_STICKY;
}
}
return START_STICKY;
}
private void bindToService(String targetPkg, int flags, IRemoteCallback callback) {
Intent intent = new Intent();
intent.setClassName(targetPkg, TEST_CLASS);
final ServiceConnection conn = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
if (callback != null) {
try {
callback.sendResult(new Bundle());
} catch (RemoteException e) {
}
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
if (getApplicationContext().bindService(intent, conn, BIND_AUTO_CREATE | flags)) {
mServiceConnections.put(targetPkg, conn);
} else if (callback != null) {
try {
callback.sendResult(null);
} catch (RemoteException e) {
}
}
}
private void unbindService(String targetPkg) {
final ServiceConnection conn = mServiceConnections.remove(targetPkg);
if (conn != null) {
getApplicationContext().unbindService(conn);
}
}
@Override
public IBinder onBind(Intent intent) {
return mBinder;