• 【Android】系统启动流程(zygote 进程启动流程)


    前言

    先上图,大致了解一下 Android 设备点击电源键开机到创建出 system_server 进程的流程,
    里面细化的子流程和 system_server 之后发生的事情我将会在后续的文章中详细讲:

    在这里插入图片描述
    图中涉及到的这些名词都是什么呢?下面来简单的说说。

    Boot Rom

    当电源键按下时,引导芯片就会启动,引导芯片代码会从预定义的地方开始执行(代码存在Rom),加载引导程序 BootLoader 到 RAM,换句话说,就是启动的时候,会把引导程序代码由 ROM 中移动到 RAM 中,再去执行引导程序 BootLoader

    ROM可以简单理解为硬盘,断电后内部的数据是不会丢失的。

    RAM可以简单理解为运行时内存,断电后内部的数据就会丢失。

    BootLoader

    BootLoader 是在 Android 操作系统开始运行前的一个小程序,它的主要作用是把系统 OS 拉起来并运行,BootLoader 执行后,就会启动操作系统。

    idle 进程

    当操作系统启动后,就会启动系统的第一个进程,即 idle 进程,它的进程号为0。

    idle 进程被启动后,会在系统文件中寻找 init.rc 文件,专门用来启动 init 进程。

    除了会启动 init 进程,还会启动另一个进程: kthreadd 进程 。

    init 进程

    init 进程的进程号为 1,它位于内核层。

    它的主要工作是初始化和管理进程,内存管理,加载 Binder Driver、Display、Camera Driver等。init 进程 是首个开辟用户空间的进程,是用户空间的鼻祖

    在init进程内部,会fork出我们所熟知的一个进程:zygote进程。

    kthreadd 进程

    kthreadd 进程,跟 init 进程一样,都位于内核层。

    它主要是用来创建内核工作线程、软中断线程等内核相关的工作,我们不需要太过关注。

    zygote 进程

    zygote 进程又名孵化器进程,它是 java 进程的鼻祖。

    zygote 进程中,它第一个 fork 出来的进程是 system_server 进程,同时,我们设备上的 App 进程都是由 zygote 进程来创建的。

    system_server 进程

    Android 中常用系统服务(AMS/WMS/PMS )都是由 system_server 这个进程启动的,所以它相当重要。

    zygote / system_server 进程启动流程

    以下源码基于 Android 11

    init 进程开启后,会执行 frameworks/base/cmds/app_process/app_main.cpp 文件的 main() 方法,

    main() 方法首先会创建 AndroidRuntime 对象 (runtime),即 Android 运行时环境对象,如下所示:

    在这里插入图片描述

    继续查阅 main() 方法,

    发现执行了 runtime.start("com,android.internal.os.ZygoteInit", args, zygote) 方法,可以猜测到,这里应该是启动 zygote 进程的入口,如下:

    在这里插入图片描述

    那么我们进入 runtime.start() 方法内部看看里面写什么东西:

    在这里插入图片描述

    可以看到,在runtime.start() 方法内,执行两个方法:

    • 执行 startVM 方法:创建虚拟机(在这里面也看出,一个进程,内部包含一个虚拟机)
    • 执行 startReg 方法:注册 JNI 方法,注册后才可以使用 jni 方法

    继续查阅 runtime.start() 方法,

    可以发现下面的代码开始使用 jni 方法调用 com.android.inter.os.ZygoteInit.main() 方法,如下:

    在这里插入图片描述

    自此之后,代码将会执行到 java 层的代码,进入 java 世界。

    那么为什么要用 jni 方法来调用 ZygoteInit.main() 方法呢?

    原因就是 jni 是 native 层和 java 层之间的桥梁,如果想要从 native 层进入 java 层,就需要用到 jni。

    zygote 进程第一个 java 进程,也是 Android 中所有 java 进程的鼻祖,比如我们平时开发的 App 都是属于 java 层进程。

    接下来继续进入 ZygoteInit.main() 方法,看看里面做了什么事情:

    在这里插入图片描述

    可以看到,代码里执行乐 preload() 方法,该方法是用来预加载信息的,而这些预加载信息包括了一部分 framework 的资源,以及一部分常用的 java 类。

    这部分预加载的信息,在后面创建的进程都是可以直接用的。所以这里预加载的作用就是加快了应用进程的启动速度。

    继续向下查阅代码:

    在这里插入图片描述

    可以看到,执行了 zygoteServer = new ZygoteServer(isPrimaryZygote) 这行代码,这行代码是用来创建 zygote 的 socket 服务的,而这个 socket 则是用来进行跨进程通信的。

    有人可能就会问了,Android 不是用 Binder 进行跨进程通信的吗,为什么这里不用 Binder 呢? 事实上,代码执行到这,Binder还没开始初始化。

    继续向下查阅 ZygoteInit.main() 方法代码:

    在这里插入图片描述

    可见,这里执行了 forkSystemServer(abiList, zygoteSocketName, zygoteServer) 方法,

    实际上,该方法是以 fork 的形式创建 system_setver 进程,并返回一个 Runnable 对象。

    得到 Runnable 对象后,执行 r.run() 方法,而在这个 r.run() 方法内部,会执行 SystemServermain 方法,从而启动 system_servier 进程。

    接下来,继续向下查阅 ZygoteInit.main() 方法代码:

    在这里插入图片描述

    会发现执行乐 zygoteServer.runSelectLoop() 方法,

    该方法使 zygote 进入无限循环,等待 AMS 给他发消息(告诉 zygote 创建进程)。

    至此,zygote 进程和 system_server 进程的启动流程就算简单的讲完了。这里贴个图,方便大家理解:

    在这里插入图片描述

  • 相关阅读:
    Linux - 正则表达式
    《我在地球学Linux》-常见指令(上)
    HBuilder X实现tabBar底部导航记录
    从 0 开始学习 Git + GitHub
    【web-攻击数据存储区】(6.2)SQL注入
    虚拟线程 - VirtualThread源码透视
    彻底搞懂Mybatis
    破茧化蝶,从Ring Bus到Mesh网络,CPU片内总线的进化之路
    技术管理责任制度《三》
    将 Vue.js 项目部署至静态网站托管,并开启 Gzip 压缩
  • 原文地址:https://blog.csdn.net/yang553566463/article/details/126544996