Android:Android系统启动(笔记)

init 进程启动

init 进程是 Android 系统中用户控件的第一个进程,进程号为 1,是 Android 系统系统流程中一个关键的步骤,作为第一个进程,它被赋予了很多极其重要的工作职责,比如创建 Zygote(孵化器)和属性服务等。init 进程是由多个源文件共同组成的,这件文件位于源码目录 system/core/init 中。

引入 init 进程

首先了解 Android 系统启动流程的前几步,以引入 init 进程

1. 启动电源以及系统启动

当电源按下时引导芯片代码从预定义的地方(固话在 Rom)开始执行,加载引导程序 BootLoader 到 RAM 中,然后执行。

2. 引导程序 BootLoader

引导程序 BootLoader 是在 Android 操作系统开始运行前的一个小程序,主要作用是把系统 OS 拉起来并运行。

3. Linux 内核启动

当内核启动时,设置缓存,被保护存储器、计划列表、加载驱动。在内核完成系统设置后,它首先在系统文件中寻找 init.rc 文件,并启动 init 进程。

4. init 进程启动

init 进程做的工作比较多,主要用来初始化和启动属性服务,也用来启动 Zygote 进程

启动电源以及系统启动
引导程序 BootLoader
Linux 内核启动
init 进程启动
初始化和启动属性服务
启动 Zygote 进程

init 进程的入口函数

在 Linux 内核加载完成后,它首先在系统文件中寻找 init.rc 文件,并启动 init 进程,然后查看 init 进程的入口函数 main。

main 里主要做了几件事,在开始的时候创建和挂载启动所需的文件目录,其中挂载了 tmpfs,devpts、proc、sysfs和 selinuxfs 共 5 种文件系统,都是系统运行时目录,即只有系统运行时才会存在,停止时会消失。

调用 property_init 函数对属性进行初始化

调用 start_property_service 函数启动属性服务

调用 signal_handler_init 函数用于设置子进程信号处理函数,如果子进程(Zygote 进程)异常退出,init 进程会调用该函数中设定的信号处理函数来进行处理。

调用 parser.ParseConfig("/init.rc") 用来解析 init.rc 文件,解析 init.rc 文件为 system/core/init/init_parse.cpp 文件。

僵尸进程与危害

在 Unix/Linux 中,父进程使用 fork 创建子进程,在子进程终止后,如果父进程对此不知道,在系统进程表中还为它保留了一定的信息,那这个子进程就叫做僵尸进程。因为系统进程表是有限资源,所以系统就可能无法创建新进程。

解析 init.rc

init.rc 是一个配置文件,由 Android 初始化语言编写的脚本。主要包含五种类型语句:Action、Command、Service、Option 和 Import。

其中 Service 用于通知 init 进程创建名为 zygote 进程,zygote 的 classname 为 main

解析 Service 类型语句

Service 类型语句采用 ServiceParser 来进行解析(ServiceParser的实现在 system/core/init/service.cpp 中),ServiceParser 用到两个函数:一个是 ParseSection,解析 Service 的 rc 文件,另一个是 ParseLineSection,用于解析子项。

总的来说就是根据参数构建出 Service 对象,然后根据选项域的内容填充 Service 对象,最后将 Service 对象加入 vector 类型的 Service 链表中。

init 启动 Zygote

在 init.rc 中,通过 class_start 这个 COMMAND(对应的函数为 do_class_start) 来启动 classname 为 main 的 Service —— class_start main

do_class_start 在 builtins.cpp 里定义,里面用到的 ForEachServiceInClass 函数会遍历 Service 链表,找到 classname 为 main 的 Zygote ,并执行 StartIfNotDisabled 函数。

如果 Service 没有在其对应的 rc 文件中设置 disabled 选项,则会调用 Start 函数启动该 Service,由于 Zygote 对应的 init.zygote64.rc 中并没有设置 disabled 选项,所以会执行 Start 函数。

在 Start 函数里,会先判断 Service 是否已经运行,如果运行则不再启动,直接返回 false;

如果没有启动,就调用 fork 函数创建子进程,并返回 pid 值,如果 pid==0,说明当前代码逻辑在子进程中运行。

接着调用 execute 函数,Service 子进程就会被启动,并进入该 Service 的 main 函数,如果该 Service 为 Zygote,它的执行路径是/system/bin/app_process64。对应的文件为app_main.cpp,这样就会进入 app_main.cpp函数中,在该文件里的 main 函数里,有调用 runtime 的 start 函数启动 Zygote。

