android 开机启动流程分析(11)Zygote启动分析

该系列文章总纲链接:专题分纲目录 android 开机启动流程分析


本章关键点总结 & 说明:

这里因为整体的导图太大,因此截取一部分 ,方便大家看的清楚:

同时,下面的图是开机启动流程分析 持续迭代的效果,可放大观看。

说明:思维导图是基于之前文章不断迭代的,本章内容我们关注➕"zygote"部分即可

1 Zygote启动分析

zygote的关键作用:从实现从native层到java层的调用,是由init进程根据init.rc文件中的配置项而创建的。

zygote名字的来历:zygote最初的名字叫app_process,这是在Android.mk文件中被指定的,但app_process在运行过程中通过Linux下的pctrl系统调用将自己的名字换成了zygote,所以我们通过ps命令看到的进程名是zygote。

1.1 解析zygote.rc

init进程启动后会解析zygote.rc,在文件中/system/core/rootdir/init.rc中包含了zygote.rc。其中${ro.zygote}是平台相关的参数,实际可对应到init.zygote32.rc, init.zygote64.rc, init.zygote64_32.rc, init.zygote32_64.rc,前两个只会启动单一app_process进程,而后两个则会启动两个app_process进程:第二个app_process进程称为secondary(有相应 secondary socket 的创建过程)。这里以 /system/core/rootdir/init.zygote32.rc 为例:

#import /init.${ro.zygote}.rc
service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
    class main
    socket zygote stream 660 root system
    onrestart write /sys/android_power/request_state wake
    onrestart write /sys/power/state on
    onrestart restart media
    onrestart restart netd

首先创建了名为zygote 的进程,这个进程是通过app_process的main 启动并以对应参数作为main的入口参数。

1.2 zygote启动

@1 zygote的原型app_process所对应的源文件是app_main.cpp,核心代码如下所示:

// Zygote进程由init通过fork而来,init.rc中设置的启动参数:
// -Xzygote/system/bin,--zygote,--start-system-server
int main(int argc, char* const argv[]) //这里argc=4,argv[0],argv[1],argv[2],argv[3]
{
    //...
    //参数的解析与处理1,start
    AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));
    
    argc--;//argc=3
    argv++;//argv变成argv[1],argv[2],argv[3]
    int i;
    for (i = 0; i < argc; i++) {
        if (argv[i][0] != '-') {
            break;
        }
        if (argv[i][1] == '-' && argv[i][2] == 0) {
            ++i; // Skip --.
            break;
        }
		//在option中添加参数 --zygote --start-system-server -Xzygote/system/bin
        runtime.addOption(strdup(argv[i]));
    }
    
    //解析参数,根据传递进来的参数值来初始化对应的bool类型变量
    bool zygote = false;
    bool startSystemServer = false;
    bool application = false;
    String8 niceName;
    String8 className;
    ++i;  // Skip unused "parent dir" argument.
    while (i < argc) {//判断参数中是否有这些选项
        const char* arg = argv[i++];
        if (strcmp(arg, "--zygote") == 0) {
            zygote = true;
            niceName = ZYGOTE_NICE_NAME;//将要设置的zygote别名
        } 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;
        }
    }
    
    Vector<String8> args;
    if (!className.isEmpty()) {
		//app mode,启动app时才不为空
        args.add(application ? String8("application") : String8("tool"));
        runtime.setClassNameAndArgs(className, argc - i, argv + i);
    } else {
        //zygote mode.初次进入,className为空,进这个分支
        maybeCreateDalvikCache();
        if (startSystemServer) {
            args.add(String8("start-system-server"));//args添加1项字符串
        }
        char prop[PROP_VALUE_MAX];
        if (property_get(ABI_LIST_PROPERTY, prop, NULL) == 0) {
            LOG_ALWAYS_FATAL("app_process: Unable to determine ABI list from property %s.",ABI_LIST_PROPERTY);
            return 11;
        }
        String8 abiFlag("--abi-list=");
        abiFlag.append(prop);//通过属性获取ABI-List
        args.add(abiFlag);//args添加1项字符串
        for (; i < argc; ++i) {
            args.add(String8(argv[i]));
        }
    }
    //参数的解析与处理1,end

    //AppRuntime类继承了AndroidRuntime类,重载了onStarted、onZygoteInit和onExit函数
    if (!niceName.isEmpty()) {
        runtime.setArgv0(niceName.string());
        set_process_name(niceName.string());//设置本进程名为zygote,是个“换名把戏”。
    }
    if (zygote) {
        //调用runtime的start,注意这里第二个参数args中包含SystemServer
        runtime.start("com.android.internal.os.ZygoteInit", args);
    } else if (className) {
        //调用runtime的start,注意这里第二个参数args中包含app启动相关参数
        runtime.start("com.android.internal.os.RuntimeInit", args);
    } else {
        app_usage();//不是zygote模式,也不是app模式
        return 10;
    }
}

