Framework学习(二)Zygote进程

一、概述

zygote,在英语中是受精卵的意思。而在Android系统中也有这么一个“受精卵进程” – Zygote进程。

在Android系统中,Zygote进程是所有Android进程的父进程。它通过fork的形式,创建SystemServer进程和应用程序进程。而Zygote进程则是通过linux系统的init进程启动的。

在Android系统中各种进程的启动过程:init进程 ––> Zygote进程 ––> SystemServer进程 ––>各种应用进程

其中,应用程序进程即我们编写的应用的进程,SystemServer进程为系统服务进程,比如后面还要学到的AMS、WMS都是在该进程中。

需要注意的是:

1、Android中所有的应用进程的创建都是一个应用进程通过Binder请求SystemServer进程,SystemServer进程发送socket消息给Zygote进程,统一由Zygote进程创建出来的。

2、Zygote进程在启动的时候会创建一个虚拟机实例,因此通过Zygote进程在父进程,创建的子进程都会继承这个虚拟机实例,App中的JAVA代码可以得到翻译执行。

3、进程与进程之间需要跨进程通信,由Zygote进程作为父进程还可以获得一个Binder线程池,这样进程之间就可以使用Binder进行跨进程通信了。

二、启动过程

/frameworks/base/cmds/app_process/app_main.cpp

192int main(int argc, char* const argv[])
193{
       ...
282    // Parse runtime arguments.  Stop at first unrecognized option.
283    bool zygote = false;
284    bool startSystemServer = false;
285    bool application = false;
286    String8 niceName;
287    String8 className;
288
289    ++i;  // Skip unused "parent dir" argument.
       //init.rc中会配置一些参数,这里进行比较设置一些变量走进不同的分支
290    while (i < argc) {
291        const char* arg = argv[i++];
292        if (strcmp(arg, "--zygote") == 0) {
               //启动的是Zygote进程
293            zygote = true;
294            niceName = ZYGOTE_NICE_NAME;
295        } else if (strcmp(arg, "--start-system-server") == 0) {
               //启动的是system-server进程
296            startSystemServer = true;
297        } else if (strcmp(arg, "--application") == 0) {
298            application = true;
299        } else if (strncmp(arg, "--nice-name=", 12) == 0) {
300            niceName.setTo(arg + 12);
301        } else if (strncmp(arg, "--", 2) != 0) {
302            className.setTo(arg);
303            break;
304        } else {
305            --i;
306            break;
307        }
308    }
309
       ...
       //设置一个“好听的名字” zygote,之前的名称是app_process
357    if (!niceName.isEmpty()) {
358        runtime.setArgv0(niceName.string(), true /* setProcName */);
359    }
360
361    if (zygote) {
             //通过runtime启动zygote
364        runtime.start("com.android.internal.os.ZygoteInit", args, zygote);
365    } else if (className) {
366        runtime.start("com.android.internal.os.RuntimeInit", args, zygote);
367    } else {
368        fprintf(stderr, "Error: no class name or --zygote supplied.\n");
369        app_usage();
370        LOG_ALWAYS_FATAL("app_process: no class name or --zygote supplied.");
371    }
372}

/frameworks/base/core/jni/AndroidRuntime.cpp

