Android系统的心脏-Zygote进程如何fork一个新的应用进程

Frida源码解析:从注入指令到JS脚本执行的全链路剖析 动态插桩技术是现代软件安全分析、逆向工程和自动化测试的核心手段,它允许在程序运行时监控和修改其行为。其原理是通过向目标进程注入代码或库,实现对函数调用、内存访问等操作的拦截与处理。这项技术的核心价值在于提供了对闭源软件的深度可观测性和可控性,无需源码即可进行调试、Hook和功能扩展。在移动安全、漏洞挖掘、自动化测试等场景中,动态插桩是分析应用逻辑、绕过安全机制的关键工具。本文以广泛使用的动态插桩框架Frida为例,深入解析其从客户端发起注入指令,到服务端通过ptrace等系统调用将Gadget库注入目标进程 阅读详情

简介:

在Android系统中,所有的应用程序进程都是有Zygote进程创建的。那么,到底是如何创建出来的呢?本节来分析一下这个创建流程。 

ZygoteInit代码回顾:

在Android初始化流程中,init进程创建了zygote进程,(通过init.rc中的指令),而且,在zygote这个进程中,注册了zygote socket, 而且,会根据是否是ZYGOTE_FORK_MODE模式,去执行zygote的创建,或进入selectLoop监听循环中,代码在ZygoteInit.java中,如下:

public static void main(String argv[]) {
 
    ......
 
    registerZygoteSocket();
 
    ......
 
    if (argv[1].equals("start-system-server")) {
                startSystemServer();
    } else if (!argv[1].equals("")) {
                throw new RuntimeException(argv[0] + USAGE_STRING);
    }
    if (ZYGOTE_FORK_MODE) {
                runForkMode();
    } else {
                runSelectLoopMode();
    }
    
 
}    

ZYGOTE_FORK_MODE的定义:

private static final boolean ZYGOTE_FORK_MODE = false;

所以,会执行到runSelectLoopMode,即在创建了SystemServer进程之后,就进入了这个runSelectLoopMode方法的执行。 

从runSelectLoopMode开始分析:

private static void runSelectLoopMode() throws MethodAndArgsCaller {
        ArrayList<FileDescriptor> fds = new ArrayList();
        ArrayList<ZygoteConnection> peers = new ArrayList();
        FileDescriptor[] fdArray = new FileDescriptor[4];
 
        fds.add(sServerSocket.getFileDescriptor());
        peers.add(null);
 
        int loopCount = GC_LOOP_COUNT;
        while (true) {
            int index;
 
            ......
 
            try {
                fdArray = fds.toArray(fdArray);
                index = selectReadable(fdArray);
            } catch (IOException ex) {
                throw new RuntimeException("Error in select()", ex);
            }
 
            if (index < 0) {
                throw new RuntimeException("Error in select()");
            } else if (index == 0) {
                ZygoteConnection newPeer = acceptCommandPeer();
                peers.add(newPeer);
                fds.add(newPeer.getFileDesciptor());
            } else {
                boolean done;
                done = peers.get(index).runOnce();
 
                if (done) {
                    peers.remove(index);
                    fds.remove(index);
                }
            }
        }
    }

分析:

1)通过前面注册的socket来获取文件描述符,通过这个描述符来处理来自外部的请求;这个描述符什么时候创建的呢?看下面的代码(ZygoteInit.java的registerZygoteSocket方法:

private static void registerZygoteSocket() {
        if (sServerSocket == null) {
            int fileDesc;
            try {
                String env = System.getenv(ANDROID_SOCKET_ENV);
                fileDesc = Integer.parseInt(env);
            } catch (RuntimeException ex) {
                throw new RuntimeException(
                        ANDROID_SOCKET_ENV + " unset or invalid", ex);
            }
 
            try {
                sServerSocket = new LocalServerSocket(
                        createFileDescriptor(fileDesc));
            } catch (IOException ex) {
                throw new RuntimeException(
                        "Error binding to local socket '" + fileDesc + "'", ex);
            }
        }
    }

这里的

sServerSocket = new LocalServerSocket(
                        createFileDescriptor(fileDesc));

在初始化sServerSocket的时候,创建了FileDescriptor,即

ANDROID_SOCKET_ENV

环境变量对应的文件描述符,ANDROID_SOCKET_ENV的定义: 

private static final String ANDROID_SOCKET_ENV = "ANDROID_SOCKET_zygote";

2)selectReadable:这是一个native方法,用于监视文件描述符,如果文件描述符中有相关的事件,则返回文件描述符在数组中的索引index。其实就是找到有事件发生的文件描述符。那么,如何监听呢?答案就是通过Linux系统调用select函数来实现; 

