1 introduction

The startActivity() function is used to start an Activity. The startActivity() function is used to start an Activity. The startActivity() function is used to start an Activity. I feel that this kind of article code details too much, but easy to get lost in the source call, thus ignoring the essence of the Activity start process. Therefore, this article simply qualitatively describes the Activity start process, not a large length of the source code, while sorting out the relevant classic problems. It is also a review summary of what we have learned before.

2 Cold start and hot start

When an Activity is started, it usually involves the process of starting an application. Application startup is divided into cold startup and hot startup.

  1. Cold start: If you click the desktop icon, the Application process does not exist in the phone system. In this case, the system will fork a child process to load the Application and start the Activity.
  2. Hot startup: Hot startup of an application is much simpler and less expensive than cold startup. In a hot start, all the system has to do is bring your Activity to the foreground because the application process is already running on the system. Cold start is an application that starts completely from 0, which involves more content, so we will discuss the process of applying cold start.

3 Application startup process

In general, a cold start includes the following:

  1. The start process click icon occurs in the application process Launcher, startActivity() function is the final Instrumentation through Android’s Binder cross-process communication mechanism to send messages to the system_server process; In system_server, ActivityManagerService tells Zygote to fork a child (app) via socket communication to start a process
  2. Once the app process starts, it instantiates the ActivityThread and executes its main() function: Create ApplicationThread, Looper, Handler objects, and start the main thread message loopLooper.loop().
  3. Create and initialize the main() calls to the Application and Activity ActivityThreadActivityThread#attach(false)Method communicates with Binder to inform the system_server process to executeActivityManagerService#attachApplication(mAppThread)Method to initialize the Application and Activity. In the system_server process,ActivityManagerService#attachApplication(mAppThread)Initializes Application and Activity in sequence, with two key functions: –thread#bindApplication()Method tells the main thread Handler to create the Application object, bind the Context, and execute the Application#onCreate() lifecycle –mStackSupervisor#attachApplicationLocked()Method callActivityThread#ApplicationThread#scheduleLaunchActivity()Method, in turn, notifies the main thread Handler message to create an Activity object and then invoke itmInstrumentation#callActivityOnCreate()Execute the Activity#onCreate() lifecycle
  4. Layout & source code process can refer to the Android View drawing process analysis and source code call tracking

At this point, the application startup process is complete.

The source code flow of 1, 2 and 3 can refer to the Android Application startup process analysis and source code call exploration, but the code details are not the focus of this article.

Here are a few key players in the above process and what they do:

3.1 the zygote process

Here is a brief description of the process mechanism under Android system. Each application runs as follows:

  1. A single Dalvik Virtual Machine (DVM) Java code needs to be compiled to run on the JVM, and android uses the Java language to run on a VM. Therefore, Google developed DVM for the lack of hardware resources such as processor and memory of mobile phones to provide an environment for Android to run. See the relationship between JVM and DVM
  2. A separate Process Each application startup runs a separate DVM, and each DVM occupies a separate Linux process. A separate process prevents all programs from being shut down in the event of a virtual machine crash. Dalvik process management relies on the Linux process architecture. To create a process for an application, it uses Linux’s fork mechanism to duplicate a process.

As we all know, Android is based on Linux, where all processes are forked either directly or indirectly by the init process. Forking processes is often more efficient than creating them. In Android, all application processes are fork out by zygote process.

When it comes to the Zygote process, we have to introduce the Android startup process:

  1. After the Linux kernel is started on an Android phone, the system/core/init/init.rc file is loaded to start the init process. This process is an Android system-specific initializer. Here’s how it works:

    • All kinds of complicated work
    • Be responsible for switching screen
    • Creating and mounting a file system
    • Start the Zygote(Incubator) process
    • Start ServiceManager, a Binder ServiceManager that manages all Android services
  2. Zygote is an incubator process, and its main function creates its own environment for incubating child processes and starts waiting for incubating requests:

    • Create a server socket with the name zynote for communicating with the client process
    • Preload classes and resources to improve application startup speed
    • Start the SystemServer process
    • Listen on the socket, make a request to it when an application starts, and then the Zygote process fock creates a new child process itself.
  3. The Zygote process forks itself to spawn the SystemServer process, and its main function is responsible for:

    • Start binder thread pools, which are the basis for SystemServer to communicate with other processes
    • Initialize the stars
    • The SystemServiceManager object is created, which launches various services in Android. Including AMS, PMS, AND WMS
    • Start the desktop process so that the user can see the phone’s interface.
    • If the loop loop is enabled and the message loop is enabled, the SystemServer process keeps running to ensure the normal running of other applications.
  4. When the Zygote process in the system is running, the subsequent startup of APP is equivalent to starting a new process. In order to achieve resource sharing and faster startup speed of Android, child processes are fork out through zygote process. So, all applications are children of Zygote, except for the first zygote fork from the init process. It’s not hard to understand why the incubator process is called Zygote (zygote), because all applications are born from it.