void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote)
1057{
1058    ALOGD(">>>>>> START %s uid %d <<<<<<\n",
1059            className != NULL ? className : "(unknown)", getuid());
1060
1061    static const String8 startSystemServer("start-system-server");
1062
1063    /*
1064     * 'startSystemServer == true' means runtime is obsolete and not run from
1065     * init.rc anymore, so we print out the boot start event here.
1066     */
1067    for (size_t i = 0; i < options.size(); ++i) {
1068        if (options[i] == startSystemServer) {
1069           /* track our progress through the boot sequence */
1070           const int LOG_BOOT_PROGRESS_START = 3000;
1071           LOG_EVENT_LONG(LOG_BOOT_PROGRESS_START,  ns2ms(systemTime(SYSTEM_TIME_MONOTONIC)));
1072        }
1073    }
1074
1075    const char* rootDir = getenv("ANDROID_ROOT");
1076    if (rootDir == NULL) {
1077        rootDir = "/system";
1078        if (!hasDir("/system")) {
1079            LOG_FATAL("No root directory specified, and /android does not exist.");
1080            return;
1081        }
1082        setenv("ANDROID_ROOT", rootDir, 1);
1083    }
1084
1085    //const char* kernelHack = getenv("LD_ASSUME_KERNEL");
1086    //ALOGD("Found LD_ASSUME_KERNEL='%s'\n", kernelHack);
1087
1088    /* start the virtual machine */
1089    JniInvocation jni_invocation;
1090    jni_invocation.Init(NULL);
1091    JNIEnv* env;
1092    if (startVm(&mJavaVM, &env, zygote) != 0) {
1093        return;
1094    }
1095    onVmCreated(env);
1096
1097    /*
1098     * Register android functions.
1099     */
1100    if (startReg(env) < 0) {
1101        ALOGE("Unable to register all android natives\n");
1102        return;
1103    }
1104
1105    /*
1106     * We want to call main() with a String array with arguments in it.
1107     * At present we have two arguments, the class name and an option string.
1108     * Create an array to hold them.
1109     */
1110    jclass stringClass;
1111    jobjectArray strArray;
1112    jstring classNameStr;
1113
1114    stringClass = env->FindClass("java/lang/String");
1115    assert(stringClass != NULL);
1116    strArray = env->NewObjectArray(options.size() + 1, stringClass, NULL);
1117    assert(strArray != NULL);
1118    classNameStr = env->NewStringUTF(className);
1119    assert(classNameStr != NULL);
1120    env->SetObjectArrayElement(strArray, 0, classNameStr);
1121
1122    for (size_t i = 0; i < options.size(); ++i) {
1123        jstring optionsStr = env->NewStringUTF(options.itemAt(i).string());
1124        assert(optionsStr != NULL);
1125        env->SetObjectArrayElement(strArray, i + 1, optionsStr);
1126    }
1127
1128    /*
1129     * Start VM.  This thread becomes the main thread of the VM, and will
1130     * not return until the VM exits.
1131     */
1132    char* slashClassName = toSlashClassName(className != NULL ? className : "");
1133    jclass startClass = env->FindClass(slashClassName);
1134    if (startClass == NULL) {
1135        ALOGE("JavaVM unable to locate class '%s'\n", slashClassName);
1136        /* keep going */
1137    } else {
1138        jmethodID startMeth = env->GetStaticMethodID(startClass, "main",
1139            "([Ljava/lang/String;)V");
1140        if (startMeth == NULL) {
1141            ALOGE("JavaVM unable to find main() in '%s'\n", className);
1142            /* keep going */
1143        } else {
1144            env->CallStaticVoidMethod(startClass, startMeth, strArray);
1145
1146#if 0
1147            if (env->ExceptionCheck())
1148                threadExitUncaughtException(env);
1149#endif
1150        }
1151    }
1152    free(slashClassName);
1153   //这行Log比较常见,因为其他应用进程也是由zygote 进程fork 出来的,所有其他进程也包含这段代码,如果其他进程在java 层crash,那么也会走到这里
1154    ALOGD("Shutting down VM\n");
1155    if (mJavaVM->DetachCurrentThread() != JNI_OK)
1156        ALOGW("Warning: unable to detach main thread\n");
1157    if (mJavaVM->DestroyJavaVM() != 0)
1158        ALOGW("Warning: VM did not shut down cleanly\n");
1159}

主要做了三件事情,1、调用startVm开启虚拟机,2、调用startReg注册JNI方法,3、使用JNI把Zygote进程启动起来。启动的类名为 com.android.internal.os.ZygoteInit,方法名为main。

frameworks/base/core/java/com/android/internal/os/ZygoteInit.java

public static void main(String argv[]) {
        //1、创建ZygoteServer
        ZygoteServer zygoteServer = new ZygoteServer();
        //此处开启设置,创建过程禁止多线程,为什么?后面会解答
        ZygoteHooks.startZygoteNoThreadCreation();
        ...
        try {
            ...
            //设置DDMS可用
            RuntimeInit.enableDdms();
            
            //初始化启动参数
            boolean startSystemServer = false;
            String socketName = "zygote";
            String abiList = null;
            boolean enableLazyPreload = false;
            // 2、解析app_main.cpp传来的参数
            for (int i = 1; i < argv.length; i++) {
                if ("start-system-server".equals(argv[i])) {
                    startSystemServer = true;
                } else if ("--enable-lazy-preload".equals(argv[i])) {
                    enableLazyPreload = true;
                } else if (argv[i].startsWith(ABI_LIST_ARG)) {
                    abiList = argv[i].substring(ABI_LIST_ARG.length());
                } else if (argv[i].startsWith(SOCKET_NAME_ARG)) {
                    socketName = argv[i].substring(SOCKET_NAME_ARG.length());
                } else {
                    throw new RuntimeException("Unknown command line argument: " + argv[i]);
                }
            }

            if (abiList == null) {
                throw new RuntimeException("No ABI list supplied.");
            }
            //3、创建一个Server端的Socket
            zygoteServer.registerServerSocketFromEnv(socketName);
            // In some configurations, we avoid preloading resources and classes eagerly.
            // In such cases, we will preload things prior to our first fork.
            if (!enableLazyPreload) {
                bootTimingsTraceLog.traceBegin("ZygotePreload");
                EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,
                    SystemClock.uptimeMillis());
               //4、预加载进程的资源和类
                preload(bootTimingsTraceLog);
                EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,
                    SystemClock.uptimeMillis());
                bootTimingsTraceLog.traceEnd(); // ZygotePreload
            } else {
                Zygote.resetNicePriority();
            }
            ...
            //此处关闭设置,允许多线程
            ZygoteHooks.stopZygoteNoThreadCreation();
                
            //5、fork一个SystemServer进程
            if (startSystemServer) {
                Runnable r = forkSystemServer(abiList, socketName, zygoteServer);
                if (r != null) {
                    r.run();
                    return;
                }
            }

           //6、启动一个死循环,监听socket,启动新的应用进程  
            caller = zygoteServer.runSelectLoop(abiList);
        } catch (Throwable ex) {
            Log.e(TAG, "System zygote died with exception", ex);
            zygoteServer.closeServerSocket();
            throw ex;
        } finally {
            zygoteServer.closeServerSocket();
        }
        if (caller != null) {
            caller.run();
         }
    }

