Android process and thread, Android process thread
As we all know, in the operating system, a process is the smallest unit for the OS to allocate resources, while a thread is the smallest unit for executing tasks. A process can have multiple threads to execute tasks. These threads can share the resources allocated by the process. After our app starts to run, the Android system starts a new Linux Process to run the app without other components running, this process only contains one thread running. By default, all app components run in the process. The thread originally contained is also called the main thread or UI thread. When we start the app, if there is already a process running the app component in the system, the app will also run in the process. Of course, we can also let different components in the app run in different processes, or we can open new threads in any process to execute tasks.
Process
As mentioned above, by default, all components of the same app are running in the same process, and most apps do not need to change this setting. However, if you really need to specify a process to run a specific component, you can set it in the manifest file. We define various components in the manifest file, such as activity, service, explorer, and provider. We can set the process attribute to specify a new thread to run the component. By setting the process attribute, we can set each component to run in different processes, or specify several components to run in the same process. We can even set different app components to run in the same process (by specifying the same process attribute and sharing the same user ID ).
As mentioned in previous articles, the Android system starts a Zygote process after it loads the code and resources of the common framework. To start a new program process, the system generates a new process fork Zygote process, and then loads and runs the application code in the new process. This allows most RAM pages to be used to allocate code to the framework, and enables RAM resources to be shared among all processes of the application.
When the memory of the Android system is insufficient, some processes will be killed to meet those processes that directly interact with the user. components running in these killed processes will also be canceled. This thread is started only when these components are re-run. How will the system decide which process to kill? The Android system depends on the importance of processes and users. For example, the system prefers to kill the processes in which the activity is no longer displayed, compared with the processes that are displaying the activity.
Process Lifecycle
The Android system will maintain the running of a process for as long as possible, but it will eventually reclaim the memory space of the old process for new or more important processes. The Android system uses the "importance level" policy based on the processes running components and component status, and clears processes layer by layer based on the importance.
The importance level is divided into five layers from high to low:
1. foreground process
The process that is currently interacting with the user. If a process P meets any of the following conditions, process P is called a foreground process:
- The activity that is currently interacting with the user (calling the resume method) is running in process P
- A service is bound to an activity that is currently interacting with the user. The service runs in process P.
- A service calls the startForeground () method and runs in process P.
- A service is executing a lifecycle callback method. The service runs in process P.
- A broadcastReceiver is executing its onReceive function. The broadcastReceiver runs in process p.
Generally, only a few foreground processes exist in the system at a certain time. They are killed only when the memory is very low. In this case, the device reaches the memory paging state, only when some foreground processes are killed can the system respond quickly.
2. Visible process Visable process
No front-end components are running in this process, but they can still affect the screen displayed by users. If process p meets any of the following conditions, process P is called a visible process:
- An activity does not run on the foreground, but can still be seen by the user (the pause method is called). The activity runs on process P. For example, if a dialog is started for an activity, you can still see the activity.
- If a service is bound to a visible activity or foreground activity, the service runs in process P.
Visible processes are relatively important, but in some cases, in order to ensure the running of foreground processes, the system will still kill these visible processes.
3. service process
If a service is started using the startservice method and does not belong to the above two higher levels, the process that runs the service is called service process. Although the service is not bound to any component that can be viewed by users, the work they do is of interest to users, such as playing music and downloading files.
4. background process
An invisible activity (the onStop method is called back) runs on this thread. Such threads cannot directly affect the user experience, and the system may kill such processes at any time to recycle the memory for the above three processes. Generally, multiple background processes are running in the system, so they are stored in an LRU list, so that processes that are least frequently used by users will be killed first. If an activity calls back its lifecycle function and stores the corresponding status data, killing the background process will not affect the user experience. Because when a user tries to return to the activity, the system will restore all the states of the activity.
5. empty process
This process does not run any components. The only reason for keeping such processes alive is to wait for the task. Once a component needs to run, the process startup time can be shortened. Therefore, the system will often kill these processes to balance the system resources between the process cache and the underlying kernel cache.
In Android, a process can be dynamically upgraded because other processes may depend on the process. A process provides services for other processes, so the level of the process is certainly not lower than the process it serves. For example, if A content provider runs in process A and serves client B in process B, or if the service in process A is bound to A component in process B, the importance level of process A is only higher than or equal to process B.
Because the process level of a running service is higher than those running in the background activity, if we need to perform operations for a long time, it is better to start a service from an activity to complete these operations than to open a subthread in the activity to complete these operations (especially when the duration of these subthreads is longer than that of the activity ). ). For example, if an activity wants to upload an image to the server, you should enable a service to complete the upload operation in the background. Even if the user leaves the current activity, these operations can be completed in the background. Using service ensures that these operations have at least the service priority, regardless of whether the status of the current activity changes. This is also why the broadcast receiver should use the service instead of simply putting time-consuming operations in the subthread.
Thread
After the application starts, the system creates a main thread to run the application. The main thread is very important. It is responsible for distributing tasks and events for appropriate user controls, including drawing tasks. At the same time, the main thread is also responsible for the interaction between the UI component and the application, so we also call the main thread as the UI thread.
The system does not enable a thread for each component to run. All components are initialized and run in the same process in the main thread. The system calls each component through the main thread. Therefore, the system callback method (such as onKeyDown and lifecycle callback) usually runs on the main thread.
For example, when a user clicks a button on the screen, the UI thread distributes the click event to the control. Control will set its own press status, and add the re-painting request to the event Request queue. After the UI thread extracts the re-painting request from the event queue, it notifies the control to re-paint.
When a user interacts with an app frequently, the single-threaded mode may lead to slow response speed and unsatisfactory user experience. If time-consuming operations such as network or database requests are performed in the main thread, the thread is blocked and the main thread cannot schedule and distribute events and tasks. An ANR window will pop up when the congestion exceeds 5s. In addition, the UI control is not thread-safe, so the system requires that the control can only be modified in the UI thread. We need to follow two rules:
Worker thread
The preceding section describes how only the UI thread works. To improve the response speed of the application UI and improve the user experience, we need to put time-consuming operations in the Child thread. However, do not operate the UI control in the Child thread. We usually use the Handler mechanism of Android to solve the problem of inter-thread communication. For details, see the source code analysis of asynchronous communication mechanism between Android threads in the previous article. Android also provides async tasks to complete asynchronous tasks.
ASYNC TASK
The async task executes time-consuming tasks in the Child thread and returns the results to the UI thread. You do not need to manually create handler. We will not introduce the use of async tasks here. During the use of async tasks, we need to note the multithreading problem. Due to the running configuration problem (for example, the screen is changed in the horizontal and vertical directions), the sub-thread task will be restarted without our permission.
Thread Security Method
In most cases, our methods may be called by multiple threads, so we must consider thread security issues. This is especially true for methods that can be remotely called, such as the method for binding a service. When we try to call the method implemented in IBinder, if the caller and IBinder are in the same process, the method will be executed in the thread where the caller is located. If the caller and IBinder are not in the same process, the system extracts a thread from the maintained thread pool to execute this method, this thread pool runs in the same process as IBinder (not in the UI thread ). For example, although the UI thread of the service process will call the onBind method of the service, the methods implemented in the IBinder object returned by the onBind method will be executed by the thread pool thread. Because a service can be accessed by multiple clients, multiple threads in the thread pool can call the same method at the same time. Therefore, the methods implemented in the IBinder object must be thread-safe.
Similarly, a ContentProvider can receive data requests from different processes. Although the cp and cr classes hide the details of inter-process communication management, the corresponding query and deletion in CP, modification, insertion, and other request methods will be handed over to the thread pool thread of the process where CP is located for execution. These methods may be called by multiple processes at the same time, so these methods must be thread-safe.
Inter-process communication
The Android system provides a remote call RPC mechanism to complete the process Communication IPC. Through the RPC mechanism, components in the application (such as activity) act as the caller to call a method locally, this method is executed remotely (in another process) and then the result is returned to the caller. In this case, you need to resolve the called method and its data to a level that can be understood by the operating system, and then pass it from the local process and address space to the remote process and address space, then reorganize and execute.