Android14 - Zygote进程办了哪些大事

491 阅读7分钟

Zygote进程是Android系统中第一个Java进程,由init进程启动的时候创建。

在Android系统中,虚拟机(DVM、ATR),应用程序进程以及系统关键服务SystemServer进程都是由Zygote进程来创建的,它通过fork的形式(复制进程)来创建应用程序和SystemServer进程,由于Zygote进程在启动的时候会创建DVM或者ART虚拟机,因此通过fork而创建的应用程序和SystemServer进程可以在内部获取DVM或者ART的实例副本。

最开始Zygote进程名称为"app_process",在Andorid.bp文件中定义的,后来进程启动后,名称才换成的"zygote":

@frameworks/base/cmds/app_process/Android.bp
cc_binary {
    name: "app_process",

    srcs: ["app_main.cpp"],

    multilib: {
        lib32: {
            suffix: "32",
        },
        lib64: {
            suffix: "64",
        },
    },
    ...
}

Zygote启动脚本

Zygote启动脚本都放在system/core/rootdir/目录下,由import 语句将init.${ro.zygote}.rc文件引入init.rc文件中:

@system/core/rootdir/init.rc
import /system/etc/init/hw/init.${ro.zygote}.rc

init.rc根据ro.zygote的值来引入不同的文件:

  • init.zygote32.rc
  • init.zygote64.rc
  • init.zygote64_32.rc

位于init.${ro.zygote}.rc文件中的启动脚本定义:

@system/core/rootdir/init.zygote64.rc
service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server --socket-name=zygote
    //1
    class main
    ...

注释1定义zygote服务为main类型服务,系统在合适的时候会统一启动main类型的的服务:

@system/core/rootdir/init.rc
on nonencrypted
    class_start main
    class_start late_start

在init.rc文件中Action语句on nonencrypted触发class_start mainCommand语句,执行do_class_start函数,最终走到system/core/init/service.cpp#Start函数中去启动zygote服务:Android14 - init进程的启动过程这篇文章

@system/core/init/service.cpp#Start
Result<void> Service::Start() {
    ...
    //如果service已经在运行了,就不启动了
    if (flags_ & SVC_RUNNING) {
        if ((flags_ & SVC_ONESHOT) && disabled) {
            flags_ |= SVC_RESTART;
        }

        LOG(INFO) << "service '" << name_
                  << "' requested start, but it is already running (flags: " << flags_ << ")";

        // It is not an error to try to start a service that is already running.
        reboot_on_failure.Disable();
        return {};
    }

    ...
    //判断需要启动的service对应的执行文件是否存在,不存在则不启动
    struct stat sb;
    if (stat(args_[0].c_str(), &sb) == -1) {
        flags_ |= SVC_DISABLED;
        return ErrnoError() << "Cannot find '" << args_[0] << "'";
    }

    ...
    //根据参数创建子进程
    pid_t pid = -1;
    if (namespaces_.flags) {
        pid = clone(nullptr, nullptr, namespaces_.flags | SIGCHLD, nullptr);
    } else {
        pid = fork();
    }
    //当前代码逻辑在子进程中运行
    if (pid == 0) {
        umask(077);
        cgroups_activated.CloseWriteFd();
        setsid_finished.CloseReadFd();
        //最终执行execv函数,Service子进程被启动
        RunService(descriptors, std::move(cgroups_activated), std::move(setsid_finished));
        _exit(127);
    } else {
        cgroups_activated.CloseReadFd();
        setsid_finished.CloseWriteFd();
    }

    if (pid < 0) {
        pid_ = 0;
        return ErrnoError() << "Failed to fork";
    }

    ...

    return {};
}

Zygote启动过程

Zygote进程在init进程中通过fork函数创建而来:

fork函数

fork函数的被调用一次,可以返回两次结果,其返回值分为三种类型:

  • 如果出现错误,fork函数返回一个负数;
  • fork操作成功,当前代码所在进程为fork执行前的进程,返回值为子进程的进程ID;
  • fork操作成功,当前代码所在进程为fork出来的子进程,返回值为0;

因此我们可以通过返回值来判断当前进程是子进程还是父进程。

image.png

相当于fork后,出现了一个与当前进程代码一样的新进程,两个进程fork返回的fpid值不一样,程序可以根据fpid为0时,即表示当前程序位于新创建的子进程中,去执行属于子进程的逻辑,比如初始化子进程的事务。