总结一下,在main方法中主要完成了6件事:

  1. 创建ZygoteServer
  2. 解析app_main.cpp传来的参数,获取abi列表,获取scoket连接名称。(这里需要注意的是:android系统中进程之间通讯的方式是Binder,但是有一个例外是SystemService进程与Zygote进程之间是通过Socket的方式进行通讯的)
  3. 通过registerZygoteSocket函数,注册Socket,作为服务端,接受ActivityManagerService的请求来创建应用程序进程
  4. 预加载类和资源,包括颜色,R文件,drawable、类等
  5. 启动system_server进程,SystemServer进程会启动系统的关键服务
  6. 调用runSelectLoop函数监听socket来等待客户端请求

/frameworks/base/core/java/com/android/internal/os/ZygoteServer.java

void registerServerSocketFromEnv(String socketName) {
        if (mServerSocket == null) {
            int fileDesc;
            final String fullSocketName = ANDROID_SOCKET_PREFIX + socketName;
            try {
                //从环境变量中获取名为ANDROID_SOCKET_zygote的fd
                String env = System.getenv(fullSocketName);
                fileDesc = Integer.parseInt(env);
            } catch (RuntimeException ex) {
                throw new RuntimeException(fullSocketName + " unset or invalid", ex);
           }

            try {
                //创建一个FD对象
                FileDescriptor fd = new FileDescriptor();
                fd.setInt$(fileDesc);
                //不是使用IP和端口,这里用这个FD创建LocalServerSocket
                mServerSocket = new LocalServerSocket(fd);
                mCloseSocketFd = true;
           } catch (IOException ex) {
                throw new RuntimeException(
                        "Error binding to local socket '" + fileDesc + "'", ex);
            }
       }
}

注意,这时通过fd创建了一个socket服务端–LocalServerSocket。当Zygote进程将SystemServer进程启动后,就会在这个服务端的Socket上来等待ActivityManagerService请求Zygote进程来创建新的应用程序进程。

这里为什么是使用FD创建呢?LocalServerSocket具体是怎么创建的?

具体可以查看 -> https://www.jianshu.com/p/ab9b83a77af6

frameworks/base/core/java/com/android/internal/os/ZygoteInit.java

static void preload(TimingsTraceLog bootTimingsTraceLog) {
124        Log.d(TAG, "begin preload");
125        bootTimingsTraceLog.traceBegin("BeginIcuCachePinning");
126        beginIcuCachePinning();
127        bootTimingsTraceLog.traceEnd(); // BeginIcuCachePinning
128        bootTimingsTraceLog.traceBegin("PreloadClasses");
           //预加载类,在preloadClasses方法中会通过Class.forName将类加载到系统中,生成字节码
129        preloadClasses();
130        bootTimingsTraceLog.traceEnd(); // PreloadClasses
131        bootTimingsTraceLog.traceBegin("PreloadResources");
           //预加载资源文件
132        preloadResources();
133        bootTimingsTraceLog.traceEnd(); // PreloadResources
134        Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "PreloadAppProcessHALs");
135        nativePreloadAppProcessHALs();
136        Trace.traceEnd(Trace.TRACE_TAG_DALVIK);
137        Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "PreloadOpenGL");
138        preloadOpenGL();
139        Trace.traceEnd(Trace.TRACE_TAG_DALVIK);
           //预加载共享库
140        preloadSharedLibraries();
           //预加载文字资源
141        preloadTextResources();
142        // Ask the WebViewFactory to do any initialization that must run in the zygote process,
143        // for memory sharing purposes.
144        WebViewFactory.prepareWebViewInZygote();
145        endIcuCachePinning();
146        warmUpJcaProviders();
147        Log.d(TAG, "end preload");
148
149        sPreloadComplete = true;
150    }

从代码中,我们可以看到哪些资源会被进行预加载:类文件、资源文件、共享库、文字资源。总的来说,这些都是系统中App共享的资源。通过此时预加载,可以减少资源加载时间,加快了应用启动速度。

在preloadClasses()函数中,会通过Class.forName将类加载到系统中,生成字节码。此时预加载的类有哪些,可以查看清单:http://androidxref.com/8.0.0_r4/xref/frameworks/base/preloaded-classes

注意:这里预加载资源都是在主线程中完成的,为什么不开多线程呢?猜测是防止多线程带来的同步问题。所以才在ZygoteInit的方法中开启了禁止多线程的设置,完成后才关闭。

你可能感兴趣的:(Android,源码)