1

Contrary to the traditional computing world, where programs won't quit without the user asking for it, in the mobile world (and Android in particular), it's generally considered up to the system to decide which app to quit and when, to the point where many if not most apps don't even have a quit option.

Up to some extent, it's justified due to :

  1. The limited amount of RAM available (contrary to the PC/Mac world where we've gone too far in the other direction, and the system by default considers a program can ask for as much virtual memory as it wants, which is a security problem, but that's another subject)
  2. The devices being for the general public, in a context where people don't necessarily have the knowledge/will/time to manage their phone usage on an app by app basis
  3. The apps are often designed to be used for short periods of time (which is linked to the previous point somehow)

However, there are cases where one doesn't want a given app to quit unless it's asked to explicitly by the end user. The reality of that need seems to have been taken into account by some mobile phone manufacturers (if I'm not mistaken, Samsung has been providing such an option for some time now).

So my question is : how shall I tell the system to not kill a given app ? I know there are apps that pretend to achieve this, but how shall I do that myself, without resorting to third party tools, only the stock Android command line tools and APIs ?

Afaik, there seem to be three criteria to decide to kill an app :

  1. Memory usage (the LMK daemon being in charge, unless a specific driver is present, in my case I have lmkd running)
  2. A limit on the number of running processes
  3. Battery optimisation, but there's already an option to disable that per-app, so I don't consider it a problem

So basically, only points 1 and 2 remain to be solved. You advices are welcome !

For what it's worth, I run Android x86 9.0 on an emulator (qemu).

EDIT : I checked the code of a program that's called App Settings, that's part of the Xposed framework. The program pretends to be able to set a program to stay resident in memory. After checking the code, it seems it modifies some application process attributes that are defined in the ProcessRecord class, namely maxAdj, curRawAdj, setRawAdj, curAdj and setAdj, setting those to the value of -12.

I wasn't able to test the program since my x86_64 Android 9.0 doesn't seem compatible with the framework, but I found this page, explaining in more detail how the activity manager service updates OOM values according to the app status, and communicates with LMK. It explains what the OOM values can be and what they mean. So clearly, trying to change the OOM values in /proc is useless, as the activity manager will change them, and probably LMK doesn't even read them anyway, and only takes what the activity manager transmits.

Is there any way to hint the Activity Manager into giving chosen OOM values to an app ? I could for example set the value to NATIVE_ADJ, or even no more than FOREGROUND_APP_ADJ at all times. Or maybe passing those parameters through a specially crafted intent ?

REEDIT : for those interested, the stop lmkd command should stop the LMK daemon until next reboot at least, which leaves only the OOM killer from Linux in charge. I didn't test it so I can't say for sure, but that should do it for some people. Beware of the consequences, however, if you continue using many apps at the same time, as a performance hit can be expected.

NovHak
  • 146
  • 5
  • It's not the Android system which decides which app to quit. But it's the app developer who decides whether their app (or one of its specific functionality) should run in background or not. You are correct that end user cannot influence the decision much. If an app that should run in background but it doesn't, that's a poorly designed app. // OOM killer is also part of Linux kernel and every OS has some phenomenon to free RAM when needed. Android's LMKD operates in userspace because it provides more fine grained control over what to kill, asking system_server when making decisions. – Irfan Latif Apr 16 '20 at 16:27
  • You can run a native process (like an init service) in background and that won't be killed (do take care of cgroups though). Exactly the same behavior as on a Linux PC. Android's decision to not let apps run in background is not only to free RAM but mainly to preserve battery. And also to provide user somewhat control on privacy i.e. what's happening in background without being noticed. Phones are 24/7 partners and hence perfect spying tools, PCs aren't. Btw I don't think there's a reliable way to prevent an app (which doesn't run a FG service) from being killed, even using 3rd party tools – Irfan Latif Apr 16 '20 at 16:39
  • @IrfanLatif Thanks for your reply. However I'm not speaking about an app being able to run in the background, I don't have any problem with that, but I want to have an app in the foreground, switch to something else and be sure it will be still there when I switch back to it. It is able to leave the foreground, except the system sometimes decides to remove it, which is annoying. – NovHak Apr 16 '20 at 22:38
  • 1
    Be aware of: https://dontkillmyapp.com/ realize that if the app is not actively on the screen, the app is in the Android Activity onPause state and may be killed. Programming related questions should be directed to https://stackoverflow.com/questions/tagged/android – Morrison Chang Apr 17 '20 at 00:15
  • @NovHak alright. You talked about LMKD and number of running processes, so I gave an overview of lower level things according to my limited knowledge. Now what you state in comment is a trivial problem (there exist duplicate Qs) and is entirely handled by Android framework (as you figured out in your edit and as mentioned by MorrisonChang). The logic to control app killing behavior is hard-coded in AOSP and is made more forceful by OEMs. So the only way is to modify the source code of your ROM (if available). It's development oriented question, not meant for end users (whom this site is for). – Irfan Latif Apr 17 '20 at 04:16
  • @MorrisonChang, thanks for the info. I didn't know about that problem of essentially Chinese phone manufacturers agressively killing apps, and I understand the concerns of the developers. However, on the other hand, I'm the kind of person who doesn't like invasive apps, trying to be everywhere on your phone and tracking as much as they can of your activity without leaving any choice, draining the battery as a bonus. And don't tell me not even one of those developers complaining don't fall into that category... But indeed, addressing that issue should be Google's job, not the manufacturer's – NovHak Apr 25 '20 at 14:10
  • @IrfanLatif, I didn't realise this place was not for development-oriented questions, I will redirect accordingly in the future ! In fact, I'm not necessarily looking for a developer's answer, using command line tools would be OK too. However, I have the feeling my only option will be to run stop lmkd, that's better than nothing after all. – NovHak Apr 25 '20 at 14:17
  • @NovHak stop lmkd would definitely break Activity Manager as there would be no way for AM to communicate with kernel for memory management. So the device may get into bootloop or at least zygote would keep on restarting. // I agree with your concerns that at least there should be a way to whitelist some apps from being killed in background (and in fact there should be if your device is configured to use memory cgroup on per UID basis (check ro.config.per_app_memcg)). But my point is that comparing to standard Linux distros, Android's memory management is no way worse. Actually it ... – Irfan Latif Apr 25 '20 at 17:59
  • ... relies on Linux kernel's built-in subsystems including vmpressure and cgroups to limitize the allocated memory to apps before the killing stage comes. Linux kernel alone (OOM killer) may kill anything (including critical native service e.g. HALs and frameowork apps) on memory pressure events (if there is no dirty data to flush out and no SWAP memory). It relies on oom_adj and oom_score_adj values (if set from userspace). Android at least controls what should be killed first to avoid any crash situation. Also LMKD is added in Android 9, on older devices lowmemorykiller was an ... – Irfan Latif Apr 25 '20 at 17:59
  • ... in-kernel driver which also depended on oom_score_adj values of processes but with a more fine grained control. That's why the problem you are highlighting is there since ever: https://android.stackexchange.com/questions/89544 // Now that said, what I have talked about above and what you are talking about IS NOT YOUR ACTUAL PROBLEM at all. Your problem is that the Android's Java framework (which runs in system_server native process and) which has a core component name Activity Manager puts your favorite app in a list of *cached processes* (to be killed if needed) as soon as ... – Irfan Latif Apr 25 '20 at 18:00
  • ... the app is no more in foreground. App's native process is still running (if you check using ps) and is *NOT KILLED BY LMKD* immediately (if there's not a shortage of RAM). So to keep your app running even in background (and not to get into cached processes list) the app must be in foreground or it must run a service (in Java framework, not native) or a broadcast receiver etc. Or the other way again, what I stated in my previous comments: modify Android source to change the behavior how Activity Manager puts apps in cached processes list, which is not exactly killing ... – Irfan Latif Apr 25 '20 at 18:11
  • ... the app, but is a quickly resume-able state. After modifying AM, playing with LMKD or kernel's OOM-killer would be the next step. // I hope it clarifies the situation now. Sorry for the length. I can improve and post it as answer if required. – Irfan Latif Apr 25 '20 at 18:12
  • Thanks for your reply ! However, you seem to be thinking I didn't understand something about the true cause of my problem, but I understood perfectly (or so I think). I know everything comes from the Activity Manager and it's where the problem should be addressed in the first place, but as you said, it requires a modification of the Android source code, since basically there seem to be no API or tool to do what I would like to do. Stopping lmkd should not be done on a regular basis, since it breaks Android memory management. I would only do that when running a specific app and nothing else. – NovHak Apr 28 '20 at 15:10
  • "I would only do that when running a specific app and nothing else." This statement of yours indicate that either me or you have a wrong understanding of what LMKD actually does. According to my understanding stopping LMKD won't let your app run in the background (if it's not running a foreground service). Activity Manager (if it manges somehow to keep on running after LMKD is stopped) will still put your app in a dormant state as soon as it leaves the foreground screen i.e. native virtual machine process is put in cached process list (see under Running Services in Dev Options). – Irfan Latif Apr 28 '20 at 17:54
  • What you suspect that LMKD does is achievable by setting Background Process Limit in Dev Options to "0". It's equivalent to Force stop in individual app settings. Or kill <pid> from CLI. This is not what LMKD does. – Irfan Latif Apr 28 '20 at 18:00

0 Answers0