3)根据index去创建ZygoteConnection,并且保存起来;

4)执行ZygoteConnection实例的runOnce方法。这是个关键函数,是创建应用程序进程的入口。

整个流程涉及到java和native,时序图如下(分为java层和native层)如下:

java层时序图:

 

select函数的功能:

它可以同时监听多个socket描述符,并且知道哪一个socket描述符已经可以读取数据了,哪个描述符可以 写入数据,以及哪个socket出现了错误。这里的socket描述符也是文件的一种。

Native层时序图:

 

 从java的forkAndSpecialize()调用到native层的forkAndSpecializeCommon()方法中,而在这个方法中,最终,通过fork系统调用创建了一个新的进程,这个进程就是用用程序进程。

forkAndSpecializeCommon()的fork:

在forkAndSpecializeCommon()中,fork的调用如下:

static pid_t forkAndSpecializeCommon(const u4* args, bool isSystemServer)
{
    pid_t pid;
    
    ......
 
    pid = fork();
 
    if (pid == 0) {
 
        /* The child process */
 
        ......
    } else if (pid > 0) {
        /* the parent process */
    }
 
    return pid;
}

可见,典型的pid处理方式:如果pid == 0,即当前处于子进程;如果pid>0,即处于父进程。 

再看一下主要代码文件列表:

1)相关代码文件:

Java代码:
frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
frameworks/base/core/java/com/android/internal/os/ZygoteConnection.java
libcore/dalvik/src/main/java/dalvik/system/Zygote.java

Native代码:
frameworks/base/core/jni/com_android_internal_os_ZygoteInit.cpp
dalvik/vm/native/dalvik_system_Zygote.cpp

 代码目录结构:

 

2)ZygoteInit中jni方法的注册:

frameworks/base/core/jni/com_android_internal_os_ZygoteInit.cpp中,

static JNINativeMethod gMethods[] = {
    /* name, signature, funcPtr */
    { "setreuid", "(II)I",
      (void*) com_android_internal_os_ZygoteInit_setreuid },
    { "setregid", "(II)I",
      (void*) com_android_internal_os_ZygoteInit_setregid },
    { "setpgid", "(II)I",
      (void *) com_android_internal_os_ZygoteInit_setpgid },
    { "getpgid", "(I)I",
      (void *) com_android_internal_os_ZygoteInit_getpgid },
    { "reopenStdio",
        "(Ljava/io/FileDescriptor;Ljava/io/FileDescriptor;"
        "Ljava/io/FileDescriptor;)V",
            (void *) com_android_internal_os_ZygoteInit_reopenStdio},
    { "setCloseOnExec", "(Ljava/io/FileDescriptor;Z)V",
        (void *)  com_android_internal_os_ZygoteInit_setCloseOnExec},
    { "setCapabilities", "(JJ)V",
        (void *) com_android_internal_os_ZygoteInit_setCapabilities },
    { "capgetPermitted", "(I)J",
        (void *) com_android_internal_os_ZygoteInit_capgetPermitted },
    { "selectReadable", "([Ljava/io/FileDescriptor;)I",
        (void *) com_android_internal_os_ZygoteInit_selectReadable },
    { "createFileDescriptor", "(I)Ljava/io/FileDescriptor;",
        (void *) com_android_internal_os_ZygoteInit_createFileDescriptor }
};
int register_com_android_internal_os_ZygoteInit(JNIEnv* env)
{
    return AndroidRuntime::registerNativeMethods(env,
            "com/android/internal/os/ZygoteInit", gMethods, NELEM(gMethods));
}

3)Zygote的jni方法的注册;

dalvik/vm/native/dalvik_system_Zygote.cpp中,

const DalvikNativeMethod dvm_dalvik_system_Zygote[] = {
    { "nativeFork", "()I",
      Dalvik_dalvik_system_Zygote_fork },
    { "nativeForkAndSpecialize", "(II[II[[I)I",
      Dalvik_dalvik_system_Zygote_forkAndSpecialize },
    { "nativeForkSystemServer", "(II[II[[IJJ)I",
      Dalvik_dalvik_system_Zygote_forkSystemServer },
    { "nativeExecShell", "(Ljava/lang/String;)V",
      Dalvik_dalvik_system_Zygote_execShell },
    { NULL, NULL, NULL },
};

