Android Init language

来源:互联网 发布:海知智能孙胜男 编辑:程序博客网 时间:2024/06/05 20:40

Android Init Language

对于大多数的Android开发者来说,Init语言使用频率应该不高; 但是阅读.rc文件对理解开机过程很有帮助,所以还是要学习下Init语言。下面的内容来自于/system/core/init目录下的readme文件,readme算是官方文档了,当作手册来用。


语法

Android Init 语言比较简单,只有五种类别的声明/语句:Actions,Commands,Services,Options和Imports。

  • 所有这些语句都是以行为单位,不同的组成符号由空格分割。
  • c语言风格的反斜杠”\”还是用来作为转义字符或者用来换行。
  • 双引号可以避免符号被分割.
  • “#”号开头的是注释。

Actions和Services隐式地声明了一个新段落。所有的commands/options都属于最靠近的段落。
第一个段落之前的commands/options都会被忽略。
Actions 的格式:
on <trigger> [&& <trigger>]*
<command>
<command>
<command>

Actions的例子:
on load_persist_props_action
load_persist_props
start logd
start logd-reinit

Service的格式:
service <name> <pathname> [ <argument> ]*
<option>
<option>

Service的例子:
service ril-daemon /vendor/bin/hw/rild
class main
user radio
group radio cache inet misc audio log readproc wakelock
capabilities BLOCK_SUSPEND NET_ADMIN NET_RAW

每一个Action 和Service的名称都是唯一的。如果后续定义的Action和已定义的Action名称相同,那么它的commands将会被追加到已经定义的Action内。如果后续定义的Service和已定义的Service名称相同,那么这个Service会被视为无效,并且系统会记录错误信息。

Init .rc Files

Init 语言用来书写以”.rc”为后缀的文件。/init.rc是最重要的.rc文件,用来初始化系统,平台厂商提供的.rc文件也会被导入(“init.${ro.hardware}.rc”),init进程在开始执行的时候就会加载它。
在Android N之前,所有内容都集中在init.rc内部; 从Android N开始,google做了调整,将很多service移出了init.rc, 根据daemon分散动态加载.rc。文件系统挂载后会为所有的Actions和Services创建/{system, vendor, odm}/etc/init目录。在mount_all命令执行的过程中,init进程会这些目录下的所有.rc文件。这也要求所有binary在system, vendor或者odm 分区的Service都应该在对应的.rc文件中设置自己的service入口,并将.rc文件放在相应的/etc/init目录下。Google提供了LOCAL_INIT_RC宏来完成这个工作,研发只需要编写好.rc文件,并在mk文件中使用LOCAL_INIT_RC指定.rc文件。

三个默认路径针有不同的用途:

  1. /system/etc/init用于系统核心服务,例如SurfaceFlinger,MediaService和logcatd等。
  2. /vendor/etc/init用于SoC平台厂商的一些定制,比如SoC核心功能的一些actions或者daemon进程。
  3. /odm/etc/init 用于设备厂商; 比如Sensor等功能相关的一些actions或者daemon进程。

以logcatd为例,logcatd.rc和Android.mk文件都在system/core/logcat目录下。在build的过程中,Android.mk文件中的LOCAL_INIT_RC宏会将logcatd.rc文件放到/system/etc/init目录下。Init进程会在mount_all命令执行的过程中加载logcatd.rc,并允许service运行,action进入队列。

...include $(CLEAR_VARS)LOCAL_MODULE := logpersist.startLOCAL_MODULE_TAGS := debugLOCAL_MODULE_CLASS := EXECUTABLESLOCAL_INIT_RC := logcatd.rcLOCAL_MODULE_PATH := $(bin_dir)LOCAL_SRC_FILES := logpersistALL_TOOLS := logpersist.start logpersist.stop logpersist.catLOCAL_POST_INSTALL_CMD := $(hide) $(foreach t,$(filter-out $(LOCAL_MODULE),$(ALL_TOOLS)),ln -sf $(LOCAL_MODULE) $(TARGET_OUT)/bin/$(t);)include $(BUILD_PREBUILT)

如果不想使用上面的默认路径,可以使用mount_all命令行来指定文件加载路径。这个功能主要是为了支持工厂模式或者其他非标准的启动模式,常规的启动过程使用的是默认路径。
在使用mount_all命令设置路径时,还有”early”和”late”两个选项供使用。
当使用”–early”时,init进程会忽略那些使用了”latemount” 标识的挂载点,并且触发文件系统加密状态事件。当使用”–late”时,init进程会只挂载那些使用了”latemount”标识的挂载点,但不会导入rc文件。对于不使用任何选项的默认情况,mount_all会处理fstab中所有的入口点。

