我就问你Zygote进程,你都干了啥

ZYGOTE

前言

OK,这是Android系统启动的第二篇文章。第二篇我们讲解一个我们一直都在用,但是却很少提起的进程---Zygote
提到Zygote可能了解一些的小伙伴会说,它是分裂进程用的。没错它最大的作用的确是分裂进程,但是它除了分裂进程外还做了什么呢。
还是老规矩,让我们抱着几个问题来看文章。最后在结尾,再对问题进行思考回复。

  1. 你能大概描述一遍Zygote的启动流程吗
  2. 我们为什么可以执行java代码,和zygote有什么关系
  3. Zygote到底都做了哪些事情

另外,我最近也看了一些写底层的文章。要么就是言简意赅到只知道Zygote的作用,但是完全不知道如何实现的,就像是背作文一样。要么是全篇都是代码,又臭又长,让人完全没有看下去的动力。

不过作为一个读者,太长的我可能完全不想看,太短的又真的完全就是被课文一点都不明白原理。

因此,本篇文章,仍旧会引入一些代码,方便大家通过代码方便记忆。但是又会将代码进行精简,以免给大家造成过度疲劳。我们的目的都是希望用最少的时间,能掌握更多的知识。

读源码时:不要过于纠结细节,不要过于纠结细节,不要过于纠结细节!重要的事情说三遍!!!

OK,让我们进入正题瞅瞅Zygote到底是个什么东西。


1.C++还是Java

选这个当标题当然是有原因的。我们知道的是Android系统启动的时候,运行的是Linux内核,执行的是C++代码。这是一个很有趣的事情。

因为我们在写App的时候,AndroidStudio默认给我们创建的都是Activity.java,而选择的语言,要么是Java要么就是Kotlin

启动时候运行的是C++代码,应用层却可以使用Java代码,这到底是为什么呢?其实这就是Zygote的功劳之一

2.Native层

Init进程创建Zygote时,会调用app_main.c的main() 方法。此时它依旧运行的是C++代码。我们通过下面的代码,来看下它到底做了什么。

这里它做的最关键的一件事就是启动AndroidRuntime(Android运行时)。,另外这里需要注意的是 start方法 中的 "com.android.internal.os.ZygoteInit" 这个类似于全类名。他到底是做什么的?别着急,大概2分钟后,你可能就会得到答案。

Zygote的新手村:app_main.cpp

int main(int argc, char* const argv[])
{
    //  创建Android运行时对象
    AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));
    // 代码省略...
    
    // 调用AppRuntime.start方法,
    // 而AppRuntime是AndroidRuntime的子类,并且没有重写start方法
    // 因此调用的是AndroidRuntime的start方法
    runtime.start("com.android.internal.os.ZygoteInit", args, zygote);
}

精简后的代码告诉我们,这里一共就做了两件事,第一件创建AppRuntime,第二件调用start方法。

不过,AppRuntimeAndroidRuntime的子类,他没有重写start方法,因此这里调用的是 AndroidRuntime的start() 方法。

奇迹的诞生地:AndroidRuntime:

这里我依旧只保留关键代码,源码关键注释也进行了保留。由下方代码看出这里做了三件改变命运的事情。

  1. startVM -- 启动Java虚拟机
  2. startReg -- 注册JNI
  3. 通过JNI调用Java方法,执行com.android.internal.os.ZygoteInit 的 main 方法
/*
 * Start the Android runtime. 
 */
void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote)
{
    /* start the virtual machine */
    JNIEnv* env;
    if (startVm(&mJavaVM, &env, zygote, primary_zygote) != 0) {
        return;
    }

    /*
     * Register android functions.
     */
    if (startReg(env) < 0) {
        ALOGE("Unable to register all android natives\n");
        return;
    }
    /*
     * Start VM.  This thread becomes the main thread of the VM, and will
     * not return until the VM exits.
     */
    jmethodID startMeth = env->GetStaticMethodID(startClass, "main","([Ljava/lang/String;)V");
    env->CallStaticVoidMethod(startClass, startMeth, strArray);
    }
}

有了JVM,注册了JNI,我们就可以执行Java代码了。

这里我个人建议不要过于纠结细节,比如JVM是如何创建的,JNI是如何注册的。如果感兴趣的童鞋,可以下载源码,到app_main.cpp里进行查看。这里就不进行赘述了。否则代码量太大,适得其反。