AndroidP_应用进程启动流程的梳理 前言 本来是要将之前Activity冷启动流程继续梳理清楚的,到了中间看到当进程尚未启动还需要启动新的进程,这也是需要梳理清楚的,于是就先将进程启动流程在源码层面给梳理一遍. 流程图 先上图,有个概况了解才能有梳理的方向: 源码 建议在进入源码阅读之前,先将上面的流程图大概的进行两遍左右的阅读,然后相信会对下面的源码梳理的理解有很大的帮助: 1. AMS.startProcess 我们在开发中中应该知道,应用进程的管理通常是由AMS来进行的,但是进程的启动也是由AMS来发起的【虽然是AMS发起的,但是创建 阅读详情

相关推荐

Android高级常见面试题:说说Activity的启动流程

Zygote端主要逻辑是在runOnce函数,函数内调用Zygote.forkAndSpecialize(…)创建子进程,创建完成之后就分别在父进程和子进程里面做各自的事情 1) 父进程通过hanleParentProc(pid)把子进程的pid通过Socket发送给AMS 2)子进程调用handleChildProc函数,做一些通用的初始化,比如启用Binder机制;执行应用程序的入口函数,也就是ActivityThread的Main函数 ActivityThread的main函数,里面会创建一个.

m0_70083119的博客 979

Zygote如何fork一个进程

文章目录1. Android系统启动流程图2. fork过程的流程图和调用堆栈3. Zygote fork过程源码跟踪4. fork成功之后ActivityThread及后续5. 小结 上一篇我们对Launcher启动的过程做了一个跟踪,跟踪到AMS通过socket向Zygote请求fork新进程之后就停止追踪了,现在我们单独写一篇,接着上一篇,当然也不仅仅是针对Launcher,对进程的fork...

wcsbhwy的博客 2303

Android进程启动核心:深入理解fork与Zygote进程模型

在Linux/Unix系统中,进程创建最常见的方式是调用fork系统调用,它一次调用两次返回,并借助写时复制机制高效复制父进程的地址空间。这一底层机制在Android运行模型中成为核心基石:Zygote进程预加载Java虚拟机和系统资源后,通过fork快速生成应用进程,极大缩短了冷启动时间。理解fork与copy-on-write的原理,不仅有助于掌握Android进程隔离与内存共享机制,还能帮助开发者规避多进程环境下的静态变量、线程锁和内存分配等经典问题。无论是排查应用启动卡顿,还是设计多进程架构,for

weixin_30162121的博客 189

理解Android进程创建流程(转)

/frameworks/base/core/java/com/android/internal/os/ - ZygoteInit.java - ZygoteConnection.java - RuntimeInit.java - Zygote.java /frameworks/base/core/java/android/os/Process.java /fra...

weixin_33781606的博客 302

深入剖析Android系统核心:SystemServer启动与系统服务加载全流程解析

SystemServer是Android系统的核心进程,负责启动和管理关键服务(如AMS、PMS、WMS等),是系统运行的基石。其启动流程分为三个阶段:1)基础环境构建(创建消息循环、系统上下文和服务管理器);2)核心服务加载(分批次启动引导级、核心级及其他服务,确保依赖有序);3)系统就绪(AMS触发启动完成广播,初始化Launcher)。通过Zygote的fork机制继承预加载资源,SystemServer高效完成服务托管。

郑伟强dev的专栏 190

深入CARLA地图底层:OpenDRIVE文件如何影响你的仿真效果与避坑指南

本文深入解析CARLA仿真中OpenDRIVE地图文件的核心作用,揭示其如何影响车道连接、交通规则和导航逻辑。通过实战案例和代码示例,提供五大典型地图问题的诊断与修复方案,帮助开发者优化仿真效果并规避常见陷阱。

weixin_34180452的博客 277

fork 是什么?——为什么它是 Android 运行模型的真正核心

本文揭示了Android系统高效运行的核心机制——Linux的fork系统调用。fork通过"写时复制"技术实现低成本进程复制,解决了ART运行时初始化耗时的难题。Android启动时,zygote进程作为ART模板初始化完成,后续通过fork快速创建system_server和所有App进程,共享已初始化的运行时环境。这种设计避免了重复初始化ART带来的性能损耗,使系统启动更快、内存占用更少、运行更稳定。文章通过对比传统进程创建方式,阐明了fork在移动设备资源限制下的不可替代性,并形

Mark Wu 的博客 795

基于MATLAB/Simulink的四旋翼无人机PID控制与仿真(3)

《基于MATLAB/Simulink的四旋翼无人机PID控制与仿真》的第三篇,将为大家继续展示并完善控制与仿真模型。本文将在前文的基础上,完成控制环节增补、参数设置、测试等工作,在不考虑性能(低超调、快、准等)的前提下,保证系统对于一般输入(阶跃、斜坡)的响应稳定性。

