android系统启动流程之init.rc详细分析笔记

        对于android系统的学习掌握,除了对一些语言基础的要求,如C,C++,java,shell,makefile等,更要整体去把握系统的架构。对于架构的熟悉入门,首先应该分析android的编译系统结构。而对于系统的启动流程的掌握,最好是深入分析init.rc、init.xx.rc等文件。这些文件相对来说代码量少,比较简单,而且对系统的整体认识有很大的帮助。以前在工作中经常要用到init.rc相关的知识,但是没有系统的去分析整体,最近写成了笔记,分享出来!


关于init.rc的几点说明:
1).在android源码目录下面jb\system\core\init\readme.txt文件中有init.rc语法的详细定义
  注意:readme.txt没有和android的版本一起更新,所以在新版本的android中,增加了一些commands、options等,在readme.txt中 没有介绍。 还是看init目录下面的源码最为准确

2).解析init.rc,init.xx.rc的相关文件目录system/core/init/

3).init.c 、init.rc init.xx.rc 等最终会编译到ramdisk.img(根文件系统)中,和kernel一起打包成boot.img。android启动后每次都会从boot.img中解压出init.c等文件到内存,所以要修改必须修改替换boot.img。

4).在init.rc中启动的服务,都是以一个进程的形式运行,属于android的本地服务。通过在终端输入PS命令可以查看在运行的相应进程,他们的ppid都为1,代表init进程。 init进程也是android系统启动的第一个应用进程

5).init.rc中所有的语句都是以行为单位的(每个语句都是单独写在一行里面)

6).注释行以“#”开头

7).Actions 和 Services表示一个新的段落section的开始。
 所有的commands和options 都是归属于上方最近的一个段落。在第一个段落之前的commands和options是无效的。

8).Actions and Services
不能重名,如果重名,后面的定义会被忽略(readme.txt说明)。
但是实际项目中同一个init.xx.rc中有重名的action,也可以正常使用。多个init.xx.rc中action也允许有重名, 比如 boot,init 等在多个rc文件中出现。services应该不能重名


init.rc (Android Init Language)语法详解:

1.init语法的四个组成原件:
Actions  :动作 ,使用格式: on ,下面行跟各种command
Commands :命令  
Services :服务  使用格式 : service [ ]* ,下面行可以添加Options
Options : 选项

2.init.rc中三大模块:
1). import 导入其他的init.xx.rc文件。
2). 以action动作为触发点的一系列命令
3). 带有各种Options的一系列services的定义


import /init.${ro.hardware}.rc
通过cat proc/cpuinfo可以查看ro.hardware的值=Hardware的值

on     //action 模型
  
  
  
   ....
  
service [ ]*   (services可以带有多个参数和选项)
  

3.对Actions官方描述的一些理解 :
当action的trigger被匹配后,action会被加入到动作执行队列中,在队列中的action按队列顺序被执行,每个action下面的command也是按顺序执行。按这个理论,在init.rc中action、command、service的执行顺序主要是和它们的触发时间有关,如果都是开机启动时执行,应该也和代码顺序有关。(有兴趣可以验证一下、想深入了解解析过程,可以查看源码目录init下面的init_parser.c等文件)


4.Triggers : 跟在on后面的动作名,用来触发action下面command的执行

1).android常用的triggers的名字:
  early-init,init,early-fs,fs,post-fs,early-boot,boot (这些都是在init.c中触发)

2).可以自定义一些triggers,并选择合适的触发方式 (例如:关机充电功能,可以只启动charger服务进程)

3).= 形式,如:on property:ro.debuggable=1

4). device-added-
    device-removed-      
   Triggers of these forms occur when a device node is added or removed
   一个设备节点/dev/XXX添加或者删除时可以触发一个action,这个可以很好的去利用
 
5).service-exited-  
   Triggers of this form occur when the specified service exits.
   当某个服务退出时,可以触发一个action


5.option 选项:(用于services下面)
android新版本上增加的一些options可以通过源码查看对应作用
init_parser.c--》lookup_keyword(const char *s)--》parse_line_service() 或者 --》parse_line_action()


1).class   
说明服务属于class_name这个类。缺省值service属于 “default” 类。同一个class下面的服务可以一起启动或停止。

2).disabled 
表示当这个服务所在的class启动的时候,服务不会自动启动,
要用start server_name 或 property_set("ctl.start", server_name);才能启动。
 
3).oneshot  
当服务退出后,不会再重新启动,如果没有加这个option,则服务默认退出后又会重新重启

4).user  
   执行服务之前,先声明服务的用户名,缺省值应该为root用户.
   如果你的进程要求具有linux内核能力,必须保证它的用户为root(没有完全明白,实例?)


5).group [ ]*
  执行服务之前,先声明服务所属组名,可以一次声明属于多个组。
   声明多个组时,除第一个组名外,其他的为服务的补充组名(调用接口 setgroups()).
  
