[Cpp]
It is well known that Android Init process is the first process after Android is started. android Init process is actually driven by the Startup Program of Linux Kernel. power on the device, Bootloader loads the Kernel, and then the Kernel drives the Android Init process. this section belongs to the Linux field. The simple function call process is as follows:
Kernel_init ==> init_post ==> run_init_process ==> start Android Init process.
As this article mainly analyzes the work of AndroidInit process in the beginning, the process in the three functions kernel_init, init_post, run_init_process is not analyzed here.
Android Init process mainly performs three tasks during initialization.
1. Analyze and execute the init. rc Script File
2. Create a devicenode file
3. Monitor System attribute changes and events
The following three points are used for research and analysis respectively.
Analyze and execute the init. rc Script File
Init. the rc Script file is mainly used to set the Android system environment and has some pending process records. the entire script file can be divided into two types: action list and service list. these two types are classified based on the keywords in the script file,
1. Elements in the actionlist starting with the keyword "on,
2. Elements in servicelist with the keyword "Services.
These two keywords are the same as init. the AIL (Android Init Language) used by the rc Script file is related. AIL mainly contains four types: Action, Commands, Services, and Option. the syntax usage of these four types is described in detail in system \ core \ init \ readme.txt. here is a brief introduction to these four types of relationships. For syntax usage, see system \ core \ init \ readme.txt.
Action and Services represent a new Section. All sections have declaration of Command and Option. command is mainly used to create some system directories or start processes. option is used as some attribute settings of ServicesSection. for example, whether the process is restarted.
The init_parse_config_file function is used to analyze and execute the init. rc Script file. This function is used to analyze the init. rc Script file.
[Cpp]
// \ System \ core \ init \ init_parser.c
Int init_parse_config_file (const char * fn)
{
Char * data;
Data = read_file (fn, 0 );
If (! Data) return-1;
Parse_config (fn, data );
DUMP ();
Return 0;
}
Static void parse_config (const char * fn, char * s)
{
Struct parse_state state;
//...
State. filename = fn;
State. line = 0;
State. ptr = s;
State. nexttoken = 0;
State. parse_line = parse_line_no_op;
//...
For (;;){
Switch (next_token (& state )){
Case T_EOF:
State. parse_line (& state, 0, 0 );
Goto parser_done;
Case T_NEWLINE:
State. line ++;
If (nargs ){
Int kw = lookup_keyword (args [0]);
If (kw_is (kw, SECTION )){
State. parse_line (& state, 0, 0 );
Parse_new_section (& state, kw, nargs, args );
} Else {
State. parse_line (& state, nargs, args );
}
Nargs = 0;
}
Break;
Case T_TEXT:
If (nargs <INIT_PARSER_MAXARGS ){
Args [nargs ++] = state. text;
}
Break;
}
}
}
Void parse_new_section (struct parse_state * state, int kw,
Int nargs, char ** args)
{
Printf ("[% s] \ n", args [0],
Nargs> 1? Args [1]: "");
Switch (kw ){
Case K_service:
State-> context = parse_service (state, nargs, args );
If (state-> context ){
State-> parse_line = parse_line_service;
Return;
}
Break;
Case K_on:
State-> context = parse_action (state, nargs, args );
If (state-> context ){
State-> parse_line = parse_line_action;
Return;
}
Break;
Case K_import:
Parse_import (state, nargs, args );
Break;
}
State-> parse_line = parse_line_no_op;
}
// \ System \ core \ init \ init_parser.c
Int init_parse_config_file (const char * fn)
{
Char * data;
Data = read_file (fn, 0 );
If (! Data) return-1;
Parse_config (fn, data );
DUMP ();
Return 0;
}
Static void parse_config (const char * fn, char * s)
{
Struct parse_state state;
//...
State. filename = fn;
State. line = 0;
State. ptr = s;
State. nexttoken = 0;
State. parse_line = parse_line_no_op;
//...
For (;;){
Switch (next_token (& state )){
Case T_EOF:
State. parse_line (& state, 0, 0 );
Goto parser_done;
Case T_NEWLINE:
State. line ++;
If (nargs ){
Int kw = lookup_keyword (args [0]);
If (kw_is (kw, SECTION )){
State. parse_line (& state, 0, 0 );
Parse_new_section (& state, kw, nargs, args );
} Else {
State. parse_line (& state, nargs, args );
}
Nargs = 0;
}
Break;
Case T_TEXT:
If (nargs <INIT_PARSER_MAXARGS ){
Args [nargs ++] = state. text;
}
Break;
}
}
}
Void parse_new_section (struct parse_state * state, int kw,
Int nargs, char ** args)
{
Printf ("[% s] \ n", args [0],
Nargs> 1? Args [1]: "");
Switch (kw ){
Case K_service:
State-> context = parse_service (state, nargs, args );
If (state-> context ){
State-> parse_line = parse_line_service;
Return;
}
Break;
Case K_on:
State-> context = parse_action (state, nargs, args );
If (state-> context ){
State-> parse_line = parse_line_action;
Return;
}
Break;
Case K_import:
Parse_import (state, nargs, args );
Break;
}
State-> parse_line = parse_line_no_op;
}
The above Code clearly shows that the init. the command and option actions in the section in the rc Script file are added to the actionlist and service list for execution. the added actions can be used to study the implementation of parse_action and parse_service. the analysis process is here first, and then you can see the implementation of parse_action and parse_service.
The above is the analysis process of the init. rc Script file, and the execution process of the init. rc Script file is implemented by the execute_one_command function.
[Cpp]
/\ System \ core \ init. c
Void execute_one_command (void)
{
Int ret;
If (! Cur_action |! Cur_command | is_last_command (cur_action, cur_command )){
Cur_action = action_remove_queue_head ();
Cur_command = NULL;
If (! Cur_action)
Return;
INFO ("processing action % p (% s) \ n", cur_action, cur_action-> name );
Cur_command = get_first_command (cur_action );
} Else {
Cur_command = get_next_command (cur_action, cur_command );
}
If (! Cur_command)
Return;
Ret = cur_command-> func (cur_command-> nargs, cur_command-> args );
INFO ("command '% s' r = % d \ n", cur_command-> args [0], ret );
}
// \ System \ core \ init. c
Void execute_one_command (void)
{
Int ret;
If (! Cur_action |! Cur_command | is_last_command (cur_action, cur_command )){
Cur_action = action_remove_queue_head ();
Cur_command = NULL;
If (! Cur_action)
Return;
INFO ("processing action % p (% s) \ n", cur_action, cur_action-> name );
Cur_command = get_first_command (cur_action );
} Else {
Cur_command = get_next_command (cur_action, cur_command );
}
If (! Cur_command)
Return;
Ret = cur_command-> func (cur_command-> nargs, cur_command-> args );
INFO ("command '% s' r = % d \ n", cur_command-> args [0], ret );
}
This function is executed to execute the command in the actionlist using the function provided by cur_command. What is the function carried by cur_command? It can be deduced by the call functions get_first_command and get_next_command.
[Cpp]
// \ System \ core \ init. c
Static struct command * get_first_command (struct action * act)
{
Struct listnode * node;
Node = list_head (& act-> commands );
If (! Node | list_empty (& act-> commands ))
Return NULL;
Return node_to_item (node, struct command, clist );
}
Static struct command * get_next_command (struct action * act, struct command * cmd)
{
Struct listnode * node;
Node = cmd-> clist. next;
If (! Node)
Return NULL;
If (node = & act-> commands)
Return NULL;
Return node_to_item (node, struct command, clist );
}
// \ System \ core \ init. c
Static struct command * get_first_command (struct action * act)
{
Struct listnode * node;
Node = list_head (& act-> commands );
If (! Node | list_empty (& act-> commands ))
Return NULL;
Return node_to_item (node, struct command, clist );
}
Static struct command * get_next_command (struct action * act, struct command * cmd)
{
Struct listnode * node;
Node = cmd-> clist. next;
If (! Node)
Return NULL;
If (node = & act-> commands)
Return NULL;
Return node_to_item (node, struct command, clist );
}
At this point, we only know that these two functions only extract the data of the actioncommand node from the action list. As for the function carried by the command node, we still don't know how to get it?
I had to look for clues in the analysis process. during the analysis process, run the parse_config function to parse init. when calling the rc action, you need to execute the lookup_keyword function to obtain a keyword as a parameter before calling parse_new_section. start from this function.