Actions

Actions以命令序列命名。Actions有一个触发器,它定义了这个action何时应该发生。当一个事件触发了触发器,action会被放到待执行队列的尾部,除非已经在队列内。队列中的每一个action会被依次处理,action中的命令也会被依次执行。Init进程在执行这些命令的间隙会处理设备的创建/销毁,设置property,进程重启等工作。
Actions take the form of:
on <trigger> [&& <trigger>]*
<command>
<command>
<command>

Services

Services是被init进程启动或者重启(可能)的应用程序。
Services take the form of:
service <name> <pathname> [ <argument> ]*
<option>
<option>

下面的内容是直接摘录,都是对具体option/command的说明。


Options

Options用来调节Services,可以影响init进程运行service的方式和时机。

critical
This is a device-critical service. If it exits more than four times in
four minutes, the device will reboot into recovery mode.

disabled
This service will not automatically start with its class.
It must be explicitly started by name.

setenv <name> <value>
Set the environment variable <name> to <value> in the launched process.

socket <name> <type> <perm> [ <user> [ <group> [ <seclabel> ] ] ]
Create a unix domain socket named /dev/socket/ and pass
its fd to the launched process. must be “dgram”, “stream” or “seqpacket”.
User and group default to 0.
‘seclabel’ is the SELinux security context for the socket.
It defaults to the service security context, as specified by seclabel or
computed based on the service executable file security context.

user <username>
Change to username before exec’ing this service.
Currently defaults to root. (??? probably should default to nobody)
As of Android M, processes should use this option even if they
require linux capabilities. Previously, to acquire linux
capabilities, a process would need to run as root, request the
capabilities, then drop to its desired uid. There is a new
mechanism through fs_config that allows device manufacturers to add
linux capabilities to specific binaries on a file system that should
be used instead. This mechanism is described on
http://source.android.com/devices/tech/config/filesystem.html. When
using this new mechanism, processes can use the user option to
select their desired uid without ever running as root.

group <groupname> [ <groupname> ]*
Change to groupname before exec’ing this service. Additional
groupnames beyond the (required) first one are used to set the
supplemental groups of the process (via setgroups()).
Currently defaults to root. (??? probably should default to nobody)

seclabel <seclabel>
Change to ‘seclabel’ before exec’ing this service.
Primarily for use by services run from the rootfs, e.g. ueventd, adbd.
Services on the system partition can instead use policy-defined transitions
based on their file security context.
If not specified and no transition is defined in policy, defaults to the init context.

oneshot
Do not restart the service when it exits.

class <name>
Specify a class name for the service. All services in a
named class may be started or stopped together. A service
is in the class “default” if one is not specified via the
class option.

onrestart
Execute a Command (see below) when service restarts.

writepid <file…>
Write the child’s pid to the given files when it forks. Meant for
cgroup/cpuset usage.

Triggers

Triggers are strings which can be used to match certain kinds of
events and used to cause an action to occur.

Triggers are subdivided into event triggers and property triggers.

Event triggers are strings triggered by the ‘trigger’ command or by
the QueueEventTrigger() function within the init executable. These
take the form of a simple string such as ‘boot’ or ‘late-init’.

Property triggers are strings triggered when a named property changes
value to a given new value or when a named property changes value to
any new value. These take the form of ‘property: <name>=<value>’ and
‘property:<name>=*’ respectively. Property triggers are additionally
evaluated and triggered accordingly during the initial boot phase of
init.

An Action can have multiple property triggers but may only have one
event trigger.

For example:
‘on boot && property:a=b’ defines an action that is only executed when
the ‘boot’ event trigger happens and the property a equals b.

‘on property:a=b && property:c=d’ defines an action that is executed
at three times,
1) During initial boot if property a=b and property c=d
2) Any time that property a transitions to value b, while property
c already equals d.
3) Any time that property c transitions to value d, while property
a already equals b.

Commands

bootchart_init
Start bootcharting if configured (see below).
This is included in the default init.rc.

chmod <octal-mode> <path>
Change file access permissions.

chown <owner> <group> <path>
Change file owner and group.

class_start <serviceclass>
Start all services of the specified class if they are
not already running.

