XJBX-2-Android启动Init进程

Init 进程初始化

Init进程的源码位于system/core/init目录中的init.c文件,标准的C代码,入口在main函数。主要进行Android系统初始化任务。

  1. 守护进程的创建
      守护进程在系统中就是执行bin文件创建的进程,如adb,ueventd,watch_dog等,这些bin文件是在Android系统编译的时候产生的,连接设备ADB,查看system/bin目录都可以查看到,有些可以直接做调试使用。
  2. 创建,挂载基本目录
js 复制代码
    mikdr("/dev",0755)
    mikdr("/proc",0755)
    mikdr("/sys",0755)
    
    mount("tmpfs","/dev","tmpfs",MS_NOSUID,"mode=0755")
    mikdr("/dev/pts",0755)

如上,init进程会通过mkdir创建一些目录,0755是目录权限等级,或使用mount将tmpfs挂载到对应目录

  1. 初始化Android属性系统
      kennel的Log系统;获取基本的硬件信息,通过/proc/cpuinfo获取,CPU属性,型号;通过/proc/cmdline/获取启动参数,console相关打印,内存大小信息等;另外解析defalut.prop属性文件,来初始化系统属性,adb通过"getprop"指令可以查到相关内容,有"ro","persist"开头的属性,prop文件可以通过厂商定制额外属性。
  2. 解析init.rc文件
      Init进程的核心逻辑,解析rc文件的时候初始化核心进程,是进入Android系统的铺垫。rc文件有固定的指令格式。初始化语言包含了四种类型的声明:Actions(行动)、 Commands(命令)、Services(服务)和Options(选项)。
      动作(Actions)就是在某种条件下触发一系列的命令,就是comman的指令合集,通常有一个trigger(触发器),用于决定Action执行的时机,当符合条件时,会将Action加入队列。每一个Action将依次从队列中取出,每个command都将依次执行。形式如下:
js 复制代码
on   <trigger>
     <command>
     <command>

Command 主要包括:

js 复制代码
exec <path> [ <argument> ]    执行指定路径下的程序,并传递参数. 
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> [ <argument> ]  安装指定路径的模块,以及指定参数. 
mkdir <path> [mode] [owner] [group] 用指定参数创建一个目录,在默认情况下,创建的目录读取权限为755.用户名为root,组名为root. 
mount <type> <device> <dir> [ <mountoption> ]* 类似于linux的mount指令 
setprop <name> <value>       设置属性及对应的值. 
setrlimit <resource> <cur> <max> 设置资源的rlimit(资源限制),不懂就百度一下rlimit 
start <service>              如果指定的服务未启动,则启动它. 例如"start ueventd " ueventd 是服务名,
stop <service>               如果指定的服务当前正在运行,则停止它. 
symlink <target> <path>      创建一个符号链接. 
sysclktz <mins_west_of_gmt>  设置系统基准时间. 
trigger <event>              启动某个触发条件,例如trigger firmware_mounts_complete,那么on  firmware_mounts_complete段的动作将会执行
write <path> <string> [ <string> ] 往指定的文件写字符串. 

服务(Services)服务是指那些需要在系统初始化时就启动或退出时自动重启的在后台执行的程序.形式如下:

js 复制代码
service    <name> <pathname> [<argument>] 
           <option>  
           <option>  

name可以随便定义一个有意义的名字,但是这个名字在rc文件里面要是唯一的,如果有重名的,那么之后的将会忽略掉。pathname 该应用程序在系统中的绝对路径 argument是传给该应用程序的参数。

Options(选项)是Servie的修订项,可以决定Service何时运行。主要包括:

  • critical 据设备相关的关键服务,如果在4分钟内,此服务重复启动了4次,那么设备将会重启进入Recovery模式。
  • disabled 该服务不能通过trigger来启动,只能以单独的名字来启动 "start name"。
  • setenv <name> <value> 设置环境变量,在Service启动时将环境变量"name"设置成"value"。
  • socket <name> <type> <perm> [ <user> [ <group> ] ] 在/dev/socket/下创建一个unix domain的socket,并传递创建的文件描述符fd给服务进程.其中type必须为dgram或stream,seqpacket.用户名和组名默认为0。
  • user <username> 在执行此服务之前先切换用户名。当前默认为root。
  • group <groupname> [ <groupname> ] 类似于user,切换组名 默认为root。
  • oneshot 当此服务退出时不会自动重启. 如果没有这个选项,只运行一次。
  • class <name> 给服务指定一个类属,这样方便操作多个服务同时启动或停止.默认情况下为default。
  • onrestart 当服务重启时执行一条指令, 例如"onrestart exec /system/bin/myapp"则表示在服务重新启动的时候执行/system/bin/myapp这个应用。

有了以上固定格式,init进程解析rc文件,就是解析关键字,解析命令行,将每个指令放入队列(双向链表),再去执行。

常见的守护进程

js 复制代码
ueventd: 负责响应ueventd事件,创建设备节点文件:
service  ueventd  /sbin/ueventd
         class core
         critical
         seclabel u:r:ueventd:s0
         
 adbd: adb的守护进程,大家都熟悉
 service  adbd  /sbin/adbd
         class core
         socket adbd stream 660  system  system
         diabled
         seclabel u:r:adbd:s0
         
 surfaceflinger: 负责合成系统所有显示图层的服务
 service  surfaceflinger  system/bin/surfaceflinger
         class main
         user system
         group graphics
         onestart restart

还有很多,比如servicemanager,负责管理binder注册; media:负责多媒体部分。

设备厂商会添加自定义业务的守护进程,在对应目录下编写C/C++代码,通过Android.mk脚本编译出bin文件,在rc文件中按照自身需求去配置参数。

Init进程对信号的处理

Init进程是系统的一号进程,系统中所有的进程,都是Init进程的后代,在Linux中,Init进程需要在这些后代进程的死亡负责,所有要专门处理这些"僵尸"进程。 僵尸进程:Linux中一种进程的特殊状态,不能被调度,不占用任何内存空间,仅仅保留一个位置,记录退出状态等信息。唯一的危害是:Linux系统对每个用户的进程分配是有限制的,超出数量创建进程会失败。当然Linux限制的进程数量也很大。 子进程退出时,会向父进程发送SIGCHLD信号,Init初始化时,会使用signal_init_action()初始化信号,会创建特定的socket来处理SIGCHLD。使用socket的原因是:信号在Linux中是一种中断,会导致进程中断当前处理的工作。所以为了解决父进程在执行SIGCHLD信号时发生等待,使用socket,不会耽搁下个信号的处理。

源码好无聊,有兴趣自己去看吧,说了那么多,面试的时候你知道该怎么吹了吧......

相关推荐
来来走走29 分钟前
Flutter SharedPreferences存储数据基本使用
android·flutter
安卓开发者2 小时前
Android模块化架构深度解析:从设计到实践
android·架构
雨白2 小时前
HTTP协议详解(二):深入理解Header与Body
android·http
阿豪元代码2 小时前
深入理解 SurfaceFlinger —— 如何调试 SurfaceFlinger
android
阿豪元代码3 小时前
深入理解 SurfaceFlinger —— 概述
android
CV资深专家4 小时前
Launcher3启动
android
stevenzqzq4 小时前
glide缓存策略和缓存命中
android·缓存·glide
雅雅姐5 小时前
Android 16 的用户和用户组定义
android
没有了遇见5 小时前
Android ConstraintLayout 之ConstraintSet
android
余辉zmh5 小时前
【MySQL基础篇】:MySQL索引——提升数据库查询性能的关键
android·数据库·mysql