zygote主要做了2件事情

  1. zygote模式下,初始化参数,调用runtime{实际上就是AndroidRuntime}的start方法启动java类
  2. app启动模式下,初始化参数,调用runtime{实际上就是AndroidRuntime}的start方法启动app进程

@2 runtime的start方法,分析其代码实现:

void AndroidRuntime::start(const char* className, const Vector<String8>& options)
{
    ...
	//创建虚拟机,关键点1,start
    JniInvocation jni_invocation;//这两句是在Android 4.4上出现的,在Android 4.0上,还没有它们
    jni_invocation.Init(NULL);// 初始化JNI接口
    JNIEnv* env;
    if (startVm(&mJavaVM, &env) != 0) {
        return;
    }
    onVmCreated(env);
    //创建虚拟机,关键点1,end
	
	//注册JNI函数,关键点2,start
    startReg(env)
    ...
    //注册JNI函数,关键点2,end
	//启动Java类,对于zygote模式是ZygoteInit类,关键点3,start
    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);
    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);
    }
    // Start VM. 该线程会成为VM的主线程, 主线程退出之前不会
    /**
      toSlashClassName
      将字符串“com.android.internal.os.ZygoteInit”中的“. ”换成“/”,
      变成了“com/android/internal/os/ZygoteInit”,这个名字符合JNI规范,
      后面简称为ZygoteInit类。
     */
    char* slashClassName = toSlashClassName(className);
    jclass startClass = env->FindClass(slashClassName);
    if (startClass == NULL) {
        ALOGE("JavaVM unable to locate class '%s'\n", slashClassName);
        /* keep going */
    } else {
		//找到ZygoteInit类的static main函数的jMethodId。
        jmethodID startMeth = env->GetStaticMethodID(startClass, "main",
            "([Ljava/lang/String;)V");
        if (startMeth == NULL) {
            ALOGE("JavaVM unable to find main() in '%s'\n", className);
        } else {
			//通过JNI调用Java函数,注意调用的函数是main,所属的类是com.android.internal.os.ZygoteInit,
            //传递的参数是“com.android.internal.os.ZygoteInit ”与args(包含systemServer),
            //调用ZygoteInit的main后,Zygote进入了Java世界!
            //也就是说,Zygote是开创Android系统中Java世界的盘古。
            env->CallStaticVoidMethod(startClass, startMeth, strArray);
        }
    }
    free(slashClassName);
    ALOGD("Shutting down VM\n");
    if (mJavaVM->DetachCurrentThread() != JNI_OK)
        ALOGW("Warning: unable to detach main thread\n");
    if (mJavaVM->DestroyJavaVM() != 0)
        ALOGW("Warning: VM did not shut down cleanly\n");
}

因为我们使用的是Android系统,所以已经定义了HAVE_ANDROID_OS宏,而且library参数为NULL,于是在JniInvocation的Init()函数中,会走到

property_get(kLibrarySystemProperty, default_library, kLibraryFallback);

