213

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.

David Wasser
  • 93,459
  • 16
  • 209
  • 274
  • 4
    Could you not just create the amount of processes required to kill yours in the background? – Alex W Jul 06 '12 at 15:40
  • See also: [Prevent Activity Stack from being Restored?](http://stackoverflow.com/q/5423571/1402846) – Pang Jul 30 '13 at 08:52
  • 3
    @Pang I think you are missing the point. I know how to detect that Android has killed the process. I've got code that handles these conditions. What I want to do is to properly (and in an automated way) **test this code**. In order to do that, I need some way of being able to provoke Android to kill my process in exactly the same way as it would normally do under resource pressure. The linked question, while interesting, doesn't add any value here. – David Wasser Aug 05 '13 at 08:21
  • These resources will be helpful to you: https://developer.android.com/reference/android/content/ComponentCallbacks2.html https://github.com/schedjoules/android-event-discovery-sdk/issues/330 https://gist.github.com/android10/6c06d488c8bd83312ab0ed947f0b5b86 – IgorGanapolsky Sep 06 '17 at 15:14
  • @IgorGanapolsky Thanks for the links, but actually none of those links have solutions to the problem. – David Wasser Sep 06 '17 at 15:37
  • @DavidWasser You read the **ComponentCallbacks** spec, and tried `am send-trim-memory`?? – IgorGanapolsky Sep 06 '17 at 15:49
  • 2
    This should become a wiki post. As seen in the several misleading answers, people so rarely understand the concept of Android killing processes. – 0101100101 Oct 23 '17 at 00:19

16 Answers16

163

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.

Adam Johns
  • 35,397
  • 25
  • 123
  • 176
Mark
  • 5,466
  • 3
  • 23
  • 24
  • 2
    Thanks for your answer but it isn't useful to me because I need an automated way to do this, for automated testing. – David Wasser Sep 09 '13 at 10:26
  • 1
    This was really helpful for me. – John Roberts Dec 19 '13 at 01:19
  • 7
    This isn't automated but it worked perfectly for my purposes. It's very important not to skip **step 2**. You must send the app to the background before stopping the process in DDMS for this to work. For those wondering where the doc quotes came from it's [here](http://developer.android.com/guide/topics/manifest/activity-element.html#always). Although I'm not sure they're actually related to the topic since it's about the `` tag in the manifest. – Tony Chan Apr 24 '14 at 02:23
  • 1
    Exactly what I needed. Thank you. For those that don't know, DDMS is in Eclipse, go to Window -> Open Perspective, and you should find it there. – Richard Jul 13 '14 at 13:43
  • 4
    Alternatively you could go to "Development options" and set background limit to "no background processes" then every time you press home the process will die. – Joao Gavazzi Jun 02 '16 at 05:33
  • Too sad they use ddms to pass the cmd for terminate the application. otherwise it would be cooler and easier to debug using command line tools. https://github.com/JetBrains/android/blob/d2567ab45cd6a284f5d7151f88df4ccf0458b0f8/android/src/com/android/tools/idea/ddms/actions/TerminateVMAction.java – Shu Zhang Apr 24 '17 at 07:00
  • @JoaoGavazzi Even after setting background limit to "no background processes", I could see my app still running using DDMS. So, I am afraid the option which you said is not an alternate solution to the one mentioned in this answer. I wanted to try your solution as DDMS is deprecated. But, unfortunately your solution does not seem to work for me. – garnet Feb 23 '18 at 12:47
  • 3
    No longer possible in IDE as of Electric Eel (the terminate button moved and changed functionality to force stop the app process). @HexAndBug's solution works however - https://stackoverflow.com/a/26890214/692167 – Tom Mar 01 '23 at 20:22
  • @Tom In Android Studio 2022 (Electric Eel), the old Logcat window can still be enabled in settings under "Experimental" > uncheck "Enable new Logcat tool window". – jvn91173 May 05 '23 at 17:07
86

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.

HexAndBugs
  • 5,549
  • 2
  • 27
  • 36
  • 2
    Thanks! this is what I was looking for! I want to specify that this command behaves differently than `adb shell am force-stop`. Tha last one will also remove any pendingIntent related to your app (like Notifications) while the first one don't. – bonnyz Mar 11 '15 at 15:32
  • Points to anyone who investigates the OS source code to see what code it runs when it kills a process to reclaim memory - my bet is it's the same code as `am kill`. – androidguy Jul 26 '17 at 20:10
  • doesn't work on Android 7.1 Samsung J5. `ps` shows my app – Valgaal Feb 13 '19 at 20:30
  • This does not work if the app is running some services in the background – Jokubas Trinkunas Dec 05 '21 at 19:49
  • This doesn't work for me at all. I built a simple hello world app with one activity that calls another and no services, made sure to press the home button, and it didn't work - nothing happens. `adb shell am force-stop` does work for me, but when I go back to the app, the previous activity is gone and it returns to the default activity. I am using an emulated Pixel 4 with API 24 in Android Studio if that makes any difference. – jvn91173 May 05 '23 at 17:11
21

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.

Merk
  • 1,441
  • 1
  • 15
  • 28
  • 2
    Interesting. I think that doesn't effect Foreground Services, right? – IgorGanapolsky Sep 06 '17 at 13:46
  • I need to do this on actual devices running Android as old as 2.3.3, so this isn't any help. – David Wasser Jul 04 '18 at 09:16
  • It worked for me, But I limit it to "at most 1process" and then opened other apps. it stimulates the exact behavior when my app is killed in the background when a user would use other apps and save memory android would kill my app – beginner Jan 30 '23 at 10:56
17

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).

