#############################################
This article is extremely ice original, reproduced please indicate the source
#############################################
After parsing the init.rc action, the remaining part is parsing the service.
Parsing the service still needs to go back inside the parse_config. Based on the previous knowledge, we can also easily know that when the keyword is section, it will go to parse_new_section.
The Parse_service is executed first, and then the service and the followed option are set to execute parse_line:parse_line_service.
To understand the service parsing process, the first thing to focus on is the service structure.
struct Service {/* List of all services */struct ListNode slist; ListNode slist const char *name; Name const char *classname; The default value is Defult unsigned flags; Option pid_t pid; The PID time_t time_started of the process where the service is located; /* Time of last start */time_t time_crashed; /* First crash within inspection window */int nr_crashed; /* Number of times crashed within window */uid_t uid; Effective user ID gid_t gid; Effective group ID gid_t Supp_gids[nr_svc_supp_gids]; Supplementary IDs size_t Nr_supp_gids; Supp_gids of size char *seclabel; struct Socketinfo *sockets; The sockets struct Svcenvinfo *envvars created for the service; Environment variables set for service struct action Onrestart; /* Actions to execute on restart. */* Keycodes for triggering this service Via/dev/keychord */int *keycodes; int nkeycodes; int keychord_id; int ioprio_class; int ioprio_pri; int Nargs; /* "Must is at the END of the STRUCT" */char *args[1];}; /* ^-------' args ' must is at the end of this struct! */
This structure is relatively simple, in addition to the service's own attributes, there is only one listnode for the data structure.
This means that in the service structure, the struct will only be added to a linked list instead of two linked lists like action.
It is also important to note that in the service structure, an action structure is maintained, which means that there is also a commands linked list of actions in the service.
And then we'll take a look at the parse_service function.
static void *parse_service (struct parse_state *state, int nargs, char **args) {struct service *svc; declare struct if (Nargs < 3) {//If the service has a parameter of less than three, we think the service is an unhealthy service. The minimum service Nargs is also 3, the Service keyword, the service name, the command to execute when the service starts Parse_error (state, "services must has a name and a Program\n "); return 0; } if (!valid_name (Args[1])) {//If the service name is a nonstandard name and contains other symbols, we will assume that the service is not a canonical service. Parse_error (state, "Invalid service name '%s ' \ n", args[1]); return 0; svc = Service_find_by_name (args[1]); Will be looked up from the existing service_list, if there is already a service presence with the same name if (SVC) {//If a service with the same name is found, the error parse_error is returned (state, "I gnored Duplicate definition of service '%s ' \ n ", args[1]); return 0; } Nargs-= 2; Remove the service keyword with the name of the service svc = calloc (1, sizeof (*SVC) + sizeof (char*) * Nargs); malloc this struct if (!svc) {//If malloc fails, prompt out of the memory Parse_error (state, "out of memory\n"); return 0; } svc->name = args[1]; Set the service name to the first parameter after the service keyword Svc->classname = "default"; The default classname is defaulted memcpy (Svc->args, args + 2, sizeof (char*) * Nargs); Copy the args remaining parameters to the SVC's args inside Svc->args[nargs] = 0; The last entry to args is set to 0 Svc->nargs = Nargs; The number of arguments equals the number of arguments passed in svc->onrestart.name = "Onrestart"; Set Onrestart.name to Onrestart list_init (&svc->onrestart.commands); Initialize the Onrestart list list_add_tail (&service_list, &svc->slist); Add the current service structure to the Service_list list return svc;}
From the above we know that after the execution of Parse_service, some properties of the service are initialized, and the service servicename is saved as args.
In addition, the parsed service is added to the Service_list list.
And then, the next thing to do is
State->parse_line = Parse_line_service;
So we're like action, and then we'll look at Parse_line_service's operation.
static void Parse_line_service (struct parse_state *state, int nargs, char **args) {struct Service *svc = State->cont Ext struct command *cmd; int i, KW, Kw_nargs; if (Nargs = = 0) {return; } svc->ioprio_class = Ioschedclass_none; KW = Lookup_keyword (Args[0]); switch (kw) {case K_capability:break; Case K_class:if (Nargs! = 2) {Parse_error (state, "class option requires a classname\n"); } else {svc->classname = args[1]; } break; Case K_console:svc->flags |= Svc_console; Break Case K_disabled:svc->flags |= svc_disabled; Svc->flags |= svc_rc_disabled; Break Case K_ioprio:if (Nargs! = 3) {Parse_error (state, "Ioprio optin usage:ioprio <rt|be|idle> <i Oprio 0-7>\n "); } else { .... ........ Case k_onrestart: nargs--; args++; & nbsp KW = Lookup_keyword (Args[0]); if (!kw_is (kw, COMMAND)) { &NBS P Parse_error (state, "Invalid command '%s ' \ n", Args[0]); break; } Kw_nargs = Kw_nargs (kw); if (Nargs < Kw_nargs) { Parse_error (state, "%s requires%d%s\n", Args[0], kw_nargs-1, &N Bsp &NBSp Kw_nargs > 2? "Arguments": "argument"); break; } &NBSP ; cmd = malloc (sizeof (*cmd) + sizeof (char*) * Nargs); Cmd->func = kw_func (kw); &N Bsp Cmd->nargs = nargs; memcpy (Cmd->args, args, sizeof (char*) * Nargs); & nbsp List_add_tail (&svc->onrestart.commands, &cmd->clist); break; ............... }
As you can see, the main function of Parse_line_service is to parse each line of service into a different case and populate the service structure.
This may be said to be difficult to understand.
But to make it easier to understand, let's look at an example from init.rc to analyze:
Service Servicemanager/system/bin/servicemanager class core User System Group system Critical Onrestart Restart HEALTHD onrestart restart zygote onrestart Restart media onrestart restart Surfaceflinger Onrestart Restart DRM
At the time of Parse_line_service, will be in
Class keyword, execute to
Case K_class: If (Nargs! = 2) {//Determine if it is two tokens, if not, format error Parse_error (state, "class option requires a classname\ n "); } else { svc->classname = args[1]; } Break
That is, change the service's classname from "Default" to "Args[1."
In the option of user system,
Will go to execute
Case K_user: if (Nargs! = 2) { parse_error (state, "user option requires a user id\n") ;} else { Svc->ui D = Decode_uid (Args[1]); } Break
The UID will be set to the system corresponding UID
Also note that in the process of parsing, there will be a more important option is restart, look at the time when executing to this keyword, what will run.
Case k_onrestart:nargs--; args++; KW = Lookup_keyword (Args[0]); if (!kw_is (kw, COMMAND)) {//Determine if command, if restart followed by command, it will return error parse_error (state, "Invalid comm and '%s ' \ n ', args[0]); Break } Kw_nargs = Kw_nargs (kw); Parameters required to get the current command if (Nargs < Kw_nargs) {//If the passed parameter is less than the parameter we need, the error parse_error (state, "%s req") is returned. Uires%d%s\n ", Args[0], kw_nargs-1, Kw_nargs > 2? "Arguments": "argument"); Break } cmd = malloc (sizeof (*cmd) + sizeof (char*) * Nargs); Initialize command Cmd->func = kw_func (kw); Assign the func contained by kw to cmd->func Cmd->nargs = Nargs; Save the number of parameters as Nargs memcpy (Cmd->args, args, sizeof (char*) * Nargs); Copy these parameters to the cmd in args list_add_tail (&svc->onrestart.commands, &cmd->clist); Add these command to the internal linked list of the service structure break;
So far, we have analyzed all the parsing problems about init.rc.
After the service is parsed, a linked list is generated to hold the service's structure, and then the service's structure runs itself to maintain an action.
This action will contain all of the content contained in the Restatt, that is, the option keyword of restart will contain the command to be executed
The structure should be much simpler and clearer than the action.
After parsing, we should look at how Android performs these actions and service in the process of booting.
Android startup process Analysis (ix) parsing INIT.RC Service