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

Androidinit.rc文件解析过程详解(三)

Androidinit.rc文件解析过程详解(三)三、相关结构体1、listnodelistnode结构体用于建立双向链表,这种结构广泛用于kernel代码中,android源代码中

Android init.rc文件解析过程详解(三)

 

三、相关结构体

 

     1、listnode

listnode结构体用于建立双向链表,这种结构广泛用于kernel代码中, android源代码中定义了listnode结构体以及相关操作双向链表的方法,与kernel中的定义类似。

 

这个实现的核心思想是:在用户自定义的结构体xx中定义一个listnode类型的成员,

这个listnode类型成员的作用就是能将xx类型的变量组成一个双向链表。下面我们来看一下是listnode是怎么做到的。

 

//listnode类型里面只有两个指针prev,next

struct listnode

{

    struct listnode *next;

    struct listnode *prev;

};

 

//将链表中的一个node转换成自定义结构体中的一个对象

#define node_to_item(node, container, member) \

    (container *) (((char*) (node)) - offsetof(container, member))

 

//初始化一个链表

void list_init(struct listnode *node)

{

    node->next = node;

    node->prev = node;

}

 

//将一个节点到链表

void list_add_tail(struct listnode *head, struct listnode *item)

{

    item->next = head;

    item->prev = head->prev;

    head->prev->next = item;

    head->prev = item;

}

 

//删除一个节点

void list_remove(struct listnode *item)

{

    item->next->prev = item->prev;

    item->prev->next = item->next;

}

 

理解node_to_item宏是理解listnode用法的关键,这个宏的作用是将一个listnode指针转换成了一个指定类型(自定义)的指针,这个宏先使用offsetof函数获取到指定结构体中指定成员变量的地址偏移量,然后通过指针运算获得listnode指针变量所在结构体变量的指针。

这种实现与我们课堂上所学的链表实现方法不太一样,教科书上的实现是在listnode中存储了自定义的数据,而这个实现是在自定义的数据当中存储listnode指针。

 

 

 

2、action结构体

     前面已经讲过on类型的section解析之后会生成一个双向链表action_list, 这个action_list每个node表示就是action结构体的对象,也就是说一个on类型的section都会生成一个action结构体的对象。

    

action结构体定义如下:

 

struct action {

        /* node in list of all actions */

    struct listnode alist;

        /* node in the queue of pending actions */

    struct listnode qlist;

        /* node in list of actions for a trigger */

    struct listnode tlist;

 

    unsigned hash;

    const char *name;

   

    struct listnode commands;        //节点为command结构体的双向链表

    struct command *current;

};

 

     action结构体除了用在on类型的section, 也用在service类型的section,下面介绍service结构体时会说明。

 

3、command结构体

 

Command结构体定义如下:

struct command

{

        /* list of commands in an action */

    struct listnode clist;

 

    int (*func)(int nargs, char **args);

    int nargs;

    char *args[1];

};

 

command结构体比较简单, 用于标识一个命令,包含双向链表指针、对应的执行函数、参数个数以及命令关键字。

 

4、service结构体

 

 

struct service {

        /* list of all services */

    struct listnode slist;                  //将结构体链接成service_list用

 

    const char *name;

    const char *classname;

 

    unsigned flags;

    pid_t pid;

    time_t time_started;    /* 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;

    gid_t gid;

    gid_t supp_gids[NR_SVC_SUPP_GIDS];

    size_t nr_supp_gids;

 

#ifdef HAVE_SELINUX

    char *seclabel;

#endif

 

    struct socketinfo *sockets;

    struct svcenvinfo *envvars;

 

    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 BE AT THE END OF THE STRUCT" */

    char *args[1];

};

 

service结构体存储了service的相关信息, 包括进程号、启动时间、名字等, 字段onrestart

就用到了action结构体, onrestart这个option后面通常跟着一个命令,所以也用action结构体来表示。

 

 

注:本文基于android4.2的源代码分析


最后我们分析一下init.c中的main()函数

