As an Android developer, it is necessary to be familiar with the Android system startup process.
Android Platform Architecture
1. The Linux kernel
The Android platform is based on the Linux kernel. Android Runtime(ART) relies on the Linux kernel to perform low-level functions such as ** threading and low-level memory management. ** Using the Linux kernel allows Android to take advantage of major security features (such as process isolation, user-based permission mode, etc.) and allows device manufacturers to develop hardware drivers for well-known kernels.
2. Hardware Abstraction Layer (HAL)
The hardware abstraction layer provides a standard interface that exposes device hardware functionality to higher-level Java API frameworks. **HAL contains multiple library modules, each of which implements an interface for a specific type of hardware component, such as a camera or Bluetooth module. ** When the framework API requires access to a hardware device, the Android system loads library modules for that hardware component.
3.Android Runtime
Above Android5.0(API 21), each application runs in its own process and has its own Android Runtime(ART) instance. ART is written to run multiple virtual machines on low-memory devices by executing Dex files, a bytecode format designed for Android. It is optimized to use very little memory. A compilation tool chain (such as Jack) compiles Java source code into Dex bytecode, making it available to run on the Android platform.
Some of the main functions of ART include:
-
AOT and JUST-in-time (JIT) compilation
-
Optimized garbage Collection (GC)
-
In Android 9(API 28) and later, Dalvik Executable format (Dex) files in application packages can be converted into more compact machine code.
-
Better debugging support, including dedicated sampling analyzers, detailed diagnostic exception and crash reports, and the ability to set observation points to monitor specific fields.
Prior to 5.0, Dalvik was the Android Runtime. If your application works well on ART, it should also work on Dalvik, but not the other way around. Android also includes a set of core runtime libraries that provide most of the Java programming capabilities used by the Java API framework, including some Java8 language capabilities.
Native C/C++ library
Many of the core Android system components and services, such as ART and HAL, are built from native code, requiring native libraries written in C and C++. The Android platform provides Java framework apis to show applications some of the functionality of its native libraries. For example, OpenGL ES can be accessed through the Java OpenGL API of the Android framework to support drawing and manipulating 2D/3D graphics in applications.
If you are developing an application that requires C or C++ code, you can use the Android NDK to access some native platform libraries directly from native code.
5. Java API framework
You can use the entire feature set of Android OS through apis written in the Java language. These apis form the building blocks needed to create Android applications. They simplify the reuse of core modular system components and services, including the following:
- A rich, extensible view system that can be used to build an application’s UI, including lists, grids, text boxes, buttons and even an embeddable Web browser
- Resource manager for accessing non-code resources, such as localized strings, graphics, and layout files
- Notifications manager, which allows all applications to display custom alerts in the status bar
- The Activity manager, which manages the application lifecycle, provides a common navigation back stack
- Content providers that allow applications to access data from other applications (such as the Contacts application) or share their own data
Developers have full access to the framework apis used by Android applications.
6. System application
Android comes with a core set of apps for email, messaging, calendar, Internet browsing and contacts. Apps that come with the platform have no special status, just like apps that users can choose to install. So third-party apps can become users’ default web browser, SMS Messenger, and even their default keyboard (with some exceptions, such as the system’s Settings app).
System applications are available to users’ applications and provide major functions that developers can access from their own applications. For example, if your application wants to send SMS messages, you don’t need to build the feature yourself, you can instead call your installed SMS application to send messages to the recipient you specify.
The general process of Android system startup
Loader layer
-
System power supply and system startup
When the power is pressed, the boot chip code starts executing from a predefined place (solidified in ROM). Load the boot program into RAM, and then execute.
-
bootstrap
Bootstrap is in front of the Android operating system began to run a small program, is the first program to run, so it is for a specific board and chip, can use redboot, uboot, qibootloader or develop their own boot, it is not a part of the Android operating system, The boot program is a place where OEM or carrier locks and limits.
The bootloader is executed in two phases:
- Detect external RAM and load programs useful for phase 2;
- The bootloader sets up the network, memory, etc., which are necessary to run the kernel, and can set up the kernel based on configuration parameters or input data to achieve specific goals.
The Android boot program can be found at \bootable\bootloader\legacy\usbloader. A traditional loader contains two files that need to be explained here: init.s initializes the stack, clears the BBS segment, and calls the _main() function of main.c;
Main.c initializes hardware (alarm clock, motherboard, keyboard, console) and creates Linux labels
The Kernel layer
Kernel layer refers to the Android Kernel layer, which is generally entered into the Android system right after startup. The startup process of Kerner layer is as follows:
-
Start the swapper process (pid=0), which is the first process created by the kernel during system initialization. It is used to initialize process management, memory management, and load driver related work such as Display, Camera, Binder, etc
-
Start the Kthreadd process, which is the Linux kernel process, and create kernel daemons such as the kernel worker thread kworkder, soft interrupt thread ksoftirqd, and thermal. Kthreadd is the granddaddy of all kernel processes.
Native layer
The native layer mainly includes user-space daemons incubated by init process, bootanim startup animation and Hal layer, etc. Init is the Linux daemon and the granddaddy of all user-space processes. The init process is the first user-space process in Linux. The process id is 1.
-
The init process incubates user daemons such as ueventd, logd, Healthd, installd, ADBD, lm, etc.
-
Init also starts important services such as ServiceManager (Binder ServiceManager) and bootanim (startup animation).
-
The init process incubates the Zygote process, which is the first Java process (virtual machine process) on the Android system. Zygote is the parent of all Java processes.
The Framework layer
The framework layer is composed of native layer and Java layer to coordinate the smooth and orderly work of the system. The framework layer mainly includes the following contents:
Media Server
Process is made up ofinit
processfork
And came to be responsible for starting and managing the wholeC++ framework
, includingAudioFlinger
.Camera Service
And other services.Zygote
The process,byInit
Process by parsinginit.rc
File generation,Zygote
Is the first Java process of the Android system and the parent of all Java processes.System Server
Process byZygote
processfork
And come,isZygote
The first child of a process incubation, responsible for starting and managing the wholeJava Framework
, includingAms
,Pms
And so on.
The App layer
The first App process Zygote incubates is the Launcher process, our desktop process, which is the user interface we see when we open our phones. Since the previous framework generated a variety of daemons and admin processes, there are listens for the Launcher with clicks, long presses, slides, and unloads. The Zygote process also creates App processes such as Browser, Phone, and Email. This means that all App processes are generated by Zygote process fork. In addition, the upper processes are all managed by the lower processes, including but not limited to interface registration, jump, message transfer.
Zygote startup process
The main function of app_main. CPP, which mainly does parameter parsing, has two startup modes
-
One is the Zygote mode, that is, to initialize the Zygote process, pass the parameter –start-system-server –socket-name=zygote, the former indicates to start SystemServer, the latter specifies the socket name.
-
One is the Application mode, which starts a normal application and passes in the class name and the class parameters
StartVm: Creating a Java virtual machine (actually a Dalvik/Art virtual machine) is mainly about setting the parameters of the virtual machine.
Zygoteinit.main () : This is where the Java layer begins
Preload () : /system/etc/preloaded classes, preload resources, preload OpenGL, etc. Zygote process load all resources in the method, when the need to fork a new process, use copy on write technology, as follows:
Zygote uses an efficient I/O multiplexing mechanism to ensure sleep when there are no client connection requests or data processing, and otherwise respond to client requests.
summary
- Parses the parameters in init.zygote.rc, creates AppRuntime and calls the appruntime.start () method;
- Call AndroidRuntime’s startVM() method to create the VM, and then call startReg() to register the JNI function.
- Call zygoteinit.main () in JNI to enter the Java world for the first time;
- RegisterZygoteSocket () establishes the socket channel, zygote as the communication server, used to respond to client requests;
- Preload () preloads common classes, drawable and color resources, openGL and shared libraries, and WebView to improve app startup efficiency;
- Zygote complete most of the work, then through startSystemServer(), fork helper system_server process, is also the upper framework of the operation carrier.
- Zygote retired, calling runSelectLoop() (an infinite loop) and standing by, waking up and performing work as soon as it received a request to create a new process.
When does Zygote restart?
- Zygote: triggers the restart of media, Netd, and subprocesses (including system_server).
- System_server: triggers zygote restart.
- Surfaceflinger: Triggers zygote restart;
- Servicemanager: Triggers zygote, HEALTHD, Media, SurfaceFlinger, and DRM restart
The fork function
pid_t fork(void)
Copy the code
- Parameters: No parameters are required
- Required header files
and
- The return value can be divided into two cases:
- A return of 0 indicates that the child process was successfully created and that the child process execution process is next
- Returns PID(>0), successfully created the child process, and continues to execute the parent process code
- The system returns a non-positive value (<0), indicating that the sub-process fails to be created. The causes of the failure are as follows: The number of processes exceeds the upper limit. Errno is set to EAGAIN
The child given by fork is a copy of the parent, inheriting the entire address space from the parent. Address space: includes process context, process stack, open file descriptor, signal control Settings, process priority, process group number, etc. The only things unique to a child process are its process number, timer, and so on. Therefore, using the fork function can be costly.
What are the differences between parent and child processes
- The process ID varies depending on the return value after fork
- Child process unprocessed signal set to null
- The child does not inherit the file lock set by the parent
- Typically, a child process does not execute exactly the same code flow as the parent process
- · · · · · ·
Orphan process, zombie process
After the fork system call, the parent and child processes execute alternately, in any order. If the parent exits before the child exits, the child’s parent becomes init. If the child exits before the parent exits, the child must wait until the parent captures the exit status of the child. Otherwise, the child becomes a zombie (zombie process: only holds exit information for the parent process to query).
A Fork call to a multi-process thread
In POSIX standards, fork behaves like this: it copies the entire user space (usually using a copy-on-write strategy, so it can be fast) to all system objects, and then copies the current thread to the child process. Here: all the other threads in the parent process suddenly evaporate in the child process.
Consider an environment where, before the fork, a child thread locks a lock and gains ownership of the lock. After the fork, all the extra threads in the child process disappear. The lock, on the other hand, is copied normally, and as far as the child process is concerned, the lock has no owner, so no one can unlock it. When the child process wants to lock the lock, there is no longer any means to unlock it. A program deadlock occurred.
The interview questions
Question1: Do you know the startup process of Android system?
When powering on, the boot program BootLoader is first loaded into RAM from a predefined place in ROM, and the BootLoader program is executed to start the Linux kernel. Then the first user-level process, init, is started. The init process parses the init.rc script to perform initialization tasks, including mounting file systems, creating functional directories, and starting system Service processes, including Zygote, Service Manager, and Media. Zygote will further start system_server, and then start AMS,WMS,PMS and other services in the system_server process. After these services are started, AMS will open the Home Activity of the application Launcher, and finally see the “desktop” of the mobile phone.
Question 2: Why should system_server be started in Zygote instead of init?
Zygote is an incubator that preloads resources so that other processes created On copy-on-write at fork() can use them without reloading. System_server, for example, can use JNI functions, shared libraries, common classes, and theme resources directly from Zygote.
Question 3: Why use Zygote to incubate application processes instead of System_server?
First, System_server runs more AMS,WMS and other services than Zygote, which are not needed for an application. In addition, the process fork is not multithreaded friendly, and only copies the calling thread into the child process, which can cause a deadlock, and there are certainly many threads in ststem_server.
Q4: can you tell us specifically how the deadlock is caused?
In POSIX standards, fork behaves like this: it copies the entire user space (usually using a copy-on-write strategy, so it can be fast) to all system objects, and then copies the current thread to the child process. Here: all the other threads in the parent process suddenly evaporate in the child process.
Consider an environment where, before the fork, a child thread locks a lock and gains ownership of the lock. After the fork, all the extra threads in the child process disappear. The lock, on the other hand, is copied normally, and as far as the child process is concerned, the lock has no owner, so no one can unlock it. When the child process wants to lock the lock, there is no longer any means to unlock it. A program deadlock occurred.
Q5: Why didn’t Zygote use Binder mechanisms for IPC communication?
Binder thread pool is the Binder thread pool, which is multithreaded. If Zygote uses Binder, there are fork() and multithreading problems mentioned above. A Binder mechanism does not have to be multithreaded strictly. A Binder thread is simply a loop reading of binder-driven messages. A single Binder thread can work, as is the case with Server Manager. In fact, Zygote is not single-threaded despite not having Binder mechanisms, but it actively stops other threads before fork() and restarts after fork().
Reference article:
Developer.android.com/guide/platf…
Gityuan.com/2016/02/13/…