1. Why does APP Survive?

Android applications wake up to each other is a Chinese characteristic, foreign because of Google Play’s evaluation system and basic review mechanism, there will not be such a crazy rogue design in China. One of the advantages of this is that it is convenient to collect user information, understand user habits, and optimize the product. In addition, it is necessary to push messages to users to ensure that the APP can survive when it exits the foreground, which is a hard requirement for IM applications. That’s why apps that you haven’t installed or that no one else is using can live tens of millions of lives a day.

       

Two, the means of survival

Currently, the industry’s Android process survival means are mainly divided into black, white, gray three, its general implementation ideas are as follows:

Black preservation:

Different APP processes wake up each other with broadcasts (including system-provided broadcasts)

Scenario 1: Wake up the APP with the broadcast generated by the system during startup, network switching, photo taking, and video shooting

Scenario 2: Accessing a third-party SDK will also wake up the corresponding APP process. For example, the wechat SDK will wake up wechat, and the Alipay SDK will wake up Alipay. Spreading out from this will directly trigger scenario 3 below

Scenario 3: If you have Alipay, Taobao, Tmall, UC and other Alibaba apps installed in your mobile phone, you may wake up other Alibaba apps after opening any of them. (Just take Ali as an example, in fact, BAT is similar)

That’s right, our Android phones are being towed step by step by step.

For scenario 1, Google is probably starting to realize these issues, so in the latest Android N, ACTION_NEW_PICTURE, ACTION_NEW_VIDEO, CONNECTIVITY_ACTION (network switching) and other three broadcasts.

White preservation:

Start foreground Service

The white preservation method is very simple. It is to call the system API to start a foreground Service process, which will generate a Notification in the Notification bar of the system to let users know that such an app is running, even if the current APP has retreated to the background. The purpose is easy to understand: to prioritize the process. Making Linux not killed first when it runs out of memory is, in some ways, the least rogue way to keep alive.

Gray preservation:

Start the foreground Service using a vulnerability in the system

Gray preservation, this means of preservation is the most widely used. It takes advantage of system vulnerabilities to start a foreground Service process. The difference with the common startup mode is that it does not show a Notification in the system Notification bar, and looks like running a background Service process. The advantage of this is that the user will not know that you are running a foreground process (because the Notification cannot be seen), but your process has a higher priority than a normal background process

Priority of the process

On Android, the priority of a process affects the following three factors:

  • The reclaiming policy of the system for processes when memory is insufficient
  • CPU scheduling policy for processes
  • Vm memory allocation and garbage collection policies for processes

The system has the following priorities for processes:

  1. Foreground process
  2. Visible process
  3. Service process
  4. Background processes
  5. An empty process

Foreground process

This process is a small number of application processes that are interacting with users and has the highest priority. The system generally does not terminate this process. The foreground process is identified by the following factors

The process contains activities in the foreground that are interacting with the user.

The process contains a service bound to the foreground activity.

Contains service that calls startForeground() method;

The process contains a service that is executing onCreate(), onStart(), or onDestroy().

The process contains the BroadcastReceiver that is executing the onReceive() method.

The visual process