6).onrestart   + command
服务重启的时,会执行onrestart后面的command.
eg:onrestart restart media 重启名为media的服务
   
7).setenv       
在当前服务进程中设置环境变量name的值为value。
注意:setenv定义的环境变量仅在本进程内生效,退出该进程,或者关闭相应的程序运行窗口,该环境变量即无效)
程序中可通过getenv("name")接口获取这个环境变量的值
setenv和export 的区别:
setenv  csh ,本进程生效,退出后,变量无效
export  bash ,全局生效,一直存在
格式:
export key=value
setenv key value

8).critical   
声明为设备的循环服务。如果服务在四分钟内退出了四次,则设备会进入recovery模式
使用实例servicemanager、ueventd等服务

9).socket [ [ ] ]  
创建名为/dev/socket/的unix domain socket ,并把它的句柄fd传给本服务进程
  必须为 "dgram", "stream" or "seqpacket".User and group default to 0 ,也就是root.
 
  
6.command   :(action下面的一系列命令)

常用命令:

1).import         
  导入init.XX.rc、xxx.conf等文件
   Parse an init config file, extending the current configuration.

2).chmod
   Change file access permissions.

3).chown
   Change file owner and group.
  
4).chdir
   Change working directory.
  
5).chroot  
  改变进程根目录
  
6).insmod    
  加载XX.ko驱动模块

7).start
   Start a service running if it is not already running.

8).stop
   Stop a service from running if it is currently running.

9).class_start
   Start all services of the specified class if they are not already running.

10).class_stop
   Stop all services of the specified class if they are currently running.
     
   class_reset    //重启class下面所有的服务
     
11).setprop   
   Set system property to .
   通过getprop命令可以查看当前系统的属性值
  
12).export        
  设置全局环境变量,这个变量值可以被所有进程访问(全局的,一直存在)
  在代码中通过value = getenv("name")接口可以获取这个环境变量的值
  
13).mkdir [mode] [owner] [group]
   创建目录,后面项缺省值为 mode,owner,group: 0755 root root

14).trigger
   Trigger an action.  Used to queue an action from another action.
   例:trigger post-fs-data

15).exec [ ]*     
   执行指定的Program,并可以带有执行参数。
   exec在调用进程内部执行一个可执行文件,并会阻塞当前进程,直到运行完成。
   最好避免和那些builtin commands一样使用exec命令,否则容易造成阻塞 or stuck ( maybe there should be a timeout?)

16).ifup
   启动某个网络接口,使其为up状态,通过netcfg可以查看,ifup eth0  等价于 netcfg eth0 up 功能一样
  
17).hostname
   设置设备的主机名,一般默认设置为localhost,可以在终端通过hostname new_name进行修改

18).domainname
   设置网络域名localdomain

19).mount

[ ]*
    把device挂接到dir目录下面,文件系统类型为type。
   s include "ro", "rw", "remount", "noatime", “nosuid”......,具体可查看linux的mount命令说明
  
20).setkey
   TBD  == to be determined 暂时没有使用

21).setrlimit
  设置本服务进程的资源上限值。(使用例子??)

22).symlink    
   path 链接到 ---》target ;创建符号链接

23).sysclktz   
  设置系统时区(0 if system clock ticks in GMT)

24).wait [ ]
 轮询查找给定的文件path是否存在,如果找到或者超时则返回默认超时为5秒。(使用实例???)

25).write [ ]*
   打开一个文件,利用write命令写入一个或多个字符串


7. Properties
----------
Init updates some system properties to provide some insight into
what it's doing:

init.action
   Equal to the name of the action currently being executed or "" if none

init.command
   Equal to the command being executed or "" if none.

init.svc.
   State of a named service ("stopped", "running", "restarting")
  属性状态,getprop命令可以查看。property_set接口函数、ctl.start、ctl.stop来设置


8.实际的一些例子,基于android4.2.1:


1).readme.txt自带的一些例子(只是整理一些有代表性的):


on boot
   export PATH /sbin:/system/sbin:/system/bin

   mount tmpfs tmpfs /dev
  mount yaffs2
mtd@system /system

   write /proc/cpu/alignment 4
  
   import /system/etc/init.conf 
   //导入相应的配置文件

on device-added-/dev/compass
   start akmd

on device-removed-/dev/compass
   stop akmd

service akmd /sbin/akmd
   disabled
   user akmd
   group akmd


Debugging notes 调试注意点:
---------------
默认的,在系统init进程中启动的程序(如XX.rc中定义的服务等) ,不能通过logcat查看相关log信息
为了调试,需要增加执行logwrapper,才能通过logcat查看log信息,(之前调试可以直接查看log信息啊,有待验证)
如:service akmd /system/bin/logwrapper /sbin/akmd 
可以通过logcat查看akmd服务中的log信息。


2).实际项目中的一些典型例子(只是整理一些有代表性的)

init.rc文件中的一些参考例子:
           
