594 lines
26 KiB
Markdown
594 lines
26 KiB
Markdown
#### step1: boot rom
|
||
|
||
执行固化在rom中的指令,把boot loader加载到内存,跳转到boot loader继续执行。
|
||
|
||
#### step2: boot loader
|
||
|
||
源代码在bootable目录。也是OEM厂商或运营商加锁和限制的地方。分为两个阶段。
|
||
|
||
第一阶段:检测ram,加载第二阶段的程序。
|
||
|
||
第二阶段:设置网络,内存等。
|
||
|
||
#### step3: Linux kernel
|
||
|
||
源代码在kernel目录。内核启动时,设置缓存、被保护存储器、计划列表,加载驱动。当内核完成系统设置,它首先在系统文件中寻找”init”文件,然后启动root进程或者系统的第一个进程。
|
||
|
||
- init/main.c : start_kernel
|
||
|
||
- init/main.c : rest_init
|
||
|
||
- init/main.c : kernel_init
|
||
|
||
`ramdisk_execute_command`是内核参数`rdinit`的值,默认为`/init`
|
||
|
||
- init/main.c : run_init_process
|
||
|
||
init进程分两个阶段,第一阶段在内核态,通过执行`kernel_execve`函数强行转到用户态,第二阶段在用户态继续执行。
|
||
|
||
#### step4: init process
|
||
|
||
源代码在system/core/init/init.c,init.rc在system/core/rootdir/init.rc。
|
||
|
||
init是第一个进程,也叫root进程或所有进程的父进程。在此阶段可以看到屏幕上的"Android" Logo。
|
||
|
||
##### init进程的职责
|
||
|
||
1. 挂载目录,比如/sys, /dev, /porc。
|
||
|
||
2. 运行init.rc脚本,这会创建系统中的几个关键进程,包括java世界的开创者zygote进程也是在这里创建的。脚本语言的介绍详见system/core/init/README.md。
|
||
|
||
3. 作为守护进程。
|
||
|
||
4. 属性服务。
|
||
|
||
5. 处理子进程终止。
|
||
|
||
详见`queue_builtin_action(signal_init_action, "signal_init")`
|
||
|
||
##### init进程第一阶段
|
||
|
||
1. 依据程序名进行跳转,就是先决定要跑哪个程序
|
||
|
||
argv[0]是当前运行程序的名称,当前运行程序的名称有可能是init, modprobe, uenventd或watchdogd。其中,modprobe、uenventd和watchdogd都是指向init的软链接。
|
||
|
||
如果当前运行的程序名是modprobe,则执行`modprobe_main`,应该是用来加载内核模块的。
|
||
|
||
如果当前运行的程序名是ueventd,则执行`ueventd_main`,进行设备节点的创建和权限设定。
|
||
|
||
如果当前运行的程序名是watchdogd,则执行`watchdogd_main`,用于系统出问题时重启系统。
|
||
|
||
如果REBOOT_BOOTLOADER_ON_PANIC,则`install_reboot_signal_handlers`,将一些信号的标志设置为SA_RESTART,一旦监听到这些信号则执行重启操作。
|
||
|
||
在当前环境中加入PATH变量。
|
||
|
||
由于INIT_SECOND_STAGE是在is_first_stage里定义的,这就确保了is_first_stage只能执行一次。
|
||
|
||
2. 挂载文件系统并创建目录,Linux需要有这些文件系统才能运行
|
||
|
||
`umask(0)`用于清空文件默认权限。这样才能保证后面代码里对文件权限的设置生效了,否则有可能被umask()的设置给屏蔽掉。
|
||
|
||
在根目录上建立initramdisk所需的基本文件系统(文件系统的其它部分是在随后的rc文件里建立的)。
|
||
|
||
> `mount`的第一个参数是源(通常是一个设备名),第二个参数是所要挂载的目标目录,第三个参数是文件系统类型,第四个参数是读写标记(MS_NOSUID表示执行时不遵照set-user-id位和set-group-id位),第五个参数是要挂载的文件系统可能会有的特有参数。
|
||
|
||
> `mount`挂载了如下五个源:**tmpfs**是内存中的文件系统,读写速度快。**proc**是内存中内核的数据结构。**devpts**为伪终端提供了一个标准接口。**sysfs**是把proc, devfs, devpts统一起来。**selinuxfs**也是虚拟文件系统,用来存放SELinux安全策略文件。
|
||
|
||
> `mknode`用于创建设备文件。第一个参数是设备所在目录,第二个参数是设备类型和读写访问标志(S_IFCHR表示字符设备文件),第三个参数是设备(设备由makedev(a,b)创建,其中a为次设备号,b为主设备号)。
|
||
|
||
3. 初始化日志输出,挂载分区设备
|
||
|
||
InitKernelLogging用于初始化日志系统,它首先把stdin,stdout,stderr重定向到/sys/fs/selinux/null,这样printf或其它打印的函数都输出不了,就不会引发异常了(因为在这个阶段,printf函数是不能用的,会引发错误)。然后调用InitLogging初始化日志系统,这是把init进程的log打印到内核printk的log buffer,因为这个时候没有shell,不能进行通用的log输出,借助内核的功能是较好的选择。
|
||
|
||
DoFirstStageMount用于初始化特定设备并挂载。
|
||
|
||
4. 启用SELinux安全策略
|
||
|
||
SetInitAvbVersionInRecovery()在刷机模式下初始化avb的版本,不是刷机模式直接跳过。
|
||
|
||
> Avb即Android Verfied boot,功能包括Secure Boot, verfying boot 和 dm-verity, 原理都是对二进制文件进行签名,在系统启动时进行认证,确保系统运行的是合法的二进制镜像文件。其中认证的范围涵盖:bootloader,boot.img,system.img
|
||
|
||
selinux_initialize(true)加载SELinux policy,也就是安全策略。
|
||
|
||
> SELinux是「Security-Enhanced Linux」的简称,是美国国家安全局和SCC开发的 Linux的一个扩张强制访问控制安全模块。 在这种访问控制体系的限制下,进程只能访问那些在他的任务中所需要文件。
|
||
|
||
现在是在内核态,所以在SELinux policy加载后,需要再次执行init转换到用户态。函数selinux_android_restorecon("/init", 0)就是做这个工作的。
|
||
|
||
5. 开始第二阶段前的准备
|
||
|
||
设置环境变量INIT_SECOND_STAGE和INIT_STARTED_AT,为第二阶段做准备。
|
||
|
||
execv(path,args)再次执行init,进入用户态的init进程。
|
||
|
||
##### init进程第二阶段
|
||
|
||
1. 创建进程会话密钥并初始化系统属性
|
||
|
||
InitKernelLogging用于初始化日志系统(第一阶段在内核态,而第二阶段在用户态,所以要再次初始化日志系统)。
|
||
|
||
keyctl_get_keyring_ID用于初始化进程会话密钥。KEY_SPEC_SESSION_KEYRING表示获取当前进程的会话密钥,1表示如获取不到则创建一个。
|
||
|
||
在`/dev`目录下创建文件`.booting`,这个文件仅仅起到标志的作用,表示系统正在启动(可以在init.rc里看到,当booting结束会删除此文件)。
|
||
|
||
property_init用于初始化属性系统,并从指定文件读取属性。
|
||
|
||
> property_init调用__system_property_area_init实现其功能。详见bionic/libc/include/sys和bionic/libc/bionic/system_properties.cpp
|
||
|
||
process_kernel_dt和process_kernel_cmdline分别处理dt(设备树)和命令行属性,设备树中参数的优先级总是高于命令行。
|
||
|
||
export_kernel_boot_props用于处理其它的一些属性。
|
||
|
||
分别将INIT_STARTED_AT、INIT_SELINUX_TOOK和INIT_AVB_VERSION的值设置为系统属性,都是通过property_set实现的(property_set就是用来设置系统属性的)。
|
||
|
||
使用unsetenv清空若干环境变量,因为这些环境变量已经存入到系统属性中去了。
|
||
|
||
2. 设置第二阶段的SELinux
|
||
|
||
selinux_initialize(false)执行第二阶段的selinux初始化,在这里参数false只起个开关的作用,表明执行的是第二阶段的初始化。
|
||
|
||
selinux_restore_context用于恢复安全上下文。
|
||
|
||
3. 新建epoll并初始化子进程终止信号处理函数
|
||
|
||
epoll_create1用于创建epoll实例,并返回epoll的文件描述符。epoll是Linux用来做事件触发的。
|
||
|
||
signal_handler_init且来注册signal信号的处理函数。
|
||
|
||
4. 设置其他系统属性并开启系统属性服务
|
||
|
||
property_load_boot_defaults从文件中加载一些属性。
|
||
|
||
export_oem_lock_status设置ro.boot.flash.locked属性。
|
||
|
||
start_property_service开启一个socket监听系统属性的设置。
|
||
|
||
set_usb_controller设置sys.usb.controller属性。
|
||
|
||
##### init进程第二阶段之解析rc文件
|
||
|
||
1. 解析rc文件
|
||
|
||
set_function_map把function_map存放到Action中作为成员属性。
|
||
|
||
创建对server、action、import的解析器。parser.AddSectionParser用来new一个Parser(解析器),然后把它们放到一个map里存起来。
|
||
|
||
获取ro.boot.init_rc的属性值,如其值为空则解析`/init.rc`和`/{system,vendor,odm}/etc/init`下的rc文件,如非空则解析其属性值。
|
||
|
||
> parser.ParseConfig()是用来解析rc文件的,其定义在init/init_parser.cpp文件。它就是判断参数是不是目录,如果是目录则调用ParseConfigDir(),如果是文件则调用ParseConfigFile()。
|
||
>
|
||
> ParseConfigFile(),首先用ReadFile()把数据读取到data,然后调用ParseData来解析data,最后遍历section_parsers_并依次调用其EndFile()。
|
||
|
||
|
||
|
||
2. 加入一些事件和Action
|
||
|
||
am.QueueEventTrigger("early-init")用于触发early-init事件。
|
||
|
||
am.QueueBuiltinAction用于添加Action,第一个参数是要执行的command,第二个参数是trigger。
|
||
|
||
am.QueueEventTrigger("init")用来触发所有的boot actions。
|
||
|
||
bootmode是个全局静态变量,用来标示启动模式,android的启动模式分为正常开机流程和关机充电流程。
|
||
|
||
##### init进程第二阶段之服务处理
|
||
|
||
init进程作为1号进程是永不退出的,这里的while(true)循环就保证了这一点。
|
||
|
||
之前的工作是建立各种各样的事件,并没有去触发。只有在本while循环里才真正的触发所有的事件,并用epoll不断监听新的事件。
|
||
|
||
1. 如要执行关机命令,则通过`HandlePowerctlMessage()`来执行之。
|
||
|
||
2. 当没有属性设置且没有Server开始运行时,才通过`am.ExecuteOneCommand()`从current_executing_actions\_列表里执行一个command,由于外部是一个无限循环,所以current_executing_actions\_列表里的每个command都会执行一遍。这样的条件设定是为了保证属性设置和Server启动的完整性。
|
||
|
||
3. 当没有属性设置且没有Server开始运行时:
|
||
- 如系统不是正在关机,执行`restart_processes()`来判断当前Server是否需要重启,如需重启则执行重启操作。
|
||
- 如有进程需要重启,设置`epoll_timeout_ms`的值
|
||
- 如有其它command需要执行,则将`epoll_timeout_ms`设置为0以立即唤醒。
|
||
|
||
4. `epoll_wait`用于监听事件的产生,参数`epoll_fd`是由前面的`epoll_create1()`创建的epoll的文件描述符,参数`ev`用于保存事件信息,参数`epoll_timeout_ms`是等待时间
|
||
|
||
5. 如未监听到事件,则向log系统添加一条监听失败的信息;如监听到事件,则直接执行`ev.data.ptr()`(即epoll_ctl注册时的回调函数)。
|
||
|
||
#### step5: Zygote
|
||
|
||
源代码在frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
|
||
|
||
Zygote是一个虚拟机进程,由init进程启动。Zygote预加载以及初始化核心库类。
|
||
|
||
在此阶段可以看到启动画面。
|
||
|
||
##### Zygote进程触发过程
|
||
|
||
- init.rc里`import /init.{ro.zygote}.rc`引入了Zygote进程
|
||
|
||
ro.zygote可能取4个值:zygote32为纯32位模式,zygote64为纯64位模式,zygote32_64以32位为主模式,zygote64_32以64位为主模式
|
||
|
||
- init.zygote64_32.rc定义了两个进程:zygote和zygote_secondary
|
||
|
||
zygote程序是app_process64,zygote_secondary程序是app_process32。两者的参数和属性基本相同。
|
||
|
||
- 在init.cpp的main里触发late-init,在init.rc的late-init里触发zygote-start,在init.rc的zygote-start里启动zygote进程和zygote_secondary进程。
|
||
|
||
- 在init/builtins.cpp的builtin_functions里定义了start命令对应的函数do_start,do_start函数最终是调用对应server的Start方法,Start方法主要是fork一个新进程然后执行对应server的二进制文件。
|
||
|
||
- zygote进程的源码在frameworks/base/cmds/app_process/app_main.cpp
|
||
|
||
##### Zygote进程之参数解析
|
||
|
||
app_main.cpp里的main函数主要做的就是参数解析。此函数有两种启动模式,一是作为Zygote进程进行初始化,一是作为普通应用程序启动。两者最终都是调用AppRuntime对象的start函数,加载对应的java类(ZygoteInit或RuntimeInit),并将之前整理的参数传入进去。
|
||
|
||
1. 将参数argv[]放入字符串argv_string
|
||
2. 创建AppRuntime对象runtime,并传入除argv[0]的所有参数
|
||
3. '--'之前或以非'-'开头的参数都将传入vm(即/system/bin),vm参数后的第一个参数(即Xzygote)不再使用。--zygote的意思是开启zygote模式,--start-system-server的意思是开启系统服务,--socket-name指定socket的名称。必须复制参数字符串,但进入vm的spaced commands是个例外。
|
||
4. spaced_commands里定义的两个参数是Java程序需要依赖的Jar包
|
||
5. 使用runtime.addOption方法加入参数,要加入的都是'--'开头的参数,但若包含spaced_commands里的参数则直接加入
|
||
6. 判断zygote, niceName, startSystemServer, application, niceName.setTo, className.setTo的值,它们主要决定了启动模式。
|
||
7. 如果className非空,表明不是zygote模式,只需传送程序参数即可。否则就是zygote模式,则创建Dalvik缓存,加入start-system-server参数,加入abiFlag参数,加入剩下的参数。
|
||
8. 如果niceName非空,则设置进程别名。
|
||
9. 如果是zygote模式,则加载ZygoteInit;如果是application模式,则加载RuntimeInit;否则打印错误。
|
||
|
||
##### 创建虚拟机
|
||
|
||
frameworks/base/core/jni/AndroidRuntime.cpp里的start方法
|
||
|
||
1. 打印一些日志,设置环境变量ANDROID_ROOT。
|
||
|
||
2. jni_invocation.Init初始化JNI
|
||
|
||
首先通过dlopen加载libart.so获得其句柄,然后调用dlsym从libart.so中找到相关函数用于后续的虚拟机创建。
|
||
|
||
3. startVm创建虚拟机
|
||
|
||
一是从各种系统属性中读取一些参数,然后通过addOption设置到AndroidRuntime的mOptions数组;二是使用libart.so中的JNI_CreateJavaVM,将这些参数传入。
|
||
|
||
4. onVmCreated表示创建完成
|
||
|
||
5. startReg注册JNI函数
|
||
|
||
首先设置了Android创建线程的处理函数,然后创建了一个局部引用作用域,最后调用register_jni_procs进行JNI注册
|
||
|
||
6. JNI方式调用ZygoteInit类的main函数
|
||
|
||
即`env->CallStaticVoidMethod(startClass, startMeth, strArray);`
|
||
|
||
##### JNI反射调用Java
|
||
|
||
frameworks/base/core/jni/AndroidRuntime.cpp里的start方法
|
||
|
||
1. 首先把参数保存在strArray里
|
||
2. 启动VM,此线程将成为VM的主线程,此线程不会返回除非VM退出。
|
||
|
||
##### ZygoteInit
|
||
|
||
framework/base/core/java/com/android/internal/os/ZygoteInit.java的main方法
|
||
|
||
1. 创建一个ZygoteServer对象
|
||
2. 设置标记不允许新建线程
|
||
3. 设置Zygote进程的组id
|
||
4. 性能统计(在一个try代码块里的内容)
|
||
- 把Zygote启动时间报告给tron(使用`MetricsLogger.histogram`)
|
||
- 跟踪调试ZygoteInit(`bootTimingsTraceLog.traceBegin`)
|
||
- 注册Ddms的处理类(`RuntimeInit.enableDdms`)
|
||
- 在一个for循环里进行参数解析
|
||
- 在某些配置里,要避免过早地加载资源和类
|
||
- 初始化垃圾回收
|
||
- 禁止追踪
|
||
- Zygote解除挂载根空间
|
||
- 设置seccomp策略
|
||
- 在zygote永远进行select循环
|
||
5. try代码块执行到最后,要执行finally代码块的内容,关闭zygoteServer的套接字。
|
||
6. 已经退出了select循环,进入了子进程,继续执行命令`caller.run()`。
|
||
|
||
#### step6: System Servers
|
||
|
||
Zygote启动系统服务,即ZygoteInit类里的startSystemServer方法。
|
||
|
||
#### step7: 引导完成
|
||
|
||
系统服务运行起来后,引导完成,此时会发送开机启动广播`ACTION_BOOT_COMPLETED`
|
||
|
||
#### 附录:init语言
|
||
|
||
详见:system/core/init/README.md
|
||
|
||
由五类语句构成:Actions, Commands, Services, Options and Imports。
|
||
|
||
从整体来看,一个rc文件是由若干个段组成的。一个段只能是Actions或Server其中之一:
|
||
|
||
- Actions,由trigger和它下面的一堆Commands组成。
|
||
- Servers,由一堆Options组成。
|
||
|
||
注意:Actions和Servers不能重名。如果重名了,后出现的定义将会作为错误而忽略掉。
|
||
|
||
##### .rc文件
|
||
|
||
init language用在.rc文件中,它可能出现在系统中的多个位置。
|
||
|
||
- /init.rc是最初的.rc文件,它会随着init的执行而执行,用于系统的最初设置。
|
||
|
||
##### Actions
|
||
|
||
Actions就是触发器(trigger)加一串命令(commands),触发器用来决定是否执行一个Action。如果满足了触发器的条件且action还不在运行队列里,则这个action会被加到运行队列的尾部。
|
||
|
||
运行的格式如下:
|
||
|
||
```
|
||
on <trigger> [&& <trigger>]*
|
||
<command>
|
||
<command>
|
||
```
|
||
|
||
以on开头,后面的trigger是判断条件(详见[Triggers](#triggers)),command是具体要执行的操作。
|
||
|
||
##### Services
|
||
|
||
Services是程序,它由init进程启动,并且可以退出后重启(可选)。
|
||
|
||
服务的格式如下:
|
||
|
||
```
|
||
service <name> <pathname> [<argument> ]*
|
||
<option>
|
||
<option>
|
||
```
|
||
|
||
name是程序名,pathname是程序所在的路径,argument是程序的参数,option是服务配置(详见[Options](#options))。
|
||
|
||
##### Options
|
||
|
||
Options是Services的修改器,它们影响init进程如何运行service以及何时运行service。
|
||
|
||
- console,此服务需要一个console。默认设备为`/dev/console`。也可自己指定,如`console /dev/tty0`,其中`/dev/`是可忽略的,即等同于`console tty0`。
|
||
|
||
- ctitical,此服务是一个设备关键服务。如果在4分钟内退出4次,设备将会重启进入recovery模式。
|
||
|
||
- disabled,此服务无法通过它所属的类型(class)来启动,必须通过它的名字来启动。这就意味着启动一个类型的服务时这种服务是不会被启动的,也就是它被disable掉了。
|
||
|
||
- setenv,在启动的进程里设置环境变量。
|
||
|
||
- socket \<name> \<type> \<perm> [\<user> [\<group>]]
|
||
|
||
创建一个unix域socket,它的名字叫/dev/socket/\<name>,并将它的fd传给启动的进程。
|
||
|
||
- file,打开一个文件并将它的fd传给启动的进程。
|
||
|
||
- user,在执行服务前改变用户(user),默认的用户是root。
|
||
|
||
- group,在执行服务前改变组名。
|
||
|
||
- capabilities,在执行服务的时候设置capabilities.
|
||
|
||
- seclabel,在执行服务前改变为seclabel。
|
||
|
||
- oneshot,当服务退出后不要重启它。
|
||
|
||
- class,为服务指定所属的类型。在同一个类型里的服务可以同时打开或关闭。如不使用此选项明确指定服务所属的类型,则默认在default里。
|
||
|
||
- animation,将会包含所有启动和关闭animation所必须的服务。
|
||
|
||
- onrestart当服务重启的时候执行一条命令。
|
||
|
||
- writepid,当子进程forks的时候将其pid写到给定文件中。
|
||
|
||
- priority,调度service进程的优先级。
|
||
|
||
- namespace,当forking一个服务的时候,进入一个新的PID或挂载namespace。
|
||
|
||
- oom_score_adjust,设置子进程的变量值。
|
||
|
||
- memcg.swappiness,设置子进程的变量值。
|
||
|
||
- memcg.soft_limit_in_bytes,设置子进程的变量值。
|
||
|
||
- memcg.limit_in_bytes,设置子进程的变量值。
|
||
|
||
- shutdown,设置关机的时候此service进程的行为。默认是关机进程通过传递SIGTERM和SIGKILL来杀死此服务。
|
||
|
||
##### Triggers
|
||
|
||
Triggers就是个字符串,用来匹配特定事件和触发一个action。分为事件触发器和权限触发器。
|
||
|
||
事件触发器就是个简单的字符串,如"boot"或"late-init"。
|
||
|
||
权限触发器就是个键值对,其格式为`property:<name>=<value>`。
|
||
|
||
一个动作可以有多个权限触发器但只能有一个事件触发器。
|
||
|
||
##### Commands
|
||
|
||
`bootchart [start|stop]`
|
||
|
||
> Start/stop bootcharting. These are present in the default init.rc files,
|
||
> but bootcharting is only active if the file /data/bootchart/enabled exists;
|
||
> otherwise bootchart start/stop are no-ops.
|
||
|
||
`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. See the start entry for more information on
|
||
> starting services.
|
||
|
||
`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`.
|
||
|
||
`class_restart <serviceclass>`
|
||
> Restarts all services of the specified class.
|
||
|
||
`copy <src> <dst>`
|
||
> Copies a file. Similar to write, but useful for binary/large
|
||
> amounts of data.
|
||
> Regarding to the src file, copying from symbolic link file and world-writable
|
||
> or group-writable files are not allowed.
|
||
> Regarding to the dst file, the default mode created is 0600 if it does not
|
||
> exist. And it will be truncated if dst file is a normal regular file and
|
||
> already exists.
|
||
|
||
`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. Properties are expanded
|
||
> within _argument_.
|
||
> Init halts executing commands until the forked process exits.
|
||
|
||
`exec_start <service>`
|
||
> Start a given service and halt the processing of additional init commands
|
||
> until it returns. The command functions similarly to the `exec` command,
|
||
> but uses an existing service definition in place of the exec argument vector.
|
||
|
||
`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 [-f] <path> [<options>]`
|
||
> Install the module at _path_ with the specified options.
|
||
> -f: force installation of the module even if the version of the running kernel
|
||
> and the version of the kernel for which the module was compiled do not match.
|
||
|
||
`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 <type> <device> <dir> [ <flag>\* ] [<options>]`
|
||
|
||
> Attempt to mount the named device at the directory _dir_
|
||
> _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
|
||
|
||
`restart <service>`
|
||
> Stops and restarts a running service, does nothing if the service is currently
|
||
> restarting, otherwise, it just starts the service.
|
||
|
||
`restorecon <path> [ <path>\* ]`
|
||
> 将<path>所代表的文件恢复到安全上下文里,这个安全上下文是在file_contexts配置中指定的。init.rc创建的目录不需要执行这个命令,因为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>`
|
||
> 如果一个服务还没有运行则启动它。
|
||
> Note that this is _not_ synchronous, and even if it were, there is
|
||
> no guarantee that the operating system's scheduler will execute the
|
||
> service sufficiently to guarantee anything about the service's status.
|
||
|
||
> This creates an important consequence that if the service offers
|
||
> functionality to other services, such as providing a
|
||
> communication channel, simply starting this service before those
|
||
> services is _not_ sufficient to guarantee that the channel has
|
||
> been set up before those services ask for it. There must be a
|
||
> separate mechanism to make any such guarantees.
|
||
|
||
`stop <service>`
|
||
|
||
> 如果一个服务正在运行则关闭它。
|
||
|
||
`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.
|
||
|
||
`wait_for_prop <name> <value>`
|
||
> Wait for system property _name_ to be _value_. Properties are expanded
|
||
> within _value_. If property _name_ is already set to _value_, continue
|
||
> immediately.
|
||
|
||
`write <path> <content>`
|
||
> 把<content>写到<path>里。<content>里的属性将会展开。
|
||
|
||
##### Imports
|
||
|
||
解析init配置文件,扩展当前配置。
|
||
|
||
#### 参考文档
|
||
|
||
- [foxleezh/AOSP](https://github.com/foxleezh/AOSP)
|
||
- 《深入理解Android卷1》邓凡平
|
||
- [freshui/Android init进程分析](https://blog.csdn.net/freshui/article/details/5747199)
|
||
- [freshui/Android init脚本解析](https://blog.csdn.net/freshui/article/details/5772564) |