Android编程之系统启动:init进程与init语言
安安 2017-11-29 来源 :网络 阅读 1209 评论 0

摘要:面向新的一年,我们可能启动了许多有意义的计划,在这个有着特殊意义的日子里,让我们来一起学习一下Android编程系统是如何启动的。

面向新的一年,我们可能启动了许多有意义的计划,在这个有着特殊意义的日子里,让我们来一起学习一下Android编程系统是如何启动的。

init进程与init.rc

init进程是一切的开始,在Android系统中,所有进程的进程号都是不确定的,唯独init进程的进程号一定是1。因为这个进程是系统起来的第一个进程。并且,init进程掌控了整个系统的启动流程。

我们知道,Android可能运行在各种不同的平台,不同的设备上。因此,启动的逻辑是不尽相同的。 为了适应各种平台和设备的需求,init进程的初始化工作通过init.rc配置文件来管理。init.rc以Android Init Language作为语法,下文我们简称Android Init Language为init语言。配置文件的主入口文件是/init.rc,这个文件会通过import关键字引入其他的配置文件。在这里,我们统称这些文件为init.rc。

/init.rc可能import以下路径中的.rc文件:

/init.${ro.hardware}.rc 硬件厂商提供的主配置文件

/system/etc/init/ 核心系统模块的配置文件

/vendor/etc/init/ SoC厂商提供的配置文件

/odm/etc/init/ 设备制造商提供的配置文件

init语法说明

init语言,以换行为语句分隔,以空格来为符号分隔,以“#“为注释开始。配置文件中支持五种类型的表达式:

Action: 包含了一系列的Command

Command: init语言中的命令

Service: init进程启动的服务

Option: 对于服务的配置选项

Import: 引入其他配置文件

这其中,Action和Service需要保证名称唯一。

Action与Command

Action表达式的语法如下:

on <trigger> [&& <trigger>]*

   <command>

   <command>

   <command>

这里的Trigger是Action执行的触发器,当触发器条件满足时,command会被执行。触发器有两类:

1.事件触发器: 事件可以由”trigger”命令发出,也可以是init进程通过QueueEventTrigger()函数发出

2.属性触发器: 当指定的属性满足时触发

一个Action可以有多个属性触发器,但是只能包含一个事件触发器。下面是一些例子:

on boot && property:a=b 在”boot”事件发生时,并且属性a的值是b时触发

on property:a=b && property:c=d 在属性a的值是b并且属性c的值是d时触发

Action中的Command是init语言定义的命令,所有支持的命令如下表所示:

Command 参数格式 说明

bootchart_init - 启动bootchart

chmod octal-mode path 改变文件的访问权限

chown owner group path 改变文件的拥有者和组

class_start serviceclass 启动指定类别的服务

class_stop serviceclass 停止并disable指定类别的服务

class_reset serviceclass 停止指定类别的服务,但是不disable它们

copy src dst 拷贝文件

domainname name 设置域名

enable servicename enable一个被disable的服务

exec [seclabel[user[group]]] – command [argument]* fork一个子进程来执行指定的命令

export name value 导出环境变量

hostname name 设置host名称

ifup iterface 使网卡在线

insmod path 安装指定路径的模块

load_all_props - 从/system, /vendor等路径载入属性

load_persist_props - 载入持久化的属性

loglevel level 设置内核的日志级别

mkdir path [mode] [owner] [group] 创建目录

mount_all fstab [ path ]* [--option] 挂载文件系统并且导入指定的.rc文件

mount type device dir [ flag ]* [options] 挂载一个文件系统

powerctl - 内部实现使用

restart service 重启服务

restorecon path [ path ]* 设定文件的安全上下文

restorecon_recursive path [ path ]* restorecon的递归版本

rm path 对于指定路径调用unlink(2)

rmdir path 删除文件夹

setprop name value 设置属性值

setrlimit resource cur max 指定资源的rlimit

start service 启动服务

stop service 停止服务

swapon_all fstab 在指定文件上调用fs_mgr_swapon_all

symlink target path 创建符号链接

sysclktz mins_west_of_gmt 指定系统时钟基准

trigger event 触发一个事件

umount path unmount指定的文件系统

verity_load_state - 内部实现使用

verity_update_state mount_point 内部实现使用

wait path [ timeout ] 等待某个文件存在直到超时,若存在则直接返回

write path content 写入内容到指定文件

Service与Option

Service是init进程启动的可执行程序。服务可以选择在自己退出之后,由init将其重启。

Service表达式的语法如下:

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

   <option>

   <option>

Option是对服务的修饰,它们影响着init进程如何以及何时启动服务。所有支持的option如下表所示:

option 参数格式 说明

critical - 标识为系统关键服务,该服务若退出多次将导致系统重启到recovery模式

disabled - 不会随着类别自动启动,必须明确start

setenv name value 为启动的进程设置环境变量