class_start 命令启动 classname 为 main 的 Service
调用 Servcie 对应 rc 文件里 Start 函数
是否已经运行
不再启动,返回 false
调用 fork 函数创建子进程,返回 pid
pid==0 表示当前代码逻辑在子进程中运行
调用 excute 函数,启动 Service 子进程
进入该 Service 的 main 函数,在 Zygote这个 Service 里,main里就是用来启动它

属性服务

Windows 上有一个注册表管理器,内容是以键值对的形式来记录用户、软件的一些使用信息。启动系统或者软件重启,还是能够根据之前注册表中的记录,进行相应的初始化工作。

Android 类似的服务叫 属性服务。

init 进程启动时会启动属性服务,并为其分配内存,用来存储这些属性,如果需要这些属性直接读取即可。

在 init.cpp 里的 main 函数中,有两行代码与此相关:

property_init();
start_property_service();

属性服务初始化与启动

property_init()用来初始化属性内存区域。

start_property_service()里会创建非阻塞的 Socket,然后调用 listen 函数对 property_set_fd 进行监听listen(property_set_fd , 8),这样 Socket 就成为 server,也就是属性服务。第二个参数 8 表示属性服务最多可以同时为 8 个试图设置属性的用户提供服务。

接着register_epoll_handler(property_set_fd , handle_property_set_fd)表示将property_set_fd 放入 epoll 中,用 epoll 来监听 property_set_fd ,当property_set_fd 中有数据到来时,init 进程将调用handle_property_set_fd 函数进行处理。(这个就跟在中间件里写 c 的那样,将各种参数还有 out 传入进去,然后赋值给 out)

服务处理客户端请求

属性服务接收到客户端的请求时,会调用 handle_property_set_fd 函数进行处理

它会处理两部分的属性,一部分是普通属性,一部分是控制属性;

控制属性用来执行一些命令,比如开机动画,属性名称以"ctl."开头

对于控制属性,如果客户端条件满足,会调用 handle_control_message 函数来修改控制属性

如果是普通属性,则会在客户端权限满足的条件下,调用property_set 函数来对普通属性进行修改。它会判断属性是否合法,合法就从属性控件中查找该属性,存在就更新值,否则就添加更新。

init 进程启动总结

  • 创建和挂载启动所需的文件目录
  • 初始化和启动属性服务
  • 解析 init.rc 配置文件并启动 Zygote 进程

Zygote 进程启动过程

Zygote 概述

在 Android 系统中,DVM (Dalvik 虚拟机)和 ART、应用程序进程以及运行系统的关键服务的 SystemServer 进程都是由 Zygote 进程来创建的,也称它为孵化器。

他通过 fork 的形式来创建应用程序进程和 SystemServer 进程,由于 Zygote 进程在启动时会创建 DVM 或者 ART,因此通过 fork 而创建的应用程序进程和 SystemServer 进程可以在内部获取一个 DVM 或者 ART 的实例副本。

Zygote 启动脚本

在 init.rc 文件中采用了 import 类型语句来引入 Zygote 启动脚本,这些启动脚本由 Android 初始化语言来编写:

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

可以看出 ro.zygote是个引用值,它有四种取值方式,代表四种 Zygote 启动脚本。

  • init.zygote32.rc
  • init.zygote32_64.rc
  • init.zygote64.rc
  • init.zygote64_32.rc

Zygote 进程启动过程介绍

init 启动 Zygote 时主要是调用 app_main.cpp的 main 函数中的 AppRuntime 的 start 方法来启动 Zygote 进程的,我们就先从 app_main.cpp 的 main 函数开始分析

init app_main AndroidRuntime ZygoteInit ZygoteServer main start main registerServerSocket preload startSystemServer runSelectLoop loop [ ] init app_main AndroidRuntime ZygoteInit ZygoteServer

因为 Zygote 进程都是通过 fork 自身来创建子进程的,这样 Zygote 进程以及它的子进程都可以进入 app_main.cpp 的 main 函数,因此 main 函数中会根据参数中是否包含"–zygote"来判断当前运行在哪个进程:

app_main.cpp

//通过关键词来判断,
if(strcmp(arg , "--zygote") == 0){
    zygote = true;
}else if(strcmp(arg , "--start-system-server") == 0){
    startSystemServer = true;
}

...

//如果在 zygote 进程中,就会调用 AppRuntime 的 start 函数
if(zygote){
    runtime.start("com.android.internal.os.ZygoteInit" , args , zygote);
}

...

那么在这个AppRuntime 的 start 函数里,它会调用 startVm 函数来创建 Java 虚拟机

if(startVm(&mJavaVM , &env , zygote) != 0)

...

if(startReg(env) < 0)

...
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值