kLibrarySystemProperty的定义是“persist.sys.dalvik.vm.lib”,这是个系统属性,它记录着系统实际需要用到的是哪种虚拟机(dalvik/ART)分别对应libdvm.so或libart.so。dlopen()之后会尝试加载libdvm.so或libart.so。这两个so中都export出了JNI_GetDefaultJavaVMInitArgs,JNI_CreateJavaVM和JNI_GetCreatedJavaVMs这三个接口函数。这里,我们找到了三个关键点,它们共同组成了开创Android系统中的Java世界。接下来对另外2个关键点进行详细的分析
@3 startVM{创建虚拟机}的代码实现如下所示:

int AndroidRuntime::startVm(JavaVM** pJavaVM, JNIEnv** pEnv)
{
    ...
    //这个函数绝大部分代码都是设置虚拟机的参数,我们只分析其中的两个。
    bool checkJni = false;
    property_get("dalvik.vm.checkjni", propBuf, "");
    if (strcmp(propBuf, "true") == 0) {
        checkJni = true;
    } else if (strcmp(propBuf, "false") != 0) {
        /* property is neither true nor false; fall back on kernel parameter */
        property_get("ro.kernel.android.checkjni", propBuf, "");
        if (propBuf[0] == '1') {
            checkJni = true;
        }
    }
    /**
      JNI check选项指的是native层调用JNI函数时系统做的一些检查
      检查工作比较耗时,一般是在eng版本中使用
      检查工作比较严格,一旦出错直接导致调用进程abort
     */
    if (checkJni) {
        addOption("-Xcheck:jni");// extended JNI checking
        addOption("-Xjnigreflimit:2000");//JNIcheck中的资源检查,系统中创建的Globalreference个数不能超过2000
    }
    ...
    parseRuntimeOption("dalvik.vm.heapstartsize", heapstartsizeOptsBuf, "-Xms", "4m");
    //设置虚拟机heapsize,默认为16MB。绝大多数厂商都会修改这个值,一般是32MB。
    //heapsize不能设置过小,否则在操作大尺寸的图片时无法分配所需内存。
    //parseRuntimeOption抓要是解析属性,将其加入到对应的Vector中
    parseRuntimeOption("dalvik.vm.heapsize", heapsizeOptsBuf, "-Xmx", "16m");
    // libart tolerates libdvm flags, but not vice versa, so only pass some options if libart.
    //判断是否为art模式启动
    property_get("persist.sys.dalvik.vm.lib.2", dalvikVmLibBuf, "libart.so");
    bool libart = (strncmp(dalvikVmLibBuf, "libart", 6) == 0);
    ...
    initArgs.version = JNI_VERSION_1_4;
    initArgs.options = mOptions.editArray();
    initArgs.nOptions = mOptions.size();
    initArgs.ignoreUnrecognized = JNI_FALSE;
    //调用JNI_CreateJavaVM创建虚拟机,pEnv返回当前线程的JNIEnv变量
    if (JNI_CreateJavaVM(pJavaVM, pEnv, &initArgs) < 0) {
        ALOGE("JNI_CreateJavaVM failed\n");
        goto bail;
    }
    result = 0;
bail:
    return result;
}

这里主要做了2件事情,初始化虚拟机参数,调用JNI_CreateJavaVM方法初始化虚拟机。
说明:关于dalvik虚拟机的参数见Dalvik/Docs/Dexopt.html中的说明。

@4 注册JNI函数startReg

因为后续Java程序用到的一些函数是采用native方式来实现的,所以才必须提前注册这些函数。startReg函数,代码如下所示:

static const RegJNIRec gRegJNI[] = {
    REG_JNI(register_com_android_internal_os_RuntimeInit),
    REG_JNI(register_android_os_SystemClock),
    ...
    REG_JNI(register_com_android_internal_net_NetworkStatsFactory),
};

