前言

本文主要讲解Android源码之init.rc文件规则和init.c解析。

本文摘抄网上大牛的文章(链接文末),方便自己查阅。

多谢分享。

正文

init.c与init.rc在源码中的位置:

init.c : /system/core/init

init.rc : /system/core/rootdir

.rc文件是 android系统一个十分重要的文件。

其是资源文件,包括比如对话框、菜单、图标、字符串等资源信息。

使用.rc资源文件的目的是为了对程序中用到的大量的资源进行统一的管理。

本文来了解文件的规则。

Android中init.rc文件简单介绍

init.rc 脚本是由Android中linux的第一个用户级进程init进行解析的。

init.rc 文件并不是普通的配置文件,而是由一种被称为“Android初始化语言”(Android Init Language,这里简称为AIL)的脚本写成的文件。

init.rc 脚本包括了启动脚本文件,主要完成一些初级的初始化,文件系统初始化。

主要是:

  1. 设置一些环境变量
  2. 创建system、sdcard、data、cache等目录(见案例1)
  3. 把一些文件系统mount到一些目录去,如,mount tmpfs tmpfs /sqlite_stmt_journals
  4. 设置一些文件的用户群组、权限
  5. 设置一些线程参数
  6. 设置TCP缓存大小

该文件在ROM中是只读的,即使有了root权限,可以修改该文件也没有。因为我们在根目录看到的文件只是内存文件的镜像。也就是说,android启动后,会将init.rc文件装载到内存。而修改init.rc文件的内容实际上只是修改内存中的init.rc文件的内容。一旦重启android,init.rc文件的内容又会恢复到最初的装载。想彻底修改init.rc文件内容的唯一方式是修改Android的ROM中的内核镜像(boot.img)。

如果想要修改启动过程只需要修改init.c(system/core/init)或者init.rc里的内容即可。

文件规则

类型

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

Actions(行为)、Commands(命令)、Services(服务)和Options(选项) Actions和Services声明一个新的分组Section。所有的命令或选项都属于最近声明的分组。位于第一个分组之前的命令或选项将会被忽略。

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

注意:这个只是一个语法文件,就像一个xml文件一样,没有执行顺序的,解析器通过读这个文件获取想要的数据,包括service,action等