An activity that is visible but not in the foreground (for example, an activity that is visible when onPause() is executed, This process has a service that binds data to the visible/foreground activity

Service process

Processes that continue to perform tasks without a visible interface are terminated only if the visible and foreground processes are short of resources (such as memory resources)

Background processes

There are a large number of background processes in the system. Terminating background processes does not affect user experience. They are terminated at any time to release resources for processes with higher priorities. Factors include the process of an activity that is not in the foreground or visible process, that is, the activity after the onStop() method has been called

An empty process

To improve overall system performance, the system saves applications that have completed their life cycles in memory, known as caches, designed for faster startup next time.

4. Memory threshold

Above is the classification of processes. How are processes killed? For the sake of experience and performance, the system does not actually kill the process when the app goes back to the background, but cache it. The more applications open, the more processes are cached in the background. When the system is running out of Memory, the system starts to determine which processes to kill based on its own process reclaiming mechanism to free up Memory for the needed APP. This process reclaiming mechanism is called Low Memory Killer. That this shortage how to rule, that is memory threshold, we can use cat/sys/module/lowmemorykiller/parameters/minfree to see a cell phone memory threshold.


Note that the units of these numbers are page. 1 page = 4 KB. The six numbers above are (MB): 72,90,108,126,144,180. These numbers are the corresponding memory thresholds, which vary from phone to phone, and once below this threshold,Android starts shutting down processes in sequence. Therefore, Android starts and terminates the empty process with the lowest priority, that is, when the available memory is less than 180MB(46080 x 4/1024).

When you read this, you may have a question, suppose now memory is insufficient, empty processes are killed, now to kill background processes, but there are many background processes in the phone, do you want to clean up all at once? This priority is reflected by the value of adj assigned to each system process by the Linux kernel. It represents the priority of the process. The process reclamation mechanism decides whether to recycle based on this priority. Adj value defined in com. Android. Server. Am. The ProcessList class, The classpath is ${android-sdK-path}\sources\ Android-23 \com\ Android \server\am\ processList.java.

oom_score_adj

For each running process, the Linux kernel exposes such a file through the PROC file system to allow other programs to change the priority of a given process:

The/proc / / oom_score_adj [pid]. (You need root permission to modify this file)

The allowed values in this file range from -1000 to +1000. The smaller the value, the more important the process is.

When memory is very tight, the system iterates through all the processes to determine which one needs to be killed to reclaim memory, and reads the value of the file oom_score_adj. The use of this value will be covered in more detail later when we talk about process recycling.

PS: Prior to Linux 2.6.36, Linux provides the file /proc/[pid]/oom_adj to adjust the priority. The allowed values in this file range from -17 to +15. The smaller the value, the more important the process. This file is deprecated in newer versions of Linux.

But you can still use this file, and when you modify it, the kernel directly converts the results to the oom_score_adj file.

Earlier versions of Android also relied on the oom_adj file. However, in the new version, you have switched to using the oom_score_adj file. The smaller the oom_adj value is, the higher the process priority is. The oom_adj value of a common process is greater than or equal to 0, while the oom_adj value of a system process is smaller than 0. You can run cat /proc/process id/oom_adj to view the adj. value of the current process.



Adj. = 0,0 indicates that the process belongs to the foreground process, so we press Back to apply it to the background and check again



The adj value becomes 8, which indicates that the process is not active. You can try the oOM_adj value in other cases, but each phone manufacturer may be different. There are several oom_adj values for reference.







Lowmemorykiller mechanism

OOM Out Of Memory is a Linux Memory protection mechanism. This mechanism monitors processes that consume too much memory, especially if they consume a lot of memory quickly, and the kernel kills them to prevent them from running out of memory.

When the Kernel encounters OOM, there are two options:

1) Kernelpanic (crash)

2) Launch OOM Killer, select one or more “appropriate” processes, and kill those selected processes to free memory.

In Linux, the system kills processes by counting points. The value of the score is the value of these three parameters. The score is divided into two parts: one part is scored by the system, which is mainly based on the memory usage of the process (OOM_score), and the other part is the user share, which is oOM_score_adj. The actual score for each process is a combination of the values of these two parameters. Oom_adj is just an old interface parameter, similar to oom_score_adj on normal Linux systems (but useful on Android).

In Android, even after the user exits the current application, the application will still exist in the system, which is convenient for the application to start again. However, as the number of open programs increases, the system runs out of memory, and some processes need to be killed to free up memory. Whether and what processes need to be killed is handled by Android’s internal LowMemoryKiller mechanism.

Low Memory Killer for Android is a Memory management mechanism modified from the OOM for standard Linux Lernel. When the system is out of memory, kill unnecessary processes to free memory. The selection of unnecessary processes is based on two factors: OOM_adj and the amount of memory occupied. Oom_adj indicates the priority of a process. The higher the value is, the lower the priority is and the easier the process is to be killed. Each oOM_ADJ can have a threshold for idle processes. The Android Kernel periodically checks whether the current free memory is below a certain threshold. If yes, the largest unnecessary oOM_adj process is killed. If there are multiple processes, the process is killed according to oOM_score_adj until the memory is restored below the threshold.

LowMemoryKiller is stored in two files. Are the/sys/module/lowmemorykiller/parameters/adj with/sys/module/lowmemorykiller/parameters/minfree. Adj stores the level of the current system kill process, and minfree stores the corresponding threshold. Their correspondence is as follows:




For example, when the current system memory is less than 55296×4K (i.e. 216MB), Android will find the current oOM_adj greater than or equal to 9 process, according to the process level, first kill the process with the highest VALUE of OOM_adj, release its memory, when their OOM_adj is equal. Compare their oOM_score_adj, and the bigger the oom_score_adj, the easier it is to kill.


At this point, one might ask, why LowMemoryKiller instead of OOM? Let’s compare the two and get the answer.




Using LowMemoryKiller allows system memory to be low when calling out the process manager to end unnecessary human processes to free up space. In Android, if you wait until the actual OOM, the process manager may not start.

How lowMemorykiller works

As mentioned above, LowMemoryKiller selects processes by controlling multiple memory thresholds. But how do these thresholds fit together? The following is my understanding of the operation of the principle.

