现在的位置: 首页 > 综合 > 正文

Android init进程启动分析

2018年04月17日 ⁄ 综合 ⁄ 共 39639字 ⁄ 字号 评论关闭
一、Android Init.c执行流程
Android中的内核启动后,kernel会启动第一个用户级别的进程:init,它是一个由内核启动的用户级进程。内核自行启动(已经被载入内存,开始运行,并已初始化所有的设备驱动程序和数据结构等)之后,就通过启动一个用户级程序init的方式,完成引导进程。init始终是第一个进程。
PS:可以通过:ps aux | grep init命令来查看其Pid为1。
init进程对应的代码在android源码目录中的:system/core/init/init.c中。
789 int main(int argc, char **argv)
        790 {
        # 创建一些linux根文件系统中的目录
        817 mkdir("/dev", 0755);
        818 mkdir("/proc", 0755);
        819 mkdir("/sys", 0755);
        820 
        821 mount("tmpfs", "/dev", "tmpfs", 0, "mode=0755");
        822 mkdir("/dev/pts", 0755);
        823 mkdir("/dev/socket", 0755);
        824 mount("devpts", "/dev/pts", "devpts", 0, NULL);
        825 mount("proc", "/proc", "proc", 0, NULL);
        826 mount("sysfs", "/sys", "sysfs", 0, NULL); 
        # 打开标准输入,标准输出,标准错误文件描述符
        834 open_devnull_stdio();
        # 读取并且解析init.rc文件
        838 parse_config_file("/init.rc");
        # 取得硬件名
        844 get_hardware_name();
        845 snprintf(tmp, sizeof(tmp), "/init.%s.rc", hardware);
        # 读取并且解析硬件相关的init脚本文件
         846 parse_config_file(tmp);
        # 触发在init脚本文件中名字为early-init的action,并且执行其commands,其实是: on early-init
         848 action_for_each_trigger("early-init", action_add_queue_tail);
        849 drain_action_queue();
        # 初始化动态设备管理,设备文件有变化时反应给内核,后面具体解释
        852 device_fd = device_init();
        # 加载启动动画,如果动画打开失败,则在屏幕上打印: A N D R O I D字样。
        872 if( load_565rle_image(INIT_IMAGE_FILE) ) {
        873 fd = open("/dev/tty0", O_WRONLY);
        874 if (fd >= 0) {
        875 const char *msg;
        876 msg = "\n"
        877 "\n"
        878 "\n"
        879 "\n"
        880 "\n"
        881 "\n"
        882 "\n" // console is 40 cols x 30 lines
        883 "\n"
        884 "\n"
        885 "\n"
        886 "\n"
        887 "\n"
        888 "\n"
        889 "\n"
        890 //" A N D R O I D ";
        891 write(fd, msg, strlen(msg));
        892 close(fd);
        893 }
        894 }
        895
         # 触发在init脚本文件中名字为init的action,并且执行其commands,其实是:on init
        919 action_for_each_trigger("init", action_add_queue_tail);
        920 drain_action_queue();
        # 启动系统属性服务: system property service
        927 property_set_fd = start_property_service();
        # 创建socket用来处理孤儿进程信号
        930 if (socketpair(AF_UNIX, SOCK_STREAM, 0, s) == 0) {
         931 signal_fd = s[0];
         932 signal_recv_fd = s[1];
        933 fcntl(s[0], F_SETFD, FD_CLOEXEC);
        934 fcntl(s[0], F_SETFL, O_NONBLOCK);
        935 fcntl(s[1], F_SETFD, FD_CLOEXEC);
        936 fcntl(s[1], F_SETFL, O_NONBLOCK);
        937 }
        # 触发在init脚本文件中名字为early-boot和boot的action,并且执行其commands,其实是:on early-boot和on boot
        948 action_for_each_trigger("early-boot", action_add_queue_tail);
        949 action_for_each_trigger("boot", action_add_queue_tail);
        950 drain_action_queue();
        # 启动所有属性变化触发命令,其实是: on property:ro.xx.xx=xx
        953 queue_all_property_triggers();
        954 drain_action_queue();
        # 进入死循环
        987 for(;;) {
         # 启动所有init脚本中声明的service,
         # 如:266 service servicemanager /system/bin/servicemanager
         # user system
        # critical
        # onrestart restart zygote
         # onrestart restart media
         994 restart_processes();
         # 多路监听设备管理,子进程运行状态,属性服务
        1012 nr = poll(ufds, fd_count, timeout);
        1013 if (nr <= 0)
        1014 continue;
        1016 if (ufds[2].revents == POLLIN) {
        1017 /* we got a SIGCHLD - reap and restart as needed */
        1018 read(signal_recv_fd, tmp, sizeof(tmp));
        1019 while (!wait_for_one_process(0))
        1020 ;
        1021 continue;
        1022 }
        1023 
        1024 if (ufds[0].revents == POLLIN)
        1025 handle_device_fd(device_fd);
        1026 
        1027 if (ufds[1].revents == POLLIN)
        1028 handle_property_set_fd(property_set_fd);
        1029 if (ufds[3].revents == POLLIN)
        1030 handle_keychord(keychord_fd);
        1031 }
        1032 
        1033 return 0;
        1034 }
