Android Boot Process Analysis, android Boot Process
First, android is based on the Linux kernel. android can be started only when kernel is loaded first. For Linux, android is only an application on it. Android startup can be divided into three processes:
Init-> init. rc-> zygote. Anyone who is engaged in Embedded Development knows that after Linux loads the kernel driver, it will mount the '/' root file system. After mounting, it will execute the '/init' binary program, this is the first user program executed after the kernel is started, as is the case in android. The main function of this program is located in android/system/core/init. c. As an operating system, initialization usually involves the following tasks:
1. create the desired directory, mount the file system, and input and read the file hard disk data.
2. Load and set global environment variables to build the necessary environment for program running.
3. for android, you also need to run the Java virtual machine, which is a unique cross-platform feature of android.
4. Load and run the Framework, load the window desktop program, that is, the system GUI, and finally hand over the control to the user before the startup is complete.
Root file "/init" program analysis:
The source code shows that init will first create some necessary directories, such as '/dev','/proc', and '/sys. Then mount the device to this directory. After the mount is complete, you can create a device node. For example:
<span style="white-space:pre"></span>mount("tmpfs", "/dev", "tmpfs", MS_NOSUID, "mode=0755");<span style="white-space:pre"></span>mount("proc", "/proc", "proc", 0, NULL);<span style="white-space:pre"></span>mount("sysfs", "/sys", "sysfs", 0, NULL);
Create a Serial Output node and redirect the output:
Open_devnull_stdio ();
The "/dev/_ kmsg _" node was created in the klog_init function, And Then unlink quickly. This function copies a Serial Output log, the log includes the printing information from the kernel startup to the android initialization, which can be printed using the dmesg command.
The Code is as follows:
Property_init (); this function mainly loads some default property attributes, which exist in the build. prop, default. prop file.
Get_hardware_name (hardware, & revision); this function is used to obtain the hardware and version information of the cpu from the "/proc/cpuinfo" node and write the information into the prop property variable.
Process_kernel_cmdline (); obtain the environment variable of bootargs from the node "/proc/cmdline" and set it to the global variable for later use.
In the program, the system will read and parse the init. rc file, which is more like a command set, but the program does not immediately execute these commands. Instead, it is parsed first and sorted into a linked list according to certain rules, init. commands in rc are not directly executed like shell, but are mapped internally. These mappings exist in init/keywords. h file, for example:
KEYWORD (mkdir, COMMAND, 1, do_mkdir );
KEYWORD (mount, COMMAND, 3, do_mount );
KEYWORD (rm, COMMAND, 1, do_rm );
KEYWORD (rmdir, COMMAND, 1, do_rmdir );
Mkdir is a command in rc, but do_mkdir is the real command execution entity.
There is a for loop behind init, where command execution is completed:
For (;;){
Execute_one_command ();
Restart_processes ();
...............
} Execute_one_command extracts the command and executes it one by one. If a service is registered in the command, it can be restarted if the execution fails.
Services are often executed by separate processes. Whether or not these programs are successfully executed is a matter of concern to the system. The system needs to supervise these processes, so it registers a signal processing function handle_signal. If a sub-process encounters an error, such as memory overflow, a semaphore is triggered. After receiving the semaphore, the parent process processes it in handle_signal, effectively managing the parent process, make these processes avoid turning them into "wild processes" or "zombie processes ". In the signal processing function wait_for_one_process, if the waiting process program fails or times out, a print of "waitpid returned pid % d, status = % 08x \" is displayed, if a service encounters an error and is executed repeatedly, the print is displayed. Init does not exit the for loop until all services are started successfully.
Init. rc Initialization File Analysis:
Analyze the init. rc file to know what the system has done, such as several key commands:
On property: ro. debuggable = 1
Start console
This statement indicates that the system will read the value in the prop attribute (Global Registry) if property: ro. if debuggable is set to 1, run the start console statement below the condition. Therefore, the print serial port of android is enabled here.
Sysclktz 0
Set the time zone.
Loglevel 3
Set the log level.
On property: ro. kernel. qemu = 1
Start adbd
Determine whether to enable remote debugging of adbd Based on the Property setting in build. prop.
Service bootanim/system/bin/bootanimation
Start the boot animation.
If you note that in Init. rc, a keyword is followed by a field starting with "on", for example:
The keyword on early-init is different from the method followed by a value in the preceding prop. It is mainly used to indicate the startup phase of android. When init loads these commands, it does not search for these keywords from the file header to the end of the file, but loads them in order of startup, the execution is also performed in this order, such as the following stages:
Early-init, init, early-fs, early-boot, boot, etc.
There is also a key phase word in init. rc. The Code is as follows:
On emmc-fs
Mount ext4 ext4 @ system/system ro
Mount ext4 ext4 @ userdata/data nosuid nodev
Mount ext4 ext4 @ cache/cache nosuid nodev
These commands are used to mount the @ system partition to the root directory/system in the format of ext4. ro indicates read-only. The emmc-fs stage starts from other stages because only the core directory of the system is mounted Can subsequent operations be performed. In addition to emmc, Init. rc also supports nand and determines which one is automatically recognized by the system. The Code is as follows:
If (check_flash_type () = NAND_TYPE ){
Action_for_each_trigger ("fs", action_add_queue_tail );
}
Else if (check_flash_type () = EMMC_TYPE ){
Action_for_each_trigger ("emmc-fs", action_add_queue_tail );
}
Check the bootargs keyword "hinand" or "mmcblk" to know the flash type.
The rc file contains a core keyword service. To use this keyword, You need to extend the subsequent command to a service. The rule for this keyword is also the most complex. For example, the following command:
Service zygote/system/bin/app_process-Xzygote/system/bin -- zygote -- start-system-server
Class main
Socket zygote stream 660 root system
Onrestart write/sys/android_power/request_state wake
Onrestart write/sys/power/state on
Onrestart restart media
Onrestart restart netd
This command uses the service command to tell the system to add zygote to the system service. The service syntax is:
Service service_name entry parameter of the executable program path
/System/bin/app_process is the actual executable program, and '-' is the execution parameter. Socket is used for the socket used by the Service. The following parameters are name, type, port, and address. The onrestart command specifies the condition for the service to restart, that is, when these conditions are met, the zygote service needs to be restarted; of course, these are some exception conditions, that is, if media or netd restarts abnormally, zgote needs to be restarted.
If sevices contains the oneshot keyword, it indicates that the service is executed only once. For example:
Service bootanim/system/bin/bootanimation
Class main
User root
Group graphics
Disabled
Oneshot
It indicates that the animation is executed once, and disabled indicates that the animation will not be executed again if an error occurs or times out. For more specific commands, see the init. rc file.
Analysis of Zygote Incubator:
From the above analysis, we can see that android is not really involved so far. If zygote is not used, android is regarded as a linux system at most. The Zygote process is the parent process of all APK applications. Other processes are generated by this process during hatching. Therefore, it is considered as an incubator. The android virtual machine can load the Java development environment. In terms of functions, the Java language is more similar to the Shell and Base languages (pseudo code ), tasks related to hardware are handed over to virtual machines. The task of a virtual machine is to shield the different attributes of the platform so that the same Java language can run on both the X86 platform and the ARM platform at the same time. The other advantage of Java is object-oriented, which is easier to use than C in application development. The disadvantage is that it is less efficient than C.
The actual execution program of Zygote is/system/bin/app_process. The Code of app_process is located in frameworks/base/cmds/app_process/app_main.cpp.
Analyze the code of app_main.cpp. app_process creates the first VM in the AndroidRuntime. startVm function:
If (JNI_CreateJavaVM (pJavaVM, pEnv, & initArgs) <0 ){
ALOGE ("JNI_CreateJavaVM failed \ n ");
Goto bail;
}
At the same time, after app_process is started, it will load the related classes and resource resources with the framework, check the jar packages under/system/framework/, and convert the jar files into dex files through dexopt optimization, install it in the/data/dalvik-cache/directory at the same time, so that you can directly search for it in the next execution. The two core classes ZygoteInit. java and SystemServer. java are started by two separate processes. The SystemServer process is the nerve hub of the Android system. Most system services that Android applications directly interact with are run in this process. The most critical aspects are WindowManagerServer (Wms) and ActivityManagerSystemService (AmS) and PackageManagerServer (PmS). These services are all started in the thread mode in this process.
PackagemanagerService is mainly used to manage the apk. This Service will parse the components in the apk, such as Activiey and Service. During system initialization, the/system/app/AND/data/app/directories are traversed, And the apk is copied to the/data/<pkgName> directory as the package name, save the class file in the apk to the/data/dalvik-cache/directory and name it with the corresponding apk. The Service uses the PackageParser class to parse AndroidManifest In the apk. the xml file obtains some information about the package and saves the information to/data/system/packages. xml and packages. list for later use. This information should be read only once. Will it be checked for updates after next Startup? If not, use the last file.
When the service is started for the first time, some directories will be created, such as data, app-asec, app-lib, and app-private under the/data/directory. Parse the/system/etc/permissions/platform. xml file to know which system permissions are defined and which ones correspond to the uid of the executable program. When you install an application, a required permission is displayed, which is defined here. From the above steps, we can see that the first opportunity to do a lot of work, that is why the first android system startup will be slow.
Start the first Activity:
When all the thread services are started, the ActivityManagerService (AmS) service checks whether other services are completed by calling the systemReady () function, the following code is executed:
MMainStack. resumeTopActivityLocked (null );
That is to say, AmS will execute the TopActivity at the top level, but the TopActivity does not exist when it is started for the first time. At this time, there will be:
If (next = null ){
// There are no more activities! Let's just start up
// Launcher...
If (mMainStack ){
ActivityOptions. abort (options );
Return mService. startHomeActivityLocked (mCurrentUser );
}
}
That is, to load HomeActivity. Unlike other systems, Android loads a fixed Activity as the main interface program, but in starHomeActiviyLocked () of AmS, the system sends a catagory field containing the intent of CATEGORY_HOME. As follows:
Intent. setComponent (mTopComponent );
If (mFactoryTest! = SystemServer. FACTORY_TEST_LOW_LEVEL ){
Intent. addCategory (Intent. CATEGORY_HOME );
}
No matter which application is declared as this type, it can be considered as the Home Program, and the system does not select any "Home" program, instead, the permission is handed over to the user. The user's choice determines the Home started by the system. This is the first Acivity to be started, there will be an operation box on the selection interface. by pressing the button, you can select an appropriate Activity as the main interface ). When AmS wants to start an activity, it needs to call the internal PackageManager to query the specific information corresponding to this name based on the activity name carried by intent. If yes, the activity will be started; otherwise, an error will be returned.
After the presentation of the system's Lancher interface is started, the system is started.
[This code is analyzed based on the android4.2 source code]