First, LowMemoryKiller starts with the system. The main LowMemoryKiller code is currently in the \system\core\ LMKD directory. The previous code \kernel\drivers\staging\ Android \ LowMemoryKiller. C is no longer in use.

LowMemoryKiller is already started by the init process when the system starts. When LowMemoryKiller is started, it continuously monitors system performance and memory. When minfree sets the threshold for memory usage, LowMemoryKiller executes a kill operation over the oOM_score_adj of the current process. For example, when the system memory is less than 315 MB, the system automatically kills processes whose OOM_score_adj is less than 1000, and processes whose oOM_score_adj is less than 216 MB, and so on.

Who controls and writes oom_adj and oom_score_adj?

In the system, oOM_adj and oOM_score_adj are controlled by ActivityManagerService. AcitivityManagerService calls and allocates resources to upper-layer applications. Oom_adj and oOM_score_adj will be discussed in more detail when we analyze ActivityManagerService later. I won’t go into details here.

The writing of Minfree values can be found in many places, but in the beginning (while using lowMemorykiller. C) it can be set in lowMemorykiller. But lowMemorykiller.c is no longer used, so the relative Settings are different. It has been found that Minfree’s threshold control is written by both ActivictyManagerService and LowMemorykiller.

Five, commonly used survival routine



The front desk service

This kind of most people know, it is said that wechat has also used the process of survival scheme, this scheme actually takes advantage of the Android front service vulnerability. If API level < 18: call startForeground(ID, new Notification()) and send empty Notification, the icon will not be displayed. For API level >= 18: Start an InnerService whose priority needs to be improved, and both services are startForeground, and bound with the same ID. Stop the InnerService so that the notification bar icon is removed

Wake up each other

Mutual awakening means that if you have Alipay, Taobao, Tmall, UC and other Alibaba apps in your mobile phone, you may wake up other Alibaba apps after opening any One of them. It’s entirely possible. The app can also be woken up by system-generated announcements during startup, network switching, photo taking, and video shooting, but Android N has removed all three announcements.



Sticky services & bundled with system services

The onStartCommand method must have an integer return value that tells the system what to do if the service is killed after it has started. This option is acceptable, but may fail in some cases or on some custom ROMs

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    return START_REDELIVER_INTENT;
}
Copy the code
  • START_STICKY If the system is destroyed after onStartCommand returns, the system will recreate the service and call onCreate and onStartCommand in sequence (note: Android4.0 can do this), which is equivalent to restarting the service and restoring it to its previous state.

  • START_NOT_STICKY If the system is destroyed after onStartCommand returns, the system will not restart the Service if the Service is killed after the onStartCommand method is executed.

  • START_REDELIVER_INTENT Compatible version of START_STICKY. The difference is that this version does not guarantee that the service can be restarted after being killed.


  • JobSheduler

    As a means of process resurrection after death, the biggest disadvantage of native process is electricity consumption. The reason for the electricity consumption of native process is that there are two ways to realize the perception of whether the main process is alive. In the native process, the main process is judged to be alive through the dead cycle or timer rotation training, and the main process is pulled alive when it is not alive. Second, 5.0 or higher systems do not support it. However, JobSheduler can replace native processes on Android5.0 or above, which can be pulled up even if the user forcibly closes it.

      JobSheduler@TargetApi(Build.VERSION_CODES.LOLLIPOP)
    public class MyJobService extends JobService {
        @Override
        public void onCreate() {
            super.onCreate();
            startJobSheduler();
        }
    
        public void startJobSheduler() {
            try {
                JobInfo.Builder builder = new JobInfo.Builder(1, new ComponentName(getPackageName(), MyJobService.class.getName()));
                builder.setPeriodic(5);
                builder.setPersisted(true);
                JobScheduler jobScheduler = (JobScheduler) this.getSystemService(Context.JOB_SCHEDULER_SERVICE);
                jobScheduler.schedule(builder.build());
            } catch (Exception ex) {
                ex.printStackTrace();
            }
        }
    
        @Override
        public boolean onStartJob(JobParameters jobParameters) {
            return false;
        }
    
        @Override
        public boolean onStopJob(JobParameters jobParameters) {
            return false; }}Copy the code

    Start an Activity with one pixel

    It is said that this is the hand Q process alive scheme, the basic idea, the system is generally not kill the foreground process. So to make the process permanent, we just need to start an Activity in the process when the screen is locked. In order to deceive the user, let the Activity size be 1 pixel, and transparent without switching animation, when the screen is opened, the Activity is closed, so this needs to listen to the system lock screen broadcast.