3.2 SystemServer process

SystemServer is the first process fork from The Zygote process. SystemServer and Zygote are the two most important processes of the Android Framework. All important services in the system are started in this process, such as ActivityManagerService, PackageManagerService, and WindowManagerService.

The application startup process basically revolves around ActivityManagerService and ActivityThread.

3.3 Client/Server Mode in Android

The well-known front-end (Web\Android\iOS) communicates with the server through the network, which is the embodiment of the client-server mode. In the Android Framework, the creation and life cycle of the four major components also communicate through this mode:

  1. Server refers to the SystemServer process. This process provides many services such as AMS, PMS, WMS, etc. All App processes can communicate with it.
  2. A client is a separate App process.

Android developers should know that you can open an APP by using the package name and Activity class name. In fact, the startActivity() method in the business code in the project does not directly create the process and pull up the APP. Instead, the request is passed to SystemServer’s AMS through a series of calls. After AMS receives the request from the client, it notifies zygote to fork a new process to start the target App. This is like opening a web page in a browser, the browser sends the URL and parameters to the server, and then the server handles the request and returns the corresponding HTML to display in the browser.

This process involves three processes: App process, AMS(SystemServer process), zygote process.

  1. App processes communicate with AMS across processes through Binder mechanisms
  2. AMS(SystemServer process) communicates with Zygote across processes through sockets.

On Android, any Activity is started by AMS and App processes (mainly ActivityThreads). AMS service uniformly schedules the Activity start of all processes in the system, and the start process of each Activity is specifically completed by the process to which it belongs.

3.4 Android Binder mechanism

We know that AMS interacts with ActivityThread primarily through interprocess communication (IPC). The mechanism for cross-process communication is to decompose a method call and its data to a level recognized by the operating system, transfer it from the local process and address space to the remote process and address space, and then reassemble and execute the call in the remote process. Android provides a Binder mechanism to perform these IPC transactions, so all we need to worry about is interface definition and implementing the RPC programming interface.

Binder interfaces are also used to communicate between App processes and SystemServer processes.

  1. IApplicationThread: serves as an interface for system processes to request application processes.
  2. IActivityManager: an interface for application processes to request system processes.

For a Binder interface, there is one implementation on the client side and one on the server side: Proxy and Native. Communication between them is triggered mainly by Transact and onTransact. Generally, it can be distinguished from the naming: xxxNative is the Binder agent in the process, xxxProxy is the Binder agent in the other process.

By the way, all binders are managed by ServiceManager:

  1. ServiceManager manages all Android services. Some compare ServiceManager to DNS servers in Binder. If a client application wants to use system services, it calls the getSystemService interface. The ServiceManager finds and returns the corresponding service Binder object with the Binder name as a string.
  2. Service process, it is a system in the native started, it’s in the system/core/rootdir/init. Rc script described in and by the init process starts.
  3. After the ServiceManager starts, it waits in a loop to process communication requests from the Client process.

Binder interfaces of App and SystemServer processes are shown as follows:

3.4.1 Server IActivityManager — ActivityManagerNative — ActivityManagerService

  1. ActivityManagerNative serves as a “Stub” on the server that unserializes data sent remotely.
  2. ActivityManagerProxy runs on the client as a “Proxy” for the service, and its main job is to “serialize” the data to a remote “Stub.” The App uses AMS functionality such as startActivity, This is initiated through ActivityManagerProxy, the AMS proxy on the client side.
  3. The bottom layer is the concrete implementation of Stub — ACTIVE Management Service (AMS), which is responsible for the startup, switchover, scheduling of the four major components in the system, and the management and scheduling of application processes. It is very complicated.