class_stop <serviceclass>
Stop and disable all services of the specified class if they are
currently running.

class_reset <serviceclass>
Stop all services of the specified class if they are
currently running, without disabling them. They can be restarted
later using class_start.

copy <src> <dst>
Copies a file. Similar to write, but useful for binary/large
amounts of data.

domainname <name>
Set the domain name.

enable <servicename>
Turns a disabled service into an enabled one as if the service did not
specify disabled.
If the service is supposed to be running, it will be started now.
Typically used when the bootloader sets a variable that indicates a specific
service should be started when needed. E.g.
on property:ro.boot.myfancyhardware=1
enable my_fancy_service_for_my_fancy_hardware

exec [ <seclabel> [ <user> [ <group> ]* ] ] – <command> [ <argument> ]*
Fork and execute command with the given arguments. The command starts
after “–” so that an optional security context, user, and supplementary
groups can be provided. No other commands will be run until this one
finishes. <seclabel> can be a - to denote default.

export <name> <value>
Set the environment variable <name> equal to <value> in the
global environment (which will be inherited by all processes
started after this command is executed)

hostname <name>
Set the host name.

ifup <interface>
Bring the network interface <interface> online.

insmod <path>
Install the module at <path>

load_all_props
Loads properties from /system, /vendor, et cetera.
This is included in the default init.rc.

load_persist_props
Loads persistent properties when /data has been decrypted.
This is included in the default init.rc.

loglevel <level>
Sets the kernel log level to level. Properties are expanded within <level>.

mkdir <path> [mode] [owner] [group]
Create a directory at <path>, optionally with the given mode, owner, and
group. If not provided, the directory is created with permissions 755 and
owned by the root user and root group. If provided, the mode, owner and group
will be updated if the directory exists already.

mount_all <fstab> [ <path> ]* [–<option>]
Calls fs_mgr_mount_all on the given fs_mgr-format fstab and imports .rc files
at the specified paths (e.g., on the partitions just mounted) with optional
options “early” and “late”.
Refer to the section of “Init .rc Files” for detail.

mount <type> <device> <dir> [ <flag> ]* [<options>]
Attempt to mount the named device at the directory <dir>
<device> may be of the form mtd@name to specify a mtd block
device by name.
<flag>s include “ro”, “rw”, “remount”, “noatime”, …
<options> include “barrier=1”, “noauto_da_alloc”, “discard”, … as
a comma separated string, eg: barrier=1,noauto_da_alloc

powerctl
Internal implementation detail used to respond to changes to the
“sys.powerctl” system property, used to implement rebooting.

restart <service>
Like stop, but doesn’t disable the service.

restorecon <path> [ <path> ]*
Restore the file named by <path> to the security context specified
in the file_contexts configuration.
Not required for directories created by the init.rc as these are
automatically labeled correctly by init.

restorecon_recursive <path> [ <path> ]*
Recursively restore the directory tree named by <path> to the
security contexts specified in the file_contexts configuration.

rm <path>
Calls unlink(2) on the given path. You might want to
use “exec – rm …” instead (provided the system partition is
already mounted).

rmdir <path>
Calls rmdir(2) on the given path.

setprop <name> <value>
Set system property <name> to <value>. Properties are expanded
within <value>.

setrlimit <resource> <cur> <max>
Set the rlimit for a resource.

start <service>
Start a service running if it is not already running.

stop <service>
Stop a service from running if it is currently running.

swapon_all <fstab>
Calls fs_mgr_swapon_all on the given fstab file.

symlink <target> <path>
Create a symbolic link at <path> with the value <target>

sysclktz <mins_west_of_gmt>
Set the system clock base (0 if system clock ticks in GMT)

trigger <event>
Trigger an event. Used to queue an action from another
action.

umount <path>
Unmount the filesystem mounted at that path.

verity_load_state
Internal implementation detail used to load dm-verity state.

verity_update_state <mount_point>
Internal implementation detail used to update dm-verity state and
set the partition.<mount_point>.verified properties used by adb remount
because fs_mgr can’t set them directly itself.

wait <path> [ <timeout> ]
Poll for the existence of the given file and return when found,
or the timeout has been reached. If timeout is not specified it
currently defaults to five seconds.

write <path> <content>
Open the file at <path> and write a string to it with write(2).
If the file does not exist, it will be created. If it does exist,
it will be truncated. Properties are expanded within <content>.

Imports

