The software version used in this article
android:4.2.2
Linux kernel: 3.1.10
This article and subsequent articles will be on the Android initialization (INIT) process of detailed, stripping and cocoon analysis, and interspersed with a lot of knowledge in the hope that the reader understand the launch process of Android and help. This chapter mainly introduces the definition of the hardware-related initialization file name and the principle and implementation of the attribute service.
Android is essentially a Linux kernel based operating system. Similar to Ubuntu Linux, Fedora Linux. Only Android has added some special support for mobile devices at the application level. Since Android is a Linux kernel system, the basic boot process should also conform to the Linux rules. If you have studied other Linux systems, you should understand that a complete Linux system will first load a Linux kernel into memory, which is to compile the Bzimage files generated by the Linux kernel source code, Zimage files are generated for Linux kernel source code optimized for Android. This file is the binary version of the Linux kernel. Since Zimage is running in kernel space, and the software we normally use is running in the application space (detailed description of kernel space and application space, refer to the book "Android Depth Exploration (Volume 1): HAL and Drive Development". In subsequent volumes, the overall Android system will be analyzed in a holistic perspective. Kernel space and application space cannot be accessed directly through the memory address level, so it is necessary to establish some kind of communication mechanism.
Linux currently has a number of communication mechanisms that can interact between user space and kernel space, such as device-driven files (in the/dev directory), memory files (/proc,/sys directories, and so on). Everyone who knows Linux should know that one of the important features of Linux is that everything is in the form of a file, for example, a device usually corresponds to one or more device files. These files that interact with kernel space are in user space, so when the Linux kernel is loaded, you need to first build the directory where the files are located. And the program that completes these work is the init that this article wants to introduce. Init is a command-line program. One of its main tasks is to create directories of these files that interact with the kernel space. When the Linux kernel is loaded, the first thing to do is invoke the INIT program, that is, Init is the first program that user space executes.
Before you analyze the core code of INIT, you need to understand that Init has done the following, in addition to creating directories
1. Initializing properties
2. Commands for processing configuration files (primarily init.rc files), including handling various action.
3. Performance analysis (using the Bootchart tool).
4. Unlimited loop execution command (start other processes).
Although the work done by Init is not much, the code is very complex. The INIT program is not made up of a source code file, but is linked to the target file of a set of source code files. These files are located in the following directory.
<android source code This directory >/system/core/init
Where init.c is the primary file for Init, now open the file and look at the contents. Since Init is a command-line program, parsing init.c should start with the main function first, now to the main function, and the code is as follows:
int main (int argc, char **argv) {int fd_count = 0;
struct POLLFD ufds[4];
Char *tmpdev;
char* debuggable;
Char tmp[32];
int property_set_fd_init = 0;
int signal_fd_init = 0;
int keychord_fd_init = 0;
BOOL Is_charger = false;
if (!strcmp (basename (argv[0)), "Ueventd") return Ueventd_main (argc, argv);
if (!strcmp (basename (argv[0)), "Watchdogd") return Watchdogd_main (argc, argv);
/* Clear the Umask * * umask (0);
The following code starts to create a variety of user space directories, such as/dev,/proc,/sys, etc. mkdir ("Dev", 0755);
mkdir ("/proc", 0755);
mkdir ("/sys", 0755);
Mount ("Tmpfs", "Dev", "Tmpfs", Ms_nosuid, "mode=0755");
mkdir ("/dev/pts", 0755);
mkdir ("/dev/socket", 0755);
Mount ("Devpts", "/dev/pts", "Devpts", 0, NULL);
Mount ("proc", "/proc", "Proc", 0, NULL);
Mount ("Sysfs", "/sys", "Sysfs", 0, NULL); /* Detects if/dev/.booting files can be read/write and created/close (open ("/dev/.booting", O_wronly |
o_creat, 0000));
Open_devnull_stdio ();
Klog_init ();
Initialize attribute Property_init ();
Get_hardware_name (Hardware, &revision);
Process kernel command line process_kernel_cmdline ();
... is_charger =!strcmp (Bootmode, "charger");
INFO ("Property init\n");
if (!is_charger) property_load_boot_defaults ();
INFO ("reading config file\n");
Analyze the contents of the/init.rc file Init_parse_config_file ("/init.rc");
...//Execute the action Action_for_each_trigger in the initialization file ("Init", action_add_queue_tail);
Skips the Mount file system work if (!is_charger) {Action_for_each_trigger ("Early-fs", Action_add_queue_tail) in charger mode;
Action_for_each_trigger ("FS", Action_add_queue_tail);
Action_for_each_trigger ("Post-fs", Action_add_queue_tail);
Action_for_each_trigger ("Post-fs-data", Action_add_queue_tail); } queue_builtin_action (Property_service_init_action, "Property_service_init ");
Queue_builtin_action (signal_init_action, "signal_init");
Queue_builtin_action (check_startup_action, "Check_startup");
if (Is_charger) {Action_for_each_trigger ("charger", action_add_queue_tail);
else {Action_for_each_trigger ("Early-boot", Action_add_queue_tail);
Action_for_each_trigger ("Boot", action_add_queue_tail); }/* Run All property triggers based to the current state of the properties/queue_builtin_action (Queue_
Property_triggers_action, "queue_property_triggers");
#if Bootchart queue_builtin_action (bootchart_init_action, "bootchart_init"); #endif//Enter an infinite loop, establish the child process of init (Init is the parent process of all processes) for (;;)
{int nr, I, timeout =-1;
Executes a command (a child process corresponds to a command) Execute_one_command ();
Restart_processes (); if (!property_set_fd_init && get_property_set_fd () > 0) {ufds[fd_count].fd = GET_PROPERTY_SET_FD (
); Ufds[fd_count].events = Pollin;
ufds[fd_count].revents = 0;
fd_count++;
Property_set_fd_init = 1;
} if (!signal_fd_init && get_signal_fd () > 0) {ufds[fd_count].fd = GET_SIGNAL_FD ();
Ufds[fd_count].events = Pollin;
ufds[fd_count].revents = 0;
fd_count++;
Signal_fd_init = 1; } if (!keychord_fd_init && get_keychord_fd () > 0) {ufds[fd_count].fd = GET_KEYCHORD_FD ()
;
Ufds[fd_count].events = Pollin;
ufds[fd_count].revents = 0;
fd_count++;
Keychord_fd_init = 1;
} if (Process_needs_restart) {timeout = (Process_needs_restart-gettime ()) * 1000;
if (Timeout < 0) Timeout = 0;
} if (!action_queue_empty () | | cur_action) Timeout = 0; Bootchart is a performance statistics tool forCollect hardware and system information and write it to disk so that it/he program uses #if bootchart if (Bootchart_count > 0) {if (Timeout < 0 | |
Timeout > Bootchart_polling_ms) timeout = Bootchart_polling_ms;
if (Bootchart_step () < 0 | |--bootchart_count = 0) {bootchart_finish ();
Bootchart_count = 0;
} #endif//Wait for the submission of the next command nr = Poll (UFDs, Fd_count, timeout);
if (NR <= 0) continue; for (i = 0; i < Fd_count i++) {if (ufds[i].revents = = Pollin) {if (ufds[i].fd = = Get_p
ROPERTY_SET_FD ()) handle_property_set_fd ();
else if (ufds[i].fd = = GET_KEYCHORD_FD ()) Handle_keychord ();
else if (ufds[i].fd = = GET_SIGNAL_FD ()) handle_signal ();
}} return 0; }