AMS is a system service that is initialized after the SystemServer process starts. In the application startup process, it acts as a server. The Activity life cycle in App is managed by AMS, which determines when to call onCreate, onResume and other life cycle functions, which stack to put the Activity on, how the context is related, and so on.

Such as:

  1. StartActivity finally calls the AMS startActivity series method to realize the start of the Activity; Activity lifecycle callbacks are also done in AMS;
  2. StartService,bindService finally calls AMS’s startService and bindService methods;
  3. Registration and reception of dynamic broadcasts are done in AMS (static broadcasts are done in PMS)
  4. The getContentResolver finally gets the ContentProvider from AMS’s getContentProvider

IApplicationThread — ApplicationThreadNative — ActivityThread

  1. Pile (stubs) : ApplicationThreadNative
  2. The agent (Proxy) : ApplicationThreadProxy, App instantiates activities, calls onCreate, and other lifecycle functions in the client process, because AMS cannot call them directly across processes. Instead, AMS handles it through the client’s proxy, ApplicationThreadProxy.
  3. The bottom layer is the concrete implementation of stubs, ApplicationThread, which is an internal class of ActivityThreads that respond to requests made by system processes, while the actual business logic that is triggered is in the ActivityThread. Instead of holding a reference to ActivityThead directly, unlike the normal broker pattern, it posts requests for processing to a Handler inside the ActivityThread.

In contrast to AMS on the Server side, ActivityThread acts as a concrete implementation on the Client side in the Client/Server mode in which the application is launched. It is not a thread, but it contains all the mechanisms by which the main thread of an application process operates:

  1. Start the main thread of the application and start the message loop
  2. An IActivityThread interface is provided to communicate with AMS, through which AMS can pass state changes to the Activity object on the client

3.5 Start the communication process of an Activity

We already know that after the application process is created, the ActivityThread of the App process communicates with the AMS of the SystemServer process through its Binder. As mentioned earlier in this article, the ActivityThread main method calls ActivityThread# Attach (false) for Binder communication. Inform the system_server process to execute ActivityManagerService#attachApplication(mAppThread) to initialize the Application and Activity.

You can summarize this communication process a little bit in conjunction with the source code flow.

3.5.1 Initialization of Application

From application process to system process

When an ActivityThread is created, you bind your ApplicationThread to AMS:

ActivityThread. The main () └ ─ ─ ActivityThread. Attach () └ ─ ─ IActivityManager. AttachApplication (mAppThread) └ ─ ─ Binder.transact()Copy the code

As the client, the application process initiates a cross-process call through the IAcitivtyManager interface. The parameter mAppThread passed across the process is the instance of IApplicationThread. The execution process enters the system process from the application process:

ActivityManagerService. OnTransact () └ ─ ─ ActivityManagerService. AttachApplication (IApplicationThread thread)Copy the code

AMS, as a server-side implementation of the IActivityManager interface, responds to requests from the client, and the ams.attachapplication () function is executed, which accepts IApplicationThread instances that are transferred across processes. Will be stored in ProcessRecord maintained by the system process. Thread is assigned to the IApplicationThread instance of the application process once a binding request has been made. In this way, calls to application processes can be made from the IApplicationThread instance in AMS.

From system process to application process

During ams.attachapplication (), information needs to be transferred to the application process for application initialization. The system process invoks the following functions:

ActivityManagerService. AttachApplication () └ ─ ─ ActivityManagerService. AttachApplicationLocked () └ ─ ─ IApplicationThread.bindApplication(processName, appInfo ...) └ ─ ─ Binder. Transact ()Copy the code

At this point, AMS reverses its role, with the system process acting as the client, making calls to the application process through the IApplicationThread interface.

  1. AMS maintains the state information of process running through ProcessRecord, and the Application process needs to be bound to ProcessRecord to start the construction of an Application.
  2. The data structure ProcessRecord maintained by AMS contains the information of the process running time, such as the application processName processName, the data structure ApplicationInfo obtained from parsing androidmanifest.xml, and so on. Data to be passed to the application process is an instance of the Parcelable type.

The invocation relationship of the application process in response to the request is shown as follows:

