How to simulate Android killing my process

Android

Android Problem Overview


Android will kill a process if it is in the background and the OS decides it needs the resources (RAM, CPU, etc.). I need to be able to simulate this behaviour during testing so that I can ensure that my application is behaving correctly. I want to be able to do this in an automated way so that I can test if the application behaves correctly whenever this happens, which means that I'll have to test this in every activity, etc.

I know how to kill my process. That isn't the problem. The problem is that when I kill my process (using DDMS, adb shell kill, Process.killProcess(), etc.) Android does not restart it the same way that it would if the Android OS had killed it itself.

If the Android OS kills the process (due to resource requirements), when the user returns to the application Android will recreate the process and then recreate the top activity on the activity stack (calling onCreate()).

On the other hand, if I kill the process, Android assumes that the activity on the top of the activity stack was badly behaved, so it automatically recreates the process and then removes the top activity from the activity stack and recreates the activity that was underneath the top activity (calling onCreate()`). This is not the behaviour I want. I want the same behaviour as when Android kills the process.

Just to explain pictorially, if my activity stack looks like this:

    ActivityA -> ActivityB -> ActivityC -> ActivityD

If Android kills the process and the user returns to the application, Android recreates the process and creates ActivityD.

If I kill the process, Android recreates the process and creates ActivityC.

Android Solutions


Solution 1 - Android

The best way to test this for me was doing this:

  • Open ActivityD in your application
  • Press Home button
  • Press Terminate Application in Logcat window in Android Studio (this will kill the app process, make sure you select your device and process in Logcat dropdowns at top)
  • Get back to the application with Home long press or opened apps (depends on the device)
  • Application will start in recreated ActivityD (ActivityA, ActivityB, ActivityC are dead and will be recreated when you get back to them)

On some devices you can also get back to application (ActivityD) with Applications -> Your launcher icon but on other devices it will start the ActivityA instead.

This is what Android docs are saying about that:

> Normally, the system clears a task (removes all activities from the stack above the root activity) in certain situations when the user re-selects that task from the home screen. Typically, this is done if the user hasn't visited the task for a certain amount of time, such as 30 minutes.

Solution 2 - Android

This seems to work for me:

adb shell am kill <package_name>

This is different to adb shell kill mentioned by the OP.

Note that the help for the am kill command says:

am kill: Kill all processes associated with <PACKAGE>.  Only kills.
  processes that are safe to kill -- that is, will not impact the user
  experience.

So, it won't kill the process if it is in the foreground. This seems to work as the OP wanted in that if I navigate away from my app, then run adb shell am kill <package_name> it will kill the app (I've confirmed this using ps on the device). Then if I return to the app I'm back in the activity I was in previously - i.e. in the OP's example the process gets recreated and creates ActivityD (rather than ActivityC like most other methods of killing seem to trigger).

Sorry I'm a couple of years late for the OP, but hopefully others will find this useful.

Solution 3 - Android

Another method, probably one that is scriptable since it doesn't require DDMS:

One time setup: go to Developer Options, select Background process limit setting, change value from 'Standard Limit' to 'No background processes'.

When you need to restart the process, press the home button. The process will be killed (you can verify in logcat/Android Monitor in studio -- the process will be marked [DEAD]). Then switch back to the app using the task switcher.

Solution 4 - Android

This question is old but, there is an answer for this question which does not require adb, Android Studio etc. The only requirement is API 23 or newer.

To simulate app restart by OS, go app settings while your app is running, disable (then you can enable) a permission and return the app from recent apps. When permission is disabled, the OS kills the app but keeps saved instance states. When user returns the app, the app and the last activity (with saved state) are recreated.

'No background processes' method sometimes causes same behavior, but not always. For example, if the app is running a background service, "No background processes" does nothing. But the app can be killed by system including its services. Permission method works even if app has a service.

Example:

Our app has two activities. ActivityA is main activity which is started from launcher. ActivityB is started from ActivityA. I will show only onCreate, onStart, onStop, onDestroy methods. Android calls onSaveInstanceState always before calling onStop, because an activity which is on stop state can be killed by system. [https://developer.android.com/reference/android/app/Activity.html#ActivityLifecycle]

Permission method:

<start app from launcher first time>
Application onCreate
ActivityA onCreate WITHOUT savedInstance
ActivityA onStart
<open ActivityB>
ActivityB onCreate WITHOUT savedInstance
ActivityB onStart
ActivityA onStop (the order is like this, it is stopped after new one is started)
<go settings>
ActivityB onStop
<disable a permission>
//Application is killed, but onDestroy methods are not called.
//Android does not call onDestroy methods if app will be killed.
<return app by recent apps>
Application onCreate (this is the important part. All static variables are reset.)
ActivityB onCreate WITH savedInstance (user does not notice activity is recreated)
//Note that ActivityA is not created yet, do not try to access it.
ActivityB onStart
<return ActivityA by back>
ActivityA onCreate WITH savedInstance (user does not notice activity is recreated)
ActivityA onStart
ActivityB onStop
ActivityB onDestroy
<press back again, return launcher>
ActivityA onStop
ActivityA onDestroy
<open app again>
//does not call Application onCreate, app was not killed
ActivityA onCreate WITHOUT savedInstance
ActivityA onStart

I want to compare other methods which are mentioned on the other answers.

Do not keep activities: This does not kill application.

<start app from launcher first time>
Application onCreate
ActivityA onCreate WITHOUT savedInstance
ActivityA onStart
<open ActivityB>
ActivityB onCreate WITHOUT savedInstance
ActivityB onStart
ActivityA onStop
ActivityA onDestroy (do not keep)
<return launcher by home button>
ActivityB onStop
ActivityB onDestroy (do not keep) 
<retun app from recent apps>
// NO Application onCreate
ActivityB onCreate WITH savedInstance (user does not notice activity recreated)
ActivityB onStart
<return ActivityA by back>
ActivityA onCreate WITH savedInstance (user does not notice activity recreated)
ActivityA onStart
ActivityB onStop
ActivityB onDestroy
<press back again, return launcher>
ActivityA onStop
ActivityA onDestroy
<open app again>
//does not call Application onCreate, app was not killed
ActivityA onCreate WITHOUT savedInstance
ActivityA onStart

Force stop method: Does not store saved instance states

<start app from launcher first time>
Application onCreate
ActivityA onCreate WITHOUT savedInstance
ActivityA onStart
<open ActivityB>
ActivityB onCreate WITHOUT savedInstance
ActivityB onStart
ActivityA onStop
<go settings>
ActivityB onStop
<force stop, return app from recent apps>
Application onCreate
ActivityA onCreate WITHOUT savedInstance 
//This is important part, app is destroyed by user.
//Root activity of the task is started, not the top activity.
//Also there is no savedInstance.

Solution 5 - Android

Put the application in background with HOME button

Select your process in "Logcat" mode in Android Studio, then click Terminate Application in the bottomleft corner

terminate button

Now launch your app from launcher on Android device


EDIT: According to the internet, the following also works:

 adb shell am kill [my-package-name]

EDIT from the future: Something to note, there has been a change in Android Studio 4.0, if you use Run from AS, then Terminate will issue a Force Stop.

However, if you launch from the launcher afterwards, and THEN you try to simulate it this way, then you'll get the results you want (low memory behavior).

Solution 6 - Android

I'm very late to the party and several before me gave the same correct answer but to simplify for whoever comes after me just press home button and run this command:

adb shell ps | grep <package name> | awk '{print $2}' | xargs adb shell run-as <package name again> kill

The app won't lose state and from my own experience this works the same way as the OS killed the app in the background. This works only for debug built applications

Solution 7 - Android

This is how you do it in Android Studio.

  1. Have your device in Debug Mode connected to your computer.
  2. Open the app on your device and go to whichever activity you want to test the "Return to it from the dead".
  3. Press Home button on your device.
  4. In Android Studio go to Android Monitor -> Monitors and press the Terminate Application icon.
  5. Now you can either go back to your app through the recent apps or by clicking on it's launcher icon, behaviour has been the same in my tests.

Solution 8 - Android

You can do next steps to reproduce sought-for behaviour:

  1. Open your app, navigate to top activity
  2. Use notification panel to navigate to any another full-screen application (for example, to system settings - in right top corner)
  3. Kill your application process
  4. Press back button

Solution 9 - Android

In the Developer options under Settings, select 'Do not keep activities', which will destroy activities as soon as you navigate away from them.

Note: As per a helpful comment below, only use this if you don't care about static values being cleared.

Solution 10 - Android

Press the Home button and put the app in the background first. Then stop or kill the process from DDMS or ADB.

Solution 11 - Android

You can also connect to your device/emulator from terminal with adb shell, then get PID of your process with ps | grep <your_package_name and execute kill -9 <pid>. Then open your minimized app from recent apps picker and it will restart last activity

Solution 12 - Android

The root of your problem seems to be that your Activity is in foreground when you kill the process.

You can observe this by pressing stop in DDMS when Activity is visible (happens exactly what you describe) and comparing that to pressing stop after home and later returning to the app.

Just make sure to moveTaskToBack(true) somehow in your tests.

Solution 13 - Android

I'm not sure this is the answer you are looking for, it's more like a logic think.

I don't think that you can really make a fully automated test, the only way to simulate it, it will be to recreate it, AKA have so many activities that Android will kill your application.

So my idea or suggestion is to make another small app, which keeps popping up new activities, till Android runs out of memory and start killing process it the background.

Something among the line:

Start activity i -> Check running process if the app is in the list, increment i and restart the loop without closing current activity, else -> decrease i and close current activity, go back to previous and recheck...

Solution 14 - Android

When the application process dies, Android goes through the activities records (the entries represent activities in the history stack), and decides which ones to keep in the history and which ones to remove from it.

One of the key points here is the ActivityRecord field called haveState, which Android Framework engineers describe as "have we gotten the last activity state?".

By default, Android considers that activity has a state. The activity becomes stateless when the application reports to the activity task manager service that activity has resumed and this is valid until the application notifies framework that activity has entered the Stopped state. In simple words, haveState value is false between activity onResume() is called and onStop() or onSaveInstanceState() is invoked, depending on the application target version.

> If I kill the process, Android recreates the process and creates ActivityC.

In this case ActivityD does not have android:stateNotNeeded="true" attribute in the application manifest and it is currently running in the foreground, so Android removes it from the history as the system has not gotten its last state.

> How to simulate Android killing my process

As it was mentioned several times, you can simply move the application into the background, so the top activity in the activity back stack will save its state, and after that you can kill the application process through Android Debug Bridge, Android Studio or using the Background Processes Limit property in the Developer Options. After that your recent activity will be successfully recreated.

Despite that, there is also another simple way to test the application process death scenario. Knowing all the described above and the fact, that if you start new ActivityE from the currently running ActivityD, then the ActivityD onStop() callback is invoked only after the ActivityE onResume() method, you can do the following trick.

class TerminatorActivity : Activity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        val isPrePie = applicationInfo.targetSdkVersion < Build.VERSION_CODES.P
        val callbacks = TerminatorLifecycleCallbacks(isPrePie)
        (applicationContext as Application).registerActivityLifecycleCallbacks(callbacks)
    }

    private class TerminatorLifecycleCallbacks(
        // Before P onSaveInstanceState() was called before onStop(), starting with P it's
        // called after
        // Used to schedule the death as app reports server that activity has stopped
        // after the latest of these was invoked
        private val isPrePie: Boolean
    ) : ActivityLifecycleCallbacksDefault {

        private val handler = Handler(Looper.getMainLooper())

        override fun onActivityPostStopped(activity: Activity) {
            if (isPrePie) {
                terminate()
            }
        }

        override fun onActivityPostSaveInstanceState(activity: Activity, outState: Bundle) {
            if (!isPrePie) {
                terminate()
            }
        }

        fun terminate() {
            handler.postDelayed(
                {
                    Process.killProcess(Process.myPid()) // This is the end... 
                },
                LAST_MILLIS
            )
        }

        companion object {
            // Let's wait for a while, so app can report and server can handle the update
            const val LAST_MILLIS = 100L
        }

    }

    private interface ActivityLifecycleCallbacksDefault : Application.ActivityLifecycleCallbacks {
        override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) {}
        override fun onActivityStarted(activity: Activity) {}
        override fun onActivityResumed(activity: Activity) {}
        override fun onActivityPaused(activity: Activity) {}
        override fun onActivityStopped(activity: Activity) {}
        override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle) {}
        override fun onActivityDestroyed(activity: Activity) {}
    }
}

Then just start TerminatorActivity when you want to kill the application.

At the end there is a lightweight tool that simplifies testing of your application process death, called Venom.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionDavid WasserView Question on Stackoverflow
Solution 1 - AndroidMarkView Answer on Stackoverflow
Solution 2 - AndroidHexAndBugsView Answer on Stackoverflow
Solution 3 - AndroidMerkView Answer on Stackoverflow
Solution 4 - AndroidfthdgnView Answer on Stackoverflow
Solution 5 - AndroidEpicPandaForceView Answer on Stackoverflow
Solution 6 - AndroidHirschenView Answer on Stackoverflow
Solution 7 - AndroiddbarView Answer on Stackoverflow
Solution 8 - AndroidIgor KostominView Answer on Stackoverflow
Solution 9 - AndroidMSpeedView Answer on Stackoverflow
Solution 10 - AndroidMonstieurView Answer on Stackoverflow
Solution 11 - AndroidqbassoView Answer on Stackoverflow
Solution 12 - AndroidMaciejGórskiView Answer on Stackoverflow
Solution 13 - AndroidEmil BorconiView Answer on Stackoverflow
Solution 14 - AndroidivkilView Answer on Stackoverflow