EpicPandaForce
  • 79,669
  • 27
  • 256
  • 428
  • This is a duplicate answer – Onik Jul 03 '18 at 16:11
  • @Onik All the other ones have a bunch of unnecessary fluff like ddms and whatever. Though technically yeah, https://stackoverflow.com/a/41975750/2413303 says the same thing. Maybe I should add pictures. – EpicPandaForce Jul 03 '18 at 16:42
  • This isn't helpful. I have a test harness and I cannot execute these actions from the test harness. Also, the behaviour is not the same as what happens when Android kills the process. – David Wasser Jul 04 '18 at 09:14
  • `the behaviour is not the same as what happens when Android kills the process` yes it is – EpicPandaForce Jul 04 '18 at 09:21
  • This process shows me the previous activity, not the activity of when the home button is pressed. – Dale Jan 02 '19 at 00:08
  • @Dale You need to press the HOME button before you press the "terminate" button *inside android studio*. See https://stackoverflow.com/questions/49046773/singleton-object-becomes-null-after-app-is-resumed/49107399#49107399 for a visual representation. – EpicPandaForce Jan 02 '19 at 00:52
16

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.
fthdgn
  • 1,339
  • 1
  • 13
  • 18
  • ~"**app can be killed by system including its service**". Not Foreground Service... – IgorGanapolsky Sep 06 '17 at 13:51
  • @DavidWasser Read the spec! https://developer.android.com/guide/components/services.html#Foreground **A foreground service is a service that the user is actively aware of and is not a candidate for the system to kill when low on memory.** – IgorGanapolsky Sep 06 '17 at 15:50
  • 3
    @IgorGanapolsky Documentation is nice, especially if it is complete and correct (which it unfortunately isn't), but I usually rely more on actual personal observations. I've seen a foreground `Service` killed plenty of times. Even if the system is not low on memory. Most device manufacturers have written their own "optimizations" and "improvements" to the Android OS in order to save battery power. Lots of devices have much more agressive "killers" than standard Android. – David Wasser Sep 06 '17 at 16:30
  • @DavidWasser Fair observation. So after all these years, did you come up with a solution? – IgorGanapolsky Sep 06 '17 at 16:42
  • @IgorGanapolsky No. I've found no solution to this problem. That's why the question is still open. – David Wasser Sep 06 '17 at 16:48
  • Executing this process put me at the main activity, NOT the activity that was running when I pressed the home button. – Dale Jan 02 '19 at 00:33
11

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

0101100101
  • 5,786
  • 6
  • 31
  • 55
Hirschen
  • 348
  • 2
  • 7
  • I get `'grep' is not recognized as an internal or external command, operable program or batch file.` – Dale Jan 02 '19 at 00:23
  • But I did it while in the shell `run-as kill 7379`, but it put me at the previous activity, not the activity I was at when I pressed the home button. – Dale Jan 02 '19 at 00:30
  • Works for me and greatly helped to debug a sticky background service restart. – lnstadrum Sep 16 '21 at 20:27
6

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.
dbar
  • 1,740
  • 1
  • 16
  • 20
3

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
  • 1
    Thanks for your answer but it isn't useful to me because I need an automated way to do this, for automated testing. – David Wasser Feb 07 '14 at 12:01
  • So, this is the only method which I found would actually simulate Android clearing memory and killing your app (my API level is 19, and so I can't use the send-trim-memory command). Other commands such as adb shell am force-stop com.my.app.package or kill, won't reproduce the same exact process which following the procedure above will! – Mark Garcia Dec 20 '18 at 23:22
2

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.

ivkil
  • 414
  • 1
  • 4
  • 11
  • This is the most informative answer by far. After a careful read I finally understand what's going on. And a solution is even provided for automated process kills. Excellent! – jvn91173 May 22 '23 at 22:00
2

Programmatically background your app and then issue this ADB command:

adb shell am kill <PACKAGE_NAME>

Note that this is different from the command adb shell kill as described in greater deal in this excellent article by Wajahat Karim: https://wajahatkarim.com/2020/03/defending-your-app/

Please note that this is different than the command adb shell kill . That command kills the whole process of your app like the Terminate App button while adb shell am kill only kills processes that are safe to kill to reallocate resources such as memory, CPU etc.

Eric Schnipke
  • 482
  • 1
  • 6
  • 22
1

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

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

MSpeed
  • 8,153
  • 7
  • 49
  • 61
  • This is effectively the same as the solution already posted - and rejected - a year ago. The only difference seems to be the application used to set it on an emulator, vs the more recent phones that support it. – Chris Stratton May 03 '13 at 21:18
  • 1
    Sorry, as Chris Stratton says, this is pretty much the same suggestion as the other answer. This isn't about Android finishing activities. This is about Android killing the whole process (which it does, pretty regularly and effectively, especially on HTC devices running Android 4.x). – David Wasser May 04 '13 at 11:47
  • 9
    This one is almost good but it will not kill the process, it only destroys the activity. What does it mean? Your activity will be opened with savedInstanceState but all static variables are still in the process. After process kill all static variables are also cleared. – Mark Sep 09 '13 at 10:17
1

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

Monstieur
  • 7,992
  • 10
  • 51
  • 77
  • Thanks for your answer but it isn't useful to me because I need an automated way to do this, for automated testing. – David Wasser Feb 07 '14 at 12:00
  • Android will never kill your process if your activity is currently in the foreground. You're trying to test a condition that will never occur. If your activity is in the background, then its state has already been saved and there is no difference between you killing it manually and Android killing it under low memory i.e. the process is just killed; there is nothing special about a low memory kill. When memory is available again your sticky services will be restarted (except on 4.4) and when you tap the icon or recent task, the stack and activity state will be restored. – Monstieur Feb 07 '14 at 12:05
  • 3
    In your example, it's going back to Activity C because you killed the process while Activity D was visible on the screen (this will never occur even under low memory) and Activity C's state was saved since it's in the background. Your process will only be killed if it's not in the foreground at all i.e. Activity D's state would have been saved when it went to the background and thus will be restored even if your process is killed. In order to perform your tests on each activity, you HAVE to send the app to the background first before you kill it. – Monstieur Feb 07 '14 at 12:11
  • What did you mean by ~"**and put the app in the background first**"? – IgorGanapolsky Sep 06 '17 at 14:00
1

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

qbasso
  • 431
  • 5
  • 11
0

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.

MaciejGórski
  • 22,187
  • 7
  • 70
  • 94
0

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...

Emil Borconi
  • 3,326
  • 2
  • 24
  • 40
0

Answer:

Run your app on the emulator and then run these commands:

adb root
adb shell ps | grep com.your.app_package | awk '{print $2}' | xargs adb shell kill

Explanation:

Why emulator? Because it allows you to get root access. Without root access, you get the following error for kill command:

/system/bin/sh: kill: <PID>: Operation not permitted

And you usually can't get root access for a real device to fix this error. You get the following error for adb root command:

adbd cannot run as root in production builds