zoukankan      html  css  js  c++  java
  • 分析脚本文件AndroidInitProcess分析心得(1)

    本篇文章是一篇关于分析脚本文件的帖子

    
    

        众所皆知,Android Init process是Android动启后先最起来的进程. 真正说来Android Init process是由Linux Kernel的动启程序所驱动起来. 从device上电, Bootloader载加Kernel, 然后Kernel接着驱动Android Init process. 这一段属于Linux 的范畴, 其简略的数函呼叫流程如下:

        kernel_init===> init_post ==> run_init_process ==> 动启 Android Init process.

        由于这篇重要是分析AndroidInit process在处始化所作的作工, 因此kernel_init, init_post,run_init_process 这三个数函里的流程就不在这里作分析.

            Android Init process 在初始化阶段重要做三件事.

        1. 分析和执行init.rc脚本文件

        2. 建创devicenode file

        3. 监控系统属性变更跟事件

        以下就分离依照这三点来做研讨分析.

        分析和执行init.rc脚本文件

            init.rc脚本文件重要是用来设定Android系统环境,还有一些待执行的进程记载.整个脚本文件可以分为两类action list跟 service list. 这两类会根据脚本文件中的关键词来作分类,

            1. 以"on"关键词扫尾的为actionlist中的素元,

            2. 以"Services"关键词的为servicelist中的素元.

        这两个关键词就跟init.rc脚本文件用使的AIL(Android Init Language)有关了.AIL 重要包括四种类型, Action, Commands, Services, Option. 这四类的法语用法在system\core\init\readme.txt中有详细描述. 这里只是简略的绍介这四类的关系, 法语用法请考参system\core\init\readme.txt.

            Action和Services代表着一段新的Section,全部的Section下都有Command跟Option的一些告宣.Command最重要是用来建创一些系统目录或是动启进程.Option则作为ServicesSection的一些属性设定. 比如进程是不是从新被动启.

            分析和执行init.rc脚本文件的研讨分析就由init_parse_config_file数函开始.因为此数函是正用来init.rc脚本文件作分析流程.

    // \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 %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;
    }
        每日一道理
    父亲对于儿子说来,是座耸立的高山,而儿子只是颗石子,源于山,却并不了解山。生活中诸多爱的密码,是需用细节来解读的,在亲情的沃土上,要想搞得最美的果实,惟有期待那存在于瞬间的心与心的共鸣,爱与爱的默契。

        由面上的程序代码可以很楚清的看到, 只是把init.rc脚本文件中的section中的command跟option的动作入加actionlist和service list待等执行.入加的动作可以研讨 parse_actionparse_service的实作.分析流程先到此, 以后再来看parse_actionparse_service的实作.

            以上是作init.rc脚本文件的分析流程, 而init.rc脚本文件的执行流程就由execute_one_command 数函来实作.

    // \system\core\init\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);
    }

        此数函执行到最后是利用cur_command所带的function去执行actionlist中的command. 此cur_command所带的function是底到甚么呢? 可以由后面的呼叫数函 get_first_command和 get_next_command去推导.

    // \system\core\init\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);
    }

        到此我们只知道这两个数函只是从action list把actioncommand node的据数取出来, 至于这个command node所带的function还是不知道怎么来的?

            只好在往分析流程去找蛛丝马迹了. 在分析流程中直一执行到利用parse_config数函来做析解init.rc的动作时, 有发明在呼叫parse_new_section之前会须要先执行lookup_keyword数函去获得一个keyword作当参数. 就来从这数函开始分析

    文章结束给大家分享下程序员的一些笑话语录: 很多所谓的牛人也不过如此,离开了你,微软还是微软,Google还是Google,苹果还是苹果,暴雪还是暴雪,而这些牛人离开了公司,自己什么都不是。

  • 相关阅读:
    .gitignore文件的位置
    robotframework 用法
    selenium 问答
    python 定时任务执行
    final关键字
    开启线程的方式。
    约瑟夫环。
    1000的阶乘,1.求出所有零的个数 2.求出尾部零的个数
    三种代码块。
    static关键字的基本用法。
  • 原文地址:https://www.cnblogs.com/xinyuyuanm/p/3067755.html
Copyright © 2011-2022 走看看