4

The Android process lifecycle documentation details the various states the application process may be in and how it relates to the visibility of the UI to the user.

For example, when the user switches from one Activity to another and the first Activity is no longer visible, the process containing the first Activity will enter the "cached" state.

The documentation also gives some detail about how the system decides to evict process based on the state the process is in.

I cannot however, find any documentation on what the different process lifecycle states mean from a CPU scheduling standpoint.

Specifically, are cached processes no longer scheduled on the CPU? Or can they still execute code? I.e. does the system actually freeze the cached processes, or do they actually execute code but are just not visible to the user and and more likely to be killed?

This is a related question, but the focuses on the memory usage and evictability, rather than CPU scheduling.

user2771609
  • 1,867
  • 1
  • 15
  • 36
  • 2
    Possible duplicate of [On Android, what's the difference between running processes and cached background processes?](https://stackoverflow.com/questions/14259504/on-android-whats-the-difference-between-running-processes-and-cached-backgroun). A "cached process" is *NOT* scheduled on the CPU. – paulsm4 Jun 30 '18 at 16:55
  • The question is focused on memory usage and evictability it seems. Neither of which I have any doubts about. – user2771609 Jun 30 '18 at 18:14
  • Read here for more info about "Processes" vs. "threads": https://www.thegeekstuff.com/2013/11/linux-process-and-threads/. Read here for another definition of "cached process": https://android.stackexchange.com/questions/71653/what-is-a-cached-background-process. You're basically asking the same question which has already been implicitly answered: "cached process" means *NOT SCHEDULED TO RUN*! It exists merely as an "optimization" - faster (re)start if a user or service manually activates it. – paulsm4 Jun 30 '18 at 18:59
  • So it looks like all this information is wrong unfortunately. See the accepted answer below and the comments. I tested and can confirm: cached processes ARE STILL SCHEDULED TO RUN! – user2771609 Jun 30 '18 at 19:08

1 Answers1

2

Specifically, are cached processes no longer scheduled on the CPU?

I don't usually think of processes being scheduled on a CPU. I think of threads as being scheduled on a CPU. Perhaps we are just using the terms differently.

A cached process' threads are no different than any other process' threads. Ideally, a cached process only has threads that are blocked waiting on something (e.g., IPC from a core OS process, telling the app process to start another activity in response to the user pressing a icon from the home screen). However, there is nothing stopping an app from having leaked some thread that continues running, for however long that process remains cached.

For example, you could create an app with a single activity like this:

class MainActivity : AppCompatActivity() {
  override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)

    Executors
        .newSingleThreadScheduledExecutor()
        .scheduleAtFixedRate({ Log.e("BadWolves", "Zombie!") }, 5, 5, TimeUnit.SECONDS)

    finish()
  }
}

Here, I fork a zombie thread, then finish() the activity. The process moves into the cached state fairly quickly, once the activity is destroyed. Yet, the zombie thread continues logging to LogCat.

How long it logs to LogCat varies by OS version and perhaps manufacturer tweaks. So, for example, on the Pixel 2 that I just tossed this onto, it has been logging for 10 minutes, which frankly is longer than I would have expected on Android 8.1.

This would mean that it was the duty of every app in existence to implement pausing correctly when backgrounded.

Yes, to an extent. The OS can terminate your process at any point, and cached processes are prime candidates to be terminated when system RAM is needed. So, leaked threads usually don't live all that long, because cached processes usually don't live all that long. Part of the reason why my zombie is staggering around as long as it is is that this device isn't used for a lot, so I don't have a lot of processes coming and going, minimizing pressure on system RAM.

Now, if you'll excuse me, I need to kill a zombie...

CommonsWare
  • 986,068
  • 189
  • 2,389
  • 2,491
  • I suppose what I mean by "process no longer scheduled" is "any thread of the process no longer scheduled". – user2771609 Jun 30 '18 at 17:59
  • Hmmm. This is very surprising behavior you are suggesting. I was almost certain that cached process' threads will not get scheduled. I was more looking for conclusive documentation. This would mean that it was the duty of every app in existence to implement pausing correctly when backgrounded. – user2771609 Jun 30 '18 at 18:02
  • @user2771609: See my updated answer for more on this. – CommonsWare Jun 30 '18 at 18:15
  • So I was naively polling a server every minute using Handler.postDelayed() and almost certain that the polling would stop when the Activity was switched out. I guess I was wrong... – user2771609 Jun 30 '18 at 18:43
  • On the point of "cached processes usually don't live all that long", given the mount of RAM on devices these days, they could be around for a while... – user2771609 Jun 30 '18 at 18:45
  • @user2771609: I have not intentionally leaked a `postDelayed()` to see whether that somehow gets cleaned up when the activity is destroyed. I always try to `removeCallbacks()` to be certain. – CommonsWare Jun 30 '18 at 18:55
  • I'm been running the test now for the last 10 min, and it is most definitely running vigorously after onDestroy(). Geez. I think there is a lot of misinformation about this. Almost everybody I know assumed that the app would not run after onDestroy(). – user2771609 Jun 30 '18 at 19:03
  • Sorry I mean onStop(). Testing with Handler.postDelayed() it's been running for more than an hour. So yeah, you are absolutely right, cached processes can really consume CPU (on the UI thread even). This has been a real eye-opener for me. – user2771609 Jun 30 '18 at 21:12