diff options
4 files changed, 88 insertions, 4 deletions
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java index 4d56c1dcaa80..907db7df68d5 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -513,10 +513,23 @@ public abstract class Context { * restart. There is no guarantee this will be respected, as the system * tries to balance such requests from one app vs. the importance of * keeping other apps around. + * + * @deprecated Repurposed to {@link #BIND_TREAT_LIKE_VISIBLE_FOREGROUND_SERVICE}. */ + @Deprecated public static final int BIND_VISIBLE = 0x10000000; /** + * @hide Flag for {@link #bindService}: Treat the binding as hosting a foreground service + * and also visible to the user. That is, the app hosting the service will get its process state + * bumped to the {@link android.app.ActivityManager#PROCESS_STATE_FOREGROUND_SERVICE}, + * and it's considered as visible to the user, thus less likely to be expunged from memory + * on low memory situations. This is intented for use by processes with the process state + * better than the {@link android.app.ActivityManager#PROCESS_STATE_TOP}. + */ + public static final int BIND_TREAT_LIKE_VISIBLE_FOREGROUND_SERVICE = 0x10000000; + + /** * @hide * Flag for {@link #bindService}: Consider this binding to be causing the target * process to be showing UI, so it will be do a UI_HIDDEN memory trim when it goes diff --git a/services/core/java/com/android/server/am/ConnectionRecord.java b/services/core/java/com/android/server/am/ConnectionRecord.java index b6757c8322d4..17fff919ba20 100644 --- a/services/core/java/com/android/server/am/ConnectionRecord.java +++ b/services/core/java/com/android/server/am/ConnectionRecord.java @@ -72,7 +72,7 @@ final class ConnectionRecord { Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE, Context.BIND_FOREGROUND_SERVICE, Context.BIND_TREAT_LIKE_ACTIVITY, - Context.BIND_VISIBLE, + Context.BIND_TREAT_LIKE_VISIBLE_FOREGROUND_SERVICE, Context.BIND_SHOWING_UI, Context.BIND_NOT_VISIBLE, Context.BIND_NOT_PERCEPTIBLE, @@ -225,8 +225,8 @@ final class ConnectionRecord { if ((flags & Context.BIND_SCHEDULE_LIKE_TOP_APP) != 0) { sb.append("SLTA "); } - if ((flags&Context.BIND_VISIBLE) != 0) { - sb.append("VIS "); + if ((flags & Context.BIND_TREAT_LIKE_VISIBLE_FOREGROUND_SERVICE) != 0) { + sb.append("VFGS "); } if ((flags&Context.BIND_SHOWING_UI) != 0) { sb.append("UI "); diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java index 3ae8b980a311..e7fcc5989467 100644 --- a/services/core/java/com/android/server/am/OomAdjuster.java +++ b/services/core/java/com/android/server/am/OomAdjuster.java @@ -39,6 +39,7 @@ import static android.app.ActivityManager.PROCESS_STATE_PERSISTENT_UI; import static android.app.ActivityManager.PROCESS_STATE_SERVICE; import static android.app.ActivityManager.PROCESS_STATE_TOP; import static android.app.ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND; +import static android.content.Context.BIND_TREAT_LIKE_VISIBLE_FOREGROUND_SERVICE; import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_CAMERA; import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_LOCATION; import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_MICROPHONE; @@ -2061,6 +2062,10 @@ public class OomAdjuster { newAdj = ProcessList.PERCEPTIBLE_APP_ADJ; } else if (clientAdj >= ProcessList.PERCEPTIBLE_APP_ADJ) { newAdj = clientAdj; + } else if (cr.hasFlag(BIND_TREAT_LIKE_VISIBLE_FOREGROUND_SERVICE) + && clientAdj <= ProcessList.VISIBLE_APP_ADJ + && adj > ProcessList.VISIBLE_APP_ADJ) { + newAdj = ProcessList.VISIBLE_APP_ADJ; } else { if (adj > ProcessList.VISIBLE_APP_ADJ) { // TODO: Is this too limiting for apps bound from TOP? @@ -2097,7 +2102,9 @@ public class OomAdjuster { // processes). These should not bring the current process // into the top state, since they are not on top. Instead // give them the best bound state after that. - if (cr.hasFlag(Context.BIND_FOREGROUND_SERVICE)) { + if (cr.hasFlag(BIND_TREAT_LIKE_VISIBLE_FOREGROUND_SERVICE)) { + clientProcState = PROCESS_STATE_FOREGROUND_SERVICE; + } else if (cr.hasFlag(Context.BIND_FOREGROUND_SERVICE)) { clientProcState = PROCESS_STATE_BOUND_FOREGROUND_SERVICE; } else if (mService.mWakefulness.get() == PowerManagerInternal.WAKEFULNESS_AWAKE diff --git a/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java b/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java index 2f68306e9ba1..8d59dce29bd9 100644 --- a/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java +++ b/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java @@ -30,6 +30,7 @@ import static android.app.ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND; import static android.app.ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND; import static android.app.ActivityManager.PROCESS_STATE_LAST_ACTIVITY; import static android.app.ActivityManager.PROCESS_STATE_NONEXISTENT; +import static android.app.ActivityManager.PROCESS_STATE_PERSISTENT; import static android.app.ActivityManager.PROCESS_STATE_PERSISTENT_UI; import static android.app.ActivityManager.PROCESS_STATE_RECEIVER; import static android.app.ActivityManager.PROCESS_STATE_SERVICE; @@ -1591,6 +1592,69 @@ public class MockingOomAdjusterTests { @SuppressWarnings("GuardedBy") @Test + public void testUpdateOomAdj_DoOne_TreatLikeVisFGS() { + final ProcessRecord app1 = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID, + MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false)); + final ProcessRecord app2 = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID, + MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false)); + final ProcessRecord client1 = spy(makeDefaultProcessRecord(MOCKAPP3_PID, MOCKAPP3_UID, + MOCKAPP3_PROCESSNAME, MOCKAPP3_PACKAGENAME, false)); + final ProcessRecord client2 = spy(makeDefaultProcessRecord(MOCKAPP4_PID, MOCKAPP4_UID, + MOCKAPP4_PROCESSNAME, MOCKAPP4_PACKAGENAME, false)); + client1.mState.setMaxAdj(PERSISTENT_PROC_ADJ); + client2.mState.setMaxAdj(PERSISTENT_PROC_ADJ); + + final ServiceRecord s1 = bindService(app1, client1, null, + Context.BIND_TREAT_LIKE_VISIBLE_FOREGROUND_SERVICE, mock(IBinder.class)); + final ServiceRecord s2 = bindService(app2, client2, null, + Context.BIND_IMPORTANT, mock(IBinder.class)); + + sService.mOomAdjuster.updateOomAdjLocked(app1, OomAdjuster.OOM_ADJ_REASON_NONE); + sService.mOomAdjuster.updateOomAdjLocked(app2, OomAdjuster.OOM_ADJ_REASON_NONE); + + assertProcStates(app1, PROCESS_STATE_FOREGROUND_SERVICE, VISIBLE_APP_ADJ, + SCHED_GROUP_DEFAULT); + assertProcStates(app2, PROCESS_STATE_PERSISTENT, PERSISTENT_SERVICE_ADJ, + SCHED_GROUP_DEFAULT); + + bindService(app2, client1, s2, Context.BIND_TREAT_LIKE_VISIBLE_FOREGROUND_SERVICE, + mock(IBinder.class)); + sService.mOomAdjuster.updateOomAdjLocked(app2, OomAdjuster.OOM_ADJ_REASON_NONE); + assertProcStates(app2, PROCESS_STATE_PERSISTENT, PERSISTENT_SERVICE_ADJ, + SCHED_GROUP_DEFAULT); + + s1.getConnections().clear(); + s2.getConnections().clear(); + client1.mState.setMaxAdj(UNKNOWN_ADJ); + client2.mState.setMaxAdj(UNKNOWN_ADJ); + client1.mServices.setHasForegroundServices(true, 0); + client2.mState.setHasOverlayUi(true); + + bindService(app1, client1, s1, Context.BIND_TREAT_LIKE_VISIBLE_FOREGROUND_SERVICE, + mock(IBinder.class)); + bindService(app2, client2, s2, Context.BIND_TREAT_LIKE_VISIBLE_FOREGROUND_SERVICE, + mock(IBinder.class)); + + sService.mOomAdjuster.updateOomAdjLocked(app1, OomAdjuster.OOM_ADJ_REASON_NONE); + sService.mOomAdjuster.updateOomAdjLocked(app2, OomAdjuster.OOM_ADJ_REASON_NONE); + + assertProcStates(app1, PROCESS_STATE_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ, + SCHED_GROUP_DEFAULT); + assertProcStates(app2, PROCESS_STATE_IMPORTANT_FOREGROUND, PERCEPTIBLE_APP_ADJ, + SCHED_GROUP_DEFAULT); + + client2.mState.setHasOverlayUi(false); + doReturn(PROCESS_STATE_TOP).when(sService.mAtmInternal).getTopProcessState(); + doReturn(client2).when(sService).getTopApp(); + sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE); + + sService.mOomAdjuster.updateOomAdjLocked(app2, OomAdjuster.OOM_ADJ_REASON_NONE); + assertProcStates(app2, PROCESS_STATE_BOUND_TOP, VISIBLE_APP_ADJ, + SCHED_GROUP_DEFAULT); + } + + @SuppressWarnings("GuardedBy") + @Test public void testUpdateOomAdj_UidIdle_StopService() { final ProcessRecord app1 = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID, MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false)); |