int AndroidRuntime::startReg(JNIEnv* env)
{
    //设置Thread类的线程创建函数为javaCreateThreadEtc
    androidSetCreateThreadFunc((android_create_thread_fn) javaCreateThreadEtc);
    env->PushLocalFrame(200);
    //注册jni函数,gRegJNI是一个全局数组。
    /**
      register_jni_procs:
      仅仅是一个封装,调用gRegJNI数组中每个元素的mProc函数 
     */
    if (register_jni_procs(gRegJNI, NELEM(gRegJNI), env) < 0) {
        env->PopLocalFrame(NULL);
        return -1;
    }
    env->PopLocalFrame(NULL);
    //下面这句话应当是“码农”休闲时的小把戏。测试用的代码。
    //createJavaThread("fubar", quickTest, (void*)"hello");
    return 0;
}

这里注意:即mProc就是为Java类注册JNI函数。这里继续查看JNI注册函数的实现,一般代码如下:

int register_com_android_internal_os_RuntimeInit(JNIEnv* env)
{   //为android.internal.os.RuntimeInit类注册它所需要的JNI函数
    return jniRegisterNativeMethods(env, "com/android/internal/os/RuntimeInit", gMethods, NELEM(gMethods));
}

至此,虚拟机已创建好,JNI函数也已注册,下一步就要分析CallStaticVoidMethod了。

通过这个函数,我们将进入Android的Java世界。{说明:如果再次回到native世界,要么是挂了,要么重启。}

2 Zygote进入Java世界

CallStaticVoidMethod启动该java类,最终调用com.android.internal.os.ZygoteInit的main函数。代码如下所示:

public static void main(String argv[]) {
        try {
            ...
            registerZygoteSocket(socketName);//注册Zygote用的socket,关键点1
          EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,SystemClock.uptimeMillis());
 
            addBootEvent(new String("Zygote:Preload Start"));
            preload();//预加载类和资源,关键点2
            EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,SystemClock.uptimeMillis());
            SamplingProfilerIntegration.writeZygoteSnapshot();
            gc();// 强制一次垃圾收集
            addBootEvent(new String("Zygote:Preload End"));
            if (startSystemServer) { //我们传入的参数满足if分支
                startSystemServer(abiList, socketName);//关键点3,启动system_server进程
            }
            runSelectLoop(abiList);//关键点4,zygote调用这个函数,开始监听来自AMS的请求
            closeServerSocket();//关闭socket
        } catch (MethodAndArgsCaller caller) {
            caller.run();    //关键点5,如果有异常,会获取caller,很重要的caller run函数。见#2里SystemServer分析中
        } catch (RuntimeException ex) {
            Log.e(TAG, "Zygote died with exception", ex);
            closeServerSocket();
            throw ex;
        }
    }

接下来分别针对4个关键点进行分析

2.1 建立IPC通信服务端registerZygoteSocket

Zygote以及系统中其他程序的通信没有使用Binder,而是采用了基于AF_UNIX类型的Socket。
registerZygoteSocket函数的使命正是建立这个Socket。代码如下所示:

//只分析核心逻辑,省略部分代码
    private static void registerZygoteSocket(String socketName) {
        if (sServerSocket == null) {
            int fileDesc;
            final String fullSocketName = ANDROID_SOCKET_PREFIX + socketName;
            String env = System.getenv(fullSocketName);// 从环境变量的字符串中解析出文件描述符
            fileDesc = Integer.parseInt(env);
            //创建服务端Socket,这个Socket将listen并accept Client
            sServerSocket = new LocalServerSocket(createFileDescriptor(fileDesc));
        }
    }

2.2 预加载类和资源

preload的实现代码如下:

static void preload() {
        Log.d(TAG, "begin preload");
        Log.i(TAG1, "preloadMappingTable() -- start ");
        PluginLoader.preloadPluginInfo();
        Log.i(TAG1, "preloadMappingTable() -- end ");        
        preloadClasses();//类的预加载
        preloadResources();//资源的预加载
        preloadOpenGL();//openGL相关预加载相关
        preloadSharedLibraries();//共享库相关预加载相关
        // Ask the WebViewFactory to do any initialization that must run in the zygote process,
        // for memory sharing purposes.
        WebViewFactory.prepareWebViewInZygote();
        Log.d(TAG, "end preload");
    }