ApplicationThread. OnTransact () └ ─ ─ ApplicationThread. BindApplication () └ ─ ─ ActivityThread. H.h andleMessage (BIND_APPLICATION) └ ─ ─ ActivityThread. HandleBindApplication () └ ─ ─ Application. The onCreate ()Copy the code

ApplicationThread as IApplicationThread interface server implementation, running in the process of application, and ApplicationThread bindApplication () will be taken. After some simple data encapsulation (AppBindData), the BIND_APPLICATION message is thrown by Handler. This left, she threw the main thread, ActivityThread. HandleBindApplication () will be performed, finally to create the Application object, Then call Application#attach(context) to bind the context and call application.oncreate (). After going back and forth between the application process and the system process, an application is finally created.

In AMS, many functions related to Activity management have Locked suffixes, indicating that the calls to these functions require synchronized, which can read/write data shared by multiple threads

3.5.2 Initialization of the Activity

ActivityManagerService#attachApplication(mAppThread) is used to initiate applications and activities in the system_server process. The mStackcontainer #attachApplicationLocked(ProcessRecord) handles the initialization of the Activity.

  1. AMS uses ActivityRecord to maintain state information about an Activity while it is running. You need to bind an Activity to ActivityRecord in AMS to start the Activity life cycle.
  2. There is an IBinder type property in the Activity class:private IBinder mToken;The IBinder type indicates that the property is a reference to a remote object. The Token holds a weak reference to an ActivityRecord instance. When an ActivityRecord is created, an object of type Token is created.

When a new Activity is started, AMS passes the ActivityRecord Token to the application process as follows:

ActivityStackSupervisor.realStartActivityLocked(ActivityRecord, ...) └ ─ ─ IApplicationThread. ScheduleLaunchActivity (... token, ...)// Pass the ActivityRecord Token to the application process across processes└ ─ ─ Binder. Transact ()Copy the code

ActivityStackSupervisor. RealStartActivityLocked () to start an Activity instance, ActivityRecord as parameters. Extracted from the ActivityRecord Token object, as the parameters of the process calls, through IApplicationThread. ScheduleLaunchActivity () to the application process.

On the application process side, you receive a cross-process call to start the Activity, which triggers the following function calls:

ApplicationThread. OnTransact () └ ─ ─ ApplicationThread. ScheduleLaunchActivity (... token, ...)// The token will be encapsulated in the ActivityClientRecord data structure└ ─ ─ ActivityThread. H.h andleMessage () └ ─ ─ ActivityThread. HandleLaunchActivity (LAUNCH_ACTIVITY) └ ─ ─ ActivityThread.performLaunchActivity(ActivityClientRecord, ...)// Retrieve token from ActivityRecord└ ─ ─ Activity. Attch (... token, ...)Copy the code

The standard Binder server process receives the Token object from AMS, performs a data encapsulation (ActivityClientRecord), and throws a LAUNCH_ACTIVITY message through a Handler. This message is thrown into the application process of the main thread to execute, so ActivityThread performLaunchActivity () function can be carried on the main thread, this function from the encapsulated data structure ActivityClientRecord Token object, Attach () to the Activity by calling the activity.attach () function, thus associating the application process’s Activity with the ActivityRecord in the system process.

The system process maintains an ActivityRecord, and the application process maintains an Activity. The mapping between the two is maintained using tokens. When an Activity is created, an application process is given a Token that it can use to communicate with the system process. When an Activity switch occurs, the application process passes the Token(resultTo, the input parameter of ams.startActivity () of the previous Activity) to the system process. The system process finds the ActivityRecord based on this Token and completes scheduling. Notify the application that the Activity state has changed.

3.5.3 Instrumentation

Each Activity holds a reference to the Instrumentation object, but only one Instrumentation object exists for the entire application process. Instrumentation can be understood as the steward of the application process. When an ActivityThread wants to create or pause an Activity, it needs to perform specific operations through Instrumentation.

Instrumentation is the Instrumentation class that completes the initialization and lifecycle of applications and activities.

As mentioned earlier, apps and AMS communicate information through binders, and ActivityThreads receive AMS commands, and then actually create activities through Instrumentation and call Activity lifecycle functions. For example, ApplicationThread takes AMS command to create Acitivity, then executes to ActivityThread, creates Activity through Instrumentation and calls onCreate() lifecycle.