The import keyword is not a command, but rather its own section and is
handled immediately after the .rc file that contains it has finished
being parsed. It takes the below form:

import <path>
Parse an init config file, extending the current configuration.
If <path> is a directory, each file in the directory is parsed as
a config file. It is not recursive, nested directories will
not be parsed.

There are only two times where the init executable imports .rc files,
1) When it imports /init.rc during initial boot
2) When it imports /{system,vendor,odm}/etc/init/ or .rc files at specified
paths during mount_all

Properties

Init以下面的方式为它负责的service提供状态信息:stopped, stopping, running和restarting。

init.svc.<name>
State of a named service (“stopped”, “stopping”, “running”, “restarting”)

在.rc文件中经常可以看到“on property:init.svc.zygote=running”,代码中也有对init.svc.<name>的操作。

Bootcharting

This version of init contains code to perform “bootcharting”: generating log
files that can be later processed by the tools provided by www.bootchart.org.

On the emulator, use the -bootchart <timeout> option to boot with bootcharting
activated for <timeout> seconds.

On a device, create /data/bootchart/start with a command like the following:

adb shell ‘echo $TIMEOUT > /data/bootchart/start’

Where the value of $TIMEOUT corresponds to the desired bootcharted period in
seconds. Bootcharting will stop after that many seconds have elapsed.
You can also stop the bootcharting at any moment by doing the following:

adb shell ‘echo 1 > /data/bootchart/stop’

Note that /data/bootchart/stop is deleted automatically by init at the end of
the bootcharting. This is not the case with /data/bootchart/start, so don’t
forget to delete it when you’re done collecting data.

The log files are written to /data/bootchart/. A script is provided to
retrieve them and create a bootchart.tgz file that can be used with the
bootchart command-line utility:

sudo apt-get install pybootchartgui
# grab-bootchart.sh uses ANDROIDSERIAL.ANDROID_BUILD_TOP/system/core/init/grab-bootchart.sh

One thing to watch for is that the bootchart will show init as if it started
running at 0s. You’ll have to look at dmesg to work out when the kernel
actually started init.

Comparing two bootcharts

A handy script named compare-bootcharts.py can be used to compare the
start/end time of selected processes. The aforementioned grab-bootchart.sh
will leave a bootchart tarball named bootchart.tgz at /tmp/android-bootchart.
If two such barballs are preserved on the host machine under different
directories, the script can list the timestamps differences. For example:

Usage: system/core/init/compare-bootcharts.py base_bootchart_dir
exp_bootchart_dir

process: baseline experiment (delta)

- Unit is ms (a jiffy is 10 ms on the system)

/init: 50 40 (-10)
/system/bin/surfaceflinger: 4320 4470 (+150)
/system/bin/bootanimation: 6980 6990 (+10)
zygote64: 10410 10640 (+230)
zygote: 10410 10640 (+230)
system_server: 15350 15150 (-200)
bootanimation ends at: 33790 31230 (-2560)

Systrace

Systrace [1] can be used for obtaining performance analysis reports during boot
time on userdebug or eng builds.
Here is an example of trace events of “wm” and “am” categories:

$ANDROID_BUILD_TOP/external/chromium-trace/systrace.py wm am –boot

This command will cause the device to reboot. After the device is rebooted and
the boot sequence has finished, the trace report is obtained from the device
and written as trace.html on the host by hitting Ctrl+C.

LIMITATION
Recording trace events is started after persistent properties are loaded, so
the trace events that are emitted before that are not recorded. Several
services such as vold, surfaceflinger, and servicemanager are affected by this
limitation since they are started before persistent properties are loaded.
Zygote initialization and the processes that are forked from the zygote are not
affected.

[1] http://developer.android.com/tools/help/systrace.html

Debugging init

By default, programs executed by init will drop stdout and stderr into
/dev/null. To help with debugging, you can execute your program via the
Android program logwrapper. This will redirect stdout/stderr into the
Android logging system (accessed via logcat).

For example
service akmd /system/bin/logwrapper /sbin/akmd

For quicker turnaround when working on init itself, use:

mm -j
m ramdisk-nodeps
m bootimage-nodeps
adb reboot bootloader
fastboot boot $ANDROID_PRODUCT_OUT/boot.img

Alternatively, use the emulator:

emulator -partition-size 1024 -verbose -show-kernel -no-window

You might want to call klog_set_level(6) after the klog_init() call
so you see the kernel logging in dmesg (or the emulator output).

原创粉丝点击