jlx142857的博客 9321

Android 系统中 ART 是如何运行的?——从 zygote 到每个 App 的真实模型

Android系统并非只有一个ART实例在运行。系统启动时,zygote作为首个ART进程常驻内存,预先完成ART初始化。随后通过fork机制创建system_server(系统服务)和各个App进程,每个进程都拥有独立的ARTRuntime实例。这种设计实现了快速启动、内存优化(COW机制)和进程隔离,确保系统稳定性。简言之,zygote是ART的"模板工厂",而system_server和App都是其派生的独立ART实例,随进程生命周期创建和销毁。

Mark Wu 的博客 1269

halcon 深度学习标注_Halcon deep learning之目标检测笔记(一)

设置输入输出的路径输入路径有两个,一个是图像路径HalconImageDir,一个是Json文件路径PillBagJsonFile。这两个参数用于后续在图像路径中读取coco文件。输出路径首先定义一个新的文件夹路径,用于存放样本和模型文件等数据。设置基于深度学习的目标检测模型的路径,该模型文件以.hdl结尾。设置样本数据文件夹ExampleDataDir:'detect_pills_data'数据...

weixin_27885313的博客 2698

PyTorch生成式人工智能(7)——生成对抗网络(Generative Adversarial Network, GAN)实践详解

生成对抗网络 (Generative Adversarial Network, GAN) 最早由 Ian Goodfellow 于 2014 年提出,其中生成器试图创建与真实样本无法区分的数据样本,而判别器则试图区分生成器生成的样本与真实样本。在本节中,我们将介绍 GAN 的理论基础。然后,介绍如何使用 PyTorch 从零开始构建 GAN,以便了解所有细节,深入理解 GAN 的内部工作原理,为后续讨论 GAN 的其他更高级内容奠定基础,比如生成高分辨率图像或逼真的音乐。

盼小辉丶的博客 1万+

深入解析Android ActivityThread:应用进程核心调度机制与性能优化

在Android应用开发中,主线程消息循环机制是UI流畅性和应用响应性的基础。其核心原理是通过Looper和Handler构建的消息队列模型,实现任务的异步调度与线程切换。这一机制的技术价值在于保障了UI操作的安全性与事件处理的顺序性,是避免ANR(应用无响应)的关键。在实际应用场景中,开发者常需优化启动速度、监控卡顿和分析内存泄漏,这些都离不开对主线程调度机制的深入理解。ActivityThread作为Android应用进程的“大脑”,正是这一机制的核心实现者,它负责协调四大组件生命周期、维护主线程消息队

weixin_30256901的博客 472

2026年江苏省职业院校技能大赛高职组“软件测试”赛项智能体辅助测试参考答案

2026年江苏省职业院校技能大赛高职组“软件测试”赛项智能体辅助测试参考答案

我是网络安全兼技能大赛工程师,专注网络安全技术学习与技能大赛实战!持续分享最新的技术文章,帮你少走弯路,一起在技术赛道上进步~ 1324

Application启动流程分析一 Zygote是如何fork进程的

一个App启动另外一个App不会直接启动Application,而是启动另外一个App的MainActivity。

qq_42426725的博客 1316

2026.5.3:Ubuntu26.04下uv所需的环境变量pyproject.toml

本文档提供了Python开发环境的配置指南。主要包括: 设置环境变量(HF_ENDPOINT、UV_PYTHON_INSTALL_MIRROR等) 创建pyproject.toml配置文件,定义项目元数据(名称、版本等) 指定依赖项(torch系列库)及其安装源(PyTorch官方CUDA 12.8镜像) 配置Python版本要求(>=3.13,<3.14) 设置平台限制(Linux/Windows) 该配置适用于需要PyTorch CUDA 12.8支持的项目开发环境搭建。

拥抱具身智能,昇腾Ascend C 587

概率的接力:拆解大模型“预测下一个词“的底层逻辑

大模型的智能不在于它拥有了意识,而在于它用纯数学的架构,将人类语言的复杂结构压缩为可计算的向量轨迹与概率接力。当我们不再将其拟人化为"思考者",而是视作高维条件概率引擎时,才能真正驾驭它。预测下一个词,从来不是终点,而是起点。未来的核心竞争力,属于那些能洞察其统计本质、善用其模式生成能力,并以人类理性与事实为锚点的协作者。词元的轨迹终会止步于上下文窗口,但对技术底层的清醒认知,才是跨越幻觉、走向真实智能的基石。