import /init.${ro.hardware}.rc
on early-init

    write /proc/1/oom_adj -16

    # Set the security context for the init process.
    # This should occur before anything else (e.g. ueventd) is started.
    setcon u:r:init:s0 
    
    start ueventd
    mkdir /mnt 0775 root system

on init

sysclktz 0
loglevel 3    设置log输出等级

# setup the global environment
    export PATH /sbin:/vendor/bin:/system/sbin:/system/bin:/system/xbin
    export ANDROID_BOOTLOGO 1

    symlink /system/etc /etc     
    mount tmpfs tmpfs /mnt/secure mode=0700,uid=0,gid=0
    write /proc/sys/kernel/panic_on_oops 1
  
    mount cgroup none /dev/cpuctl cpu
    chown system system /dev/cpuctl
    chmod 0660 /dev/cpuctl/tasks

on fs
# mount mtd partitions
    #mount yaffs2
mtd@system /system ro remount
 
on post-fs
    mount rootfs rootfs / shared rec
    mount tmpfs tmpfs /mnt/secure private rec
    # We restorecon /cache in case the cache partition has been reset.
    restorecon /cache  

on post-fs-data
   
    write /proc/apanic_console 1
    mkdir /data/misc 01771 system misc
   mkdir /data/misc/adb 02750 system shell 
    setprop vold.post_fs_data_done 1


on boot

# basic network init
    ifup lo
    hostname localhost
    domainname localdomain

# set RLIMIT_NICE to allow priorities from 19 to -20
    setrlimit 13 40 40

    class_start core
    class_start main

on charger
    class_start charger

on property:vold.decrypt=trigger_reset_main
    class_reset main

on property:vold.decrypt=trigger_load_persist_props
    load_persist_props
    //加载用户空间设置的系统属性persist_props 

on property:vold.decrypt=trigger_post_fs_data
    trigger post-fs-data

service ueventd /sbin/ueventd
    class core
    critical
    seclabel u:r:ueventd:s0 

on property:selinux.reload_policy=1
    restart ueventd
    restart installd

service console /system/bin/sh
    class core
    console       //requires console
    disabled
    user shell
    group log

on property:ro.debuggable=1
    start console

# adbd is controlled via property triggers in init..usb.rc
service adbd /sbin/adbd
    class core
    socket adbd stream 660 system system
    disabled
    seclabel u:r:adbd:s0
    ioprio rt 4 
  ioprio be 2
IoSchedClass, usage: ioprio \n . 
  
service servicemanager /system/bin/servicemanager
    class core
    user system
    group system
    critical  //添加了此选项,如果servicemanager在四分钟内退出了四次,则设备会进入recovery模式
    onrestart restart zygote  //如果servicemanager服务重启,则zygote服务也会重启

 
service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server   (后面都是所带参数app_process)
    class main
    socket zygote stream 660 root system
    socket keystore stream 666
    onrestart write /sys/power/state on  //如果zygote服务重启,则执行write命令,写state为on

 
init.hardware.rc内容 :

import /init.usb.rc

on init
    export EXTERNAL_STORAGE /mnt/sdcard    getenv("EXTERNAL_STORAGE") 获取变量值/ dalvik_system_Zygote.cpp
    mkdir /mnt/sdcard 0000 system system  
    symlink /mnt/sdcard /sdcard
   
  #通过USB接口的U盘虚拟成SD卡的操作
  #export EXTERNAL_STORAGE /mnt/usb/sda1
    #mkdir /mnt/usb/sda1 0000 system system
    #symlink /mnt/usb/sda1 /sdcard
    #symlink /mnt/usb/sda1 /mnt/sdcard
  
on early-init
    mount tmpfs tmpfs /mnt/usb mode=0755,gid=1000

on init
    mkdir /var 0775 system system

on fs
  mount -o size=110m -t tmpfs tmpfs /dev/cache mode=0777,gid=1000 
    mount ext4 /dev/block/mmcblk0p4 /system wait ro noatime block_validity nodiscard data=ordered journal_checksum 
    mount ext4 /dev/block/mmcblk0p5 /data wait nosuid nodev noatime block_validity nodiscard data=ordered journal_checksum
    mount ext4 /dev/block/mmcblk0p7 /tvservice wait ro noatime block_validity nodiscard data=ordered journal_checksum
 
on post-fs
    command
   
on post-fs-data
    write /proc/sys/kernel/core_pattern /var/coredump.%p.gz

on boot

# After launcher is displayed, trigger related drivers initialization
on property:init.svc.bootanim=stopped// 开机后启动加载或者启动某些服务,提高开机速度
    insmod /system/lib/modules/usb-storage.ko
   
# bugreport is triggered by holding down volume down, volume up and power
service bugreport /system/bin/bugmailer.sh -v
    class main
    disabled
    oneshot
    keycodes 114 115 116   
 //keycodes for triggering this service via /dev/keychord 。参见init.h






你可能感兴趣的:(android)