Android Framework学习三:zygote剖析

文章目录

在 Android 系统中,Zygote 是一个非常关键的进程,有 "App 孵化器" 之称 ,主要有以下特点和作用:
进程地位与创建
它是 Android 系统上所有应用进程的父进程 ,由 Linux 系统用户空间的第一个进程 ------init 进程,通过 fork 的方式创建。在一些双架构系统中,可能会创建 64 位和 32 位两个 Zygote 进程 ,现代部分设备(如 Pixel 7 及后续机型 )存在 64 位 Zygote 进程 ,还有专门针对 WebView 的 WebView Zygote 。

Zygote工作内容

这是一张描述 Android 系统中 Zygote 进程启动流程的流程图

起始点

zygote 进程启动:Zygote 是 Android 系统中一个重要的进程,是所有 Java 应用程序进程的孵化器 ,它的启动是整个流程的开端。

随后进入app_main.cpp中的main()函数,这是 Zygote 进程在 C++ 层面启动的入口函数。

初始化步骤

  1. 初始化 AndroidRuntime:在app_main.cpp的main()函数中,首先进行AndroidRuntime的初始化。AndroidRuntime类用于管理 Android 运行时环境相关的操作。
  2. 设置 zygote 启动模式:通过strcmp(arg, "--zygote")来判断并设置当前为 Zygote 启动模式。这一步确定了进程是以 Zygote 模式启动,后续的操作都基于此模式进行。
  3. 给 start 函数的参数 args 赋值:通过args.add(String8("start-system-server")) 给start函数的参数args添加一个值 ,这个值用于指示后续启动过程中需要启动系统服务器(System Server)。

启动 ZygoteInit

AndroidRuntime::start函数:

  1. runtime.start () 启动 ZygoteInit:调用runtime.start()函数来启动ZygoteInit。这是 Zygote 进程启动过程中的关键步骤,它会进一步调用一系列函数来完成虚拟机和 JNI 相关的初始化。

  2. startVm () 创建虚拟机:runtime.start()内部首先调用startVm()函数,用于创建 Java 虚拟机(JVM)。这是为后续运行 Java 代码做准备,是 Zygote 进程能够执行 Java 程序的基础。

  3. startReg () 注册 JNI 方法:接着调用startReg()函数,用于注册 JNI(Java Native Interface)方法。JNI 允许 Java 代码和本地 C/C++ 代码进行交互,注册这些方法后,Java 层就可以调用本地方法,本地方法也可以回调 Java 方法, 比如BitMap的创建最终调用的JNI方法。

    如gRegJNI保存有要注册的JNI方法:

    在startReg中把gRegJNI中JNI注册:

  4. 使用 JNI 调用 ZygoteInit 的 main 函数,进入 java 世界:通过env->CallStaticVoidMethod()使用 JNI 调用ZygoteInit类的main函数,至此,程序流程从 C++ 层进入到 Java 层。

ZygoteInit.main () 函数内部操作

  1. preload () 预加载信息:在ZygoteInit.main()函数中,首先调用preload()函数,预加载一些类、资源等信息。预加载可以提高后续应用程序启动的速度,因为一些常用的类和资源已经提前加载到内存中。

  2. new ZygoteServer () 创建 zygote 的 socket 服务:创建ZygoteServer对象,该对象用于创建 Zygote 的 socket 服务。Zygote 通过这个 socket 服务来监听客户端请求,后续应用程序进程的创建请求就是通过这个 socket 来传递的。

  3. r = forkSystemServer () fork 创建 systemserver 进程:通过forkSystemServer()函数使用fork系统调用创建SystemServer进程。SystemServer进程是 Android 系统中非常重要的一个进程,它负责启动和管理系统中的各种服务,如 ActivityManagerService、PackageManagerService 等。

  4. r.run () 执行 systemserver 的 main 方法:在创建SystemServer进程后,调用r.run()来执行SystemServer进程的main方法,启动系统服务相关的逻辑。

  5. zygoteServer.runSelectLoop():最后调用zygoteServer.runSelectLoop(),Zygote 进入循环监听状态,等待客户端(通常是应用程序启动请求)的连接,一旦有请求到来,就会通过fork机制创建新的应用程序进程。