//ActivityThread. PerformLaunchActivity () └ ─ ─ mInstrumentation. NewActivity (appContext. GetClassLoader (), Component. The getClassName (), activityClientRecord. Intent) └ ─ ─return(Activity) cl. LoadClass (className). NewInstance () └ ─ ─ mInstrumentation. CallActivityOnCreate (Activity, ├ ─ garbage () ├ ─ garbage () ├ ─ garbage ()Copy the code

4 Activity management mode

Application startup and Activity startup are a process of cross-process communication. This is because each application is an independent process, and the Activity life cycle will affect each other among different processes. Therefore, a system process is required to manage all activities in a unified manner. When an application is installed, the system parses information about all activities in APK, and when the user interface in APK is displayed, the Activity lifecycle functions need to be scheduled. The state of all activities is maintained in the SystemServer process, and ActivityManagerService is the management hub.

How do system processes manage activities?

On the application side, the Activity life cycle occurs in the main thread of the process, which is completed by ActivityThread calling Instrumentation. On the SystemServer side, AMS maintains data structures such as ActivityRecord for scheduling. The data structures managed by the Activity include: ActivityRecord TaskRecord ActivityStack ActivityDisplay ActivityStackSupervisor ProcessRecord These data structures belong to JAVA entity classes. They are built and destroyed in system processes.

The link between them can be seen below:

The box in the figure can be interpreted as an inclusion relationship: for example, a TaskRecord contains multiple ActivityRecords; The connection lines in the figure can be interpreted as equivalents, such that the same ActivityRecord is referenced by TaskRecord and ProcessRecord, which manage activityRecords from different dimensions.

  1. ActivityRecord is the smallest unit of Activity management. It corresponds to an Activity of an application process.
  2. TaskRecord is also a stack management structure. Each TaskRecord may have one or more ActivityRecords. The ActivityRecord at the top of the stack represents the currently visible interface.
  3. ActivityStack is a stack management structure. Each ActivityStack may have one or more TaskRecords. The TaskRecord at the top of the stack represents the currently visible task.
  4. The ActivityStackSupervisor manages multiple Activitystacks, but currently there is only one ActivityStack that gets Focused.
  5. ProcessRecord records all activityRecords that belong to a process. Activityrecords running in different TaskRecords may belong to the same ProcessRecord.

The properties and behavior of each data structure

5 Operation mechanism of Binder

With Binder, applications communicate with AMS across processes. How does Binder work?

  1. A process space is divided into user space and Kernel space, that is, the process user and Kernel are separated.
  2. To ensure security and independence, one process cannot directly operate or access another process. In other words, Android processes are independent and isolated from each other.
  3. Principles of cross-process communication
    • Data is first exchanged through the kernel space between processes
    • Then through the user space and kernel space in the process of data interaction, so as to achieve the user space data interaction between processes
    • Binder acts as a channel between two processes (kernel space).

Binder implementation in Android

5.1 Registration Service

The Server process creates a Binder object and registers the service with the ServiceManager.

5.2 Obtaining Services

Binder drivers are used to obtain Service information from ServiceManager when Client processes need to use services provided by Server processes. The ServiceManager returns Binder proxy objects for Server processes

5.3 Using the Service

  1. Client process request data is sent to the kernel space through the transact method of binder objects. The current thread is suspended
  2. The Binder driver finds the real Binder object of the server process through the proxy object used by the client process and sends the data to the server process
  3. The Server process receives notification from the Binder driver, deserializes data in the thread pool & calls the target method (onTransact), and sends the execution results to the Binder driver.
  4. Binder drivers copy target method execution results of server processes into the kernel space of client processes
  5. The Binder driver notifies the client process that the previously suspended thread is awakened and receives a return result

6 summarizes

  1. In Android, all applications are a single process.
  2. Each application process is fork by the Zygote process.
  3. Application startup is a complex cross-process task. The application startup process basically revolves around the ActivityManagerService of SystemServer and the ActivityThread of the application process.

reference

  1. Android source code learning directory
  2. Communication between application processes and system processes (IActivityManager & IApplicationThread)
  3. Android Binder cross-process communication mechanism