对于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 <Triggers>,下面行跟各种command
Commands :命令
Services :服务 使用格式 : service <name> <pathname> [ <argument> ]* ,下面行可以添加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 <trigger> //action 模型
<command>
<command>
<command>
....
service <name> <pathname> [ <argument> ]* (services可以带有多个参数和选项)
<option>
<option>
...
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).<name>=<value> 形式,如:on property:ro.debuggable=1
4). device-added-<path>
device-removed-<path>
Triggers of these forms occur when a device node is added or removed
一个设备节点/dev/XXX添加或者删除时可以触发一个action,这个可以很好的去利用
5).service-exited-<name>
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>
说明服务属于class_name这个类。缺省值service属于 “default” 类。同一个class下面的服务可以一起启动或停止。
2).disabled
表示当这个服务所在的class启动的时候,服务不会自动启动,
要用start server_name 或 property_set("ctl.start", server_name);才能启动。
3).oneshot
当服务退出后,不会再重新启动,如果没有加这个option,则服务默认退出后又会重新重启
4).user <username>
执行服务之前,先声明服务的用户名,缺省值应该为root用户.
如果你的进程要求具有Linux内核能力,必须保证它的用户为root(没有完全明白,实例?)
5).group <groupname> [ <groupname> ]*
执行服务之前,先声明服务所属组名,可以一次声明属于多个组。
声明多个组时,除第一个组名外,其他的为服务的补充组名(调用接口 setgroups()).
6).onrestart + command
服务重启的时,会执行onrestart后面的command.
eg:onrestart restart media 重启名为media的服务
7).setenv <name> <value>
在当前服务进程中设置环境变量name的值为value。
注意:setenv定义的环境变量仅在本进程内生效,退出该进程,或者关闭相应的程序运行窗口,该环境变量即无效)
程序中可通过getenv("name")接口获取这个环境变量的值
setenv和export 的区别:
setenv csh ,本进程生效,退出后,变量无效
export bash ,全局生效,一直存在
格式:
export key=value
setenv key value
8).critical
声明为设备的循环服务。如果服务在四分钟内退出了四次,则设备会进入recovery模式
使用实例servicemanager、ueventd等服务
9).socket <name> <type> <perm> [ <user> [ <group> ] ]
创建名为/dev/socket/<name>的unix domain socket ,并把它的句柄fd传给本服务进程
<type> 必须为 "dgram", "stream" or "seqpacket".User and group default to 0 ,也就是root.
6.command :(action下面的一系列命令)
常用命令:
1).import <filename>
导入init.XX.rc、xxx.conf等文件
Parse an init config file, extending the current configuration.
2).chmod <octal-mode> <path>
Change file access permissions.
3).chown <owner> <group> <path>
Change file owner and group.
4).chdir <directory>
Change working directory.
5).chroot <directory>
改变进程根目录
6).insmod <path>
加载XX.ko驱动模块
7).start <service>
Start a service running if it is not already running.
8).stop <service>
Stop a service from running if it is currently running.
9).class_start <serviceclass>
Start all services of the specified class if they are not already running.
10).class_stop <serviceclass>
Stop all services of the specified class if they are currently running.
class_reset <serviceclass> //重启class下面所有的服务
11).setprop <name> <value>
Set system property <name> to <value>.
通过getprop命令可以查看当前系统的属性值
12).export <name> <value>
设置全局环境变量,这个变量值可以被所有进程访问(全局的,一直存在)
在代码中通过value = getenv("name")接口可以获取这个环境变量的值
13).mkdir <path> [mode] [owner] [group]
创建目录,后面项缺省值为 mode,owner,group: 0755 root root
14).trigger <event>
Trigger an action. Used to queue an action from another action.
例:trigger post-fs-data
15).exec <path> [ <argument> ]*
执行<path>指定的Program,并可以带有执行参数。
exec在调用进程内部执行一个可执行文件,并会阻塞当前进程,直到运行完成。
最好避免和那些builtin commands一样使用exec命令,否则容易造成阻塞 or stuck ( maybe there should be a timeout?)
16).ifup <interface>
启动某个网络接口,使其为up状态,通过netcfg可以查看,ifup eth0 等价于 netcfg eth0 up 功能一样
17).hostname <name>
设置设备的主机名,一般默认设置为localhost,可以在终端通过hostname new_name进行修改
18).domainname <name>
设置网络域名localdomain
19).mount <type> <device> <dir> [ <mountoption> ]*
把device挂接到dir目录下面,文件系统类型为type。
<mountoption>s include "ro", "rw", "remount", "noatime", “nosuid”......,具体可查看linux的mount命令说明
20).setkey
TBD == to be determined 暂时没有使用
21).setrlimit <resource> <cur> <max>
设置本服务进程的资源上限值。(使用例子??)
22).symlink <target> <path>
path 链接到 ---》target ;创建符号链接
23).sysclktz <mins_west_of_gmt>
设置系统时区(0 if system clock ticks in GMT)
24).wait <path> [ <timeout> ]
轮询查找给定的文件path是否存在,如果找到或者超时则返回默认超时为5秒。(使用实例???)
25).write <path> <string> [ <string> ]*
打开一个文件,利用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.<name>
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.<platform>.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 <rt|be|idle> <ioprio 0-7>\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