精华内容
下载资源
问答
  • Android系统init进程启动及init.rc全解析

    万次阅读 多人点赞 2017-11-23 16:14:40
    system/core/init/init.c文件main函数中parse_config_file(init.rc)读取并解析init.rc文件内容。将service信息放置到system/core/init/init_parser.cpp的service_list中 system/core/init/init.c文

    这是一篇用心写的博客,也希望大家用心看并帮忙找到文章的改进之处,谢谢;

    服务启动机制

    1. system/core/init/init.c文件main函数中parse_config_file(init.rc)读取并解析init.rc文件内容。将service信息放置到system/core/init/init_parser.cpp的service_list中
    2. system/core/init/init.c文件main函数继续执行restart_servie_if_needed(…) -> service_start(…) -> Execve(…)建立service进程;

    为了让大伙看得更明白,上个图先《总体启动框架图》:
    这里写图片描述

    init.rc 简介

    目前Linux有很多通讯机制可以在用户空间和内核空间之间交互,例如设备驱动文件(位于/dev目录中)、内存文件(/proc、/sys目录等)。了解Linux的同学都应该知道Linux的重要特征之一就是一切都是以文件的形式存在的,例如,一个设备通常与一个或多个设备文件对应。这些与内核空间交互的文件都在用户空间,所以在Linux内核装载完,需要首先建立这些文件所在的目录。而完成这些工作的程序就是本文要介绍的init。Init是一个命令行程序。其主要工作之一就是建立这些与内核空间交互的文件所在的目录。当Linux内核加载完后,要做的第一件事就是调用init程序,也就是说,init是用户空间执行的第一个程序。

    尽管init完成的工作不算很多,不过代码还是非常复杂的。Init程序并不是由一个源代码文件组成的,而是由一组源代码文件的目标文件链接而成的。这些文件位于如下的目录。

    需要明白的是,这些init.rc只是语法文件,并不是程序,真正的入口则是上面提到的system/core/init/init.c
    因为init.c文件比较大,在文章的第二部分我会简要的通过main函数分析init启动流程;

    init.rc有两个,分别位于:
    ./system/core/rootdir/init.rc
    ./bootable/recovery/etc/init.rc
    从目录上大致可以猜测,这两个init.rc使用场景不一样,一个是刷机用到的,也就是进入recorvery模式,一个是正常启动用到的;我们这里重点分析的是上面那个,也是init.c关联的那个;

    init.rc语法结构解析

    要了解init.rc是怎么解析的,我们需要先看看说明文档,说明文档在,当然也可以看下热心网友的中文对照版本
    init.rc位于/bootable/recovery/etc/init.rc

    Android初始化语言包含了四种类型的声明:
    Actions(行为)、Commands(命令)、Services(服务)和Options(选项)

    所有这些都是以行为单位的,各种记号由空格来隔开。
    C语言风格的反斜杠号可用于在记号间插入空格。
    双引号也可用于防止字符串被空格分割成多个记号。
    行末的反斜杠用于折行,注释行以井号(#)开头(允许以空格开头)。

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

    Actions和Services声明一个新的分组Section。所有的命令或选项都属于最近声明的分组。位于第一个分组之前的命令或选项将会被忽略。
    Actions和Services有唯一的名字。如果有重名的情况,第二个申明的将会被作为错误忽略。

    Actions

    Actions(行为)是一系列命令的开始
    Actions代表一些Action.Action代表一组命令(Commands),Actions都有一个trigger(触发器),该触发器决定了何时执行这个Action,即在什么情况下才能执行该Action中的定义命令.当一些条件满足触发器的条件时,该Action中定义的命令会被添加到要执行命令队列的尾部(如果这组命令已经在队列中,则不会再次添加).

    队列中的每一个action都被依次提取出,而这个action中的每个command(命令)在一个Action从队列移除时,该Action定义的命令会依次被执行.

    Action的格式如下:

    on <trgger> [&& <trigger>]*
       <command1>
       <command2>
       <command3>
       ...
    

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

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

    ###Triggers(触发器)
    trigger即我们上面所说的触发器,本质上是一个字符串,能够匹配某种包含该字符串的事件.
    trigger又被细分为事件触发器(event trigger)和属性触发器(property trigger).
    Triggers(触发器)是一个用于匹配特定事件类型的字符串,用于使Actions发生。

    事件触发器可由"trigger"命令或初始化过程中通过QueueEventTrigger()触发,通常是一些事先定义的简单字符串,例如:boot,late-init
    属性触发器是当指定属性的变量值变成指定值时触发,其格式为property:=*

    一个Action可以有多个属性触发器,但是最多有一个事件触发器.下面我们看两个例子:

    on boot && property:a=b
    

    该Action只有在boot事件发生时,并且属性a和b相等的情况下才会被触发.

    on property:a=b && property:c=d
    

    该Action会在以下三种情况被触发:

    • 在启动时,如果属性a的值等于b并且属性c的值等于d
    • 在属性c的值已经是d的情况下,属性a的值被更新为b
    • 在属性a的值已经是b的情况下,属性c的值被更新为d

    当前AIL中常用的有以下几种事件触发器:

    类型						说明
    -------------------------------------------------
    boot					init.rc被装载后触发
    device-added-<path>		指定设备被添加时触发
    device-removed-<path>	指定设备被移除时触发
    service-exited-<name>	在特定服务(service)退出时触发
    early-init				初始化之前触发
    late-init				初始化之后触发
    init					初始化时触发(在 /init.conf (启动配置文件)被装载之后)
    

    Init的触发是由init.c里的函数action_for_each_trigger来决定的(在main函数中被调用)。

    Services

    Services(服务)是一个程序,以 service开头,由init进程启动,一般运行于另外一个init的子进程,所以启动service前需要判断对应的可执行文件是否存在。init生成的子进程,定义在rc文件,其中每一个service,在启动时会通过fork方式生成子进程。Services(服务)的形式如下:

    service <name> <pathname> [ <argument> ]*
        <option>
        <option>
        ...
    

    其中:

    • name:服务名
    • pathname:当前服务对应的程序位置
    • option:当前服务设置的选项
    • argument 可选参数

    init.rc文件详解

    为了方便理解,我把整个init.rc解析一边,便于大家了解整个流程;如果想要了解recovery下的init语法解析,参考这篇文章《recovery下的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全解析

    接下来我们具体分析以下这个main函数的执行过程;可能比较长,大家耐心看一下:

     
    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);
    }
    
    
    展开全文
  • init.rc是在Android的根目录下。init.rc由许多的Action和Service组成。每一个语句占据一行,并且各个关键字被空格分开.由 # (前面允许有空格)开始的行都是注释行(comment)一个actions 或 services 的开始隐含声明了...

    init.rc是在Android的根目录下。

    init.rc由许多的Action和Service组成。每一个语句占据一行,并且各个关键字被空格分开.

    由 # (前面允许有空格)开始的行都是注释行(comment)

    一个actions 或 services 的开始隐含声明了一个新的段,所有commands 或 options 属于最近的声明。在第一个段之前的 commands 或 options 都会被忽略

    每一个actions 和 services 都有不同的名字。后面与前面发生重名的,那么这个后面重名的将被忽略或被认为是一个错误。

    actions其实就是一组被命名的命令序列。actions 都有一个触发条件,触发条件决定了action何时执行。当一个事件发生如果匹配action的触发条件,那么这个action将会被添加到预备执行队列的尾部(除非它已经在队列当中)

    每一个action中的命令将被顺序执行。init进程负责在其它activities(如:设备创建/销毁,属性设置,进程重启)之间执行这些命令序列。

    每一个action格式如下:

    on

    ...

    trigger是一个action触发的条件,一共有如下几种:

    1、boot

    发生在init启动时,/init.conf被加载以后。

    2、=

    发生在名字为的属性的值被设置为时。

    3、device-added-/device-removed-

    当一个device node被添加/删除时。

    4、service-exited-当某个服务退出时。

    command一共有如下几种:

    1、exec []*

    fork并execute一个路径下面的程序,直到程序执行完毕后,init才会继续前进。尽量避免使用这个command,它有可能导致init阻塞。其它command不存在这个问题。

    2、export

    把全局环境变量的值设置为。这个命令执行完毕以后启动的所有进程都会继承这个全局变量。

    3、ifup

    Bring the network interface online.(打开某个网卡)

    4、import

    Parse an init config file, extending the current configuration.

    5、hostname

    Set the host name.

    6、class_start

    如果某一类service没有运行,启动它们。

    7、class_stop

    如果某一类service正在运行,停止它们。

    8、domainname

    Set the domain name.

    9、insmod

    安装路径指定的模块。

    10、mkdir

    创建代表的文件夹,只能一层层地创建。

    11、mount

    把挂载到系统类型为的文件系统的

    12、setkey

    未定义

    13、setprop

    设置系统属性。

    14、setrlimit

    Set the rlimit for a resource.

    15、start

    如果服务没有运行,启动它。

    16、stop

    如果服务正在运行,停止它。

    17、symlink

    把链接到目录下。

    18、write [ ]*

    打开所指的文件,并把写入。

    关于3、5、8,参见init.rc里面的

    on boot

    # basic network init

    ifup lo

    hostname localhost

    domainname localdomain

    关于14,参见init.rc里面的

    # set RLIMIT_NICE to allow priorities from 19 to -20

    setrlimit 13 40 40

    说完了action下来我们来说说service

    services 是一些由init 启动 和 重新(如果有需要)启动的程序,当然这些程序如果是存在的。

    每一个service格式如下:

    service [ ]*

    ...

    例如:

    1

    service ppp /system/bin/pppd call gprs

    user root

    group system radio

    disabled

    oneshot

    2

    service mtpd /system/bin/mtpd

    socket mtpd stream 600 system system

    user vpn

    group vpn net_admin net_raw

    disabled

    oneshot

    options 是service的修饰符,用来告诉init 怎样及何时启动service。一共有如下几种:

    1、disableds

    这个服务不能通过启动一类服务来启动,只能单独以名字来启动。

    2、socket   

    创建一个名字为/dev/socket/的unix domain socket,并把它的fd传递给 加载的进程。的值是dgram或stream.

    注意:在init.rc中使用socket时,是放在之后的。

    init程序在运行过程中可能会设置几个特殊属性的值,来告诉其它程序它正在做什么。这些属性是:

    (1)、init.action

    当前正在执行的action的名字,如果没有,就是“”。

    (2)、init.command

    当前正在执行的command的名字,如果没有,就是“”。

    (3)、init.svc.

    一个服务的状态。可能的值有:“stopped”,"running","restarting"

    3、user

    在启动服务之前,把用户名切换到。默认是root

    4、group [ ]*

    在启动服务之前,把组名切换到。一个服务可能属于多个组。

    5、capability [ ]+

    Set linux capability before exec'ing this service

    6、oneshot

    服务之运行一次,退出后不再重启。

    7、class

    为服务设定一个类别,一个类别是中的服务可以同时启动或停止。如果没有这个属性,服务的默认类别是“default”

    默认情况下,通过init启动的程 序都会把stdout和stderr定向到/dev/null。有时为了调试方便,可以通过Android的logwrapper程序启动某个程序。这 样,被启动程序stdout和stderr就被定向到了Android的LOG系统中,可以通过logcat来查看了。

    例如:

    service akmd /system/bin/logwraper /sbin/akmd

    展开全文
  • androidInit进程

    2017-05-17 21:59:52
    init进程事Linux内核启动后创建的第一个进程。init在初始化过程中会启动很多重要的守护进程。  |守护进程 BUD ADB  ---fastboot(通过USB更新手机分区映像)


    init进程事Linux内核启动后创建的第一个进程。init在初始化过程中会启动很多重要的守护进程。

                                                                                             |守护进程  BUD ADB

                     ---fastboot(通过USB更新手机分区映像)                            | --应用程 launcher phonebook

                                                                                             |Zygote                              | --sensorservice

                                                                                                                   | ---systemserver

                             (boot.img)                                                                                     | --ActivityManager service   contentservice  Usbservwice

    bootloader---Linux kernel-------------------------------------init|

                                                                                                             | --camera service 

                    ----Recover                                                      |Mediaserver  

                                                                                                             |--MediaPlayer service

                                                                                            |serviceManager


        在init启动过程中会解析init.rc,根据init.rc装载android的文件系统,创建系统目录,启动android系统重要的守护进程,这些进程包括USB守护进程,ADB守护进程,Vold守护进程,rild守护进程

        Init进程的源码在system/core/init/init.c   main函数中

       

    int main(int argc, char **argv)
    {
        int fd_count = 0;
        struct pollfd ufds[4];
        char *tmpdev;
        char* debuggable;
        char tmp[32];
        int property_set_fd_init = 0;
        int signal_fd_init = 0;
        int keychord_fd_init = 0;
        bool is_charger = false;
    
        if (!strcmp(basename(argv[0]), "ueventd")).  //检查启动程序文件名
            return ueventd_main(argc, argv);
    
        if (!strcmp(basename(argv[0]), "watchdogd"))
            return watchdogd_main(argc, argv);
    
        /* clear the umask */
        umask(0);   //修改创建目录的权限
    
            /* Get the basic filesystem setup we need put
             * together in the initramdisk on / and then we'll
             * let the rc file figure out the rest.
             */
        mkdir("/dev", 0755);
        mkdir("/proc", 0755);
        mkdir("/sys", 0755);
    
        mount("tmpfs", "/dev", "tmpfs", MS_NOSUID, "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);
    
            /* indicate that booting is in progress to background fw loaders, etc */
        close(open("/dev/.booting", O_WRONLY | O_CREAT, 0000));//is_booting()来判断是否进程处于初始化中,初始化结束后这个文件将被删除
    
            /* We must have some place other than / to create the
             * device nodes for kmsg and null, otherwise we won't
             * be able to remount / read-only later on.
             * Now that tmpfs is mounted on /dev, we can actually
             * talk to the outside world.
             */
        open_devnull_stdio();//把标准输入,标准输出和标准出错重定向到空设备文件
        klog_init();//这个函数用来创建节点/dev/_kmsg_,这样init进程可以使用kernel的log系统来输出log
        memlog_init();
        property_init();//主要是创建一个共享区域来储存属性值
    
        rk_parse_cpu();
    
        get_hardware_name(hardware, &revision);//通过/proc/cpuinfo文件取得系统硬件名称
    
        process_kernel_cmdline();//解析kernel的启动参数,启动参数通常放在/proc/cmdline
    
        union selinux_callback cb;//初始化SELinux
        cb.func_log = klog_write;
        selinux_set_callback(SELINUX_CB_LOG, cb);
    
        cb.func_audit = audit_callback;
        selinux_set_callback(SELINUX_CB_AUDIT, cb);
    
        selinux_initialize();
        /* These directories were necessarily created before initial policy load
         * and therefore need their security context restored to the proper value.
         * This must happen before /dev is populated by ueventd.
         */
        restorecon("/dev");
        restorecon("/dev/socket");
        restorecon("/dev/__properties__");
        restorecon_recursive("/sys");
    
        is_charger = !strcmp(bootmode, "charger");
    
        INFO("property init\n");
        if (!is_charger)
            property_load_boot_defaults();//解析设备根目录下的default。prop文件把文件
    中定义的属性值读出来设置到属性系统中
        INFO("reading config file\n");
     
        init_parse_config_file("/init.rc");//解析init,rc文件
    
        action_for_each_trigger("early-init", action_add_queue_tail);//用来将指定的action加入到执行列表action_queue
    
        queue_builtin_action(wait_for_coldboot_done_action, "wait_for_coldboot_done");//等待冷插拔设备初始化完成
        queue_builtin_action(mix_hwrng_into_linux_rng_action, "mix_hwrng_into_linux_rng");//从硬件RNG的设备文件/dev/HW_random中读取512字节并写到Linux RNG的设备文件/dev/urandom中
        queue_builtin_action(keychord_init_action, "keychord_init");//初始化组合键监听模块
        queue_builtin_action(console_init_action, "console_init");//在屏幕上显示android 字样Logo
    
        /* execute all the boot actions to get us started */
        action_for_each_trigger("init", action_add_queue_tail);
    
        /* skip mounting filesystems in charger mode */
        if (!is_charger) {
            action_for_each_trigger("early-fs", action_add_queue_tail);
            action_for_each_trigger("fs", action_add_queue_tail);
            action_for_each_trigger("post-fs", action_add_queue_tail);
            action_for_each_trigger("post-fs-data", action_add_queue_tail);
        }
    
        /* Repeat mix_hwrng_into_linux_rng in case /dev/hw_random or /dev/random
         * wasn't ready immediately after wait_for_coldboot_done
         */
        queue_builtin_action(mix_hwrng_into_linux_rng_action, "mix_hwrng_into_linux_rng");
    
        queue_builtin_action(property_service_init_action, "property_service_init");//初始化属性服务,读取系统预制的属性值
        queue_builtin_action(signal_init_action, "signal_init");//初始化信号处理模块
        queue_builtin_action(check_startup_action, "check_startup");//检查是否已经完成Init进程初始化,如果初始化完成删除.booting文件
    
        if (is_charger) {
            action_for_each_trigger("charger", action_add_queue_tail);
        } else {
            action_for_each_trigger("early-boot", action_add_queue_tail);
            action_for_each_trigger("boot", action_add_queue_tail);
        }
    
            /* run all property triggers based on current state of the properties */
        queue_builtin_action(queue_property_triggers_action, "queue_property_triggers");
    
    
    #if BOOTCHART
        queue_builtin_action(bootchart_init_action, "bootchart_init");
    #endif
    
        for(;;) {
            int nr, i, timeout = -1;
    
            execute_one_command();//每循环执行命令列表中的一条命令
            restart_processes();
    
            if (!property_set_fd_init && get_property_set_fd() > 0) {
                ufds[fd_count].fd = get_property_set_fd();
                ufds[fd_count].events = POLLIN;
                ufds[fd_count].revents = 0;
                fd_count++;
                property_set_fd_init = 1;
            }
            if (!signal_fd_init && get_signal_fd() > 0) {
                ufds[fd_count].fd = get_signal_fd();
                ufds[fd_count].events = POLLIN;
                ufds[fd_count].revents = 0;
                fd_count++;
                signal_fd_init = 1;
            }
            if (!keychord_fd_init && get_keychord_fd() > 0) {
                ufds[fd_count].fd = get_keychord_fd();
                ufds[fd_count].events = POLLIN;
                ufds[fd_count].revents = 0;
                fd_count++;
                keychord_fd_init = 1;
            }
    
            if (process_needs_restart) {//设置等待超时的时间
                timeout = (process_needs_restart - gettime()) * 1000;
                if (timeout < 0)
                    timeout = 0;
            }
    
            if (!action_queue_empty() || cur_action)
                timeout = 0;
    
    #if BOOTCHART
            if (bootchart_count > 0) {
                if (timeout < 0 || timeout > BOOTCHART_POLLING_MS)
                    timeout = BOOTCHART_POLLING_MS;
                if (bootchart_step() < 0 || --bootchart_count == 0) {
                    bootchart_finish();
                    bootchart_count = 0;
                }
            }
    #endif
    
            nr = poll(ufds, fd_count, timeout);
            if (nr <= 0)
                continue;
    
            for (i = 0; i < fd_count; i++) {
                if (ufds[i].revents == POLLIN) {
                    if (ufds[i].fd == get_property_set_fd())
                        handle_property_set_fd();//修改属性
                    else if (ufds[i].fd == get_keychord_fd())
                        handle_keychord();//监控组合键
                    else if (ufds[i].fd == get_signal_fd())
                        handle_signal();//监听到信号
                }
            }
        }
        memlog_close();
        return 0;
    }
    


    
    

    
    

     

    展开全文
  • init.d scripts support 介绍init.d scripts supportThis app allows the user to select a folder (at sdcard) that includes a serie of scripts that can be executed at boot time.If your device is rooted the...

    init.d scripts support 介绍

    init.d scripts support

    This app allows the user to select a folder (at sdcard) that includes a serie of scripts that can be executed at boot time.If your device is rooted the scripts can be executed using superuser permissions, but normal users can do also.Note that some actions (like update the cpu max/min speed and others) requires ROOT permissions. Don't blame to me if you execute in a not rooted device at don't works!Pro version removes Ads.

    来自应用汇: init.d scripts support http://www.appchina.com/app/com.ryosoftware.initd?from=spi-desc

    init.d scripts support 历史版本

    a28eedfd4cbe2ea3c322ca6735270fec.png

    init.d scripts support

    版本: 1.1.35

    大小: 2.92 M

    "Execute scripts now" and "Show last execution results" options are now available only for PREMIUM users.

    Added option to display "Rewarded Ad" to become PREMIUM for a day.

    下载

    8cc5955ef6094184c8e6aa819e600440.png

    init.d scripts support

    版本: 1.1.30

    大小: 2.94 M

    Updated SDK to Android Q

    Upgraded from Support Libraries to AndroidX Libraries

    下载

    8f2b04a19c51aebc5e3b88e94a2bd340.png

    init.d scripts support

    版本: 1.1.29

    大小: 2.57 M

    Updated SDK

    下载

    512f7952277b405def3b1c3d63a1c15c.png

    init.d scripts support

    版本: 1.1.28

    大小: 2.12 M

    Solved FC

    下载

    be3153a3ee617e75c8537f7b8187c973.png

    init.d scripts support

    版本: 1.1.27

    大小: 2.12 M

    Updated SDK target version to Oreo (26)

    下载

    948d9d218a0f40f1cdc4be3784bb3457.png

    init.d scripts support

    版本: 1.1.25

    大小: 2.12 M

    Updated SDK to Android 8

    下载

    7815f31769800b605ee4c278d0cc1289.png

    init.d scripts support

    版本: 1.1.24

    大小: 3.56 M

    Added User Data policy insided the app

    下载

    8ad57ed7cef96b523efc529d3dba9a7e.png

    init.d scripts support

    版本: 1.1.23

    大小: 3.56 M

    Added User Data policy insided the app (see app settings)

    下载

    init.d scripts support 版本更新

    Internal improvements

    init.d scripts support 类似软件

    包含 init.d scripts support 的应用集

    4a6671ef5351ff27ecd4aec33a45a21b.png

    5d9a7a9070294a79720345dcd328161e.png

    054893536aca88d7ffa5a8e1d2e242f4.png

    杂乱收集库

    轩爱

    75ee6f5f5629a12115e6b5958df898ea.png96763

    79b3d8483a835fc456cdfa7bcb7aef04.png951

    2017-11-09

    用户对 init.d scripts support 的评论

    当前还没有用户评论 ㄟ( ▔, ▔ )ㄏ

    亲,想发表评论请下载[应用汇手机客户端]哦~

    展开全文
  • android init进程

    2018-08-13 09:41:59
    android init进程 Init进程在Android系统中非常重要,他是Linux系统中用户空间的第一个进程。它的任务主要做2件事情: 1.解析配置文件init.rc,然后启动系统各种native进程,例如非常重要的进程Nygote进程,...
  • Android Init Language

    2016-12-29 10:42:57
    使用安卓初始化语言可以...可以到自己Android手机的根目录寻找init.rc文件,最好下载到本地以便查看,如果有编译好的Android源代码, 在<Android源代码根目录>out/target/product/generic/root目录也可找到init.rc文件
  • 这几天打算看下安卓的代码,看优秀的源代码也是一种学习过程,看源代码的过程就感觉到,安卓确实是...而是由一种被称为“Android初始化语言”(Android Init Language。这里简称为AIL)的脚本写成的文件。在了解...
  • 最近看了《深入理解Android卷I》中关于init进程与zygote进程的知识,特此写一篇博客记录一下收获。 init进程 init进程是Android系统中的用户空间的第一个进程,它的进程号是1,作为天字第一号进程,init进程...
  • 本篇文章主要介绍了"Android C语言_init函数和constructor属性及.init/.init_array节探索",主要涉及到Android C语言_init函数和constructor属性及.init/.init_array节探索方面的内容,对于Android C语言_init函数和...
  • 关于androidinit进程

    2014-09-18 14:17:21
    源码位置:system/core/init/init.c 编译结果: init
  • androidinit.rc文件详解

    千次阅读 2015-06-08 16:36:55
    转自: http://www.cnblogs.com/nokiaguy/archive/2013/04/14/3020774.html ... Androidinit过程详解(一) Androidinit过程(二):初始化语言(init.rc)解析 本文使用的软件版本
  • Android init.rc详解

    千次阅读 2014-09-12 17:37:03
    init.rc 文件并不是普通的配置文件,而是由...为了学习AIL,读者可以到自己Android手机的根目录寻找init.rc文件,最好下载到本地以便查看,如果有编译好的Android源代码, 在<Android源代码根目录>out/target/product/g
  • Android init简介

    2013-08-08 16:41:09
    声明: init.c 位置:system/core/init/init.c init.rc 位置:system/core/rootdir/...由于Android是基于Linux内核的,所以init也是Android系统中用户空间的第一个进程,它的进程号是1。作为天字第一号进程,init被赋
  • AndroidInit进程

    千次阅读 2014-01-13 21:36:44
    **************************************************************************Android-2.3.1源码:**************************************************************************************** 源文件路径: ...
  • 在曾经的项目中,因为需要添加网络管控的东西,要...在init中启动自己的脚本,并不需要修改init进程的源代码,只需要修改 init.tc文件即可。 service auto_init_sh /system/AutoInit.sh class main user root ...
  • Androidinit.c简析

    千次阅读 2013-07-21 20:42:01
    Android系统启动时,内核引导参数上一般都会设置“init=/init”,这样的话,如果内核成功挂载了这个文件系统之后,首先运行的就是这个根目录下的init程序。这个程序所了什么呢?我们只有RFSC(Read the Fucking ...
  • Android 修改init.rc

    千次阅读 2015-03-29 16:01:37
    有时候希望在启动后做点事情,比如在sdcard上建立目录,修改/data的访问权限等,这些都可以放在init.rc中去完成,那么如何来完成呢,最近由于工作的需要,在这方面进行了一些研究,特写于此,供大家参考。...
  • Android O init.rc语法及解析过程总结

    千次阅读 2018-03-20 19:44:17
    Android O高通默认使用QMMI取代了fastmmi,但是由于QMMI是一个APK,属于Android应用层面,所以必须...所以应公司要求,尝试将fastmmi移植到Android O,期间一直在折腾FFBM模式下各服务启动流程,即不断修改相关init...
  • Androidinit过程(二):初始化语言(init.rc)解析

    万次阅读 多人点赞 2013-06-17 09:36:09
    Androidinit过程(一)本文使用的软件版本Android:4.2.2Linux内核:3.1.10 在上一篇文章中介绍了init的初始化第一阶段,也就是处理各种属性。在本文将会详细分析init最重要的一环:解析init.rc文件。init.rc文件...
  • Android init进程(长文)

    千次阅读 2017-03-31 15:44:11
    android init
  • android init.rc路径问题

    千次阅读 2014-08-20 19:47:27
    android init.rc是android启动入口 那么
  • Android init进程——属性服务

    千次阅读 2015-08-05 14:33:16
    目录目录 概述 属性服务 属性服务初始化 创建存储空间 __system_property_area_init init_workspace 客户端进程访问属性内存区域 ...由于Android是基于Linux内核的,所以init也是Android系统中用户空
  • Android init.c简析

    千次阅读 2013-11-12 14:42:42
    Android系统启动时,内核引导参数上一般都会设置“init=/init”,这样的话,如果内核成功挂载了这个文件系统之后,首先运行的就是这个根目录下的init程序。这个程序所了什么呢? 我们只有RFSC(Read the Fucking ...
  • 看懂androidinit.rc文件 (2012-05-24 20:27) init.rc相当于是init程序的配置文件。如何看懂它对于了解Android挺有帮助的。 文章的末尾是摘自init的readme原文 不翻译了,英语太蹩脚,翻了估计更...
  • Android init.rc文件解析

    千次阅读 2016-03-15 19:57:44
     Android init.rc文件由系统第一个启动的init程序解析,此文件由语句组成,主要包含了四种类型的语句:Action, Commands,Services, Options. 在init.rc 文件中一条语句通常是占据一行.单词之间是通过空格符来相隔的...
  • 本篇文章主要介绍了"Android C语言_init函数和constructor属性及.init/.init_array节探索",主要涉及到Android C语言_init函数和constructor属性及.init/.init_array节探索方面的内容,对于Android C语言_init函数和...
  • Android系统启动流程-AndroidInit进程一、Linux内核启动 1、启动电源以及系统启动 当电源按下时引导芯片代码开始从预定义的地方(固化在ROM)开始执行。加载引导程序Bootloader到RAM,然后执行。 2、引导程序...
  • 在and4.4上之前在init进程中读取amt/sn.txt中的内容,设置到"ro.serialno"的系统属性中。而Settings会去读取这个属性的值,从而将手机的序列码显示出来。 if (!is_charger) { action_for_each_trigger("early-fs",...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 43,138
精华内容 17,255
关键字:

安卓手机init