这里着重分析preloadClasses和preloadResources

2.2.1 preloadClasses的代码实现如下所示:

//只分析核心逻辑,省略部分代码
private static void preloadClasses() {
    final VMRuntime runtime = VMRuntime.getRuntime();
    InputStream is;
    //预加载类的信息存储在"/system/etc/preloaded-classes"文件中;
    is = new FileInputStream(PRELOADED_CLASSES);
    long startTime = SystemClock.uptimeMillis();
    // Drop root perms while running static initializers.
    setEffectiveGroup(UNPRIVILEGED_GID);
    setEffectiveUser(UNPRIVILEGED_UID);
    // Alter the target heap utilization.  With explicit GCs this's not likely to have any effect.
    float defaultUtilization = runtime.getTargetHeapUtilization();
    runtime.setTargetHeapUtilization(0.8f);
    // Start with a clean slate.
    System.gc();
    runtime.runFinalizationSync();
    int count = 0;
    try {
      BufferedReader br= new BufferedReader(new InputStreamReader(is), 256);
        String line;
      //循环读取文件的每一行,忽略#开头的注释行
        while ((line = br.readLine()) != null) {
            // Skip comments and blank lines.
            line = line.trim();
            if (line.startsWith("#") || line.equals("")) {
                continue;
            }
            Class.forName(line);  //通过Java反射来加载类,line中存储的是预加载的类名(每行读出来就是一个类名)
            if (Debug.getGlobalAllocSize() > PRELOAD_GC_THRESHOLD) {
                System.gc();
                runtime.runFinalizationSync();
            }
            count++;
        }
        Log.i(TAG, "...preloaded " + count + " classes in " + (SystemClock.uptimeMillis()-startTime) + "ms.");
    } finally {
        IoUtils.closeQuietly(is);
        // Restore default.
        runtime.setTargetHeapUtilization(defaultUtilization);
        // Fill in dex caches with classes, fields, and methods brought in by preloading.
        runtime.preloadDexCaches();
        Debug.stopAllocCounting();
        // Bring back root. We'll need it later.
        setEffectiveUser(ROOT_UID);
        setEffectiveGroup(ROOT_GID);
        addBootEvent(new String("Zygote:Preload "+ count + " classes in " +
        (SystemClock.uptimeMillis()-startTime)+ "ms"));
    }
}

preloadClasses看起来是如此简单,但是需要预先加载的类很多(在framework/base目录下),它是一个文本文件,内容如下:

# Classes which are preloaded bycom.android.internal.os.ZygoteInit.
# Automatically generated by frameworks/base/tools/preload/WritePreloadedClassFile.java.
# MIN_LOAD_TIME_MICROS=1250  //超时控制
android.R$styleable
android.accounts.AccountManager
android.accounts.AccountManager$4
android.accounts.AccountManager$6
android.accounts.AccountManager$AmsTask
android.accounts.AccountManager$BaseFutureTask
android.accounts.AccountManager$Future2Task
......//一共有3009行

特殊说明:

  1. preload_class文件由framework/base/tools/preload工具生成,它需要判断每个类加载的时间是否大于1250微秒。
  2. 超过这个时间的类就会被写到preload-classes文件中,最后由zygote预加载。
  3. preloadClass函数的执行时间比较长,这是导致Android系统启动慢的原因之一。

2.2.2 preloadResources的代码实现如下所示:

private static void preloadResources() {
    final VMRuntime runtime = VMRuntime.getRuntime();
    System.gc();
    runtime.runFinalizationSync();
    mResources = Resources.getSystem();
    mResources.startPreloading();
    if (PRELOAD_RESOURCES) {
        //与图片有关资源的获取和预加载
        TypedArray ar = mResources.obtainTypedArray(
                com.android.internal.R.array.preloaded_drawables);
        int N = preloadDrawables(runtime, ar);
        ar.recycle();
        //与颜色有关资源的获取和预加载
        ar = mResources.obtainTypedArray(
                com.android.internal.R.array.preloaded_color_state_lists);
        N = preloadColorStateLists(runtime, ar);
        ar.recycle();
    }
    mResources.finishPreloading();
    ...
}