Zygote在Native层

因此在上文Service的start函数中,通过fork函数创建Zygote进程后,在子进程Zygote中调用RunService函数,最终通过execv函数进入Zygote进程的入口main函数中,位于frameworks/base/cmds/app_process/app_main.cpp中,执行后续的进程初始化操作:

@frameworks/base/cmds/app_process/app_main.cpp#main
int main(int argc, char* const argv[])
{
    static const char ZYGOTE_NICE_NAME[] = "zygote64";

    while (i < argc) {
        const char* arg = argv[i++];
        //1
        if (strcmp(arg, "--zygote") == 0) {
            zygote = true;
            niceName = ZYGOTE_NICE_NAME;
        } else if (strcmp(arg, "--start-system-server") == 0) {
            startSystemServer = true;
        } else if (strcmp(arg, "--application") == 0) {
            application = true;
        } else if (strncmp(arg, "--nice-name=", 12) == 0) {
            niceName.setTo(arg + 12);
        } else if (strncmp(arg, "--", 2) != 0) {
            className.setTo(arg);
            break;
        } else {
            --i;
            break;
        }
    }
    ...
    if (!niceName.isEmpty()) {
        runtime.setArgv0(niceName.string(), true /* setProcName */);
    }
    
    if (zygote) {
        //2
        runtime.start("com.android.internal.os.ZygoteInit", args, zygote);
    } else if (!className.isEmpty()) {
        runtime.start("com.android.internal.os.RuntimeInit", args, zygote);
    } else {
        fprintf(stderr, "Error: no class name or --zygote supplied.\n");
        app_usage();
        LOG_ALWAYS_FATAL("app_process: no class name or --zygote supplied.");
    }
}

在zygote进程的启动脚本service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server --socket-name=zygote中,有参数--zygote,因此在注释1处解析参数后,在注释2处通过runtime的start函数进入ZygoteInit的main方法:

@frameworks/base/core/jni/AndroidRuntime.cpp?#start
void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote)
{
    ...
    /* start the virtual machine */
    JniInvocation jni_invocation;
    jni_invocation.Init(NULL);
    JNIEnv* env;
    //启动、创建Java虚拟机
    if (startVm(&mJavaVM, &env, zygote, primary_zygote) != 0) {
        return;
    }
    onVmCreated(env);

    /*
     *
     * 为JVM虚拟机注册JNI方法
     */
    if (startReg(env) < 0) {
        ALOGE("Unable to register all android natives\n");
        return;
    }

    /*
     * We want to call main() with a String array with arguments in it.
     * At present we have two arguments, the class name and an option string.
     * Create an array to hold them.
     */
    jclass stringClass;
    jobjectArray strArray;
    jstring classNameStr;

    stringClass = env->FindClass("java/lang/String");
    assert(stringClass != NULL);
    strArray = env->NewObjectArray(options.size() + 1, stringClass, NULL);
    assert(strArray != NULL);
    //根据前文可知此时className为com.android.internal.os.ZygoteInit
    classNameStr = env->NewStringUTF(className);
    assert(classNameStr != NULL);
    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);
    }

    //将className中的"."替换为"/"
    char* slashClassName = toSlashClassName(className != NULL ? className : "");
    //找打ZygoteInit
    jclass startClass = env->FindClass(slashClassName);
    if (startClass == NULL) {
        ALOGE("JavaVM unable to locate class '%s'\n", slashClassName);
        /* keep going */
    } else {
        //找到ZygoteInit的main方法
        jmethodID startMeth = env->GetStaticMethodID(startClass, "main",
            "([Ljava/lang/String;)V");
        if (startMeth == NULL) {
            ALOGE("JavaVM unable to find main() in '%s'\n", className);
            /* keep going */
        } else {
            //通过JNI调用ZygoteInit的main方法
            env->CallStaticVoidMethod(startClass, startMeth, strArray);
            
        }
    }

}

在AndroidRuntime的start方法中,先创建启动Java虚拟机,然后为虚拟机注册JNI方法,最后因为此时位于Native层,通过JNI方法进入ZygoteInit的main方法。从此Zygote便进入了Java框架层,可以说Zygote开创了Java框架层。

Zygote在Java框架层