01 int main(int argc, char **argv)
02 {
03     ... ...
04         /* Get the basic filesystem setup we need put
05          * together in the initramdisk on / and then we'll
06          * let the rc file figure out the rest.
07          */
08     // 创建一些linux根文件系统中的目录
09     mkdir("/dev", 0755);
10     mkdir("/proc", 0755);
11     mkdir("/sys", 0755);
12  
13     mount("tmpfs""/dev""tmpfs", MS_NOSUID, "mode=0755");
14     mkdir("/dev/pts", 0755);
15     mkdir("/dev/socket", 0755);
16     mount("devpts""/dev/pts""devpts", 0, NULL);
17     mount("proc""/proc""proc", 0, NULL);
18     mount("sysfs""/sys""sysfs", 0, NULL);
19  
20     //open_devnull_stdio();
21     klog_init();
22  
23     ... ...
24  
25     printf("Parsing init.rc ...\n"); 
26     // 读取并且解析init.rc文件
27     init_parse_config_file("/init.rc");
28  
29     ... ...
30  
31     // 取得硬件名
32     get_hardware_name();
33     snprintf(tmp, sizeof(tmp), "/init.%s.rc", hardware);
34  
35     // 读取并且解析硬件相关的init脚本文件
36     parse_config_file(tmp);
37  
38     ... ...
39  
40     # 触发在init脚本文件中名字为early-init的action,并且执行其commands,其实是: on early-init
41     action_for_each_trigger("early-init", action_add_queue_tail);
42  
43     queue_builtin_action(wait_for_coldboot_done_action, "wait_for_coldboot_done");
44     queue_builtin_action(property_init_action, "property_init");
45     queue_builtin_action(keychord_init_action, "keychord_init");
46     # 控制台相关初始化,在这里会加载启动动画,如果动画打开失败,则在屏幕上打印: A N D R O I D字样。
47     queue_builtin_action(console_init_action, "console_init");
48     queue_builtin_action(set_init_properties_action, "set_init_properties");
49  
50     /* execute all the boot actions to get us started */
51     # 触发在init脚本文件中名字为init的action,并且执行其commands,其实是:on init
52     action_for_each_trigger("init", action_add_queue_tail);
53  
54     /* skip mounting filesystems in charger mode */
55     if (strcmp(bootmode, "charger") != 0) {
56         action_for_each_trigger("early-fs", action_add_queue_tail);
57         action_for_each_trigger("fs", action_add_queue_tail);
58         action_for_each_trigger("post-fs", action_add_queue_tail);
59         action_for_each_trigger("post-fs-data", action_add_queue_tail);
60     }
61  
62     // 启动系统属性服务: system property service
63     queue_builtin_action(property_service_init_action, "property_service_init");
64     queue_builtin_action(signal_init_action, "signal_init");
65     queue_builtin_action(check_startup_action, "check_startup");
66  
67     queue_builtin_action(queue_early_property_triggers_action, "queue_early_propety_triggers");
68  
69     if (!strcmp(bootmode, "charger")) {
70         action_for_each_trigger("charger", action_add_queue_tail);
71     else {
72         // 触发在init脚本文件中名字为early-boot和boot的action,并且执行其commands,其实是:on early-boot和on boot
73         action_for_each_trigger("early-boot", action_add_queue_tail);
74         action_for_each_trigger("boot", action_add_queue_tail);
75     }
76  
77         /* run all property triggers based on current state of the properties */
78     // 启动所有属性变化触发命令,其实是: on property:ro.xx.xx=xx
79     queue_builtin_action(queue_property_triggers_action, "queue_propety_triggers");
80  
81     // 进入死循环
82     for(;;) {
83         int nr, i, timeout = -1;
84  
85         execute_one_command();
86         // 启动所有init脚本中声明的service
87         restart_processes();
88         ... ...
89         // 多路监听设备管理,子进程运行状态,属性服务
90         nr = poll(ufds, fd_count, timeout);
91         ... ...
92     }
93  
94     return 0;
95 }



转载:http://blog.itpub.net/7232789/viewspace-758168/

http://blog.csdn.net/mk1111/article/details/16357327


推荐阅读
  • 本文介绍了Java工具类库Hutool,该工具包封装了对文件、流、加密解密、转码、正则、线程、XML等JDK方法的封装,并提供了各种Util工具类。同时,还介绍了Hutool的组件,包括动态代理、布隆过滤、缓存、定时任务等功能。该工具包可以简化Java代码,提高开发效率。 ... [详细]
  • android listview OnItemClickListener失效原因
    最近在做listview时发现OnItemClickListener失效的问题,经过查找发现是因为button的原因。不仅listitem中存在button会影响OnItemClickListener事件的失效,还会导致单击后listview每个item的背景改变,使得item中的所有有关焦点的事件都失效。本文给出了一个范例来说明这种情况,并提供了解决方法。 ... [详细]
  • 本文讨论了在手机移动端如何使用HTML5和JavaScript实现视频上传并压缩视频质量,或者降低手机摄像头拍摄质量的问题。作者指出HTML5和JavaScript无法直接压缩视频,只能通过将视频传送到服务器端由后端进行压缩。对于控制相机拍摄质量,只有使用JAVA编写Android客户端才能实现压缩。此外,作者还解释了在交作业时使用zip格式压缩包导致CSS文件和图片音乐丢失的原因,并提供了解决方法。最后,作者还介绍了一个用于处理图片的类,可以实现图片剪裁处理和生成缩略图的功能。 ... [详细]
  • Android系统源码分析Zygote和SystemServer启动过程详解
    本文详细解析了Android系统源码中Zygote和SystemServer的启动过程。首先介绍了系统framework层启动的内容,帮助理解四大组件的启动和管理过程。接着介绍了AMS、PMS等系统服务的作用和调用方式。然后详细分析了Zygote的启动过程,解释了Zygote在Android启动过程中的决定作用。最后通过时序图展示了整个过程。 ... [详细]
  • vue使用
    关键词: ... [详细]
  • 向QTextEdit拖放文件的方法及实现步骤
    本文介绍了在使用QTextEdit时如何实现拖放文件的功能,包括相关的方法和实现步骤。通过重写dragEnterEvent和dropEvent函数,并结合QMimeData和QUrl等类,可以轻松实现向QTextEdit拖放文件的功能。详细的代码实现和说明可以参考本文提供的示例代码。 ... [详细]
  • 本文介绍了数据库的存储结构及其重要性,强调了关系数据库范例中将逻辑存储与物理存储分开的必要性。通过逻辑结构和物理结构的分离,可以实现对物理存储的重新组织和数据库的迁移,而应用程序不会察觉到任何更改。文章还展示了Oracle数据库的逻辑结构和物理结构,并介绍了表空间的概念和作用。 ... [详细]
  • Webpack5内置处理图片资源的配置方法
    本文介绍了在Webpack5中处理图片资源的配置方法。在Webpack4中,我们需要使用file-loader和url-loader来处理图片资源,但是在Webpack5中,这两个Loader的功能已经被内置到Webpack中,我们只需要简单配置即可实现图片资源的处理。本文还介绍了一些常用的配置方法,如匹配不同类型的图片文件、设置输出路径等。通过本文的学习,读者可以快速掌握Webpack5处理图片资源的方法。 ... [详细]
  • Java序列化对象传给PHP的方法及原理解析
    本文介绍了Java序列化对象传给PHP的方法及原理,包括Java对象传递的方式、序列化的方式、PHP中的序列化用法介绍、Java是否能反序列化PHP的数据、Java序列化的原理以及解决Java序列化中的问题。同时还解释了序列化的概念和作用,以及代码执行序列化所需要的权限。最后指出,序列化会将对象实例的所有字段都进行序列化,使得数据能够被表示为实例的序列化数据,但只有能够解释该格式的代码才能够确定数据的内容。 ... [详细]
  • 开发笔记:加密&json&StringIO模块&BytesIO模块
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了加密&json&StringIO模块&BytesIO模块相关的知识,希望对你有一定的参考价值。一、加密加密 ... [详细]
  • 拥抱Android Design Support Library新变化(导航视图、悬浮ActionBar)
    转载请注明明桑AndroidAndroid5.0Loollipop作为Android最重要的版本之一,为我们带来了全新的界面风格和设计语言。看起来很受欢迎࿰ ... [详细]
  • Linux环境变量函数getenv、putenv、setenv和unsetenv详解
    本文详细解释了Linux中的环境变量函数getenv、putenv、setenv和unsetenv的用法和功能。通过使用这些函数,可以获取、设置和删除环境变量的值。同时给出了相应的函数原型、参数说明和返回值。通过示例代码演示了如何使用getenv函数获取环境变量的值,并打印出来。 ... [详细]
  • web.py开发web 第八章 Formalchemy 服务端验证方法
    本文介绍了在web.py开发中使用Formalchemy进行服务端表单数据验证的方法。以User表单为例,详细说明了对各字段的验证要求,包括必填、长度限制、唯一性等。同时介绍了如何自定义验证方法来实现验证唯一性和两个密码是否相等的功能。该文提供了相关代码示例。 ... [详细]
  • 如何查询zone下的表的信息
    本文介绍了如何通过TcaplusDB知识库查询zone下的表的信息。包括请求地址、GET请求参数说明、返回参数说明等内容。通过curl方法发起请求,并提供了请求示例。 ... [详细]
  • 本文介绍了Swing组件的用法,重点讲解了图标接口的定义和创建方法。图标接口用来将图标与各种组件相关联,可以是简单的绘画或使用磁盘上的GIF格式图像。文章详细介绍了图标接口的属性和绘制方法,并给出了一个菱形图标的实现示例。该示例可以配置图标的尺寸、颜色和填充状态。 ... [详细]
author-avatar
原来我不帅S_420
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有