@1 加载第一类资源需要调用preloadDrawables(),逐个加载TypedArray里记录的图片资源,preloadDrawables()的实现如下:

private static int preloadDrawables(VMRuntime runtime, TypedArray ar) {
    int N = ar.length();
    for (int i=0; i<N; i++) {
		...
        int id = ar.getResourceId(i, 0);//得到数组项对应的资源id了
		/**
          mResources是ZygoteInit的私有静态成员
		  getDrawable
		  ->loadDrawable(value, id, theme);加载drawable对象
		  -->cacheDrawable(value, theme, isColorDrawable, caches, key, dr)//缓存到本地
          到此,这些图片资源就都加载到ZygoteInit的mResources里了。  
		  */
        mResources.getDrawable(id, null);
	    ...
    }
    return N;
}

@2 加载第二类资源是颜色资源,是用preloadColorStateLists()加载的:

private static int preloadColorStateLists(VMRuntime runtime, TypedArray ar) {
    int N = ar.length();
    for (int i=0; i<N; i++) {
        ...
        int id = ar.getResourceId(i, 0);
        /**
		  mResources是ZygoteInit的私有静态成员
		  ->loadColorStateList(value, id);//加载colorstatelits对象
		  -->sPreloadedColorStateLists.put(key, csl);//缓存到本地
		  到此,这些颜色资源就都加载到ZygoteInit的mResources里了。 
          */
        mResources.getColorStateList(id);
        ...
    }
    return N;
}

preloadResources和preloadClass类似,都主要是加载framework-res.apk中的资源。

说明:在UI编程中常使用的com.android.R.XXX资源,是系统默认的资源,它们就是由Zygote加载的。

@3 preloadOpenGL主要是加载openGL相关。
@4 preloadSharedLibraries的代码实现如下所示:

private static void preloadSharedLibraries() {//加载各种各样的so库
    Log.i(TAG, "Preloading shared libraries...");
    System.loadLibrary("android");
    System.loadLibrary("compiler_rt");
    System.loadLibrary("jnigraphics");
}

2.3 启动system_server

这个函数会创建Java世界中系统Service所驻留的进程system_server,该进程是framework的核心。如果它挂了,就会导致zygote自杀重启。启动systen_server的代码如下所示:

private static boolean startSystemServer(String abiList, String socketName) throws MethodAndArgsCaller, RuntimeException {
        long capabilities = posixCapabilitiesAsBits(
            OsConstants.CAP_BLOCK_SUSPEND,
            ...
            OsConstants.CAP_SYS_TTY_CONFIG
        );
        //设置参数
        String args[] = {
            "--setuid=1000",
            "--setgid=1000",
            "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1032,3001,3002,3003,3006,3007",
            "--capabilities=" + capabilities + "," + capabilities,
            "--runtime-init",
            "--nice-name=system_server",//进程名,叫system_server
            "com.android.server.SystemServer", //启动的类名
        };
        ZygoteConnection.Arguments parsedArgs = null;
        int pid;
        try {
            //把上面字符串数组参数转换成Arguments对象parsedArgs。
            parsedArgs = new ZygoteConnection.Arguments(args);
            ZygoteConnection.applyDebuggerSystemProperty(parsedArgs);
            ZygoteConnection.applyInvokeWithSystemProperty(parsedArgs);
            /* Request to fork the system server process */
            pid = Zygote.forkSystemServer(//fork一个子进程,这个子进程就是system_server进程。 
                    ...
                    parsedArgs.effectiveCapabilities);
        } catch (IllegalArgumentException ex) {
            throw new RuntimeException(ex);
        }
        /* For child process */
        if (pid == 0) {pid为零,则表示处于子进程中,也就是处于system_server进程中
            if (hasSecondZygote(abiList)) {//hasSecondZygote 是针对 init.zygote64_32.rc, init.zygote32_64.rc 这两者情况的
                waitForSecondaryZygote(socketName);
            }
            handleSystemServerProcess(parsedArgs);system_server进程的工作,后面会单独分析
        }
        return true;
    }