AI浩 328

【安卓源码】安卓app应用进程启动原理

fork的主要工作是寻找空闲的进程号pid,然后从父进程拷贝进程信息,例如数据段和代码段,fork()后子进程要执行的代码等。===== startProcessLocked 在fork 一个应用进程之后,保存这个 pid 值:handleProcessStartedLocked =====Zygote利用fork方法生成新进程,对于新进程A复用Zygote进程本身的资源,再加上新进程A相关的资源,构成新的应用进程A。// 执行 runSelectLoop 循环监听客户端的创建进程的消息。

mike_jun的博客 1634

卸载python弹框报错:Could not set file security for file ‘D:\Config.Msi\abd5.rbf‘. Error: 5. Verify...如何解决?

🏆本文收录于 《全栈 Bug 调优(实战版)》 专栏。专栏聚焦真实项目中的各类疑难 Bug,从成因剖析 → 排查路径 → 解决方案 → 预防优化全链路拆解,形成一套可复用、可沉淀的实战知识体系。无论你是初入职场的开发者,还是负责复杂项目的资深工程师,都可以在这里构建一套属于自己的「问题诊断与性能调优」方法论,助你稳步进阶、放大技术价值 。

**My Coding Family** 6479

理解Android进程创建流程

基于Android 6.0的源码剖析, 分析Android进程是如何一步步创建的,本文涉及到的源码: /frameworks/base/core/java/android/os/Process.java /frameworks/base/core/java/com/android/internal/os/ZygoteInit.java /frameworks/base/core/java

湛蓝湖泊 3338

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

从源码解析-Android中Zygote进程是如何fork一个APP进程的

zygote进程fork子进程前言 前言 每个APP可能运行在一个进程,也可能在多个进程,这些进程拥有自己独立的资源;然而这些进程都是由Zygote进程fork出来的,再往前一步其实是system server进程使用LocalSocket去通知zygote进程,然后zygote去fork一个子进程,也就是APP进程(更往前一步就是APP进程使用Binder机制去通知system server进程...

Mango先生的博客 9226

SIMATIC S7-1200, S7-1500 PID 控制[手册]

SIMATIC S7-1200, S7-1500 PID 控制[手册]

android中AMS进程通知Zygote进程fork新进程的通信方式

AMS通知Zygote去fork进程的时候,使用的是socket的方式,而不是binder。我们都知道,安卓中跨进程的方式是binder,而为什么这里偏偏使用Socket呢?有点人会说LocalSocket本来就是用来本地进程间通讯的,这没错,但知其然更要知其所以然。

allen_xu_2012_new的博客 1276

IMSL CNL 7.0.0 (x86-64)Crack

IMSL CNL 7.0.0 (x86-64)Crack intel的算法库破解文件,这是C++版本的破解文件

zygoteinit.java_Zygote解析

一、Zygote简介init会创建Zygote进程,SystemServer进程和应用进程都是Zygote(孵化器)fock(复制进程)出来的。所以有必要了解下Zygote的流程。二、Zygote启动流程分析Zygote启动首先会调用ZygoteInit的main函数。frameworks/base/core/java/com/android/internal/os/ZygoteInit.java...

weixin_29031161的博客 785

Zygote进程的理解

Zygote进程是安卓系统的一个重要进程,由init进程创建而来;另外系统里的重要进程(system_server等)都是由zygote进程fork的,所有的app进程也是由zygote进程fork的。

cfc1243570631的专栏 553

ubuntu 20.04系统AOSP(Android 11)集成Frida

ubuntu 20.04系统AOSP(Android 11)集成Frida 参考 ubuntu 20.04编译Android 11源代码&模拟器 完成Android 11源代码的编译工作,保证能编译通过。 想自己手工编译Frida源代码的话,请参照下面: $ git clone https://github.com/frida/frida.git $ cd frida $ make $ export ANDROID_NDK_ROOT=/data/Android/android-sdk-linux/n

guyezhou51的博客 1699

android中AMS通知Zygote去fork进程为什么使用socket而不使用binder?

android中AMS通知Zygote去fork进程为什么使用socket而不使用binder? 通过综合各种文章的原理描述,加之源码的阅读以及实际的尝试,得出一个目前最为准确的答案。 本篇文章中给出的答案,一定和你看到的任何一个版本都不一样。.........

分享+记录 6414
上一篇: 学习C++的50条忠告(转载)
下一篇: Linux进程间通讯之消息队列
liranke
博客等级 码龄20年 4939粉丝 594原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

liranke

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值