二、Android init脚本语言
前面简单分析了下init.c里的操作,里面提到了解析Init.rc和硬件脚本下面详细解析下Android init脚本语言的规范。
Android初始化语言包含了四种类型的声明:
Actions(行为)、Commands(命令)、Services(服务)和Options(选项)
所有这些都是以行为单位的,各种记号由空格来隔开。
C语言风格的反斜杠号可用于在记号间插入空格。
双引号也可用于防止字符串被空格分割成多个记号。
行末的反斜杠用于折行,注释行以井号(#)开头(允许以空格开头)。
Actions和Services声明一个新的分组Section。所有的命令或选项都属于最近声明的分组。位于第一个分组之前的命令或选项将会被忽略。
Actions和Services有唯一的名字。如果有重名的情况,第二个申明的将会被作为错误忽略。
Actions(行为)
Actions其实就是一序列的Commands(命令)。Actions都有一个trigger(触发器),它被用于决定action的执行时间。当一个符合action触发条件的事件发生时,action会被加入到执行队列的末尾,除非它已经在队列里了。
队列中的每一个action都被依次提取出,而这个action中的每个command(命令)都将被依次执行。
Actions的形式如下: 
        on <trigger>
        <command1>
        <command2>
         <command3>
on后面跟着一个触发器,当trigger被触发时,command1,command2,command3,会依次执行,直到下一个Action或下一个Service。
简单来说,Actions就是Android在启动时定义的一个启动脚本,当条件满足时,会执行该脚本,脚本里都是一些命令commands,不同的脚本用on来区分。
Triggers(触发器)
Triggers(触发器)是一个用于匹配特定事件类型的字符串,用于使Actions发生。
boot:
这是init执行后的第一个被触发的Triggers(触发器)。(在 /init.conf (启动配置文件)被装载之后)
        <name>=<value>:
        这种形式的Triggers(触发器)会在属性<name>被设置为指定的<value>时被触发。
        device-added-<path>:
        device-removed-<path>:
        这种形式的Triggers(触发器)会在一个设备节点文件被增删时触发。
        service-exited-<name>:
        这种形式的Triggers(触发器)会在一个特定的服务退出时触发。
        触发器通常和on一起来联合使用。
        示例:
        on init 
        export LD_LIBRARY_PATH /system/lib
        insmod modules/fsr.ko
        symlink /system/etc /etc
        mkdir /sdcard 0000 system system
        write /proc/cpu/alignment 4
        on boot
        …
        on property:ro.kernel.qemu=1
        start adbd
        上面声明了三个action:init,boot和一个属性触发器,当init被触发时,会顺序执行后面的命令,直到on boot新的action。Init的触发是由init.c里的函数action_for_each_trigger来决定的。当属性ro.kernel.qemu为1 时,会触发start adbd命令。
Services(服务)
Services(服务)是一个程序,它在初始化时启动,并在退出时可选择让其重启。Services(服务)的形式如下: 
         service <name> <pathname> [ <argument> ]*
        <option>
        <option>
        ...
name:服务名
pathname:当前服务对应的程序位置
         option:当前服务设置的选项
         Options(选项)
         Options(选项)是一个Services(服务)的修正者。他们影响Services(服务)在何时,并以何种方式运行。
 critical:
说明这是一个对于设备关键的服务。如果他四分钟内退出大于四次,系统将会重启并进入recovery(恢复)模式。
disabled:
说明这个服务不会同与他同trigger(触发器)下的服务自动启动。他必须被明确的按名启动。
setenv <name> <value> (设置环境变量)
在进程启动时将环境变量<name>设置为<value>。
socket <name> <type> <perm> [ <user> [ <group> ] ]
创建一个Uinx域的名为/dev/socket/<name> 的套接字,并传递它的文件描述符给已启动的进程。<type> 必须是 "dgram"或"stream"。User 和 group默认为0。
user <username>
在启动这个服务前改变该服务的用户名。此时默认为root。(???有可能的话应该默认为nobody)。当前,如果你的进程要求Linux capabilities(能力),你无法使用这个命令。即使你是root,你也必须在程序中请求capabilities(能力)。然后降到你想要的 uid。
group <groupname> [ <groupname> ]*
在启动这个服务前改变该服务的组名。除了(必需的)第一个组名,附加的组名通常被用于设置进程的补充组(通过setgroups())。此时默认为root。(???有可能的话应该默认为nobody)。
oneshot
服务退出时不重启。
class <name>
指定一个服务类。所有同一类的服务可以同时启动和停止。如果不通过class选项指定一个类,则默认为"default"类服务。
onrestart
当服务重启,执行一个命令(下详)。
Commands(命令)
exec <path> [ <argument> ]*
创建和执行一个程序(<path>)。在程序完全执行前,init将会阻塞。由于它不是内置命令,应尽量避免使用exec,它可能会引起init卡死。(??? 是否需要一个超时设置?)
export <name> <value>
在全局环境变量中设在环境变量 <name>为<value>。(这将会被所有在这命令之后运行的进程所继承)
ifup <interface>
启动网络接口<interface>
import <filename>
解析一个init配置文件,扩展当前配置。
hostname <name>
设置主机名。
chmod <octal-mode> <path>
更改文件访问权限。
chown <owner> <group> <path>
更改文件的所有者和组。
class_start <serviceclass>
启动所有指定服务类下的未运行服务。
class_stop <serviceclass>
停止指定服务类下的所有已运行的服务。
domainname <name>
设置域名。
insmod <path>
加载<path>中的模块。
mkdir <path> [mode] [owner] [group]
创建一个目录<path>,可以选择性地指定mode、owner以及group。如果没有指定,默认的权限为755,并属于root用户和root组。
mount <type> <device> <dir> [ <mountoption> ]*
试图在目录<dir>挂载指定的设备。<device> 可以是以 mtd@name 的形式指定一个mtd块设备。<mountoption>包括 "ro"、"rw"、"remount"、"noatime"、 ...
setprop <name> <value>
设置系统属性 <name> 为 <value>值. 
setrlimit <resource> <cur> <max>
设置<resource>的rlimit(资源限制)。
start <service>
启动指定服务(如果此服务还未运行)。
stop <service>
停止指定服务(如果此服务在运行中)。
symlink <target> <path>
创建一个指向<path>的软连接<target>。
sysclktz <mins_west_of_gmt>
设置系统时钟基准(0代表时钟滴答以格林威治平均时(GMT)为准)
trigger <event>
触发一个事件。用于将一个action与另一个 action排列。
write <path> <string> [ <string> ]*
打开路径为<path>的一个文件,并写入一个或多个字符串。
Properties(属性)
Init更新一些系统属性以提供对正在发生的事件的监控能力: 
init.action
此属性值为正在被执行的action的名字,如果没有则为""。
init.command
此属性值为正在被执行的command的名字,如果没有则为""。
init.svc.<name>
名为<name>的service的状态("stopped"(停止), "running"(运行), "restarting"(重启))
三、Android init 示例
1 on init
        2 
        3 sysclktz 0
        4 
        5 loglevel 3
        6 
        7 # setup the global environment
        8 export PATH /system/busybox/bin:/system/busybox/sbin:/system/busybox/usr/bin:/system/busybox/usr/sbin:/sbin:/system/sbin:/system/bin:/system/xbin
        9 export LD_LIBRARY_PATH /system/lib
        10 export ANDROID_BOOTLOGO 1
         11 export ANDROID_ROOT /system
        12 export ANDROID_ASSETS /system/app
        13 export ANDROID_DATA /data
        14 export EXTERNAL_STORAGE /sdcard
        ... ...
         23 symlink /system/etc /etc
         24 symlink /sys/kernel/debug /d
         25 
         26 # create mountpoints and mount tmpfs on sqlite_stmt_journals
         27 mkdir /sdcard 0000 system system
        28 mkdir /system
        29 mkdir /data 0771 system system
        30 mkdir /cache 0770 system cache
        31 mkdir /config 0500 root root
         32 mkdir /sqlite_stmt_journals 01777 root root
        33 mount tmpfs tmpfs /sqlite_stmt_journals size=4m
         34 
         35 # mount rootfs rootfs / ro remount
         36 
        37 write /proc/sys/kernel/panic_on_oops 1
         38 write /proc/sys/kernel/hung_task_timeout_secs 0
         39 write /proc/cpu/alignment 4
         40 write /proc/sys/kernel/sched_latency_ns 10000000
         41 write /proc/sys/kernel/sched_wakeup_granularity_ns 2000000
         42 write /proc/sys/kernel/sched_compat_yield 1
         43 write /proc/sys/kernel/sched_child_runs_first 0
        44 
         45 # Create cgroup mount points for process groups
         46 mkdir /dev/cpuctl
         47 mount cgroup none /dev/cpuctl cpu
         48 chown system system /dev/cpuctl
         49 chown system system /dev/cpuctl/tasks
         50 chmod 0777 /dev/cpuctl/tasks
         51 write /dev/cpuctl/cpu.shares 1024
         52 
         53 mkdir /dev/cpuctl/fg_boost
         54 chown system system /dev/cpuctl/fg_boost/tasks
        55 chmod 0777 /dev/cpuctl/fg_boost/tasks
         56 write /dev/cpuctl/fg_boost/cpu.shares 1024
         57 
         58 mkdir /dev/cpuctl/bg_non_interactive
         59 chown system system /dev/cpuctl/bg_non_interactive/tasks
         60 chmod 0777 /dev/cpuctl/bg_non_interactive/tasks
        61 # 5.0 %
         62 write /dev/cpuctl/bg_non_interactive/cpu.shares 52
         ... ...
        146 on boot
        147 # basic network init
         148 ifup lo
         149 hostname localhost
         150 domainname localdomain
         151 
         152 # set RLIMIT_NICE to allow priorities from 19 to -20
         153 setrlimit 13 40 40
         154 
         155 # Define the oom_adj values for the classes of processes that can be
         156 # killed by the kernel. These are used in ActivityManagerService.
         157 setprop ro.FOREGROUND_APP_ADJ 0
         158 setprop ro.VISIBLE_APP_ADJ 1
         159 setprop ro.SECONDARY_SERVER_ADJ 2
         160 setprop ro.BACKUP_APP_ADJ 2
         161 setprop ro.HOME_APP_ADJ 4
         162 setprop ro.HIDDEN_APP_MIN_ADJ 7
         ... ...
         233 # Define TCP buffer sizes for various networks
         234 # ReadMin, ReadInitial, ReadMax, WriteMin, WriteInitial, WriteMax,
         235 setprop net.tcp.buffersize.default 4096,87380,110208,4096,16384,110208
         236 setprop net.tcp.buffersize.wifi 4095,87380,110208,4096,16384,110208
         237 setprop net.tcp.buffersize.umts 4094,87380,110208,4096,16384,110208
         238 setprop net.tcp.buffersize.edge 4093,26280,35040,4096,16384,35040
         239 setprop net.tcp.buffersize.gprs 4092,8760,11680,4096,8760,11680
         240 setprop net.dns1 8.8.8.8
         241 setprop net.eth0.dns1 8.8.8.8
         242 
         243 class_start default
         ... ...
         247 service console /system/bin/sh
        248 console
        249
         252 service adbd /sbin/adbd
         253 disabled'
        259 on property:persist.service.adb.enable=1
        260 start adbd
         261 
        262 on property:persist.service.adb.enable=0
        263 stop adbd
        265 service servicemanager /system/bin/servicemanager
        266 user system
         267 critical
         268 onrestart restart zygote
         269 onrestart restart media
         271 service vold /system/bin/vold
         272 socket vold stream 0660 root mount
         282 service ril-daemon /system/bin/rild
         283 socket rild stream 660 root radio
         284 socket rild-debug stream 660 radio system
         285 user root
         286 group radio cache inet misc
         287 
        288 service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
        289 socket zygote stream 666
        290 onrestart write /sys/android_power/request_state wake
         291 onrestart write /sys/power/state on
        292 onrestart restart media
         293 
         294 service media /system/bin/mediaserver
         295 user media
         296 group system audio camera graphics inet net_bt net_bt_admin
         297 
         298 service bootsound /system/bin/playmp3
         299 user media
         300 group audio
         301 oneshot
         302 
         303 service bootanim /system/bin/bootanimation
         304 user graphics
         305 group graphics
        306 disabled
         307 oneshot
         ... ...
         由上面的例子可知:该init.rc里定义了4个actions:
        on init
        on boot
        on property:persist.service.adb.enable=1
        on property:persist.service.adb.enable=0
其中,前两个的触发器是由Init.c里的代码action_for_each_trigger实现触发的,后两个是由属性的值发生改变时触发的。当他们被触发时,会依次执行其后面的值,直到遇到一个新的Action或service。
该init.rc中定义了9个services,这些service属于本地服务,它们都是由c或c++代码写的,以可执行文件的方式存在文件系统里的/system/bin或/sbin目录下。由前面知识可知,如果一个服务没有使用class选项指定其分类,则其默认分类为:default,那么这9个services的分类为default。在on boot action触发时,其最后一个命令是class_start default,也就是将这9个services都依次启动。
init.rc中的9个service里,以zygote和servicemanager最为重要。
1> zygote service
该service主要用于创建Dalvik Java虚拟机,然后启动SystemServer,启动所有的Android服务,最终启动Android系统。
2> servicemanager
该service主要用来打开binder驱动,binder是Android Service通信机制的底层实现,在该service里封装了binder的操作接口。
技巧:
在调试或理解系统的工作原理的时候,我们经常要去找服务程序对应的源码。
寻找c或c++程序的源码文件:
例如:以寻找init程序对应的源码为例。
find ./ -name Android.mk -exec grep -l init {} \;
注:通过find命令查找所有的Android.mk, 通过grep从中查找程序字符串,得到其路径,然后去路径下找源码即可,这么做的原因是,c或c++代码都是通过Android.mk来指导编译的。
寻找java源码文件:
java源码的特点是和类名一致,所以如果我们知道一个类名,找其java源码就直接加上java后缀即可。
例如:寻找com.android.internal.os.ZygoteInit类的代码。
find ./ -name ZygoteInit.java
本文来自:我爱研发网(52RD.com) - R&D大本营
详细出处:http://www.52rd.com/Blog/Archive_Thread.asp?SID=63452

一、Android Init.c执行流程
Android中的内核启动后,kernel会启动第一个用户级别的进程:init,它是一个由内核启动的用户级进程。内核自行启动(已经被载入内存,开始运行,并已初始化所有的设备驱动程序和数据结构等)之后,就通过启动一个用户级程序init的方式,完成引导进程。init始终是第一个进程。
PS:可以通过:ps aux | grep init命令来查看其Pid为1。
init进程对应的代码在android源码目录中的:system/core/init/init.c中。
789 int main(int argc, char **argv)
        790 {
        # 创建一些linux根文件系统中的目录
        817 mkdir("/dev", 0755);
        818 mkdir("/proc", 0755);
        819 mkdir("/sys", 0755);
        820
        821 mount("tmpfs", "/dev", "tmpfs", 0, "mode=0755");
        822 mkdir("/dev/pts", 0755);
        823 mkdir("/dev/socket", 0755);
        824 mount("devpts", "/dev/pts", "devpts", 0, NULL);
        825 mount("proc", "/proc", "proc", 0, NULL);
        826 mount("sysfs", "/sys", "sysfs", 0, NULL);
        # 打开标准输入,标准输出,标准错误文件描述符
        834 open_devnull_stdio();
        # 读取并且解析init.rc文件
        838 parse_config_file("/init.rc");
        # 取得硬件名
        844 get_hardware_name();
        845 snprintf(tmp, sizeof(tmp), "/init.%s.rc", hardware);
        # 读取并且解析硬件相关的init脚本文件
         846 parse_config_file(tmp);
        # 触发在init脚本文件中名字为early-init的action,并且执行其commands,其实是: on early-init
         848 action_for_each_trigger("early-init", action_add_queue_tail);
        849 drain_action_queue();
        # 初始化动态设备管理,设备文件有变化时反应给内核,后面具体解释
        852 device_fd = device_init();
        # 加载启动动画,如果动画打开失败,则在屏幕上打印: A N D R O I D字样。
        872 if( load_565rle_image(INIT_IMAGE_FILE) ) {
        873 fd = open("/dev/tty0", O_WRONLY);
        874 if (fd >= 0) {
        875 const char *msg;
        876 msg = "\n"
        877 "\n"
        878 "\n"
        879 "\n"
        880 "\n"
        881 "\n"
        882 "\n" // console is 40 cols x 30 lines
        883 "\n"
        884 "\n"
        885 "\n"
        886 "\n"
        887 "\n"
        888 "\n"
        889 "\n"
        890 //" A N D R O I D ";
        891 write(fd, msg, strlen(msg));
        892 close(fd);
        893 }
        894 }
        895
         # 触发在init脚本文件中名字为init的action,并且执行其commands,其实是:on init
        919 action_for_each_trigger("init", action_add_queue_tail);
        920 drain_action_queue();
        # 启动系统属性服务: system property service
        927 property_set_fd = start_property_service();
        # 创建socket用来处理孤儿进程信号
        930 if (socketpair(AF_UNIX, SOCK_STREAM, 0, s) == 0) {
         931 signal_fd = s[0];
         932 signal_recv_fd = s[1];
        933 fcntl(s[0], F_SETFD, FD_CLOEXEC);
        934 fcntl(s[0], F_SETFL, O_NONBLOCK);
        935 fcntl(s[1], F_SETFD, FD_CLOEXEC);
        936 fcntl(s[1], F_SETFL, O_NONBLOCK);
        937 }
        # 触发在init脚本文件中名字为early-boot和boot的action,并且执行其commands,其实是:on early-boot和on boot
        948 action_for_each_trigger("early-boot", action_add_queue_tail);
        949 action_for_each_trigger("boot", action_add_queue_tail);
        950 drain_action_queue();
        # 启动所有属性变化触发命令,其实是: on property:ro.xx.xx=xx
        953 queue_all_property_triggers();
        954 drain_action_queue();
        # 进入死循环
        987 for(;;) {
         # 启动所有init脚本中声明的service,
         # 如:266 service servicemanager /system/bin/servicemanager
         # user system
        # critical
        # onrestart restart zygote
         # onrestart restart media
         994 restart_processes();
         # 多路监听设备管理,子进程运行状态,属性服务
        1012 nr = poll(ufds, fd_count, timeout);
        1013 if (nr <= 0)
        1014 continue;
        1016 if (ufds[2].revents == POLLIN) {
        1017 /* we got a SIGCHLD - reap and restart as needed */
        1018 read(signal_recv_fd, tmp, sizeof(tmp));
        1019 while (!wait_for_one_process(0))
        1020 ;
        1021 continue;
        1022 }
        1023
        1024 if (ufds[0].revents == POLLIN)
        1025 handle_device_fd(device_fd);
        1026
        1027 if (ufds[1].revents == POLLIN)
        1028 handle_property_set_fd(property_set_fd);
        1029 if (ufds[3].revents == POLLIN)
        1030 handle_keychord(keychord_fd);
        1031 }
        1032
        1033 return 0;
        1034 }
二、Android init脚本语言
前面简单分析了下init.c里的操作,里面提到了解析Init.rc和硬件脚本下面详细解析下Android init脚本语言的规范。
Android初始化语言包含了四种类型的声明:
Actions(行为)、Commands(命令)、Services(服务)和Options(选项)
所有这些都是以行为单位的,各种记号由空格来隔开。
C语言风格的反斜杠号可用于在记号间插入空格。
双引号也可用于防止字符串被空格分割成多个记号。
行末的反斜杠用于折行,注释行以井号(#)开头(允许以空格开头)。
Actions和Services声明一个新的分组Section。所有的命令或选项都属于最近声明的分组。位于第一个分组之前的命令或选项将会被忽略。
Actions和Services有唯一的名字。如果有重名的情况,第二个申明的将会被作为错误忽略。
Actions(行为)
Actions其实就是一序列的Commands(命令)。Actions都有一个trigger(触发器),它被用于决定action的执行时间。当一个符合action触发条件的事件发生时,action会被加入到执行队列的末尾,除非它已经在队列里了。
队列中的每一个action都被依次提取出,而这个action中的每个command(命令)都将被依次执行。
Actions的形式如下:
        on <trigger>
        <command1>
        <command2>
         <command3>
on后面跟着一个触发器,当trigger被触发时,command1,command2,command3,会依次执行,直到下一个Action或下一个Service。
简单来说,Actions就是Android在启动时定义的一个启动脚本,当条件满足时,会执行该脚本,脚本里都是一些命令commands,不同的脚本用on来区分。
Triggers(触发器)
Triggers(触发器)是一个用于匹配特定事件类型的字符串,用于使Actions发生。
boot:
这是init执行后的第一个被触发的Triggers(触发器)。(在 /init.conf (启动配置文件)被装载之后)
        <name>=<value>:
        这种形式的Triggers(触发器)会在属性<name>被设置为指定的<value>时被触发。
        device-added-<path>:
        device-removed-<path>:
        这种形式的Triggers(触发器)会在一个设备节点文件被增删时触发。
        service-exited-<name>:
        这种形式的Triggers(触发器)会在一个特定的服务退出时触发。
        触发器通常和on一起来联合使用。
        示例:
        on init
        export LD_LIBRARY_PATH /system/lib
        insmod modules/fsr.ko
        symlink /system/etc /etc
        mkdir /sdcard 0000 system system
        write /proc/cpu/alignment 4
        on boot
        …
        on property:ro.kernel.qemu=1
        start adbd
        上面声明了三个action:init,boot和一个属性触发器,当init被触发时,会顺序执行后面的命令,直到on boot新的action。Init的触发是由init.c里的函数action_for_each_trigger来决定的。当属性ro.kernel.qemu为1 时,会触发start adbd命令。
Services(服务)
Services(服务)是一个程序,它在初始化时启动,并在退出时可选择让其重启。Services(服务)的形式如下:
         service <name> <pathname> [ <argument> ]*
        <option>
        <option>
        ...
name:服务名
pathname:当前服务对应的程序位置
         option:当前服务设置的选项
         Options(选项)
         Options(选项)是一个Services(服务)的修正者。他们影响Services(服务)在何时,并以何种方式运行。
 critical:
说明这是一个对于设备关键的服务。如果他四分钟内退出大于四次,系统将会重启并进入recovery(恢复)模式。
disabled:
说明这个服务不会同与他同trigger(触发器)下的服务自动启动。他必须被明确的按名启动。
setenv <name> <value> (设置环境变量)
在进程启动时将环境变量<name>设置为<value>。
socket <name> <type> <perm> [ <user> [ <group> ] ]
创建一个Uinx域的名为/dev/socket/<name> 的套接字,并传递它的文件描述符给已启动的进程。<type> 必须是 "dgram"或"stream"。User 和 group默认为0。
user <username>
在启动这个服务前改变该服务的用户名。此时默认为root。(???有可能的话应该默认为nobody)。当前,如果你的进程要求Linux capabilities(能力),你无法使用这个命令。即使你是root,你也必须在程序中请求capabilities(能力)。然后降到你想要的 uid。
group <groupname> [ <groupname> ]*
在启动这个服务前改变该服务的组名。除了(必需的)第一个组名,附加的组名通常被用于设置进程的补充组(通过setgroups())。此时默认为root。(???有可能的话应该默认为nobody)。
oneshot
服务退出时不重启。
class <name>
指定一个服务类。所有同一类的服务可以同时启动和停止。如果不通过class选项指定一个类,则默认为"default"类服务。
onrestart
当服务重启,执行一个命令(下详)。
Commands(命令)
exec <path> [ <argument> ]*
创建和执行一个程序(<path>)。在程序完全执行前,init将会阻塞。由于它不是内置命令,应尽量避免使用exec,它可能会引起init卡死。(??? 是否需要一个超时设置?)
export <name> <value>
在全局环境变量中设在环境变量 <name>为<value>。(这将会被所有在这命令之后运行的进程所继承)
ifup <interface>
启动网络接口<interface>
import <filename>
解析一个init配置文件,扩展当前配置。
hostname <name>
设置主机名。
chmod <octal-mode> <path>
更改文件访问权限。
chown <owner> <group> <path>
更改文件的所有者和组。
class_start <serviceclass>
启动所有指定服务类下的未运行服务。
class_stop <serviceclass>
停止指定服务类下的所有已运行的服务。
domainname <name>
设置域名。
insmod <path>
加载<path>中的模块。
mkdir <path> [mode] [owner] [group]
创建一个目录<path>,可以选择性地指定mode、owner以及group。如果没有指定,默认的权限为755,并属于root用户和root组。
mount <type> <device> <dir> [ <mountoption> ]*
试图在目录<dir>挂载指定的设备。<device> 可以是以 mtd@name 的形式指定一个mtd块设备。<mountoption>包括 "ro"、"rw"、"remount"、"noatime"、 ...
setprop <name> <value>
设置系统属性 <name> 为 <value>值.
setrlimit <resource> <cur> <max>
设置<resource>的rlimit(资源限制)。
start <service>
启动指定服务(如果此服务还未运行)。
stop <service>
停止指定服务(如果此服务在运行中)。
symlink <target> <path>
创建一个指向<path>的软连接<target>。
sysclktz <mins_west_of_gmt>
设置系统时钟基准(0代表时钟滴答以格林威治平均时(GMT)为准)
trigger <event>
触发一个事件。用于将一个action与另一个 action排列。
write <path> <string> [ <string> ]*
打开路径为<path>的一个文件,并写入一个或多个字符串。
Properties(属性)
Init更新一些系统属性以提供对正在发生的事件的监控能力:
init.action
此属性值为正在被执行的action的名字,如果没有则为""。
init.command
此属性值为正在被执行的command的名字,如果没有则为""。
init.svc.<name>
名为<name>的service的状态("stopped"(停止), "running"(运行), "restarting"(重启))
三、Android init 示例
1 on init
        2
        3 sysclktz 0
        4
        5 loglevel 3
        6
        7 # setup the global environment
        8 export PATH /system/busybox/bin:/system/busybox/sbin:/system/busybox/usr/bin:/system/busybox/usr/sbin:/sbin:/system/sbin:/system/bin:/system/xbin
        9 export LD_LIBRARY_PATH /system/lib
        10 export ANDROID_BOOTLOGO 1
         11 export ANDROID_ROOT /system
        12 export ANDROID_ASSETS /system/app
        13 export ANDROID_DATA /data
        14 export EXTERNAL_STORAGE /sdcard
        ... ...
         23 symlink /system/etc /etc
         24 symlink /sys/kernel/debug /d
         25
         26 # create mountpoints and mount tmpfs on sqlite_stmt_journals
         27 mkdir /sdcard 0000 system system
        28 mkdir /system
        29 mkdir /data 0771 system system
        30 mkdir /cache 0770 system cache
        31 mkdir /config 0500 root root
         32 mkdir /sqlite_stmt_journals 01777 root root
        33 mount tmpfs tmpfs /sqlite_stmt_journals size=4m
         34
         35 # mount rootfs rootfs / ro remount
         36
        37 write /proc/sys/kernel/panic_on_oops 1
         38 write /proc/sys/kernel/hung_task_timeout_secs 0
         39 write /proc/cpu/alignment 4
         40 write /proc/sys/kernel/sched_latency_ns 10000000
         41 write /proc/sys/kernel/sched_wakeup_granularity_ns 2000000
         42 write /proc/sys/kernel/sched_compat_yield 1
         43 write /proc/sys/kernel/sched_child_runs_first 0
        44
         45 # Create cgroup mount points for process groups
         46 mkdir /dev/cpuctl
         47 mount cgroup none /dev/cpuctl cpu
         48 chown system system /dev/cpuctl
         49 chown system system /dev/cpuctl/tasks
         50 chmod 0777 /dev/cpuctl/tasks
         51 write /dev/cpuctl/cpu.shares 1024
         52
         53 mkdir /dev/cpuctl/fg_boost
         54 chown system system /dev/cpuctl/fg_boost/tasks
        55 chmod 0777 /dev/cpuctl/fg_boost/tasks
         56 write /dev/cpuctl/fg_boost/cpu.shares 1024
         57
         58 mkdir /dev/cpuctl/bg_non_interactive
         59 chown system system /dev/cpuctl/bg_non_interactive/tasks
         60 chmod 0777 /dev/cpuctl/bg_non_interactive/tasks
        61 # 5.0 %
         62 write /dev/cpuctl/bg_non_interactive/cpu.shares 52
         ... ...
        146 on boot
        147 # basic network init
         148 ifup lo
         149 hostname localhost
         150 domainname localdomain
         151
         152 # set RLIMIT_NICE to allow priorities from 19 to -20
         153 setrlimit 13 40 40
         154
         155 # Define the oom_adj values for the classes of processes that can be
         156 # killed by the kernel. These are used in ActivityManagerService.
         157 setprop ro.FOREGROUND_APP_ADJ 0
         158 setprop ro.VISIBLE_APP_ADJ 1
         159 setprop ro.SECONDARY_SERVER_ADJ 2
         160 setprop ro.BACKUP_APP_ADJ 2
         161 setprop ro.HOME_APP_ADJ 4
         162 setprop ro.HIDDEN_APP_MIN_ADJ 7
         ... ...
         233 # Define TCP buffer sizes for various networks
         234 # ReadMin, ReadInitial, ReadMax, WriteMin, WriteInitial, WriteMax,
         235 setprop net.tcp.buffersize.default 4096,87380,110208,4096,16384,110208
         236 setprop net.tcp.buffersize.wifi 4095,87380,110208,4096,16384,110208
         237 setprop net.tcp.buffersize.umts 4094,87380,110208,4096,16384,110208
         238 setprop net.tcp.buffersize.edge 4093,26280,35040,4096,16384,35040
         239 setprop net.tcp.buffersize.gprs 4092,8760,11680,4096,8760,11680
         240 setprop net.dns1 8.8.8.8
         241 setprop net.eth0.dns1 8.8.8.8
         242
         243 class_start default
         ... ...
         247 service console /system/bin/sh
        248 console
        249
         252 service adbd /sbin/adbd
         253 disabled'
        259 on property:persist.service.adb.enable=1
        260 start adbd
         261
        262 on property:persist.service.adb.enable=0
        263 stop adbd
        265 service servicemanager /system/bin/servicemanager
        266 user system
         267 critical
         268 onrestart restart zygote
         269 onrestart restart media
         271 service vold /system/bin/vold
         272 socket vold stream 0660 root mount
         282 service ril-daemon /system/bin/rild
         283 socket rild stream 660 root radio
         284 socket rild-debug stream 660 radio system
         285 user root
         286 group radio cache inet misc
         287
        288 service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
        289 socket zygote stream 666
        290 onrestart write /sys/android_power/request_state wake
         291 onrestart write /sys/power/state on
        292 onrestart restart media
         293
         294 service media /system/bin/mediaserver
         295 user media
         296 group system audio camera graphics inet net_bt net_bt_admin
         297
         298 service bootsound /system/bin/playmp3
         299 user media
         300 group audio
         301 oneshot
         302
         303 service bootanim /system/bin/bootanimation
         304 user graphics
         305 group graphics
        306 disabled
         307 oneshot
         ... ...
         由上面的例子可知:该init.rc里定义了4个actions:
        on init
        on boot
        on property:persist.service.adb.enable=1
        on property:persist.service.adb.enable=0
其中,前两个的触发器是由Init.c里的代码action_for_each_trigger实现触发的,后两个是由属性的值发生改变时触发的。当他们被触发时,会依次执行其后面的值,直到遇到一个新的Action或service。
该init.rc中定义了9个services,这些service属于本地服务,它们都是由c或c++代码写的,以可执行文件的方式存在文件系统里的/system/bin或/sbin目录下。由前面知识可知,如果一个服务没有使用class选项指定其分类,则其默认分类为:default,那么这9个services的分类为default。在on boot action触发时,其最后一个命令是class_start default,也就是将这9个services都依次启动。
init.rc中的9个service里,以zygote和servicemanager最为重要。
1> zygote service
该service主要用于创建Dalvik Java虚拟机,然后启动SystemServer,启动所有的Android服务,最终启动Android系统。
2> servicemanager
该service主要用来打开binder驱动,binder是Android Service通信机制的底层实现,在该service里封装了binder的操作接口。
技巧:
在调试或理解系统的工作原理的时候,我们经常要去找服务程序对应的源码。
寻找c或c++程序的源码文件:
例如:以寻找init程序对应的源码为例。
find ./ -name Android.mk -exec grep -l init {} \;
注:通过find命令查找所有的Android.mk, 通过grep从中查找程序字符串,得到其路径,然后去路径下找源码即可,这么做的原因是,c或c++代码都是通过Android.mk来指导编译的。
寻找java源码文件:
java源码的特点是和类名一致,所以如果我们知道一个类名,找其java源码就直接加上java后缀即可。
例如:寻找com.android.internal.os.ZygoteInit类的代码。
find ./ -name ZygoteInit.java
本文来自:我爱研发网(52RD.com) - R&D大本营
详细出处:http://www.52rd.com/Blog/Archive_Thread.asp?SID=63452

一、Android Init.c执行流程

Android中的内核启动后,kernel会启动第一个用户级别的进程:init,它是一个由内核启动的用户级进程。内核自行启动(已经被载入内存,开始运行,并已初始化所有的设备驱动程序和数据结构等)之后,就通过启动一个用户级程序init的方式,完成引导进程。init始终是第一个进程。

PS:可以通过:ps aux | grep init命令来查看其Pid为1。

init进程对应的代码在android源码目录中的:system/core/init/init.c中。

789 int main(int argc, char **argv)
        790 {
        # 创建一些linux根文件系统中的目录
        817 mkdir("/dev", 0755);
        818 mkdir("/proc", 0755);
        819 mkdir("/sys", 0755);
        820
        821 mount("tmpfs", "/dev", "tmpfs", 0, "mode=0755");
        822 mkdir("/dev/pts", 0755);
        823 mkdir("/dev/socket", 0755);
        824 mount("devpts", "/dev/pts", "devpts", 0, NULL);
        825 mount("proc", "/proc", "proc", 0, NULL);
        826 mount("sysfs", "/sys", "sysfs", 0, NULL);
        # 打开标准输入,标准输出,标准错误文件描述符
        834 open_devnull_stdio();
        # 读取并且解析init.rc文件
        838 parse_config_file("/init.rc");
        # 取得硬件名
        844 get_hardware_name();
        845 snprintf(tmp, sizeof(tmp), "/init.%s.rc", hardware);
        # 读取并且解析硬件相关的init脚本文件
         846 parse_config_file(tmp);
        # 触发在init脚本文件中名字为early-init的action,并且执行其commands,其实是: on early-init
         848 action_for_each_trigger("early-init", action_add_queue_tail);
        849 drain_action_queue();
        # 初始化动态设备管理,设备文件有变化时反应给内核,后面具体解释
        852 device_fd = device_init();
        # 加载启动动画,如果动画打开失败,则在屏幕上打印: A N D R O I D字样。
        872 if( load_565rle_image(INIT_IMAGE_FILE) ) {
        873 fd = open("/dev/tty0", O_WRONLY);
        874 if (fd >= 0) {
        875 const char *msg;
        876 msg = "\n"
        877 "\n"
        878 "\n"
        879 "\n"
        880 "\n"
        881 "\n"
        882 "\n" // console is 40 cols x 30 lines
        883 "\n"
        884 "\n"
        885 "\n"
        886 "\n"
        887 "\n"
        888 "\n"
        889 "\n"
        890 //" A N D R O I D ";
        891 write(fd, msg, strlen(msg));
        892 close(fd);
        893 }
        894 }
        895
         # 触发在init脚本文件中名字为init的action,并且执行其commands,其实是:on init
        919 action_for_each_trigger("init", action_add_queue_tail);
        920 drain_action_queue();
        # 启动系统属性服务: system property service
        927 property_set_fd = start_property_service();
        # 创建socket用来处理孤儿进程信号
        930 if (socketpair(AF_UNIX, SOCK_STREAM, 0, s) == 0) {
         931 signal_fd = s[0];
         932 signal_recv_fd = s[1];
        933 fcntl(s[0], F_SETFD, FD_CLOEXEC);
        934 fcntl(s[0], F_SETFL, O_NONBLOCK);
        935 fcntl(s[1], F_SETFD, FD_CLOEXEC);
        936 fcntl(s[1], F_SETFL, O_NONBLOCK);
        937 }
        # 触发在init脚本文件中名字为early-boot和boot的action,并且执行其commands,其实是:on early-boot和on boot
        948 action_for_each_trigger("early-boot", action_add_queue_tail);
        949 action_for_each_trigger("boot", action_add_queue_tail);
        950 drain_action_queue();
        # 启动所有属性变化触发命令,其实是: on property:ro.xx.xx=xx
        953 queue_all_property_triggers();
        954 drain_action_queue();
        # 进入死循环
        987 for(;;) {
         # 启动所有init脚本中声明的service,
         # 如:266 service servicemanager /system/bin/servicemanager
         # user system
        # critical
        # onrestart restart zygote
         # onrestart restart media
         994 restart_processes();
         # 多路监听设备管理,子进程运行状态,属性服务
        1012 nr = poll(ufds, fd_count, timeout);
        1013 if (nr <= 0)
        1014 continue;
        1016 if (ufds[2].revents == POLLIN) {
        1017 /* we got a SIGCHLD - reap and restart as needed */
        1018 read(signal_recv_fd, tmp, sizeof(tmp));
        1019 while (!wait_for_one_process(0))
        1020 ;
        1021 continue;
        1022 }
        1023
        1024 if (ufds[0].revents == POLLIN)
        1025 handle_device_fd(device_fd);
        1026
        1027 if (ufds[1].revents == POLLIN)
        1028 handle_property_set_fd(property_set_fd);
        1029 if (ufds[3].revents == POLLIN)
        1030 handle_keychord(keychord_fd);
        1031 }
        1032
        1033 return 0;
        1034 }

二、Android init脚本语言

前面简单分析了下init.c里的操作,里面提到了解析Init.rc和硬件脚本下面详细解析下Android init脚本语言的规范。

Android初始化语言包含了四种类型的声明:

Actions(行为)、Commands(命令)、Services(服务)和Options(选项)

所有这些都是以行为单位的,各种记号由空格来隔开。

C语言风格的反斜杠号可用于在记号间插入空格。

双引号也可用于防止字符串被空格分割成多个记号。

行末的反斜杠用于折行,注释行以井号(#)开头(允许以空格开头)。

Actions和Services声明一个新的分组Section。所有的命令或选项都属于最近声明的分组。位于第一个分组之前的命令或选项将会被忽略。

Actions和Services有唯一的名字。如果有重名的情况,第二个申明的将会被作为错误忽略。

Actions(行为)

Actions其实就是一序列的Commands(命令)。Actions都有一个trigger(触发器),它被用于决定action的执行时间。当一个符合action触发条件的事件发生时,action会被加入到执行队列的末尾,除非它已经在队列里了。

队列中的每一个action都被依次提取出,而这个action中的每个command(命令)都将被依次执行。

Actions的形式如下:
        on <trigger>
        <command1>
        <command2>
         <command3>

on后面跟着一个触发器,当trigger被触发时,command1,command2,command3,会依次执行,直到下一个Action或下一个Service。

简单来说,Actions就是Android在启动时定义的一个启动脚本,当条件满足时,会执行该脚本,脚本里都是一些命令commands,不同的脚本用on来区分。

Triggers(触发器)

Triggers(触发器)是一个用于匹配特定事件类型的字符串,用于使Actions发生。

boot:

这是init执行后的第一个被触发的Triggers(触发器)。(在 /init.conf (启动配置文件)被装载之后)
        <name>=<value>:
        这种形式的Triggers(触发器)会在属性<name>被设置为指定的<value>时被触发。
        device-added-<path>:
        device-removed-<path>:
        这种形式的Triggers(触发器)会在一个设备节点文件被增删时触发。
        service-exited-<name>:
        这种形式的Triggers(触发器)会在一个特定的服务退出时触发。
        触发器通常和on一起来联合使用。
        示例:
        on init
        export LD_LIBRARY_PATH /system/lib
        insmod modules/fsr.ko
        symlink /system/etc /etc
        mkdir /sdcard 0000 system system
        write /proc/cpu/alignment 4
        on boot
        …
        on property:ro.kernel.qemu=1
        start adbd
        上面声明了三个action:init,boot和一个属性触发器,当init被触发时,会顺序执行后面的命令,直到on boot新的action。Init的触发是由init.c里的函数action_for_each_trigger来决定的。当属性ro.kernel.qemu为1 时,会触发start adbd命令。

Services(服务)

Services(服务)是一个程序,它在初始化时启动,并在退出时可选择让其重启。Services(服务)的形式如下:
         service <name> <pathname> [ <argument> ]*
        <option>
        <option>
        ...

name:服务名

pathname:当前服务对应的程序位置
         option:当前服务设置的选项
         Options(选项)
         Options(选项)是一个Services(服务)的修正者。他们影响Services(服务)在何时,并以何种方式运行。

 critical:

说明这是一个对于设备关键的服务。如果他四分钟内退出大于四次,系统将会重启并进入recovery(恢复)模式。

disabled:

说明这个服务不会同与他同trigger(触发器)下的服务自动启动。他必须被明确的按名启动。

setenv <name> <value> (设置环境变量)

在进程启动时将环境变量<name>设置为<value>。

socket <name> <type> <perm> [ <user> [ <group> ] ]

创建一个Uinx域的名为/dev/socket/<name> 的套接字,并传递它的文件描述符给已启动的进程。<type> 必须是 "dgram"或"stream"。User 和 group默认为0。

user <username>

在启动这个服务前改变该服务的用户名。此时默认为root。(???有可能的话应该默认为nobody)。当前,如果你的进程要求Linux capabilities(能力),你无法使用这个命令。即使你是root,你也必须在程序中请求capabilities(能力)。然后降到你想要的 uid。

group <groupname> [ <groupname> ]*

在启动这个服务前改变该服务的组名。除了(必需的)第一个组名,附加的组名通常被用于设置进程的补充组(通过setgroups())。此时默认为root。(???有可能的话应该默认为nobody)。

oneshot

服务退出时不重启。

class <name>

指定一个服务类。所有同一类的服务可以同时启动和停止。如果不通过class选项指定一个类,则默认为"default"类服务。

onrestart

当服务重启,执行一个命令(下详)。

Commands(命令)

exec <path> [ <argument> ]*

创建和执行一个程序(<path>)。在程序完全执行前,init将会阻塞。由于它不是内置命令,应尽量避免使用exec,它可能会引起init卡死。(??? 是否需要一个超时设置?)

export <name> <value>

在全局环境变量中设在环境变量 <name>为<value>。(这将会被所有在这命令之后运行的进程所继承)

ifup <interface>

启动网络接口<interface>

import <filename>

解析一个init配置文件,扩展当前配置。

hostname <name>

设置主机名。

chmod <octal-mode> <path>

更改文件访问权限。

chown <owner> <group> <path>

更改文件的所有者和组。

class_start <serviceclass>

启动所有指定服务类下的未运行服务。

class_stop <serviceclass>

停止指定服务类下的所有已运行的服务。

domainname <name>

设置域名。

insmod <path>

加载<path>中的模块。

mkdir <path> [mode] [owner] [group]

创建一个目录<path>,可以选择性地指定mode、owner以及group。如果没有指定,默认的权限为755,并属于root用户和root组。

mount <type> <device> <dir> [ <mountoption> ]*

试图在目录<dir>挂载指定的设备。<device> 可以是以 mtd@name 的形式指定一个mtd块设备。<mountoption>包括 "ro"、"rw"、"remount"、"noatime"、 ...

setprop <name> <value>

设置系统属性 <name> 为 <value>值.

setrlimit <resource> <cur> <max>

设置<resource>的rlimit(资源限制)。

start <service>

启动指定服务(如果此服务还未运行)。

stop <service>

停止指定服务(如果此服务在运行中)。

symlink <target> <path>

创建一个指向<path>的软连接<target>。

sysclktz <mins_west_of_gmt>

设置系统时钟基准(0代表时钟滴答以格林威治平均时(GMT)为准)

trigger <event>

触发一个事件。用于将一个action与另一个 action排列。

write <path> <string> [ <string> ]*

打开路径为<path>的一个文件,并写入一个或多个字符串。

Properties(属性)

Init更新一些系统属性以提供对正在发生的事件的监控能力:

init.action

此属性值为正在被执行的action的名字,如果没有则为""。

init.command

此属性值为正在被执行的command的名字,如果没有则为""。

init.svc.<name>

名为<name>的service的状态("stopped"(停止), "running"(运行), "restarting"(重启))

三、Android init 示例

1 on init
        2
        3 sysclktz 0
        4
        5 loglevel 3
        6
        7 # setup the global environment
        8 export PATH /system/busybox/bin:/system/busybox/sbin:/system/busybox/usr/bin:/system/busybox/usr/sbin:/sbin:/system/sbin:/system/bin:/system/xbin
        9 export LD_LIBRARY_PATH /system/lib
        10 export ANDROID_BOOTLOGO 1
         11 export ANDROID_ROOT /system
        12 export ANDROID_ASSETS /system/app
        13 export ANDROID_DATA /data
        14 export EXTERNAL_STORAGE /sdcard
        ... ...
         23 symlink /system/etc /etc
         24 symlink /sys/kernel/debug /d
         25
         26 # create mountpoints and mount tmpfs on sqlite_stmt_journals
         27 mkdir /sdcard 0000 system system
        28 mkdir /system
        29 mkdir /data 0771 system system
        30 mkdir /cache 0770 system cache
        31 mkdir /config 0500 root root
         32 mkdir /sqlite_stmt_journals 01777 root root
        33 mount tmpfs tmpfs /sqlite_stmt_journals size=4m
         34
         35 # mount rootfs rootfs / ro remount
         36
        37 write /proc/sys/kernel/panic_on_oops 1
         38 write /proc/sys/kernel/hung_task_timeout_secs 0
         39 write /proc/cpu/alignment 4
         40 write /proc/sys/kernel/sched_latency_ns 10000000
         41 write /proc/sys/kernel/sched_wakeup_granularity_ns 2000000
         42 write /proc/sys/kernel/sched_compat_yield 1
         43 write /proc/sys/kernel/sched_child_runs_first 0
        44
         45 # Create cgroup mount points for process groups
         46 mkdir /dev/cpuctl
         47 mount cgroup none /dev/cpuctl cpu
         48 chown system system /dev/cpuctl
         49 chown system system /dev/cpuctl/tasks
         50 chmod 0777 /dev/cpuctl/tasks
         51 write /dev/cpuctl/cpu.shares 1024
         52
         53 mkdir /dev/cpuctl/fg_boost
         54 chown system system /dev/cpuctl/fg_boost/tasks
        55 chmod 0777 /dev/cpuctl/fg_boost/tasks
         56 write /dev/cpuctl/fg_boost/cpu.shares 1024
         57
         58 mkdir /dev/cpuctl/bg_non_interactive
         59 chown system system /dev/cpuctl/bg_non_interactive/tasks
         60 chmod 0777 /dev/cpuctl/bg_non_interactive/tasks
        61 # 5.0 %
         62 write /dev/cpuctl/bg_non_interactive/cpu.shares 52
         ... ...
        146 on boot
        147 # basic network init
         148 ifup lo
         149 hostname localhost
         150 domainname localdomain
         151
         152 # set RLIMIT_NICE to allow priorities from 19 to -20
         153 setrlimit 13 40 40
         154
         155 # Define the oom_adj values for the classes of processes that can be
         156 # killed by the kernel. These are used in ActivityManagerService.
         157 setprop ro.FOREGROUND_APP_ADJ 0
         158 setprop ro.VISIBLE_APP_ADJ 1
         159 setprop ro.SECONDARY_SERVER_ADJ 2
         160 setprop ro.BACKUP_APP_ADJ 2
         161 setprop ro.HOME_APP_ADJ 4
         162 setprop ro.HIDDEN_APP_MIN_ADJ 7
         ... ...
         233 # Define TCP buffer sizes for various networks
         234 # ReadMin, ReadInitial, ReadMax, WriteMin, WriteInitial, WriteMax,
         235 setprop net.tcp.buffersize.default 4096,87380,110208,4096,16384,110208
         236 setprop net.tcp.buffersize.wifi 4095,87380,110208,4096,16384,110208
         237 setprop net.tcp.buffersize.umts 4094,87380,110208,4096,16384,110208
         238 setprop net.tcp.buffersize.edge 4093,26280,35040,4096,16384,35040
         239 setprop net.tcp.buffersize.gprs 4092,8760,11680,4096,8760,11680
         240 setprop net.dns1 8.8.8.8
         241 setprop net.eth0.dns1 8.8.8.8
         242
         243 class_start default
         ... ...
         247 service console /system/bin/sh
        248 console
        249
         252 service adbd /sbin/adbd
         253 disabled'
        259 on property:persist.service.adb.enable=1
        260 start adbd
         261
        262 on property:persist.service.adb.enable=0
        263 stop adbd
        265 service servicemanager /system/bin/servicemanager
        266 user system
         267 critical
         268 onrestart restart zygote
         269 onrestart restart media
         271 service vold /system/bin/vold
         272 socket vold stream 0660 root mount
         282 service ril-daemon /system/bin/rild
         283 socket rild stream 660 root radio
         284 socket rild-debug stream 660 radio system
         285 user root
         286 group radio cache inet misc
         287
        288 service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
        289 socket zygote stream 666
        290 onrestart write /sys/android_power/request_state wake
         291 onrestart write /sys/power/state on
        292 onrestart restart media
         293
         294 service media /system/bin/mediaserver
         295 user media
         296 group system audio camera graphics inet net_bt net_bt_admin
         297
         298 service bootsound /system/bin/playmp3
         299 user media
         300 group audio
         301 oneshot
         302
         303 service bootanim /system/bin/bootanimation
         304 user graphics
         305 group graphics
        306 disabled
         307 oneshot
         ... ...
         由上面的例子可知:该init.rc里定义了4个actions:
        on init
        on boot
        on property:persist.service.adb.enable=1
        on property:persist.service.adb.enable=0

其中,前两个的触发器是由Init.c里的代码action_for_each_trigger实现触发的,后两个是由属性的值发生改变时触发的。当他们被触发时,会依次执行其后面的值,直到遇到一个新的Action或service。

该init.rc中定义了9个services,这些service属于本地服务,它们都是由c或c++代码写的,以可执行文件的方式存在文件系统里的/system/bin或/sbin目录下。由前面知识可知,如果一个服务没有使用class选项指定其分类,则其默认分类为:default,那么这9个services的分类为default。在on boot action触发时,其最后一个命令是class_start default,也就是将这9个services都依次启动。

init.rc中的9个service里,以zygote和servicemanager最为重要。

1> zygote service

该service主要用于创建Dalvik Java虚拟机,然后启动SystemServer,启动所有的Android服务,最终启动Android系统。

2> servicemanager

该service主要用来打开binder驱动,binder是Android Service通信机制的底层实现,在该service里封装了binder的操作接口。

技巧:

在调试或理解系统的工作原理的时候,我们经常要去找服务程序对应的源码。

寻找c或c++程序的源码文件:

例如:以寻找init程序对应的源码为例。

find ./ -name Android.mk -exec grep -l init {} \;

注:通过find命令查找所有的Android.mk, 通过grep从中查找程序字符串,得到其路径,然后去路径下找源码即可,这么做的原因是,c或c++代码都是通过Android.mk来指导编译的。

寻找java源码文件:

java源码的特点是和类名一致,所以如果我们知道一个类名,找其java源码就直接加上java后缀即可。

例如:寻找com.android.internal.os.ZygoteInit类的代码。

find ./ -name ZygoteInit.java

 

抱歉!评论已关闭.