Zygote进行了一次分裂,fork一个system_server子进程。同时,这里的args字符串详细内容如下所示:

2.4 等待请求runSelectLoop

在{第1个关键点处}registerZygoteSocket中注册了一个用于IPC的Socket,在这个runSelectLoop中体现出来,实现如下:

private static void runSelectLoop(String abiList) throws MethodAndArgsCaller {
    ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>();
    ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();
    FileDescriptor[] fdArray = new FileDescriptor[4];
	//sServerSocket是我们先前在registerZygoteSocket建立的Socket
    fds.add(sServerSocket.getFileDescriptor());
    peers.add(null);
    int loopCount = GC_LOOP_COUNT;
    while (true) {
        int index;
        if (loopCount <= 0) {
            gc();
            loopCount = GC_LOOP_COUNT;
        } else {
            loopCount--;
        }
        fdArray = fds.toArray(fdArray);
        //selectReadable内部调用select,使用多路复用I/O模型。当有客户端连接或有数据时,则selectReadable就会返回。
        index = selectReadable(fdArray);//返回-1表示错误,返回0表示fd不在监听的集合fd_set内,返回>0,表示fd在fd_set中
        
		if (index == 0) {
            //如有监听到一个客户端连接上,其客户端在Zygote的代表是ZygoteConnection
            ZygoteConnection newPeer = acceptCommandPeer(abiList);
            peers.add(newPeer);					 //添加peer对象
            fds.add(newPeer.getFileDescriptor());//将newPeer的fd添加fds的描述符集合中
        } else {
            boolean done;
            //客户端发送了请求,peers.get返回的是ZygoteConnection
            //后续处理将交给ZygoteConnection的runOnce函数完成。
            done = peers.get(index).runOnce(); //后面根据AMS数据来创建对象时会调用该方法
            
            if (done) {
                peers.remove(index);
                fds.remove(index);
            }
        }
    }
}

runSelectLoopMode实现的功能是:

  1. 处理客户连接和客户请求。其中客户在Zygote中用ZygoteConnection对象来表示。
  2. 客户的请求由ZygoteConnection的runOnce来处理。

3 Zygote的总结

Zygote是创建Android系统中Java世界的盘古,它创建了第一个Java虚拟机,且它成功创建了一个子进程system_server。回顾一下Zygote创建Java世界的步骤:

  1. 创建AppRuntime对象,并调用它的start。此后的活动则由AppRuntime来控制。
  2. 调用startVm创建Java虚拟机,然后调用startReg来注册JNI函数。
  3. 通过JNI调用com.android.internal.os.ZygoteInit类的main函数,从此进入了Java世界。
  4. 调用registerZygoteSocket。响应子孙后代的请求。同时Zygote调用preload来初始化Java世界。
  5. Zygote调用startSystemServer分裂一个子进程system_server来为Java世界服务。
  6. Zygote完成了Java世界的初创工作。下一步该做的就是调用runSelectLoopMode后一直等待子孙们的请求。

4 一个疑问?为啥zygote不使用binder机制和systemserver之间进行通信呢?

这里主要是怕父进程binder线程有锁,然后子进程的主线程一直在等其子线程(从父进程拷贝过来的子进程)的资源,但是其实父进程的子进程并没有被拷贝过来,造成死锁,所以fork不允许存在多线程。而非常巧的是Binder通讯偏偏就是多线程,所以干脆父进程(Zgote)这个时候就不使用binder线程。详细内容可以参照一篇比较好的文章,👇:为什么SystemServer进程与Zygote进程通讯采用Socket而不是Binder

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

图王大胜

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

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

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

打赏作者

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

抵扣说明:

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

余额充值