Zygote如何启动SystemServer

这是一张展示 Android 系统中 Zygote 进程创建 SystemServer 进程相关流程的时序图

参与的类和文件

  • ZygoteInit:Java 类,在 Zygote 进程启动过程中起重要作用,负责协调 Java 层相关初始化工作。
  • Zygote:Java 类,与 Zygote 进程功能紧密相关,包含一些关键的进程创建等逻辑。
  • com_android_internal_os_Zygote:JNI 相关的 C++ 代码,用于实现 Java 层与本地代码的交互,这里主要涉及 Zygote 相关功能的本地实现。
  • AndroidRuntime.cpp:C++ 文件,主要处理 Android 运行时环境相关操作,是连接 Java 层和底层系统的重要桥梁。
  • App_main.cpp:C++ 文件,是 Zygote 进程在 C++ 层面启动的入口文件,包含main函数等关键启动逻辑。
  • RuntimeInit:Java 类,负责运行时初始化相关工作。

流程步骤

  1. 在 ZygoteInit 的 main 函数中发起创建 SystemServer 进程
    ZygoteInit的main函数首先调用forkSystemServer方法,这个方法定义在Zygote类中。
  2. Zygote 类的 forkSystemServer 方法
    Zygote类的forkSystemServer方法调用com_android_internal_os_Zygote类的nativeForkSystemServer本地方法,通过 JNI 进入到本地 C++ 代码层。
  3. 进入本地 C++ 代码的 ForkCommon
    nativeForkSystemServer方法调用ForkCommon中的fork()函数来创建进程。fork()是操作系统提供的系统调用,用于创建一个新进程,新进程是当前进程(Zygote 进程)的副本。
  4. 当fork()调用成功后,会在子进程(即将成为 SystemServer 进程)和父进程(Zygote 进程)中分别返回,子进程继续后续 SystemServer 进程的初始化,父进程则继续 Zygote 进程的其他工作。

进程创建完成后的处理

  1. 在 Zygote 进程这边,当收到 "进程创建完" 的通知后,调用handleSystemServerProcess方法,继续后续 Zygote 相关的处理逻辑。
  2. 对于新创建的 SystemServer 进程,会进行一系列初始化操作:
  • 首先调用nativeZygoteInit方法,这个方法在AndroidRuntime.cpp中实现,主要进行一些本地层面的初始化。
  • 接着调用onZygoteInit方法,在App_main.cpp中实现,用于构建进程对应的 binder。Binder 是 Android 系统中进程间通信(IPC)的重要机制,通过构建 binder,SystemServer 进程可以与其他进程进行通信。
  • 最后调用applicationInit方法,在RuntimeInit类中实现,构建一个反射调用main函数的runnable,为 SystemServer 进程后续执行其main函数逻辑做准备。

Framework学习之系列文章

Android Framework学习一:系统框架、启动过程
Android Framework学习二:Activity创建及View绘制流程
Android Framework学习三:zygote剖析

作者:帅得不敢出门

相关推荐
JANYI20185 分钟前
C文件在C++平台编译时的注意事项
java·c语言·c++
蓝莓味柯基12 分钟前
Python 学习路线与笔记跳转(持续更新笔记链接)
笔记·python·学习
benpaodeDD1 小时前
双列集合——map集合和三种遍历方式
java
Rytter1 小时前
Android逆向学习(八)Xposed快速上手(上)
android·学习
Kx…………2 小时前
Day3:设置页面全局渐变线性渐变背景色uniapp壁纸实战
前端·学习·uni-app·实战·项目
Q_Boom2 小时前
前端跨域问题怎么在后端解决
java·前端·后端·spring
搬砖工程师Cola2 小时前
<Revit二次开发> 通过一组模型线构成墙面,并生成墙。Create(Document, IList.Curve., Boolean)
java·前端·javascript
等什么君!2 小时前
学习spring boot-拦截器Interceptor,过滤器Filter
java·spring boot·学习
林十一npc2 小时前
Fiddler抓取APP端,HTTPS报错全解析及解决方案(一篇解决常见问题)
android·前端·网络协议·https·fiddler·接口测试
caihuayuan42 小时前
Linux环境部署iview-admin项目
java·大数据·sql·spring·课程设计