socket name type perm [user [group [seclabel]]] 创建Unix Domain Socket

user username 在执行服务之前切换用户

group groupname [ groupname]* 在执行执行之前切换组

seclabel seclabel 在执行服务之前切换seclabel

oneshot - 一次性服务,死亡之后不用重启

class name 指定服务的类别

onrestart - 当服务重启时执行指定命令

writepid file… 写入子进程的pid到指定文件

Import

import是一个关键字,并不是一个命令。可以在.rc文件中通过这个关键字来加载其他的.rc文件。它的语法很简单:

import path

path可以是另外一个.rc文件,也可以是一个文件夹。如果是文件夹,那么这个文件夹下面的所有文件都会被导入,但是它不会循环加载子目录中的文件。

init.rc代码实例

AOSP中包含了Android系统需要的最基本的.rc文件,它们位于这个路径:/system/core/rootdir/ 。

我们选取其中了一两个代码片段来了解一下:

# /system/core/rootdir/init.rc


import /init.environ.rc

import /init.usb.rc

import /init.${ro.hardware}.rc

import /init.usb.configfs.rc

import /init.${ro.zygote}.rc


on early-init

    # Set init and its forked children's oom_adj.

    write /proc/1/oom_score_adj -1000


    # Disable sysrq from keyboard

    write /proc/sys/kernel/sysrq 0


    # Set the security context of /adb_keys if present.

    restorecon /adb_keys


    # Shouldn't be necessary, but sdcard won't start without it. //b/22568628.

    mkdir /mnt 0775 root system


    # Set the security context of /postinstall if present.

    restorecon /postinstall


    start ueventd


on init

    sysclktz 0


    # Mix device-specific information into the entropy pool

    copy /proc/cmdline /dev/urandom

    copy /default.prop /dev/urandom


    # Backward compatibility.

    symlink /system/etc /etc

    symlink /sys/kernel/debug /d


    # Link /vendor to /system/vendor for devices without a vendor partition.

    symlink /system/vendor /vendor

...

这是根目录/init.rc文件中一开始的代码片段。有了前面的讲解之后,这段代码应当还是比较好理解的。在这段代码中:

通过import关键字引入了其他几个.rc文件

设定了一个事件为early-init的Action

设定了一个事件init的Action

“eraly-init”和”init”这两个事件都是由init进程发出的。

下面,我们再来看另外一个代码片段:

这段代码定义了一个名称为zygote的Service,这个服务是通过可执行命令/system/bin/app_process启动的,启动的时候传递了参数:-Xzygote /system/bin --zygote --start-system-server。

Zygote是Android系统中一个非常重要的服务,zygote的中文意思是“受精卵“。这是一个很有寓意的名称:所有的应用进程都是由zygote fork出来的子进程,因此zygote进程是所有应用进程的父进程。

关于Zygote,我们已经在另外一篇文章中讲解过了,参见这里Zygote进程,有兴趣的读者可以再次回顾一下。

结束语

Android系统是一个跨越了多种设备的操作系统,从最初的系统的研发到最终终端用户的使用,这其中经历了许多道的开发流程。而每一道流程的开发者都有可能对系统做不同程度的定制。

Android系统的设计者从一开始就考虑到了这种复杂性,这一点从很多系统模块的设计中很能看得出来。系统启动的机制便是一个很好的范例:这里在保证系统核心服务启动顺序的前提下,还为不同阶段的开发者预留好了便于调整和扩展的机制,并且不用修改任何的源代码。

这种对于“开闭原则”的遵守,是非常值得我们学习的。


本文由职坐标整理并发布,希望对同学们学习Android编程的知识有所帮助。了解更多详情请关注职坐标Android编程!

本文由 @安安 发布于职坐标。未经许可,禁止转载。
喜欢 | 0 不喜欢 | 0
看完这篇文章有何感觉?已经有0人表态,0%的人喜欢 快给朋友分享吧~
评论(0)
后参与评论

您输入的评论内容中包含违禁敏感词

我知道了

助您圆梦职场 匹配合适岗位
验证码手机号,获得海同独家IT培训资料
选择就业方向:
人工智能物联网
大数据开发/分析
人工智能Python
Java全栈开发
WEB前端+H5

请输入正确的手机号码

请输入正确的验证码

获取验证码

您今天的短信下发次数太多了,明天再试试吧!

提交

我们会在第一时间安排职业规划师联系您!

您也可以联系我们的职业规划师咨询:

小职老师的微信号:z_zhizuobiao
小职老师的微信号:z_zhizuobiao

版权所有 职坐标-一站式IT培训就业服务领导者 沪ICP备13042190号-4
上海海同信息科技有限公司 Copyright ©2015 www.zhizuobiao.com,All Rights Reserved.
 沪公网安备 31011502005948号    

©2015 www.zhizuobiao.com All Rights Reserved

208小时内训课程