Zygote 启动流程

283 阅读4分钟

当摁住电源键,引导芯片代码开始从固化在ROM中预定义的地方开始执行,加载引导程序Bootloader到RAM,然后执行引导程序。
Bootloader引导程序是Android操作系统被拉起来之前的一个程序,类似于window一样,它的作用就是把系统拉起运行起来,然后启动内核。
内核启动会设置缓存、被保护存储器、计划列表,加载驱动。当内核完成系统设置,它首先在系统文件中寻找”init”文件,然后启动init进程。

Init 进程解析init.rc脚本

Init 进程启动之后会挂载文件系统、再挂载相应的分区,启动SELinux安全策略,启动属性服务,解析init.rc脚本,并启动相应属性服务进程 。
zygote 进程的启动就在init.rc脚本中 。 源码点这 zygote64.rc image.png

  • service zygote: 表示 Zygote 进程是以服务的形式启动的
  • /system/bin/app_process64: 表示 Zygote 进程的应用程序文件
  • 后面四个选项表示 Zygote 进程的启动参数
    • –start-system-server: 表示在 Zygote 进程启动过程中, 需要启动 System 进程
  • socket zygote stream 660 root system: 表示 Zygote 进程启动过程中需要创建一个名为 zygote 的 Socket
    • 这个 Socket 的用于执行进程间的通信
    • 访问权限为 660 root system, 即所有用户都可以对它进行读写

调用Zygote 进程main方法

Zygote 的入口在 /system/bin/app_process64 目录下 , 最终会调用到 image.png\frameworks\base\cmds\app_process\app_main.cpp 中main方法 , main 方法中有个关键代码runtime.start("com.android.internal.os.ZygoteInit", args, zygote) , 通过runtime来启动zygote 。 image.pngruntime 为 AppRuntime , 继承自AndroidRuntime类,重载了AndroidRuntime类的onVmCreated()、onStarted()、onZygoteInit()和onExit()函数,是zygote进程处理时实际runtime入口。 AndroidRumtime主要功能:

  • 创建并启动JAVA虚拟机。
  • 注册JNI 方法 。
  • 开启JAVA世界。

AndroidRuntime#start 方法 , 创建JVM虚拟机并启动。

void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote)
{
 
    //创建jvm虚拟机
    JniInvocation jni_invocation;
    jni_invocation.Init(NULL);
    JNIEnv* env;
    if (startVm(&mJavaVM, &env, zygote) != 0) {
        return;
    }
    onVmCreated(env);

}

JniInvocation,是一个外部和虚拟机之间的一个中间层,是外部访问虚拟机的API接口,允许外部动态的调用虚拟机内部的实现。其主要实现如下功能: 指定加载的虚拟机。现在Android系统中有两种虚拟机:dalvik和art。现在已基本使用art虚拟机了。

我们再来看下对jni方法的处理,在AndroidRuntime 可以看到定义了很多jni方法。 image.png 我们来看下是怎么注册jni方法的 。 image.png 在jvm创建好之后,会调用startReg方法。

/*static*/ int AndroidRuntime::startReg(JNIEnv* env)
{
    androidSetCreateThreadFunc((android_create_thread_fn) javaCreateThreadEtc);

    ALOGV("--- registering native functions ---\n");

    env->PushLocalFrame(200);

    if (register_jni_procs(gRegJNI, NELEM(gRegJNI), env) < 0) {
        env->PopLocalFrame(NULL);
        return -1;
    }
    env->PopLocalFrame(NULL);


    return 0;
}

gRegJNI 为 上图定义的jni方法 , 调用register_jni_procs注册定义好的jni方法。

总结一下 : native的zygote 启动主要功能都交给AndroidRuntime 处理 ,AndroidRuntime 先创建JVM 虚拟机 , 然后注册JNI方法 。

完成了JVM的创建以及JNI方法注册 , 就可以去到JAVA的世界了 。 在AndroidRuntime#start 方法末尾。

void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote)
{

    
    JniInvocation jni_invocation;
    jni_invocation.Init(NULL);
    JNIEnv* env;
    if (startVm(&mJavaVM, &env, zygote) != 0) {
        return;
    }
    onVmCreated(env);


    if (startReg(env) < 0) {
        ALOGE("Unable to register all android natives\n");
        return;
    }


    jclass stringClass;
    jobjectArray strArray;
    jstring classNameStr;

    stringClass = env->FindClass("java/lang/String");
 
    strArray = env->NewObjectArray(options.size() + 1, stringClass, NULL);

    //className = com.android.internal.os.ZygoteInit
    classNameStr = env->NewStringUTF(className);
    
    env->SetObjectArrayElement(strArray, 0, classNameStr);

    for (size_t i = 0; i < options.size(); ++i) {
        jstring optionsStr = env->NewStringUTF(options.itemAt(i).string());
        assert(optionsStr != NULL);
        env->SetObjectArrayElement(strArray, i + 1, optionsStr);
    }


    char* slashClassName = toSlashClassName(className != NULL ? className : "");
    jclass startClass = env->FindClass(slashClassName);
    if (startClass == NULL) {
     
    } else {
        jmethodID startMeth = env->GetStaticMethodID(startClass, "main",
            "([Ljava/lang/String;)V");
        
        env->CallStaticVoidMethod(startClass, startMeth, strArray);

    }

}

env->CallStaticVoidMethod , 调用 java层 com.android.internal.os.ZygoteInit 的 main 方法 , 打开java世界的大门 , 我们来看下ZygoteInit的main方法 。

Java层ZygoteInit#main方法

ZygoteInit #main方法主要做三歩

  1. 创建用于通信的socket
  2. fork SystemServer 进程
  3. 调用runSelectLoopMode 沉睡 ,当接收到子孙后代的请求时,它会随时醒来,为它们工作,为它们创建一个进程。
public static void main(String argv[]) {
        ZygoteServer zygoteServer = null;

        ZygoteHooks.startZygoteNoThreadCreation();

        Runnable caller;
        try {
       
            final boolean isPrimaryZygote = zygoteSocketName.equals(Zygote.PRIMARY_SOCKET_NAME);

            //创建socket 服务端
            zygoteServer = new ZygoteServer(isPrimaryZygote);

            if (startSystemServer) {
                // fork system server 进程
                Runnable r = forkSystemServer(abiList, zygoteSocketName, zygoteServer);
                 
                // r == nul 表示在zygote进程中
                if (r != null) {
                    //在system_server进程中直接 return
                    r.run();
                    return;
                }
            }

            // 沉睡 ,等待唤醒
            caller = zygoteServer.runSelectLoop(abiList);
            
        } catch (Throwable ex) { 
            throw ex;
        } finally {
            if (zygoteServer != null) {
                //关闭socket
                zygoteServer.closeServerSocket();
            }
        }

        if (caller != null) {
            //在子进程中 , 并且退出了select loop执行
            caller.run();
        }
    }

SystemServer 进程的启动以后讲。

总结

Init 进程通过解析init.rc脚本在native层创建了Zygote进程 ,zygote在native层中创建java层需要的 JVM 虚拟机 和 注册了用于与Native层通信的JNI 方法, 最后调用zygote 在JAVA层的main 方法 。

zygote java 层的 main 方法中 初始化了用于通信的socket 服务端 ,然后 fork SystemServer进程并启动。 参考文章:

Android runtime机制(二)zygote进程的启动流程