3.Java层

命运的十字路口:ZygoteInit.java:

之所以说是命运的十字路口,因为Zygote会在这里创建SystemServer,但是二者却走向了截然不同的道路。

从这里就开始执行Java代码了,当然这些Java代码是运行在JVM中的。

让我们通过代码来看一下,到底都做了些什么。

class ZygoteInit{

    /**
     * This is the entry point for a Zygote process.  It creates the Zygote server, loads resources,
     * and handles other tasks related to preparing the process for forking into applications.
     * This process is started with a nice value of -20 (highest priority).  
     */
     // 上面是源码中的注释,小伙伴们可以自行翻译一下。
     // 创建了ZygoteServer,加载资源,并且介绍了这个进程的优先级是最高的-20.
    public static void main(String argv[]) {
        ZygoteServer zygoteServer = null;

        // 1. 预加载资源,常用的:resource,class,library等在此处进行加载
        preload(bootTimingsTraceLog);
            
        // 2. 创建ZygoteServer,实际是一个Socket用来进行跨进程间通信用的。
        zygoteServer = new ZygoteServer(isPrimaryZygote);

        // 3. fork出SystemServer进程,这个进程会创建AMS,ATMS,WMS,电池服务等一切只有你想不到没有它做不到的服务
        forkSystemServer(abiList, zygoteSocketName, zygoteServer);

        // 4.里面是一个while(true)循环,等待接收AMS创建进程的消息,类似于handler中的Looper.loop()
        zygoteServer.runSelectLoop(abiList);
    }
}

上面代码里的注释基本说明了ZygoteInit都干了啥。下面会再稍微总结下:

  1. 创建了ZygoteServer:这是一个Socket相关的服务,目的是进行跨进程通信。
  2. 预加载preload:预加载相关的资源,
  3. 创建SystemServer进程:通过forkSystemServer分裂除了两个进程,一个Zygote进程,一个SystemServer进程。而且由于是分裂的,所以新分裂出来的进程也拥有虚拟机,也能调用JNI,也拥有预加载的资源,也会执行后续的代码。
  4. 执行runSelectLoop():内部是一个while(true)循环,等待AMS创建新的进程的消息。(想想Looper.loop())

4. 戛然而止

没错就是这么突然,Zygote的故事到这就结束了。至于它是如何创建SystemServer,如何去创建App那就是后面的故事了。所以你还记得我的问题嘛?我替你总结一下Zygote到底做了什么:

  1. 创建虚拟机
  2. 注册JNI
  3. 回调Java方法ZygoteInit.java 的main方法,从这儿开始运行Java代码
  4. 创建ZygoteServer,内部包含Socket用于跨进程通信
  5. 预加载class,resource,library等相关资源
  6. fork 出了 SystemServer进程。他俩除了返回的pid不同,剩下一模一样。通过返回值不同来决定剩下的代码如何运行。这个留待后续进行讲解。
  7. 进入while(true)循环等待,等待AMS创建进程的消息(类似于Looper.loop()

5. 多说一句

这个系列才刚刚进行到第二章,我尽量让文章不是特别长的情况下,既有代码整理思路,又有总结方便记忆。代码是源码中摘抄的省略了很大一部分,只能保证执行顺序。有兴趣的小伙伴可以下载源码进行查看。

其实最近我看了很多文章和视频,最后却选择写文章来对知识进行总结。归根结底就是因为一句话,好记性不如烂笔头。要是真的想快速记住,真的需要亲自查看一下源码。翻源码的同时,也是在不知不觉中锻炼你阅读源码的能力。 万一以后让你学习一个新的库,你也知道大概该怎么看。

都已经到这儿了,就稍微厚个脸皮,希望各位看官,能够点个赞加个关注。毕竟一篇文章可能就要耗费几个小时的时间,上一篇文章就几个赞,感谢这几个小伙伴,让我有继续写下去的动力。 真心感谢你们。

另外,文章中有哪里出错,请及时指出。毕竟各位才是真正的大佬。希望各位Androider,可以一起取暖,度过这个互联网寒冬!加油各位!!!


6. Zygote功能图

Zygote.png
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,332评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,508评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,812评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,607评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,728评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,919评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,071评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,802评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,256评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,576评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,712评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,389评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,032评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,798评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,026评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,473评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,606评论 2 350

推荐阅读更多精彩内容