基本规则
  1. 以行为单位的,各种记号由空格来隔开。
  2. C语言风格的反斜杠号可用于在记号间插入空格。
  3. 双引号也可用于防止字符串被空格分割成多个记号。
  4. 行末的反斜杠用于折行,注释行以井号(#)开头(允许以空格开头)
关键字

关键字位于语句块的首部,决定了这个语句块的种类

Action   :  动作

trigger  : 触发器或者叫做触发条件

commands :  命令

service  : 服务
动作(Action)

动作表示了一组命令(commands)组成。

动作包括一个触发器,决定了何时运行这个动作。

当触发器的条件满足时,这个动作会被增加到已被运行的队列尾。假设此动作在队列中已经存在,那么它将不会运行

on  <trigger>      ## 触发条件
    <command>      ##执行命令
    <command1>     ##可以执行多个命令

举个例子:

 # /device/rockchip/rk322x/init.rc

 on property:vold.decrypt=trigger_encryption
    start surfaceflinger
    start encrypt
触发器(trigger)

在"动作"(action)里面的,on后面跟着的字符串是触发器(trigger),trigger是一个用于匹配某种事件类型的字符串,它将对应的Action的执行。

触发器(trigger)有几种格式:

  1. 最简单的一种是一个单纯的字符串。比如“on boot”。这种简单的格式可以使用命令"trigger"来触发。
  2. 还有一种常见的格式是"on property : <属性>=<值>"。如果属性值在运行时设成了指定的值,则"块"(action)中的命令列表就会执行。

常见的格式:

on early-init	  在初始化早期阶段触发

on init	          在初始化阶段触发

on late-init	  在初始化晚期阶段触发

on boot/charger	  当系统启动/充电时触发

on property	      当属性值满足条件时触发
commands(命令)

command是action的命令列表中的命令,或者是service中的选项 onrestart 的参数命令。

命令将在所属事件发生时被一个个地执行。

常见命令:

exec <path> [ ]*	                            运行指定路径下的程序,并传递參数.

export <name> <value>	                        设置全局环境參数。此參数被设置后对全部进程都有效.

ifup <interface>	                            使指定的网络接口"上线",相当激活指定的网络接口

hostname <name>	                                 设置主机名

chdir <directory>	                             改变工作文件夹.

chmod <octal-mode> <path>	                     改变指定文件的读取权限.

chown <owner> <group> <path>	                 改变指定文件的拥有都和组名的属性.

chroot <directory>          	                 改变进行的根文件夹.

class_start <serviceclass>	                     启动指定类属的全部服务,假设服务已经启动,则不再反复启动.

class_stop <serviceclass>	                     停止指定类属的所胡服务.

domainname <name>	                             设置域名

insmod <path>	                                 安装模块到指定路径.

mkdir <path> [mode] [owner] [group]              用指定參数创建一个文件夹,在默认情况下,创建的文件夹读取权限为755.username为root,组名为root.

mount<type> <device> <dir> [ <mountoption> ]*	 类似于linux的mount指令

setprop <name> <value>	                         设置属性及相应的值.

setrlimit <resource> <cur> <max>	             设置资源的rlimit(资源限制),不懂就百度一下rlimit

start <service>	                                 假设指定的服务未启动,则启动它.

stop <service>	                                 假设指定的服务当前正在执行。则停止它.

symlink <target> <path>	                         创建一个符号链接.

sysclktz <mins_west_of_gmt>	                     设置系统基准时间.

write <path> <string>\ [ <string> ]*	         往指定的文件写字符串.
服务(services)

服务是指那些须要在系统初始化时就启动或退出时自己主动重新启动的程序.

service <name><pathname> [ <argument> ]*
    <option>
    <option>
name        表示此服务的名称

pathname    此服务所在路径因为是可执行文件,所以一定有存储路径。

argument    启动服务所带的参数

option      对此服务的约束选项
service gpio_read /system/bin/gpio_read.sh
    user root
    group root
    class main
    disabled
    oneshot

设置一个gpio_read服务对应可执行文件 gpio_read.sh脚本 。设置运行的user 和group,设置为不自动启动disabled,设置为退出之后不重启oneshot。

当属性 sys.wifi.on=true时,就会启动goio_read这个服务。

选项(option)

options是Service的修订项。它们决定一个服务何时以及如何运行。

critical	         据设备相关的关键服务,如果在4分钟内,此服务重复启动了4次,那么设备将会重启进入还原模式。

disabled	         服务不会自动运行,必须显式地通过服务器来启动。

setenv	             设置环境变量

socket [ [ ] ]	     在/dev/socket/下创建一个unix domain的socket,并传递创建的文件描述符fd给服务进程.其中type必须为dgram或stream,seqpacket.

user	             在执行此服务之前先切换用户名。当前默认为root.

group [ ]*	         类似于user,切换组名

oneshot	             当此服务退出时不会自动重启.

class	             给服务指定一个类属,这样方便操作多个服务同时启动或停止.默认情况下为default.

onrestart	        当服务重启时执行一条指令,

示例详解

init.rc文件详解
# Copyright (C) 2012 The Android Open Source Project
#
# IMPORTANT: Do not create world writable files or directories.
# This is a common source of Android security bugs.
#

"【import <filename>一个init配置文件,扩展当前配置。】"
import /init.environ.rc
import /init.usb.rc
import /init.${ro.hardware}.rc
import /init.${ro.zygote}.rc
import /init.trace.rc

"【触发条件early-init,在early-init阶段调用以下行】"
on early-init
    # Set init and its forked children's oom_adj.
    write /proc/1/oom_score_adj -1000
	"【打开路径为<path>的一个文件,并写入一个或多个字符串】"
    # Apply strict SELinux checking of PROT_EXEC on mmap/mprotect calls.
    write /sys/fs/selinux/checkreqprot 0

    # Set the security context for the init process.
    # This should occur before anything else (e.g. ueventd) is started.
    "【这段脚本的意思是init进程启动之后就马上调用函数setcon将自己的安全上下文设置为“u:r:init:s0”,即将init进程的domain指定为init。】"
    setcon u:r:init:s0

    # Set the security context of /adb_keys if present.
    "【恢复指定文件到file_contexts配置中指定的安全上线文环境】"
    restorecon /adb_keys

	"【执行start ueventd的命令。ueventd是一个service后面有定义】 "
    start ueventd

	"【mkdir <path> [mode] [owner] [group]   //创建一个目录<path>,可以选择性地指定mode、owner以及group。如果没有指定,默认的权限为755,并属于root用户和root组。】"
    # create mountpoints
    mkdir /mnt 0775 root system

on init
	"【设置系统时钟的基准,比如0代表GMT,即以格林尼治时间为准】"
    sysclktz 0

"【设置kernel日志等级】"
loglevel 6 ####
    write /proc/bootprof "INIT: on init start" ####

	"【symlink <target> <path>    //创建一个指向<path>的软连接<target>。】"
    # Backward compatibility
    symlink /system/etc /etc
    symlink /sys/kernel/debug /d

    # Right now vendor lives on the same filesystem as system,
    # but someday that may change.
    symlink /system/vendor /vendor

	"【创建一个目录<path>,可以选择性地指定mode、owner以及group。】"
    # Create cgroup mount point for cpu accounting
    mkdir /acct
    mount cgroup none /acct cpuacct
    mkdir /acct/uid

	"【mount <type> <device> <dir> [ <mountoption> ]   //在目录<dir>挂载指定的设备。<device> 可以是以 mtd@name 的形式指定一个mtd块设备。<mountoption>包括 ro、rw、remount、noatime、 ...】"
    # Create cgroup mount point for memory
    mount tmpfs none /sys/fs/cgroup mode=0750,uid=0,gid=1000
    mkdir /sys/fs/cgroup/memory 0750 root system
    mount cgroup none /sys/fs/cgroup/memory memory
    write /sys/fs/cgroup/memory/memory.move_charge_at_immigrate 1
    "【chown <owner> <group> <path>   //改变文件的所有者和组。】"

    "【后面的一些行因为类似,就省略了】"
    .....

# Healthd can trigger a full boot from charger mode by signaling this
# property when the power button is held.
on property:sys.boot_from_charger_mode=1
	"【停止指定类别服务类下的所有已运行的服务】"
    class_stop charger
    "【触发一个事件,将该action排在某个action之后(用于Action排队)】"
    trigger late-init

# Load properties from /system/ + /factory after fs mount.
on load_all_props_action
	"【从/system,/vendor加载属性。默认包含在init.rc】"
    load_all_props

# Indicate to fw loaders that the relevant mounts are up.
on firmware_mounts_complete
	"【删除指定路径下的文件】"
    rm /dev/.booting

# Mount filesystems and start core system services.
on late-init
	"【触发一个事件。用于将一个action与另一个 action排列。】"
    trigger early-fs
    trigger fs
    trigger post-fs
    trigger post-fs-data

    # Load properties from /system/ + /factory after fs mount. Place
    # this in another action so that the load will be scheduled after the prior
    # issued fs triggers have completed.
    trigger load_all_props_action

    # Remove a file to wake up anything waiting for firmware.
    trigger firmware_mounts_complete

    trigger early-boot
    trigger boot


on post-fs
	...
    "【一些创造目录,建立链接,更改权限的操作,这里省略】"

on post-fs-data
	...
	"【一些创造目录,建立链接,更改权限的操作,这里省略】"

	"【恢复指定文件到file_contexts配置中指定的安全上线文环境】"
    restorecon /data/mediaserver

	"【将系统属性<name>的值设置为<value>,即以键值对的方式设置系统属性】"
    # Reload policy from /data/security if present.
    setprop selinux.reload_policy 1

	"【以递归的方式恢复指定目录到file_contexts配置中指定的安全上下文中】"
    # Set SELinux security contexts on upgrade or policy update.
    restorecon_recursive /data

    # If there is no fs-post-data action in the init.<device>.rc file, you
    # must uncomment this line, otherwise encrypted filesystems
    # won't work.
    # Set indication (checked by vold) that we have finished this action
    #setprop vold.post_fs_data_done 1

on boot
	"【初始化网络】"
    # basic network init
    ifup lo
    "【设置主机名为localhost】"
    hostname localhost
    "【设置域名localdomain】"
    domainname localdomain

	"【设置资源限制】"
    # set RLIMIT_NICE to allow priorities from 19 to -20
    setrlimit 13 40 40

	"【这里省略了一些chmod,chown,等操作,不多解释】"
   ...


    # Define default initial receive window size in segments.
    setprop net.tcp.default_init_rwnd 60

	"【重启core服务】"
    class_start core

on nonencrypted
    class_start main
    class_start late_start

on property:vold.decrypt=trigger_default_encryption
    start defaultcrypto

on property:vold.decrypt=trigger_encryption
    start surfaceflinger
    start encrypt

on property:sys.init_log_level=*
    loglevel ${sys.init_log_level}

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

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

on property:vold.decrypt=trigger_restart_min_framework
    class_start main

on property:vold.decrypt=trigger_restart_framework
    class_start main
    class_start late_start

on property:vold.decrypt=trigger_shutdown_framework
    class_reset late_start
    class_reset main

on property:sys.powerctl=*
    powerctl ${sys.powerctl}

# system server cannot write to /proc/sys files,
# and chown/chmod does not work for /proc/sys/ entries.
# So proxy writes through init.
on property:sys.sysctl.extra_free_kbytes=*
    write /proc/sys/vm/extra_free_kbytes ${sys.sysctl.extra_free_kbytes}

# "tcp_default_init_rwnd" Is too long!
on property:sys.sysctl.tcp_def_init_rwnd=*
    write /proc/sys/net/ipv4/tcp_default_init_rwnd ${sys.sysctl.tcp_def_init_rwnd}

"【守护进程】"
## Daemon processes to be run by init.
##
service ueventd /sbin/ueventd
    class core
    critical
    seclabel u:r:ueventd:s0

"【日志服务进程】"
service logd /system/bin/logd
    class core
    socket logd stream 0666 logd logd
    socket logdr seqpacket 0666 logd logd
    socket logdw dgram 0222 logd logd
    seclabel u:r:logd:s0

"【Healthd是android4.4之后提出来的一种中介模型,该模型向下监听来自底层的电池事件,向上传递电池数据信息给Framework层的BatteryService用以计算电池电量相关状态信息】"
service healthd /sbin/healthd
    class core
    critical
    seclabel u:r:healthd:s0

"【控制台进程】"
service console /system/bin/sh
	"【为当前service设定一个类别.相同类别的服务将会同时启动或者停止,默认类名是default】"
    class core
    "【服务需要一个控制台】"
    console
    "【服务不会自动启动,必须通过服务名显式启动】"
    disabled
    "【在执行此服务之前切换用户名,当前默认的是root.自Android M开始,即使它要求linux capabilities,也应该使用该选项.很明显,为了获得该功能,进程需要以root用户运行】"
    user shell
    seclabel u:r:shell:s0

on property:ro.debuggable=1
    start console

# adbd is controlled via property triggers in init.<platform>.usb.rc
service adbd /sbin/adbd --root_seclabel=u:r:su:s0
    class core
    "【创建一个unix域下的socket,其被命名/dev/socket/<name>. 并将其文件描述符fd返回给服务进程.其中,type必须为dgram,stream或者seqpacke,user和group默认是0.seclabel是该socket的SELLinux的安全上下文环境,默认是当前service的上下文环境,通过seclabel指定】"
    socket adbd stream 660 system system
    disabled
    seclabel u:r:adbd:s0

# adbd on at boot in emulator
on property:ro.kernel.qemu=1
    start adbd

"【内存管理服务,内存不够释放内存】"
service lmkd /system/bin/lmkd
    class core
    critical
    socket lmkd seqpacket 0660 system system

"【ServiceManager是一个守护进程,它维护着系统服务和客户端的binder通信。
在Android系统中用到最多的通信机制就是Binder,Binder主要由Client、Server、ServiceManager和Binder驱动程序组成。其中Client、Service和ServiceManager运行在用户空间,而Binder驱动程序运行在内核空间。核心组件就是Binder驱动程序了,而ServiceManager提供辅助管理的功能,无论是Client还是Service进行通信前首先要和ServiceManager取得联系。而ServiceManager是一个守护进程,负责管理Server并向Client提供查询Server的功能。】"
service servicemanager /system/bin/servicemanager
    class core
    user system
    group system
    critical
    onrestart restart healthd
    "【servicemanager 服务启动时会重启zygote服务】"
    onrestart restart zygote
    onrestart restart media
    onrestart restart surfaceflinger
    onrestart restart drm

"【Vold是Volume Daemon的缩写,它是Android平台中外部存储系统的管控中心,是管理和控制Android平台外部存储设备的后台进程】"
service vold /system/bin/vold
    class core
    socket vold stream 0660 root mount
    ioprio be 2

"【Netd是Android系统中专门负责网络管理和控制的后台daemon程序】"
service netd /system/bin/netd
    class main
    socket netd stream 0660 root system
    socket dnsproxyd stream 0660 root inet
    socket mdns stream 0660 root system
    socket fwmarkd stream 0660 root inet

"【debuggerd是一个daemon进程,在系统启动时随着init进程启动。主要负责将进程运行时的信息dump到文件或者控制台中】"
service debuggerd /system/bin/debuggerd
    class main

service debuggerd64 /system/bin/debuggerd64
    class main

"【Android RIL (Radio Interface Layer)提供了Telephony服务和Radio硬件之间的抽象层】"
# for using TK init.modem.rc rild-daemon setting
#service ril-daemon /system/bin/rild
#    class main
#    socket rild stream 660 root radio
#    socket rild-debug stream 660 radio system
#    user root
#    group radio cache inet misc audio log

"【提供系统 范围内的surface composer功能,它能够将各种应用 程序的2D、3D surface进行组合。】"
service surfaceflinger /system/bin/surfaceflinger
    class core
    user system
    group graphics drmrpc
    onrestart restart zygote

"【DRM可以直接访问DRM clients的硬件。DRM驱动用来处理DMA,内存管理,资源锁以及安全硬件访问。为了同时支持多个3D应用,3D图形卡硬件必须作为一个共享资源,因此需要锁来提供互斥访问。DMA传输和AGP接口用来发送图形操作的buffers到显卡硬件,因此要防止客户端越权访问显卡硬件。】"
#make sure drm server has rights to read and write sdcard ####
service drm /system/bin/drmserver
    class main
    user drm
    # group drm system inet drmrpc ####
    group drm system inet drmrpc sdcard_r ####

"【媒体服务,无需多说】"
service media /system/bin/mediaserver
    class main
    user root ####
#   google default ####
#   user media    ####
    group audio camera inet net_bt net_bt_admin net_bw_acct drmrpc mediadrm media sdcard_r system net_bt_stack ####
#   google default ####
#   group audio camera inet net_bt net_bt_admin net_bw_acct drmrpc mediadrm ####

    ioprio rt 4

"【设备加密相关服务】"
# One shot invocation to deal with encrypted volume.
service defaultcrypto /system/bin/vdc --wait cryptfs mountdefaultencrypted
    disabled
    "【当服务退出时,不重启该服务】"
    oneshot
    # vold will set vold.decrypt to trigger_restart_framework (default
    # encryption) or trigger_restart_min_framework (other encryption)

# One shot invocation to encrypt unencrypted volumes
service encrypt /system/bin/vdc --wait cryptfs enablecrypto inplace default
    disabled
    oneshot
    # vold will set vold.decrypt to trigger_restart_framework (default
    # encryption)

"【开机动画服务】"
service bootanim /system/bin/bootanimation
    class core
    user graphics
#    group graphics audio ####
    group graphics media audio ####
    disabled
    oneshot

"【在Android系统中,PackageManagerService用于管理系统中的所有安装包信息及应用程序的安装卸载,但是应用程序的安装与卸载并非PackageManagerService来完成,而是通过PackageManagerService来访问installd服务来执行程序包的安装与卸载的。】"
service installd /system/bin/installd
    class main
    socket installd stream 600 system system

service flash_recovery /system/bin/install-recovery.sh
    class main
    seclabel u:r:install_recovery:s0
    oneshot

"【vpn相关的服务】"
service racoon /system/bin/racoon
    class main
    socket racoon stream 600 system system
    # IKE uses UDP port 500. Racoon will setuid to vpn after binding the port.
    group vpn net_admin inet
    disabled
    oneshot

"【android中有mtpd命令可以连接vpn】"
service mtpd /system/bin/mtpd
    class main
    socket mtpd stream 600 system system
    user vpn
    group vpn net_admin inet net_raw
    disabled
    oneshot

service keystore /system/bin/keystore /data/misc/keystore
    class main
    user keystore
    group keystore drmrpc

"【可以用dumpstate 获取设备的各种信息】"
service dumpstate /system/bin/dumpstate -s
    class main
    socket dumpstate stream 0660 shell log
    disabled
    oneshot

"【mdnsd 是多播 DNS 和 DNS 服务发现的守护程序。】"
service mdnsd /system/bin/mdnsd
    class main
    user mdnsr
    group inet net_raw
    socket mdnsd stream 0660 mdnsr inet
    disabled
    oneshot

"【触发关机流程继续往下走】"
service pre-recovery /system/bin/uncrypt
    class main
    disabled
    "【当服务退出时,不重启该服务】"
    oneshot
init.c全解析
int main( int argc, char **argv )
{
	#创 建一些linux根文件系统中的目录
	mkdir( "/dev", 0755 );
	mkdir( "/proc", 0755 );
	mkdir( "/sys", 0755 );

	mount( "tmpfs", "/dev", "tmpfs", 0, "mode=0755" );
	mkdir( "/dev/pts", 0755 );
	mkdir( "/dev/socket", 0755 );
	mount( "devpts", "/dev/pts", "devpts", 0, NULL );
	mount( "proc", "/proc", "proc", 0, NULL );
	mount( "sysfs", "/sys", "sysfs", 0, NULL );
	#init的 标准输入,标准输出,标准错误文件描述符定向到__null__,意味着没有输入和输出,它的输入和输出全部写入到Log中
	open_devnull_stdio();
	#初始化 log 写入init进 信息
	log_init();
	#读取并 且解析init.rc文件(这个文件在根目录下)
	parse_config_file( "/init.rc" );
	#取得硬件 为打印我们的设备名fs100
	get_hardware_name();
	snprintf( tmp, sizeof(tmp), "/init.%s.rc", hardware );
    #读取并 且解析硬件相关的init脚本文件,
	parse_config_file( tmp );
	#触发在init脚本文件中名字为early-init的action,并且执行其commands,其实是: on early-init
	action_for_each_trigger( "early-init", action_add_queue_tail );
	drain_action_queue();
	#初始化动态设备管理,设备文件有变化时反应给内核,后面具体解释
	device_fd = device_init(); # 初 始 化 设 备 管 理 务
	#加载启动动画,如果动画打开失败,则在屏幕上打印: A N D R O I D字样。
	if ( load_565rle_image( INIT_IMAGE_FILE ) )
	{
		fd = open( "/dev/tty0", O_WRONLY );
		if ( fd >= 0 )
		{
			const char *msg;
			msg = "\n"
			      "\n"
			      "\n"
			      879         "\n"
			      "\n"
			      "\n"
			      "\n" /* console is 40 cols x 30 lines */
			      "\n"
			      "\n"
			      "\n"
			      "\n"
			      "\n"
			      "\n"
			      "\n"
			      /* "             A N D R O I D ";开机动画 */
			      write( fd, msg, strlen( msg ) );
			close( fd );
		}
	}

	#触发 在init脚本文件中名字为init的action,并且执行其commands,其实是:on init
	action_for_each_trigger( "init", action_add_queue_tail );
	drain_action_queue();
	#启动系统属性服务: system property service
	property_set_fd = start_property_service();
	#创建socket用来处理孤儿进程信号
	if ( socketpair( AF_UNIX, SOCK_STREAM, 0, s ) == 0 )
	{
		signal_fd	= s[0];
		signal_recv_fd	= s[1];
		fcntl( s[0], F_SETFD, FD_CLOEXEC );
		fcntl( s[0], F_SETFL, O_NONBLOCK );
		fcntl( s[1], F_SETFD, FD_CLOEXEC );
		fcntl( s[1], F_SETFL, O_NONBLOCK );
	}
	#触发 在init脚本文件中名字为early-boot和boot的action,并且执行其commands,其实是:on early-boot和on boot
	action_for_each_trigger( "early-boot", action_add_queue_tail );
	action_for_each_trigger( "boot", action_add_queue_tail );
	drain_action_queue();
	#启动所有属性变化触发命令,其实是: on property:ro.xx.xx=xx
	queue_all_property_triggers();
	drain_action_queue();
	#进入 死循环()
	for (;; )
	{
	#启 动所有init脚本中声明的service,
	#如 :266 service servicemanager /system/bin/servicemanager
	#user system
	#critical
	#onrestart restart zygote
	#onrestart restart media
	restart_processes();
	#多路监听设备管理,子进程运行状态,属性服务
		nr = poll( ufds, fd_count, timeout );
		if ( nr <= 0 )
			continue;
		if ( ufds[2].revents == POLLIN )
		{
			read( signal_recv_fd, tmp, sizeof(tmp) );
			while ( !wait_for_one_process( 0 ) )
				;
			continue;
		}

		if ( ufds[0].revents == POLLIN )
			handle_device_fd( device_fd );

		if ( ufds[1].revents == POLLIN )
			handle_property_set_fd( property_set_fd );
		if ( ufds[3].revents == POLLIN )
			handle_keychord( keychord_fd );
	}

	return(0);
}

参考文章

  1. Android源码之init.rc文件详解
  2. Android系统init进程启动及init.rc全解析

 历史上的今天

  1. 2023: Android图片旋转+倒影(0条评论)
  2. 2018: Android消息机制之三Handler分析(0条评论)
版权声明 1、 本站名称: 笔友城堡
2、 本站网址: https://www.biumall.com/
3、 本站部分文章来源于网络,仅供学习与参考,如有侵权,请留言

暂无评论

暂无评论...

随机推荐

Android View Binding的使用简介

前言简单记录一下,方便自己查阅。好记性不如烂笔头正文PS: 本文内容大都摘抄,感谢什么是View BindingView Binding是Android Studio 3.6推出的新特性,目的是为了替代findViewById(内部实现还是使用findViewById)。在启动视图绑...

朱湘:海外寄霓君(节选)

一霓妹,我的爱妻:你从般若庵十二月初五写的“第一封”信我收到了。我后天就要搬家,你的信可以寄到憩轩四兄第一次替你打的信封那里。我在芝加哥城里过得好些,身体也好,望你不要记挂。我到今天总共收到你八封信。你信内并不曾提到岳母大人同憩轩四兄的病,想必是都好了。你的奶水不够,务必要请奶妈子。照我如今这般...

Android的fontScale不随系统设置变化

前言由于Android开发中部分第三方应用字体过小,用户会调整Android系统的字体大小,但由于我们应用是定制化开发的,改变字体也会影响我们应用的字体显示。因此需求:定制化的APP内字体大小不随系统设置变化。正文在Activity中重写如下方法 @Override pr...

IjkPlayer和MediaPlayer常见错误码

前言现在媒体播放使用很多项目都使用bilibili开源的IjkPlayer,当然也用系统自带的MediaPlayer,都有回调onError()和onInfo(),因此这里整理一下常见的INFO码。 @Override public boolean onError(MediaPl...

[摘]Android对Bitmap缩放图片的记录

前言在Android项目中经常需要调整图片的尺寸大小以适应存储、传输和图片处理等需求。虽然Android API中提供了一些缩放图片的方法,在调试中发现,使用Android API中的Canvas、BitmapFactory和ThumbnailUtils等类的相关方法缩放图片,锯齿感明显,图像质...

俞平伯:浆声灯影里的秦淮河

我们消受得秦淮河上的灯影,当圆月犹皎的仲夏之夜。在茶店里吃了一盘豆腐干丝,两个烧饼之后,以歪歪的脚步踅上夫子庙前停泊着的画舫,就懒洋洋躺到藤椅上去了。好郁蒸的江南,傍晚也还是热的。“快开船罢!”桨声响了。小的灯舫初次在河中荡漾;于我,情景是颇朦胧,滋味是怪羞涩的。我要错认它作七里的山塘;可是,河...