热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Android源代码解析系列(一):init.c文件详解

本文详细解析了Android系统启动过程中的核心文件`init.c`,探讨了其在系统初始化阶段的关键作用。通过对`init.c`的源代码进行深入分析,揭示了其如何管理进程、解析配置文件以及执行系统启动脚本。此外,文章还介绍了`init`进程的生命周期及其与内核的交互方式,为开发者提供了深入了解Android启动机制的宝贵资料。

                                                                                              init.c源码跟踪

      工具:Source Insight

      最好也打开源码,一步一步的跟,并仔细看后面的注释。


一、linux内核起来后,android的第一个用户进程:init
   1.那么来看看init.c中的main函数,它做了什么?
   Init.c system\core\Init打开source Insigt
   可以看到:
    ...
    open_devnull_stdio();
    log_init();
    INFO("reading config file\n");
    parse_config_file("/init.rc");
    ...
   2. 现在主要分析:parse_config_file("/init.rc");这个函数
    跟进去:int parse_config_file(const char *fn)
            {
                char *data;
                data = read_file(fn, 0);/*读取配置文件内容,这个文件就是init.c*/
                if (!data) return -1;
           
                parse_config(fn, data);/*调用parse_config做真正的解析*/
                DUMP();
                return 0;
            }
    3.看parse_config到底什么解析:
              state.parse_line = parse_line_no_op;             /*设置解析函数,                        
                for (;;) {                                不同的内容用不同的解析函数*/
                   switch (next_token(&state)) {
                   case T_EOF:
                       state.parse_line(&state, 0, 0);
                       return;
                   case T_NEWLINE:
                       if (nargs) {
                           int kw = lookup_keyword(args[0]);
                           if (kw_is(kw, SECTION)) {                       /*判断关键字类型是不是SECTION*/
                               state.parse_line(&state, 0, 0);
                               parse_new_section(&state, kw, nargs, args);  /*是的话解析新的SECTION*/
                           } else {
                               state.parse_line(&state, nargs, args);
                           }
                           nargs = 0;
                       }
                       break;
                   case T_TEXT:
                       if (nargs                            args[nargs++] = state.text;
                       }
                       break;
                   }
               }
     可见,这个函数是以一个一个Section进行解析的,而且不同的section使用不同的解析函数。
    4. 那么,如何判断那些属于一个section呢?
       1) 先去看看keyword.h中:
          #ifndef KEYWORD                           
          int do_class_start(int nargs, char **args);         /*声明一些函数,不同的内容用不同的解析函数*/
          int do_class_stop(int nargs, char **args);        
          ...
          ...
          #define __MAKE_KEYWORD_ENUM__                                      
          #define KEYWORD(symbol, flags, nargs, func) K_##symbol,   /*定义KEYWORD宏,虽然有四个参数,但这里只用一个 (得到K_symbol)*/
          enum {                                                    /*定义了各个关键字的枚举值*/                                      
          #endif                                                
              KEYWORD(capability,  OPTION,  0, 0)                  /*宏展开为:K_capability*/   
              KEYWORD(class,       OPTION,  0, 0)               
              KEYWORD(class_start, COMMAND, 1, do_class_start)  
          ....
          ....
          #ifdef __MAKE_KEYWORD_ENUM__
              KEYWORD_COUNT,         
          };                         
          #undef __MAKE_KEYWORD_ENUM__
          #undef KEYWORD                                             /*取消宏定义*/          
          #endif     
         
         
    2) 再看看,parser.c中:
     /*第一次包含*/ #include "keywords.h"                            /*第一次包含得到了一个枚举定义。*/
                                             /*接下来重新定义KEYWORD宏,*/
                    #define KEYWORD(symbol, flags, nargs, func) \
                        [ K_##symbol ] = { #symbol, func, nargs + 1, flags, },
                       
                   
                    struct {
                        const char *name; /*关键字的名称*/
                        int (*func)(int nargs, char **args);/*对应关键字的处理函数*/
                        unsigned char nargs;  /*参数个数,每个关键字的参数个数是固定的*/
                        unsigned char flags; /*关键字的属性有三种:COMMEND,OPTION,SECTION,
                           其中COMMAND有对应的处理函数*/
                    } keyword_info[KEYWORD_COUNT] = {
                        [ K_UNKNOWN ] = { "unknown", 0, 0, 0 },
    /*第二次包含*/  #include "keywords.h"
      
                    };
                  
                   
                    #undef KEYWORD
                   
                    #define kw_is(kw, type) (keyword_info[kw].flags & (type))
                    #define kw_name(kw) (keyword_info[kw].name)
                    #define kw_func(kw) (keyword_info[kw].func)
                    #define kw_nargs(kw) (keyword_info[kw].nargs)    
     从中可以发现,包含了两次头文件,第一次包含得到了一个枚举定义。
     
     将#include "keywords.h"替换,就可以很清楚的知道什么回事了:
                    第一步为:(也就是第一次#include "keywords.h"之前)
                                KEYWORD(capability,  OPTION,  0, 0) /*宏展开为:K_capability*/
                                KEYWORD(class,       OPTION,  0, 0)
                                KEYWORD(class_start, COMMAND, 1, do_class_start)
                                KEYWORD(class_stop,  COMMAND, 1, do_class_stop)
                                ......
                    第二步:第一次替换成:   (第一次#include "keywords.h"之后)
                                K_capability
                                K_class
                                K_class_start
                                K_class_stop
                               
                    第三步:重新定义KEYWORD
                          #define KEYWORD(symbol, flags, nargs, func) \
                                  [ K_##symbol ] = { #symbol, func, nargs + 1, flags, },
                    第四步:第二次#include "keywords.h"   
                            struct {
                                const char *name; /*关键字的名称*/
                                int (*func)(int nargs, char **args);/*对应关键字的处理函数*/
                                unsigned char nargs;  /*参数个数,每个关键字的参数个数是固定的*/
                                unsigned char flags; /*关键字的属性有三种:COMMEND,OPTION,SECTION,
                                   其中COMMAND有对应的处理函数*/
                            } keyword_info[KEYWORD_COUNT] = {
                                [ K_UNKNOWN ] = { "unknown", 0, 0, 0 },
                             
                                [K_capability] = "capability",func,nargs+1,flags,},
                                [K_class] = "class",func,nargs+1,flags,},
                                .....
                              }; 
                             
             回到第四点的问题:我们在keywords.h中发现只有
                 KEYWORD(on,          SECTION, 0, 0)
                 KEYWORD(service,     SECTION, 0, 0)
             这两的中含有关键字SECTION。
            
     5.我们进init.rc中
    
                on init     #on 关键字标志一个section,对应的名字为“init”
                            # 下面所有的内容都属于这个section,直到下一个section开始时
                sysclktz 0
               
                loglevel 3
               
                # setup the global environment
                    export PATH /sbin:/system/sbin:/system/bin:/system/xbin
                    export LD_LIBRARY_PATH /system/lib
                    export ANDROID_BOOTLOGO 1       #根据keyword.h可知,export表示一个command
                    export ANDROID_ROOT /system
                    export ANDROID_ASSETS /system/app
                    export ANDROID_DATA /data
                 ....
                 ....           
                 on boot
                 ...
                 ...
                 class_start default
                
                 #class_start也是一个command,对应函数为do_class_start
              #keywords.h--->KEYWORD(class_start, COMMAND, 1, do_class_start)
              ...
              ...
                 service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
                    socket zygote stream 666
                    onrestart write /sys/android_power/request_state wake
                    onrestart write /sys/power/state on
                    onrestart restart media
  
   6. 解析service
             service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
                    socket zygote stream 666  #socket是OPTION
                    #下面的onrestart是OPTION,而write和restart是COMMAND。
                    onrestart write /sys/android_power/request_state wake
                    onrestart write /sys/power/state on
                    onrestart restart media
      解析section的入口函数是parser.c---->parse_new_section(&state, kw, nargs, args);
             void parse_new_section(struct parse_state *state, int kw,
                       int nargs, char **args)
                                {
                                    printf("[ %s %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;
                                    }
                                    state->parse_line = parse_line_no_op;
                                }


推荐阅读
author-avatar
许先生不会再想过去的事观_307
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有