Loading core/java/android/content/Context.java +13 −0 Original line number Diff line number Diff line Loading @@ -513,9 +513,22 @@ 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 Loading services/core/java/com/android/server/am/ConnectionRecord.java +3 −3 Original line number Diff line number Diff line Loading @@ -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, Loading Loading @@ -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 "); Loading services/core/java/com/android/server/am/OomAdjuster.java +8 −1 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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? Loading Loading @@ -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 Loading services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java +64 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -1589,6 +1590,69 @@ public class MockingOomAdjusterTests { SCHED_GROUP_DEFAULT); } @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() { Loading Loading
core/java/android/content/Context.java +13 −0 Original line number Diff line number Diff line Loading @@ -513,9 +513,22 @@ 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 Loading
services/core/java/com/android/server/am/ConnectionRecord.java +3 −3 Original line number Diff line number Diff line Loading @@ -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, Loading Loading @@ -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 "); Loading
services/core/java/com/android/server/am/OomAdjuster.java +8 −1 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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? Loading Loading @@ -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 Loading
services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java +64 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -1589,6 +1590,69 @@ public class MockingOomAdjusterTests { SCHED_GROUP_DEFAULT); } @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() { Loading