@frameworks/base/core/java/com/android/internal/os/ZygoteInit.java#main
public static void main(String[] argv) {
    ZygoteServer zygoteServer = null;
    ...
    Runnable caller;
    try {
        // Store now for StatsLogging later.
        final long startTime = SystemClock.elapsedRealtime();
        //读取系统是否启动完成
        final boolean isRuntimeRestarted = "1".equals(
                SystemProperties.get("sys.boot_completed"));

        RuntimeInit.preForkInit();

        boolean startSystemServer = false;
        String zygoteSocketName = "zygote";
        String abiList = null;
        boolean enableLazyPreload = false;
        for (int i = 1; i < argv.length; i++) {
            if ("start-system-server".equals(argv[i])) {
                //从 AndroidRuntime.cpp 中传递上来,已经包含了 start-system-server
                //此时startSystemServer为ture
                startSystemServer = true;
            } 
            ...
        }

        final boolean isPrimaryZygote = zygoteSocketName.equals(Zygote.PRIMARY_SOCKET_NAME);
        ...
        if (!enableLazyPreload) {
            //1.预加载类和资源
            preload(bootTimingsTraceLog);
        }

        //2.实例化ZygoteServer,主要为了创建管理一个名为ANDROID_SOCKET_zygote的socket,用来等待AMS来请求Zygote来fork处新的应用进程。
        //因此AMS里启动的应用程序,都是由该socket进行处理并fork出子进程的。
        zygoteServer = new ZygoteServer(isPrimaryZygote);
        //默认为ture,用于启动SystemServer
        if (startSystemServer) {
            //3. fork出SystemServer进程并启动
            //在子进程中返回Runnable对象用于在SystemServer进程中去启动执行
            //在父进程中返回null
            Runnable r = forkSystemServer(abiList, zygoteSocketName, zygoteServer);

            if (r != null) {
                //4. 表示当前代码逻辑在子进程SystemServer中,运行Runnable,里面主要是通过反射找到并进入SystemServer的main方法
                r.run();
                return;
            }
        }

        //5. forkSystemServer返回null,进入zygoteServer的runSelectLoop开始while死循环,不断读取来自client端进程的请求(等待AMS的请求)
        caller = zygoteServer.runSelectLoop(abiList);
    } catch (Throwable ex) {
        Log.e(TAG, "System zygote died with fatal exception", ex);
        throw ex;
    } finally {
        //如果发生异常,关闭zygoteServer里面的socket
        if (zygoteServer != null) {
            zygoteServer.closeServerSocket();
        }
    }
    ...
}

注释1通过preload去预加载一些系统资源,包括类资源,文件资源,Graphics库等:

@frameworks/base/core/java/com/android/internal/os/ZygoteInit.java#preload
static void preload(TimingsTraceLog bootTimingsTraceLog) {

    preloadClasses();
    cacheNonBootClasspathClassLoaders();
    preloadResources();
    nativePreloadAppProcessHALs();

    maybePreloadGraphicsDriver();
    preloadSharedLibraries();
    preloadTextResources();
    ...

    sPreloadComplete = true;
}

注释2处构造ZygoteServer对象,在其构造方法中创建了名为ANDROID_SOCKET_zygote的socket:

@frameworks/base/core/java/com/android/internal/os/ZygoteServer.java#ZygoteServer
ZygoteServer(boolean isPrimaryZygote) {
    mUsapPoolEventFD = Zygote.getUsapPoolEventFD();

    //创建socket
    if (isPrimaryZygote) {
        mZygoteSocket = Zygote.createManagedSocketFromInitSocket(Zygote.PRIMARY_SOCKET_NAME);
        ...
    } 
    ...
}

注释3fork出SystemServer进程并启动,注释4主要是在SyetemServer进程进入frameworks/base/services/java/com/android/server/SystemServer.java:main()方法执行SystemServer的后续操作。注释5主要是为了让zygoteServer中的zygotesocket循环运行,等待client进程的请求后创建子进程(比如等待AMS的请求)。

Zygote进程在Java框架层主要做了3件事:

  • 预加载类和资源
  • 创建socket,等待其他进程的请求后创建新的应用程序进程
  • 启动SystemServer进程

总结

Zygote进程自init进程创建,主要做了以下几件事:

  1. 创建Java虚拟机并为Java虚拟机注册JNI方法。
  2. 通过JNI调用ZygoteInit的main方法,标识这Zygote从Native层进入Java框架层。
  3. 预加载类和资源
  4. 创建服务端socket,等待其他client端请求后创建新的应用程序进程。
  5. 启动SystemServer进程。