精华内容
参与话题
问答
  • Zygote进程

    2019-01-22 15:11:26
    zygote是Android一个非常重要的进程,和init、systemServer进程这三个进程是Android系统非常重要的进程。 Linux的进程是通过fork产生,fork出来的进程除了一些核心数据结构和父进程不一样,其余的内存映像都是和父...

    Zygote简介

    zygote是Android一个非常重要的进程,和init、systemServer进程这三个进程是Android系统非常重要的进程。

    Linux的进程是通过fork产生,fork出来的进程除了一些核心数据结构和父进程不一样,其余的内存映像都是和父进程共享的。通常子进程fork出来后,会继续执行exec。exec将用一个新的可执行文件的内容替代当前进程的代码段、数据段、堆和栈。init进程启动各种service就是这样的。

    Zygote创建应用却只用了fork,没有调用exec。Android应用执行的是java代码,java代码的不同才造成了应用的区别,而对于java的环境要求却是一样的。

    Zygote初始化会创建虚拟机、同时把需要的系统类库和资源文件加载到内存里。zygote fork出子进程后,子进程也继承了能正常工作的虚拟机的各种系统资源,接下来子进程只需要装载apk文件中的字节码就可以运行了。

    在init.rc 中zygote是通过import /init.${ro.zygote}.rc引入的,有32位、64位之分,我们主要看下32位的。

    zygote是属于class main的当zygote重新启动 audioserver等一些service也会重启。

    service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
        class main
        priority -20
        user root
        group root readproc
        socket zygote stream 660 root system
        onrestart write /sys/android_power/request_state wake
        onrestart write /sys/power/state on
        onrestart restart audioserver
        onrestart restart cameraserver
        onrestart restart media
        onrestart restart netd
        onrestart restart wificond
        writepid /dev/cpuset/foreground/tasks
    

    app_process

    app_process的main函数

    这个函数主要就是解析启动参数。app_process除了能创建Zygote进程外、还能创建普通进程。我们从init.rc中传入的参数:

    -Xzygote /system/bin --zygote --start-system-server。

    最后niceName是zygote、startSystemServer是true zygote是true。

        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;
            } 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;
            }
        }

    如果启动参数有--zygote执行ZygoteInit类,否则执行通过参数传进来的Java类。

        if (zygote) {
            runtime.start("com.android.internal.os.ZygoteInit", args, zygote);
        } else if (className) {
            runtime.start("com.android.internal.os.RuntimeInit", args, zygote);
        }

    app_process除了能启动Zygote进程,也可以使用它来执行系统的某个java类,比如am命令。

    AndroidRuntime

    AndroidRuntime一个Android底层的一个类,负责启动虚拟机java线程。AndroidRuntime类在一个进程中只有一个实例对象。

    前面在app_process的main函数中最后调用了AndroidRuntime的start函数。这个函数主要启动虚拟机,然后通过CallStaticVoidMethod函数来调用java层的函数。这样Zygote的初始化过程转到了java层了。当然如果启动的不是Zygote而是执行的java类将是调用RuntimeInit函数。

    void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote)
    {
        ALOGD(">>>>>> START %s uid %d <<<<<<\n",
                className != NULL ? className : "(unknown)", getuid());
    
        static const String8 startSystemServer("start-system-server");
    
        /*
         * 'startSystemServer == true' means runtime is obsolete and not run from
         * init.rc anymore, so we print out the boot start event here.
         */
        for (size_t i = 0; i < options.size(); ++i) {
            if (options[i] == startSystemServer) {
               /* track our progress through the boot sequence */
               const int LOG_BOOT_PROGRESS_START = 3000;
               LOG_EVENT_LONG(LOG_BOOT_PROGRESS_START,  ns2ms(systemTime(SYSTEM_TIME_MONOTONIC)));
            }
        }
    
        const char* rootDir = getenv("ANDROID_ROOT");
        if (rootDir == NULL) {
            rootDir = "/system";
            if (!hasDir("/system")) {
                LOG_FATAL("No root directory specified, and /android does not exist.");
                return;
            }
            setenv("ANDROID_ROOT", rootDir, 1);
        }
    
        //const char* kernelHack = getenv("LD_ASSUME_KERNEL");
        //ALOGD("Found LD_ASSUME_KERNEL='%s'\n", kernelHack);
    
        /* start the virtual machine */
        JniInvocation jni_invocation;
        jni_invocation.Init(NULL);
        JNIEnv* env;
        if (startVm(&mJavaVM, &env, zygote) != 0) {
            return;
        }
        onVmCreated(env);
    
        /*
         * 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.
         */
        char* slashClassName = toSlashClassName(className != NULL ? className : "");
        jclass startClass = env->FindClass(slashClassName);
        if (startClass == NULL) {
            ALOGE("JavaVM unable to locate class '%s'\n", slashClassName);
            /* keep going */
        } else {
            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 {
                env->CallStaticVoidMethod(startClass, startMeth, strArray);
    
            }
        }

    ZygoteInit

    ZygoteInit类负责Zygote进程java层的初始化工作。这个类的main函数主要注册了zygote的socket来监听应用程序的启动消息,加载资源、启动systemserver、然后进入socket监听等。我们需要注意这个函数已经fork了一个system_server并且zygote主线程最后在执行runSelectLoop函数监听其他应用进程启动的消息。当有启动进程的socket消息,runSelectLoop函数就会返回,当然这个时候返回是在子进程中,zygote进程还是不听监控socket,最后通过返回的caller,然后执行器run函数。这样就到应用进程的ActivityThread的main函数了。

        public static void main(String argv[]) {
            ZygoteServer zygoteServer = new ZygoteServer();
    
            ......
    
            final Runnable caller;
            try {
                ......
    
                boolean startSystemServer = false;
                String socketName = "zygote";
                String abiList = null;
                boolean enableLazyPreload = false;
                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.");
                }
    
                zygoteServer.registerServerSocket(socketName);//注册socket监听,用来接收启动应用启动的消息
                // In some configurations, we avoid preloading resources and classes eagerly.
                // In such cases, we will preload things prior to our first fork.
                if (!enableLazyPreload) {
                    preload(bootTimingsTraceLog);//加载资源
    
                } else {
                    Zygote.resetNicePriority();
                }
    
                // Do an initial gc to clean up after startup
                bootTimingsTraceLog.traceBegin("PostZygoteInitGC");
                gcAndFinalize();
                bootTimingsTraceLog.traceEnd(); // PostZygoteInitGC
    
                bootTimingsTraceLog.traceEnd(); // ZygoteInit
                // Disable tracing so that forked processes do not inherit stale tracing tags from
                // Zygote.
                Trace.setTracingEnabled(false, 0);
    
                // Zygote process unmounts root storage spaces.
                Zygote.nativeUnmountStorageOnInit();
    
                // Set seccomp policy
                Seccomp.setPolicy();
    
                ZygoteHooks.stopZygoteNoThreadCreation();
    
                if (startSystemServer) {
                    Runnable r = forkSystemServer(abiList, socketName, zygoteServer);//启动systemserver进程
    
                    // {@code r == null} in the parent (zygote) process, and {@code r != null} in the
                    // child (system_server) process.
                    if (r != null) {
                        r.run();
                        return;
                    }
                }
    
                Log.i(TAG, "Accepting command socket connections");
    
                // The select loop returns early in the child process after a fork and
                // loops forever in the zygote.
                caller = zygoteServer.runSelectLoop(abiList);//监听socket消息,并且获取到java的函数入口,这里zygote会一直循环,能返回的都是fork出来的子进程
            } catch (Throwable ex) {
                Log.e(TAG, "System zygote died with exception", ex);
                throw ex;
            } finally {
                zygoteServer.closeServerSocket();
            }
    
            // We're in the child process and have exited the select loop. Proceed to execute the
            // command.
            if (caller != null) {
                caller.run();//这个时候在子进程中,一般调用ActivityThread的main方法了
            }
        }

    请求启动应用进程

    Android启动一个新的进程都是在AMS中通过其startProcessLocked函数来完成,这个我们在之前分析AMS的博客分析过了。

    这个函数最后会调用如下代码,而这个entryPoint就是android.app.ActivityThread

                    startResult = Process.start(entryPoint,
                            app.processName, uid, uid, gids, debugFlags, mountExternal,
                            app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,
                            app.info.dataDir, invokeWith, entryPointArgs);

    而最后是调用了ZygotePrcocess的startViaZygote函数,这个函数又调用了zygoteSendArgsAndGetResult函数,而zygoteSendArgsAndGetResult这个函数把会这些参数通过socket传给zygote,而我们现在的进程就是system_server。

    然后我们再来看zygote进程的ZygoteInit类中main方法调用的runSelectLoop方法来监听和处理启动应用的消息。

    这个函数当有事件到来才会唤醒线程,然后调用ZygoteConnection的processOneCommand分析。最后这个函数返回的是子进程的函数入口的Runnable接口。

        Runnable runSelectLoop(String abiList) {
            ......
            while (true) {
                StructPollfd[] pollFds = new StructPollfd[fds.size()];
                for (int i = 0; i < pollFds.length; ++i) {
                    pollFds[i] = new StructPollfd();
                    pollFds[i].fd = fds.get(i);
                    pollFds[i].events = (short) POLLIN;
                }
                try {
                    Os.poll(pollFds, -1);
                } catch (ErrnoException ex) {
                    throw new RuntimeException("poll failed", ex);
                }
                for (int i = pollFds.length - 1; i >= 0; --i) {
                    if ((pollFds[i].revents & POLLIN) == 0) {
                        continue;
                    }
    
                    if (i == 0) {
                        ZygoteConnection newPeer = acceptCommandPeer(abiList);
                        peers.add(newPeer);
                        fds.add(newPeer.getFileDesciptor());
                    } else {
                        try {
                            ZygoteConnection connection = peers.get(i);
                            final Runnable command = connection.processOneCommand(this);
    
                            if (mIsForkChild) {
                                // We're in the child. We should always have a command to run at this
                                // stage if processOneCommand hasn't called "exec".
                                if (command == null) {
                                    throw new IllegalStateException("command == null");
                                }
    
                                return command;//子进程就返回函数入口
                            } else {
                                // We're in the server - we should never have any commands to run.
                                if (command != null) {
                                    throw new IllegalStateException("command != null");
                                }
    
                                // We don't know whether the remote side of the socket was closed or
                                // not until we attempt to read from it from processOneCommand. This shows up as
                                // a regular POLLIN event in our regular processing loop.
                                if (connection.isClosedByPeer()) {
                                    connection.closeSocket();
                                    peers.remove(i);
                                    fds.remove(i);
                                }
                            }
                        } catch (Exception e) {
                            ......
                        }
                    }
                }
            }
        }
    }
    

    processOneCommand最后调用了Zygote.forkAndSpecialize来fork了应用进程。这里我们先主要看handleChildProc函数,这里主要是调用了ZygoteInit.zygoteInit函数。

            pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids,
                    parsedArgs.debugFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo,
                    parsedArgs.niceName, fdsToClose, fdsToIgnore, parsedArgs.instructionSet,
                    parsedArgs.appDataDir);//fork子进程
    
            try {
                if (pid == 0) {
                    // in child
                    zygoteServer.setForkChild();
    
                    zygoteServer.closeServerSocket();
                    IoUtils.closeQuietly(serverPipeFd);
                    serverPipeFd = null;
    
                    return handleChildProc(parsedArgs, descriptors, childPipeFd);//子进程初始化
                } else {
                    // In the parent. A pid < 0 indicates a failure and will be handled in
                    // handleParentProc.
                    IoUtils.closeQuietly(childPipeFd);
                    childPipeFd = null;
                    handleParentProc(pid, descriptors, serverPipeFd);
                    return null;

    而这个函数中调用了nativeZygoteInit主要是初始化binder,而在applicationInit中就是返回了应用进程的函数入口(也就是ActivityThread的main函数)。

        public static final Runnable zygoteInit(int targetSdkVersion, String[] argv, ClassLoader classLoader) {
            if (RuntimeInit.DEBUG) {
                Slog.d(RuntimeInit.TAG, "RuntimeInit: Starting application from zygote");
            }
    
            Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ZygoteInit");
            RuntimeInit.redirectLogStreams();
    
            RuntimeInit.commonInit();
            ZygoteInit.nativeZygoteInit();
            return RuntimeInit.applicationInit(targetSdkVersion, argv, classLoader);
        }

    我们再回到ZygoteInit的main函数,前面runSelectLoop返回的话肯定是子进程,而caller就是子进程的函数入口,后面调用caller的run函数就进入应用进程的ActivtityThread的main函数了。而Zygote的主进程依然在runSelectLoop中循环。

                caller = zygoteServer.runSelectLoop(abiList);
            } catch (Throwable ex) {
                Log.e(TAG, "System zygote died with exception", ex);
                throw ex;
            } finally {
                zygoteServer.closeServerSocket();
            }
    
            // We're in the child process and have exited the select loop. Proceed to execute the
            // command.
            if (caller != null) {
                caller.run();
            }

    预加载系统类和资源

    为了加快应用程序的启动,Android把系统常用的java类和一部分Framework资源在zygote进程中预加载。这些预加载的类和资源在所有经zygote进程fork出的子进程中都是共享的。

    前面我们在ZygoteInit的main中调用preload方法来加载系统资源,比如系统类,系统资源、opengl资源、共享库、webview资源等。

        static void preload(TimingsTraceLog bootTimingsTraceLog) {
            preloadClasses();
            preloadResources();
            nativePreloadAppProcessHALs();
            preloadOpenGL();
            preloadSharedLibraries();
            preloadTextResources();
            WebViewFactory.prepareWebViewInZygote();
        }

     

    展开全文
  • Android6.0 Zygote进程

    千次阅读 2016-08-20 13:16:45
    Android Zygote进程

    背景
    从字面上看,zygote是受精卵的意思,它的主要工作就是进行细胞分裂。

    在Android中,zygote的行为就如同受精卵一样,在系统发出请求时,负责分裂出其它的进程。

    Android为什么要这么设计呢?

    要知道从受精卵分裂出来的细胞,将继承受精卵的DNA。这些细胞只需要按照规则复制DNA就行了,而不需要重新思考DNA应该怎么排序。

    大概也可以按照这个思路来理解zygote进程吧。

    zygote进程启动时,将在内部启动Dalvik虚拟机,注册JNI函数,继而加载一些必要的系统资源和必要类等,然后进入到监听状态。

    在后续的运作中,当其它系统模块希望创建新进程时,只需向zygote进程发出请求。zygote进程监听到该请求后,会相应地“分裂”出新的进程。

    于是新创建出的进程,从一开始就具有了自己的Dalvik虚拟机以及一些必要的系统资源。这将减少每个进程启动消耗的时间。进一步来说,由于fork的copy-on-write策略,zygote的这种分裂方式还有可能减少系统整体内存的占用。

    版本
    android 6.0

    主要流程分析
    在分析init进程时,我们知道init进程会解析init.rc文件,然后加载对应的进程。zygote就是以这种方式,被init进程加载的。

    在system/core/rootdir/init.rc中,可以看到:

    import /init.${ro.zygote}.rc
    

    从import的文件命名方式,我们可以看出在不同的平台(32、64及64_32)上,init.rc将包含不同的zygote.rc文件。不同的zygote.rc内容大致相同,主要区别体现在启动的是32位,还是64位的进程。

    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
        writepid /dev/cpuset/foreground/tasks
    

    以上是init.zygote32.rc中的内容。

    从init.zygote32.rc可以看出,zygote实际上对应于app_process进程,对应源文件为frameworks/base/cmds/app_process/app_main.cpp,其main函数对应的传入参数为:–zygote, --start-system-server 。

    这里需要补充说明的是:
    1、在init.zygote64.rc中,启动的进程为app_process64;在init.zyote64_32.rc中,会启动两个进程,分别为app_process64和app_process32(目前,不太清楚这种设置的实际含义)。
    2、从zyote的rc文件,我们可以看到zygote启动的时候,创建了一个socket(后文将介绍这个socket)。

    接下来我们按照zygote进程启动涉及文件的先后顺序,一起来看看zygote的主要工作情况。

    1、app_main.cpp
    首先从入口文件app_main.cpp的main函数开始分析。

    int main(int argc, char* const argv[])
    {
    	//AppRuntime定义于app_main.cpp中,继承自AndroidRuntime
    	//个人感觉该对象就是对Android运行时环境的一种抽象
    	AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));
    	..........
    	//开始解析输入参数
    	while (i < argc) {
            const char* arg = argv[i++];
            if (strcmp(arg, "--zygote") == 0) {
                //init.zygote.rc中定义了该字段
                zygote = true;
                //记录app_process进程名的nice name,即zygote
                niceName = ZYGOTE_NICE_NAME;
            } else if (strcmp(arg, "--start-system-server") == 0) {
    	        //init.zygote.rc中定义了该字段
                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()) {
    		//启动zygote时,class name is empty,不进入该分支
    		........
    	} else {
    		//创建dalvikCache所需的目录,并定义权限
    		maybeCreateDalvikCache();
    		
    		if (startSystemServer) {
    			//增加参数
                args.add(String8("start-system-server"));
            }
    		.........
    		for (; i < argc; ++i) {
    			//将main函数未处理的参数都递交给下个调用函数处理
                args.add(String8(argv[i]));
            }
    	}
    	
    	if (!niceName.isEmpty()) {
    		//将app_process的进程名,替换为zygote
            runtime.setArgv0(niceName.string());
            set_process_name(niceName.string());
        }
    	
    	if (zygote) {
    		//调用Runtime的start函数
            runtime.start("com.android.internal.os.ZygoteInit", args, zygote);
        } else if (className) {
    	    //启动zygote没有进入这个分支,但这个分支说明,通过配置init.rc文件,其实是可以不通过zygote来启动一个进程
            runtime.start("com.android.internal.os.RuntimeInit", args, zygote);
        } else {
            ...............
        }
    }
    

    由于AppRuntime继承自AndroidRuntime,且没有重写start方法,因此zygote的流程进入到了AndroidRuntime.cpp。

    2、AndroidRuntime.cpp
    我们一起来看看在AndroidRuntime的start函数中,进行了哪些重要操作:

    void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote) {
    	.........
        JniInvocation jni_invocation;
        jni_invocation.Init(NULL);
        JNIEnv* env;
        //创建虚拟机,其中大多数参数由系统属性决定
        //最终,startVm利用JNI_CreateVM创建出虚拟机
        if (startVm(&mJavaVM, &env, zygote) != 0) {
            return;
        }
    	...........
    	//注册JNI函数
    	if (startReg(env) < 0) {
            ALOGE("Unable to register all android natives\n");
            return;
        }
        ......
    

    ==以下非主干部分

    我们先来看看startReg具体是在干什么。

    int AndroidRuntime::startReg(JNIEnv* env) {
    	..........
    	if (register_jni_procs(gRegJNI, NELEM(gRegJNI), env) < 0) {
            env->PopLocalFrame(NULL);
            return -1;
        }
    	........
    }
    

    从上述代码可以看出,startReg函数中主要是通过register_jni_procs来注册JNI函数。

    其中,gRegJNI是一个全局数组,该数组的定义类似于:

    static const RegJNIRec gRegJNI[] = {
        REG_JNI(register_android_util_SeempLog),
        REG_JNI(register_com_android_internal_os_RuntimeInit),
        REG_JNI(register_android_os_SystemClock),
        REG_JNI(register_android_util_EventLog),
        ............
    

    其中,REG_JNI的宏定义及RegJNIRec结构体的定义为:

    #ifdef NDEBUG
        #define REG_JNI(name)      { name }
        struct RegJNIRec {
            int (*mProc)(JNIEnv*);
        };
    #else
        #define REG_JNI(name)      { name, #name }
        struct RegJNIRec {
            int (*mProc)(JNIEnv*);
            const char* mName;
        };
    #endif
    

    根据宏定义可以看出,宏REG_JNI将得到函数名;定义RegJNIRec数组时,函数名被赋值给RegJNIRec结构体,于是每个函数名被强行转换为函数指针。

    明白宏及数组的定义后,我们再回头来看register_jni_procs的定义:

    static int register_jni_procs(const RegJNIRec array[], size_t count, JNIEnv* env)
    {
        for (size_t i = 0; i < count; i++) {
            if (array[i].mProc(env) < 0) {
    #ifndef NDEBUG
                ALOGD("----------!!! %s failed to load\n", array[i].mName);
    #endif
                return -1;
            }
        }
        return 0;
    }
    

    结合前面的分析,容易知道register_jni_procs函数,实际上就是调用函数指针对应的函数,以进行实际的JNI函数注册。

    我们随意举个例子,看看register_android_util_SeempLog被调用时的情况:

    /*
     * JNI registration.
     */
    static JNINativeMethod gMethods[] = {
        /* name, signature, funcPtr */
        { "seemp_println_native",  "(ILjava/lang/String;)I",
                (void*) android_util_SeempLog_println_native },
    };
    
    int register_android_util_SeempLog(JNIEnv* env)
    {
        jclass clazz = env->FindClass("android/util/SeempLog");
        if (clazz == NULL) {
            return -1;
        }
    
        return AndroidRuntime::registerNativeMethods(env, "android/util/SeempLog", gMethods, NELEM(gMethods));
    }
    

    可以看到,这实际上是自己定义JNI函数并进行动态注册的标准写法。

    int AndroidRuntime::registerNativeMethods(JNIEnv* env, const char* className, const JNINativeMethod* gMethods, int numMethods)
    {
        return jniRegisterNativeMethods(env, className, gMethods, numMethods);
    }
    

    最后,还是利用jniRegisterNativeMethods进行实际的注册工作。

    ==以上非主干部分

    在介绍完AndroidRuntime.cpp中注册JNI的工作后,我们将思路拉回到它的start函数。

    	........
    	//将"com.android.internal.os.ZygoteInit"替换为"com/android/internal/os/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的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 {
    	        //调用ZygoteInit的main函数
                env->CallStaticVoidMethod(startClass, startMeth, strArray);
    		........
    

    当调用ZygoteInit.java的main函数后,zygote进程进入了java世界。

    其实我们仔细想一想,就会觉得zygote的整个流程实际上是非常符合实际情况的。

    在Android中,每个进程都运行在对应的虚拟机上,因此zygote首先就负责创建出虚拟机。

    然后,为了反射调用java代码,必须有对应的JNI函数,于是zygote进行了JNI函数的注册。

    当一切准备妥当后,zygote进程才进入到了java世界。

    3、ZygoteInit.java

     public static void main(String argv[]) {
    	try {
    		.........
    		String socketName = "zygote";
    		.........
    		//注册server socket
    		registerZygoteSocket(socketName);
    		.........
    		//预加载
    		preload();
    		.........
    		if (startSystemServer) {
    			//启动system server
    			startSystemServer(abiList, socketName);
    		}
    
    		//zygote进程进入无限循环,处理请求
    		runSelectLoop(abiList);
    
    		closeServerSocket();
    	} catch (MethodAndArgsCaller caller) {
    		//通过反射调用新进程函数的地方
    		//后续介绍新进程启动时,再介绍
    		caller.run();
        } catch (RuntimeException ex) {
    		closeServerSocket();
    		throw ex;
    	}
    }
    

    上面是ZygoteInit的main函数的主干部分,接下来我们进一步分析它们的主要工作。

    3.1 创建server socket

    private static void registerZygoteSocket(String socketName) {
    	if (sServerSocket == null) {
    		int fileDesc;
    		//此处的socket name,就是zygote
    		final String fullSocketName = ANDROID_SOCKET_PREFIX + socketName;
    		try {
    			//记得么?在init.zygote.rc被加载时,就会创建一个名为zygote的socket
    			String env = System.getenv(fullSocketName);
    			fileDesc = Integer.parseInt(env);
    		} catch (RuntimeException ex) {
    			throw new RuntimeException(fullSocketName + " unset or invalid", ex);
    		}
    
    		try {
    			FileDescriptor fd = new FileDescriptor();
    			//获取zygote socket的文件描述符
    			fd.setInt$(fileDesc);
    			//将zygote socket包装成一个server socket
    			sServerSocket = new LocalServerSocket(fd);
    		} catch (IOException ex) {
    			throw new RuntimeException("Error binding to local socket '" + fileDesc + "'", ex);
    		}
    	}
    }
    

    zygote进程与系统中其它进程的通信没有使用Binder,而是采用了基于AF_UNIX类型的socket。(实际上,在这个时候Binder根本无法使用)。

    3.2 预加载

    static void preload() {
    	Log.d(TAG, "begin preload");
    	//读取文件framework/base/preloaded-classes,然后通过反射加载对应的类
    	//需要加载数千个类,启动慢的原因之一
    	preloadClasses();
    	//负载加载一些常用的系统资源
    	preloadResources();
    	//图形相关的
    	preloadOpenGL();
    	//一些必要库
    	preloadSharedLibraries();
    	//好像是语言相关的字符信息
    	preloadTextResources();
    	// 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");
    }
    

    为了让系统实际运行时更加流畅,在zygote启动时候,调用preload函数进行了一些预加载操作。

    Android 通过zygote fork的方式创建子进程。zygote进程预加载这些类和资源,在fork子进程时,仅需要做一个复制即可。

    这样可以节约子进程的启动时间。同时,根据fork的copy-on-write机制可知,有些类如果不做改变,甚至都不用复制,子进程可以和父进程共享这部分数据,从而省去不少内存的占用。

    3.3 启动SystemServer进程

    private static boolean startSystemServer(String abiList, String socketName) {
    	//准备capabilities参数
    	........
    	String args[] = {
    		"--setuid=1000",
    		"--setgid=1000",
            "--setgroups=.........",
            "--capabilities=" + capabilities + "," + capabilities,
            "--nice-name=system_server",
            "--runtime-args",
            "com.android.server.SystemServer",
        };
        ZygoteConnection.Arguments parsedArgs = null;
    
    	int pid;
    
    	try {
    		//将上面准备的参数,按照ZygoteConnection的风格进行封装
    		parsedArgs = new ZygoteConnection.Arguments(args);
    		...........
    
    		//通过fork"分裂"出system server,具体的过程在介绍system server时再分析
    		/* Request to fork the system server process */
    		pid = Zygote.forkSystemServer(
    			parsedArgs.uid, parsedArgs.gid,
    			parsedArgs.gids,
                parsedArgs.debugFlags,
                null,
                parsedArgs.permittedCapabilities,
                parsedArgs.effectiveCapabilities);
    	} catch (IllegalArgumentException ex) {
    		throw new RuntimeException(ex);
    	}
    	
    	if (pid == 0) {
    		............
    		//pid = 0, 在进程system server中
    		//system server进程处理自己的工作
    		handleSystemServerProcess(parsedArgs);
    	}
    
        return true;
    }
    

    3.4 处理请求信息

    创建出SystemServer进程后,zygote进程利用函数runSelectLoop,处理server socket收到的命令。

    private static void runSelectLoop(String abiList) throws MethodAndArgsCaller {
    	ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>();
        ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();
    
    	//首先将server socket加入到fds
        fds.add(sServerSocket.getFileDescriptor());
        peers.add(null);
    
    	while (true) {
    		StructPollfd[] pollFds = new StructPollfd[fds.size()];
    		for (int i = 0; i < pollFds.length; ++i) {
    			pollFds[i] = new StructPollfd();
    			pollFds[i].fd = fds.get(i);
    			//关注事件到来
    			pollFds[i].events = (short) POLLIN;
            }
    		try {
    			//等待事件到来
    			Os.poll(pollFds, -1);
    		} catch (ErrnoException ex) {
    			throw new RuntimeException("poll failed", ex);
    		}
    		//注意这里是倒序的
    		for (int i = pollFds.length - 1; i >= 0; --i) {
    			if ((pollFds[i].revents & POLLIN) == 0) {
    				continue;
    			}
    			//server socket最先加入fds, 因此这里是server socket收到数据
    			if (i == 0) {
    			    //收到新的建立通信的请求,建立通信连接
    				ZygoteConnection newPeer = acceptCommandPeer(abiList);
    				//加入到peers和fds
    				peers.add(newPeer);
    				fds.add(newPeer.getFileDesciptor());
    			 } else {
    				//其它通信连接收到数据,runOnce执行对应命令
    				boolean done = peers.get(i).runOnce();
    				if (done) {
    					//对应通信连接不再需要执行其它命令,关闭并移除
    					peers.remove(i);
                        fds.remove(i);
                    }
    			}
    		}
    	}
    }
    

    从上面代码可知,初始时,fds中仅有server socket,因此当有数据到来时,将执行i等于0的分支。
    此时,显然是需要创建新的通信连接,因此acceptCommandPeer将被调用。

    private static ZygoteConnection acceptCommandPeer(String abiList) {
    	try {
    		return new ZygoteConnection(sServerSocket.accept(), abiList);
    	} catch (IOException ex) {
    		throw new RuntimeException("IOException during accept()", ex);
        }
    }
    

    acceptCommandPeer封装了socket的accpet函数。于是我们知道,对应的新的连接,zygote将会创建出一个新的socket与其通信,并将该socket加入到fds中。因此,一旦通信连接建立后,fds中将会包含有多个socket。

    当poll监听到这一组sockets上有数据到来时,就会从阻塞中恢复。于是,我们需要判断到底是哪个socket收到了数据。

    在runSelectLoop中采用倒序的方式轮询,由于server socket第一个被加入到fds,因此最后轮询到的socket才需要处理新建连接的操作;其它socket收到数据时,仅需要调用zygoteConnection的runonce函数执行数据对应的操作。

    若一个连接处理完所有对应消息后,该连接对应的socket和连接等将被移除。

    socket编程中,accept()调用主要用在基于连接的套接字类型,比如SOCK_STREAM和SOCK_SEQPACKET。
    它提取出所监听套接字的等待连接队列中第一个连接请求,创建一个新的套接字,并返回指向该套接字的文件描述符。
    新建立的套接字不在监听状态,原来所监听的套接字的状态也不受accept()调用的影响。

    结束语
    以上是自己对zygote进程的一些初步分析,我们知道了zygote如何由init进程加载后,一步一步地进入到java世界。由于经验原因,自己的分析难免存在纰漏和不够详细的地方,欢迎大家指正。

    展开全文
  • 原文地址:... Android系统启动流程 Android系统启动过程往细了说可以分为5步: Loader --》Kernel --》Native --》Framework --》Application Loader ...Boot ROM: 当手机处于关机状态时,长按Power键...

    原文地址:https://blog.csdn.net/qq_30993595/article/details/82714409

    Android系统启动流程

    Android系统启动过程往细了说可以分为5步:
    Loader --》Kernel --》Native --》Framework --》Application

    Loader

    Boot ROM: 当手机处于关机状态时,长按Power键开机,引导芯片开始从固化在ROM里的预设出代码开始执行,然后加载引导程序到RAM
    Boot Loader:这是启动Android系统之前的引导程序,主要是检查RAM,初始化硬件参数等功能

    Kernel

    Kernel层是指Android内核层,到这里才刚刚开始进入Android系统

    启动Kernel的swapper进程(pid=0):该进程又称为idle进程, 系统初始化过程Kernel由无到有开创的第一个进程, 用于初始化进程管理、内存管理,加载Display,Camera Driver,Binder Driver等相关工作
    启动kthreadd进程(pid=2):是Linux系统的内核进程,会创建内核工作线程kworkder,软中断线程ksoftirqd,thermal等内核守护进程。kthreadd进程是所有内核进程的鼻祖

    Native

    这里的Native层主要包括init孵化来的用户空间的守护进程、HAL层以及开机动画等。启动init进程(pid=1),是Linux系统的用户进程,init进程是所有用户进程的鼻祖

    init进程会孵化出ueventd、logd、healthd、installd、adbd、lmkd等用户守护进程
    init进程还启动servicemanager(binder服务管家)、bootanim(开机动画)等重要服务
    init进程孵化出Zygote进程,Zygote进程是Android系统的第一个Java进程(即虚拟机进程),Zygote是所有Java进程的父进程

    Framework

    Zygote进程启动后,加载ZygoteInit类,注册Zygote Socket服务端套接字;加载虚拟机;加载类,加载系统资源
    System Server进程,是由Zygote进程fork而来,System Server是Zygote孵化的第一个进程,System Server负责启动和管理整个Java framework,包含ActivityManager,PowerManager等服务
    Media Server进程,是由init进程fork而来,负责启动和管理整个C++ framework,包含AudioFlinger,Camera Service等服务
    Application

    Zygote进程孵化出的第一个App进程是Launcher,即手机桌面APP,没错,手机桌面就是跟我们平时使用的APP一样,它也是一个应用
    所有APP进程都是由zygote进程fork出来的
    这些层之间,有的并不能直接交流,比如Native与Kernel之间要经过系统调用才能访问,Java层和Native层需要通过JNI进行调用

    严格来说,Android系统实际上是运行于Linux内核上的一系列服务进程,这些进程是维持设备正常运行的关键,而这些进程的老祖宗就是init进程

    init进程

    上面也介绍到了,当内核启动完成后,就会创建用户空间的第一个进程,即init进程;后面所有的进程,比如Binder机制中的ServiceManager,Zygote都是由init进程孵化出来的

    启动

    当init进程启动后会调用/system/core/init/Init.cpp的main()方法
     

    int main(int argc, char** argv) {
        ...
        
        klog_init();  //初始化kernel log,位于设备节点/dev/kmsg
        klog_set_level(KLOG_NOTICE_LEVEL); //设置输出的log级别
        // 输出init启动阶段的log
        NOTICE("init%s started!\n", is_first_stage ? "" : " second stage");
        
        property_init(); //创建一块共享的内存空间,用于属性服务
        signal_handler_init();  //初始化子进程退出的信号处理过程
    
        property_load_boot_defaults(); //加载default.prop文件
        start_property_service();   //启动属性服务器(通过socket通信)
        init_parse_config_file("/init.rc"); //解析init.rc文件
    
        //执行rc文件中触发器为 on early-init的语句
        action_for_each_trigger("early-init", action_add_queue_tail);
        //等冷插拔设备初始化完成
        queue_builtin_action(wait_for_coldboot_done_action, "wait_for_coldboot_done");
        queue_builtin_action(mix_hwrng_into_linux_rng_action, "mix_hwrng_into_linux_rng");
        //设备组合键的初始化操作
        queue_builtin_action(keychord_init_action, "keychord_init");
        // 屏幕上显示Android静态Logo 
        queue_builtin_action(console_init_action, "console_init");
        
        //执行rc文件中触发器为 on init的语句
        action_for_each_trigger("init", action_add_queue_tail);
        queue_builtin_action(mix_hwrng_into_linux_rng_action, "mix_hwrng_into_linux_rng");
        
        char bootmode[PROP_VALUE_MAX];
        //当处于充电模式,则charger加入执行队列;否则late-init加入队列。
        if (property_get("ro.bootmode", bootmode) > 0 && strcmp(bootmode, "charger") == 0) {
           action_for_each_trigger("charger", action_add_queue_tail);
        } else {
           action_for_each_trigger("late-init", action_add_queue_tail);
        }
        //触发器为属性是否设置
        queue_builtin_action(queue_property_triggers_action, "queue_property_triggers");
         
        while (true) {
            if (!waiting_for_exec) {
                execute_one_command();
                restart_processes(); 
            }
            int timeout = -1;
            if (process_needs_restart) {
                timeout = (process_needs_restart - gettime()) * 1000;
                if (timeout < 0)
                    timeout = 0;
            }
            if (!action_queue_empty() || cur_action) {
                timeout = 0;
            }
    
            epoll_event ev;
            //循环 等待事件发生
            int nr = TEMP_FAILURE_RETRY(epoll_wait(epoll_fd, &ev, 1, timeout));
            if (nr == -1) {
                ERROR("epoll_wait failed: %s\n", strerror(errno));
            } else if (nr == 1) {
                ((void (*)()) ev.data.ptr)();
            }
        }
        return 0;
    }
    

    这里很重要的一句话就是init_parse_config_file,然后去解析init.rc文件,init.rc位于/bootable/recovery/etc/init.rc;需要注意的是这就是一个脚本文件,就像Android打包用到的gradle脚本一样

    rc文件规则
    这个文件解析具体实现在init_parser.cpp文件中,一个完整的init.rc脚本由四种类型的声明组成

    Action(动作)
    Commands(命令)
    Service(服务)
    Options(选项)
    rc文件有一些通用的语法规则

    注释以 # 开头
    关键字和参数以空格分割,每个语句以行为单位
    C语言风格的反斜杠转义字符("")可以用来为参数添加空格
    为了防止字符串中的空格把其切割成多个部分,我们需要对其使用双引号
    行尾的反斜杠用来表示下面一行是同一行
    Actions和Service暗示着下一个新语句的开始,这两个关键字后面跟着的commands或者options都属于这个新语句
    ActionsService有唯一的名字,如果出现和已有Actions和Service重名的会被当做错误而忽略
    Actions
    Actions代表一些Action,Action代表一组命令(Commands),每个Action都有一个trigger(触发器),这个触发器决定了在什么情况下执行该Action中定义的命令;当一些条件满足触发器的条件时,该Action中定义的命令会被添加到“命令执行队列”的尾部,如果命令已经存在了就不会再添加了

    Action的格式如下

    on <trgger> ## on后面接触发条件
       <command1> ## 命令1
       <command2> ## 命令2
       <command3> ## 命令3
       ...
    

    不同的脚本用【on】来区分,on后面跟一个触发器,当被触发时,下面的命令就会以此执行

    常用的有以下几种事件触发器

    类型                      说明
    -------------------------------------------------
    boot                    init.rc被装载后触发
    device-added-<path>     当设备节点添加时触发
    device-removed-<path>   当设备节点移除时触发
    service-exited-<name>   在指定的服务(service)退出时触发
    early-init              init程序初始化之前触发
    late-init               init程序初始化之后触发
    init                    初始化时触发(在 /init.conf (启动配置文件)被装载之后)
    

    Commands


    exec< path>[< argument>]* :fork并执行一个程序,其路径为< path>,这条命令将阻塞直到该程序启动完成
    ifup< interface>:使网络接口< interface>成功连接
    chdir< directory>:更改工作目录< directory>
    chmod< octal-mode>< path>:更改文件访问权限
    chroot< directory>:更改根目录位置
    class_start< serviceclass>:启动由< serviceclass>类名指定的所有相关服务,如果它们不在运行状态的话
    class_stop< serviceclass>:停止所有由< serviceclass>类名指定的服务,如果它们还在运行的话
    domainname< name>:设置域名
    start< service>:启动一个服务,如果没有运行
    stop< service>:停止一个服务,如果还在运行
    sysclktz< mins_west_of_gmt>:设置基准时间
    write< path>< String>[< String>]*:打开一个文件,写入一个或者多个String
    Service
    Service其实是一个可执行程序,以service开头的脚本,在特定选项的约束下会被init程序启动或者重启(Service可以在配置中指定是否需要在退出时重启,这样当Service出现crash时就可以有机会复原)

    脚本格式如下

    service <name> <pathname> [ <argument> ]*
        <option>
        <option>
        ...
    
    • service开头表明这是一个可执行程序
    • < name> 表示服务名
    • < pathname> 此服务所在路径,因为是可执行文件,所以肯定有存储路径
    • < argument> 启动Service所带的参数
    • < option> 对service的设置的选项

    Options


    可用选项如下,也就是上面Service所用到的< option>

    critical:表明这是对设备至关重要的一个服务,如果它在四分钟内退出超过四次,则设备进入恢复模式
    disabled:此服务不会自动启动,而是需要显示调用服务名来启动
    socket< name>< type>< perm>[< user>[< group>] ]:创建一个名为/dev/socket/< name>的unix domain socket,然后将它的fd值传给启动它的进程;有效的< type>值包括dgram,stream,seqpacket,而user和group默认值是0
    user< username>:在启动服务前将用户切换至< username>,默认情况下用户都是root
    group< groupname>[< groupname>]*:在启动服务前将用户组切换至< groupname>]
    oneshot:当该服务退出时,不要主动去重启它
    class< name>:为该服务指定一个class名,同一个class的所有服务必须同时启动或者停止,默认情况下< name>值是default
    onrestart:当此服务重启时执行某些命令

    init.rc文件
     

    # Copyright (C) 2012 The Android Open Source Project
    #
    # IMPORTANT: Do not create world writable files or directories.
    # This is a common source of Android security bugs.
    #
    
    "【import <filename>一个init配置文件,扩展当前配置。】"
    import /init.environ.rc
    import /init.usb.rc
    import /init.${ro.hardware}.rc
    import /init.${ro.zygote}.rc
    import /init.trace.rc
    
    "【触发条件early-init,在early-init阶段调用以下行】"
    on early-init
        # Set init and its forked children's oom_adj.
        write /proc/1/oom_score_adj -1000
        "【打开路径为<path>的一个文件,并写入一个或多个字符串】"
        # Apply strict SELinux checking of PROT_EXEC on mmap/mprotect calls.
        write /sys/fs/selinux/checkreqprot 0
    
        # Set the security context for the init process.
        # This should occur before anything else (e.g. ueventd) is started.
        "【这段脚本的意思是init进程启动之后就马上调用函数setcon将自己的安全上下文设置为“u:r:init:s0”,即将init进程的domain指定为init。】"
        setcon u:r:init:s0
    
        # Set the security context of /adb_keys if present.
        "【恢复指定文件到file_contexts配置中指定的安全上线文环境】"
        restorecon /adb_keys
    
        "【执行start ueventd的命令。ueventd是一个service后面有定义】 "
        start ueventd
    
        "【mkdir <path> [mode] [owner] [group]   //创建一个目录<path>,可以选择性地指定mode、owner以及group。如果没有指定,默认的权限为755,并属于root用户和root组。】"
        # create mountpoints
        mkdir /mnt 0775 root system
    
    on init
        "【设置系统时钟的基准,比如0代表GMT,即以格林尼治时间为准】"
        sysclktz 0
    
    "【设置kernel日志等级】"
    loglevel 6 ####
        write /proc/bootprof "INIT: on init start" ####
    
        "【symlink <target> <path>    //创建一个指向<path>的软连接<target>。】"
        # Backward compatibility
        symlink /system/etc /etc
        symlink /sys/kernel/debug /d
    
        # Right now vendor lives on the same filesystem as system,
        # but someday that may change.
        symlink /system/vendor /vendor
    
        "【创建一个目录<path>,可以选择性地指定mode、owner以及group。】"
        # Create cgroup mount point for cpu accounting
        mkdir /acct
        mount cgroup none /acct cpuacct
        mkdir /acct/uid
    
        "【mount <type> <device> <dir> [ <mountoption> ]   //在目录<dir>挂载指定的设备。<device> 可以是以 mtd@name 的形式指定一个mtd块设备。<mountoption>包括 ro、rw、remount、noatime、 ...】"
        # Create cgroup mount point for memory
        mount tmpfs none /sys/fs/cgroup mode=0750,uid=0,gid=1000
        mkdir /sys/fs/cgroup/memory 0750 root system
        mount cgroup none /sys/fs/cgroup/memory memory
        write /sys/fs/cgroup/memory/memory.move_charge_at_immigrate 1
        "【chown <owner> <group> <path>   //改变文件的所有者和组。】"
    
        "【后面的一些行因为类似,就省略了】"
        .....
    
    # Healthd can trigger a full boot from charger mode by signaling this
    # property when the power button is held.
    on property:sys.boot_from_charger_mode=1
        "【停止指定类别服务类下的所有已运行的服务】"
        class_stop charger
        "【触发一个事件,将该action排在某个action之后(用于Action排队)】"
        trigger late-init
    
    # Load properties from /system/ + /factory after fs mount.
    on load_all_props_action
        "【从/system,/vendor加载属性。默认包含在init.rc】"
        load_all_props
    
    # Indicate to fw loaders that the relevant mounts are up.
    on firmware_mounts_complete
        "【删除指定路径下的文件】"
        rm /dev/.booting
    
    # Mount filesystems and start core system services.
    on late-init
        "【触发一个事件。用于将一个action与另一个 action排列。】"
        trigger early-fs
        trigger fs
        trigger post-fs
        trigger post-fs-data
    
        # Load properties from /system/ + /factory after fs mount. Place
        # this in another action so that the load will be scheduled after the prior
        # issued fs triggers have completed.
        trigger load_all_props_action
    
        # Remove a file to wake up anything waiting for firmware.
        trigger firmware_mounts_complete
    
        trigger early-boot
        trigger boot
    
    
    on post-fs
        ...
        "【一些创造目录,建立链接,更改权限的操作,这里省略】"
    
    on post-fs-data
        ...
        "【一些创造目录,建立链接,更改权限的操作,这里省略】"
    
        "【恢复指定文件到file_contexts配置中指定的安全上线文环境】"
        restorecon /data/mediaserver
    
        "【将系统属性<name>的值设置为<value>,即以键值对的方式设置系统属性】"
        # Reload policy from /data/security if present.
        setprop selinux.reload_policy 1
    
        "【以递归的方式恢复指定目录到file_contexts配置中指定的安全上下文中】"
        # Set SELinux security contexts on upgrade or policy update.
        restorecon_recursive /data
    
        # If there is no fs-post-data action in the init.<device>.rc file, you
        # must uncomment this line, otherwise encrypted filesystems
        # won't work.
        # Set indication (checked by vold) that we have finished this action
        #setprop vold.post_fs_data_done 1
    
    on boot
        "【初始化网络】"
        # basic network init
        ifup lo
        "【设置主机名为localhost】"
        hostname localhost
        "【设置域名localdomain】"
        domainname localdomain
    
        "【设置资源限制】"
        # set RLIMIT_NICE to allow priorities from 19 to -20
        setrlimit 13 40 40
    
        "【这里省略了一些chmod,chown,等操作,不多解释】"
       ...
    
    
        # Define default initial receive window size in segments.
        setprop net.tcp.default_init_rwnd 60
    
        "【重启core服务】"
        class_start core
    
    on nonencrypted
        class_start main
        class_start late_start
    
    on property:vold.decrypt=trigger_default_encryption
        start defaultcrypto
    
    on property:vold.decrypt=trigger_encryption
        start surfaceflinger
        start encrypt
    
    on property:sys.init_log_level=*
        loglevel ${sys.init_log_level}
    
    on charger
        class_start charger
    
    on property:vold.decrypt=trigger_reset_main
        class_reset main
    
    on property:vold.decrypt=trigger_load_persist_props
        load_persist_props
    
    on property:vold.decrypt=trigger_post_fs_data
        trigger post-fs-data
    
    on property:vold.decrypt=trigger_restart_min_framework
        class_start main
    
    on property:vold.decrypt=trigger_restart_framework
        class_start main
        class_start late_start
    
    on property:vold.decrypt=trigger_shutdown_framework
        class_reset late_start
        class_reset main
    
    on property:sys.powerctl=*
        powerctl ${sys.powerctl}
    
    # system server cannot write to /proc/sys files,
    # and chown/chmod does not work for /proc/sys/ entries.
    # So proxy writes through init.
    on property:sys.sysctl.extra_free_kbytes=*
        write /proc/sys/vm/extra_free_kbytes ${sys.sysctl.extra_free_kbytes}
    
    # "tcp_default_init_rwnd" Is too long!
    on property:sys.sysctl.tcp_def_init_rwnd=*
        write /proc/sys/net/ipv4/tcp_default_init_rwnd ${sys.sysctl.tcp_def_init_rwnd}
    
    "【守护进程】"
    ## Daemon processes to be run by init.
    ##
    service ueventd /sbin/ueventd
        class core
        critical
        seclabel u:r:ueventd:s0
    
    "【日志服务进程】"
    service logd /system/bin/logd
        class core
        socket logd stream 0666 logd logd
        socket logdr seqpacket 0666 logd logd
        socket logdw dgram 0222 logd logd
        seclabel u:r:logd:s0
    
    "【Healthd是android4.4之后提出来的一种中介模型,该模型向下监听来自底层的电池事件,向上传递电池数据信息给Framework层的BatteryService用以计算电池电量相关状态信息】"
    service healthd /sbin/healthd
        class core
        critical
        seclabel u:r:healthd:s0
    
    "【控制台进程】"
    service console /system/bin/sh
        "【为当前service设定一个类别.相同类别的服务将会同时启动或者停止,默认类名是default】"
        class core
        "【服务需要一个控制台】"
        console
        "【服务不会自动启动,必须通过服务名显式启动】"
        disabled
        "【在执行此服务之前切换用户名,当前默认的是root.自Android M开始,即使它要求linux capabilities,也应该使用该选项.很明显,为了获得该功能,进程需要以root用户运行】"
        user shell
        seclabel u:r:shell:s0
    
    on property:ro.debuggable=1
        start console
    
    # 启动adbd服务进程
    service adbd /sbin/adbd --root_seclabel=u:r:su:s0
        class core
        "【创建一个unix域下的socket,其被命名/dev/socket/<name>. 并将其文件描述符fd返回给服务进程.其中,type必须为dgram,stream或者seqpacke,user和group默认是0.seclabel是该socket的SELLinux的安全上下文环境,默认是当前service的上下文环境,通过seclabel指定】"
        socket adbd stream 660 system system
        disabled
        seclabel u:r:adbd:s0
    
    # adbd on at boot in emulator
    on property:ro.kernel.qemu=1
        start adbd
    
    "【内存管理服务,内存不够释放内存】"
    service lmkd /system/bin/lmkd
        class core
        critical
        socket lmkd seqpacket 0660 system system
    
    "【ServiceManager是一个守护进程,它维护着系统服务和客户端的binder通信。
    在Android系统中用到最多的通信机制就是Binder,Binder主要由Client、Server、ServiceManager和Binder驱动程序组成。其中Client、Service和ServiceManager运行在用户空间,而Binder驱动程序运行在内核空间。核心组件就是Binder驱动程序了,而ServiceManager提供辅助管理的功能,无论是Client还是Service进行通信前首先要和ServiceManager取得联系。而ServiceManager是一个守护进程,负责管理Server并向Client提供查询Server的功能。】"
    service servicemanager /system/bin/servicemanager
        class core
        user system
        group system
        critical
        onrestart restart healthd
        "【servicemanager 服务启动时会重启zygote服务】"
        onrestart restart zygote
        onrestart restart media
        onrestart restart surfaceflinger
        onrestart restart drm
    
    "【Vold是Volume Daemon的缩写,它是Android平台中外部存储系统的管控中心,是管理和控制Android平台外部存储设备的后台进程】"
    service vold /system/bin/vold
        class core
        socket vold stream 0660 root mount
        ioprio be 2
    
    "【Netd是Android系统中专门负责网络管理和控制的后台daemon程序】"
    service netd /system/bin/netd
        class main
        socket netd stream 0660 root system
        socket dnsproxyd stream 0660 root inet
        socket mdns stream 0660 root system
        socket fwmarkd stream 0660 root inet
    
    "【debuggerd是一个daemon进程,在系统启动时随着init进程启动。主要负责将进程运行时的信息dump到文件或者控制台中】"
    service debuggerd /system/bin/debuggerd
        class main
    
    service debuggerd64 /system/bin/debuggerd64
        class main
    
    "【Android RIL (Radio Interface Layer)提供了Telephony服务和Radio硬件之间的抽象层】"
    # for using TK init.modem.rc rild-daemon setting
    #service ril-daemon /system/bin/rild
    #    class main
    #    socket rild stream 660 root radio
    #    socket rild-debug stream 660 radio system
    #    user root
    #    group radio cache inet misc audio log
    
    "【提供系统 范围内的surface composer功能,它能够将各种应用 程序的2D、3D surface进行组合。】"
    service surfaceflinger /system/bin/surfaceflinger
        class core
        user system
        group graphics drmrpc
        onrestart restart zygote
    
    "【DRM可以直接访问DRM clients的硬件。DRM驱动用来处理DMA,内存管理,资源锁以及安全硬件访问。为了同时支持多个3D应用,3D图形卡硬件必须作为一个共享资源,因此需要锁来提供互斥访问。DMA传输和AGP接口用来发送图形操作的buffers到显卡硬件,因此要防止客户端越权访问显卡硬件。】"
    #make sure drm server has rights to read and write sdcard ####
    service drm /system/bin/drmserver
        class main
        user drm
        # group drm system inet drmrpc ####
        group drm system inet drmrpc sdcard_r ####
    
    "【媒体服务,无需多说】"
    service media /system/bin/mediaserver
        class main
        user root ####
    #   google default ####
    #   user media    ####
        group audio camera inet net_bt net_bt_admin net_bw_acct drmrpc mediadrm media sdcard_r system net_bt_stack ####
    #   google default ####
    #   group audio camera inet net_bt net_bt_admin net_bw_acct drmrpc mediadrm ####
    
        ioprio rt 4
    
    "【设备加密相关服务】"
    # One shot invocation to deal with encrypted volume.
    service defaultcrypto /system/bin/vdc --wait cryptfs mountdefaultencrypted
        disabled
        "【当服务退出时,不重启该服务】"
        oneshot
        # vold will set vold.decrypt to trigger_restart_framework (default
        # encryption) or trigger_restart_min_framework (other encryption)
    
    # One shot invocation to encrypt unencrypted volumes
    service encrypt /system/bin/vdc --wait cryptfs enablecrypto inplace default
        disabled
        oneshot
        # vold will set vold.decrypt to trigger_restart_framework (default
        # encryption)
    
    "【开机动画服务】"
    service bootanim /system/bin/bootanimation
        class core
        user graphics
    #    group graphics audio ####
        group graphics media audio ####
        disabled
        oneshot
    
    "【在Android系统中,PackageManagerService用于管理系统中的所有安装包信息及应用程序的安装卸载,但是应用程序的安装与卸载并非PackageManagerService来完成,而是通过PackageManagerService来访问installd服务来执行程序包的安装与卸载的。】"
    service installd /system/bin/installd
        class main
        socket installd stream 600 system system
    
    service flash_recovery /system/bin/install-recovery.sh
        class main
        seclabel u:r:install_recovery:s0
        oneshot
    
    "【vpn相关的服务】"
    service racoon /system/bin/racoon
        class main
        socket racoon stream 600 system system
        # IKE uses UDP port 500. Racoon will setuid to vpn after binding the port.
        group vpn net_admin inet
        disabled
        oneshot
    
    "【android中有mtpd命令可以连接vpn】"
    service mtpd /system/bin/mtpd
        class main
        socket mtpd stream 600 system system
        user vpn
        group vpn net_admin inet net_raw
        disabled
        oneshot
    
    service keystore /system/bin/keystore /data/misc/keystore
        class main
        user keystore
        group keystore drmrpc
    
    "【可以用dumpstate 获取设备的各种信息】"
    service dumpstate /system/bin/dumpstate -s
        class main
        socket dumpstate stream 0660 shell log
        disabled
        oneshot
    
    "【mdnsd 是多播 DNS 和 DNS 服务发现的守护程序。】"
    service mdnsd /system/bin/mdnsd
        class main
        user mdnsr
        group inet net_raw
        socket mdnsd stream 0660 mdnsr inet
        disabled
        oneshot
    
    "【触发关机流程继续往下走】"
    service pre-recovery /system/bin/uncrypt
        class main
        disabled
        "【当服务退出时,不重启该服务】"
        oneshot
    

    启动顺序是on early-init -> init -> late-init -> boot,接下来就是各种服务的启动

    init进程的功能

     

    • 分析和运行所有的init.rc文件
    • 生成设备驱动节点(通过rc文件创建)
    • 处理子进程的终止(signal方式)
    • 提供属性服务


    Zygote进程


    在Android中,zygote是整个系统创建新进程的核心进程。在init进程启动后就会创建zygote进程;zygote进程在内部会先启动Dalvik虚拟机,继而加载一些必要的系统资源和系统类,最后进入一种监听状态。在之后的运作中,当其他系统模块(比如AMS)希望创建新进程时,只需向zygote进程发出请求,zygote进程监听到该请求后,会相应地fork出新的进程,于是这个新进程在初生之时,就先天具有了自己的Dalvik虚拟机以及系统资源

    其实在早期的Android版本中,Zygote的启动命令直接是写在init.rc中的,但是随着硬件的不断升级换代,Android系统也要面对32位和64位机器同时存在的情况,所以对Zygote启动也需要根据不同情况对待

    在init.rc顶部可以看到有这么一句话

    import /init.${ro.zygote}.rc

    这里会根据系统属性ro.zygote的值去加载不同的描述Zygote的rc脚本,比如

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

    以init.zygote64_32.rc为例

    service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server --socket-name=zygote
        class main
        socket zygote stream 660 root system
        onrestart write /sys/android_power/request_state wake
        onrestart write /sys/power/state on
        onrestart restart audioserver
        onrestart restart cameraserver
        onrestart restart media
        onrestart restart netd
        writepid /dev/cpuset/foreground/tasks
     
    service zygote_secondary /system/bin/app_process32 -Xzygote /system/bin --zygote --socket-name=zygote_secondary
        class main
        socket zygote_secondary stream 660 root system
        onrestart restart zygote
        writepid /dev/cpuset/foreground/tasks
    

    如上,可以看到服务名(进程名)是zygote,对应的可执行程序是app_processXX,而且还创建了一个名为zygote的unix domain socket,类型是stream,这个socket是为了后面IPC所用;上面可以看到还有一个zygote_secondary的进程,其实这是为了适配不同的abi型号

    其中Zygote进程能够重启的地方有

    • servicemanager进程被杀
    • surfaceflinger进程被杀
    • Zygote进程自己被杀
    • system_server进程被杀


    接下来看看zygote启动过程,zygote对应的可执行文件就是/system/bin/app_processXX,也就是说系统启动时会执行到这个可执行文件的main()函数里

    main
     

    int main(int argc, char* const argv[])
    {
        //Android运行时环境,传到的参数argv为“-Xzygote /system/bin --zygote --start-system-server”
        AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));
        argc--; argv++; //忽略第一个参数
    
        int i;
        for (i = 0; i < argc; i++) {
            if (argv[i][0] != '-') {
                break;
            }
            if (argv[i][1] == '-' && argv[i][2] == 0) {
                ++i;
                break;
            }
            runtime.addOption(strdup(argv[i]));
        }
        //参数解析
        bool zygote = false;
        bool startSystemServer = false;
        bool application = false;
        String8 niceName;
        String8 className;
        ++i;
        while (i < argc) {
            const char* arg = argv[i++];
            if (strcmp(arg, "--zygote") == 0) {
                zygote = true;
                //--zygote表示当前进程用于承载zygote
                //对于64位系统nice_name为zygote64; 32位系统为zygote
                niceName = ZYGOTE_NICE_NAME;
            } else if (strcmp(arg, "--start-system-server") == 0) {
    	        //是否需要启动system server
                startSystemServer = true;
            } else if (strcmp(arg, "--application") == 0) {
    	        //启动进入独立的程序模式
                application = true;
            } else if (strncmp(arg, "--nice-name=", 12) == 0) {
    	        //niceName 为当前进程别名,区别abi型号
                niceName.setTo(arg + 12);
            } else if (strncmp(arg, "--", 2) != 0) {
                className.setTo(arg);
                break;
            } else {
                --i;
                break;
            }
        }
        Vector<String8> args;
        if (!className.isEmpty()) {
            // 运行application或tool程序
            args.add(application ? String8("application") : String8("tool"));
            runtime.setClassNameAndArgs(className, argc - i, argv + i);
        } else {
            //进入zygote模式,创建 /data/dalvik-cache路径
            maybeCreateDalvikCache();
            if (startSystemServer) {
                args.add(String8("start-system-server"));
            }
            char prop[PROP_VALUE_MAX];
            if (property_get(ABI_LIST_PROPERTY, prop, NULL) == 0) {
                return 11;
            }
            String8 abiFlag("--abi-list=");
            abiFlag.append(prop);
            args.add(abiFlag);
    
            for (; i < argc; ++i) {
                args.add(String8(argv[i]));
            }
        }
    
        //设置进程名
        if (!niceName.isEmpty()) {
            runtime.setArgv0(niceName.string());
            set_process_name(niceName.string());
        }
        if (zygote) {
            runtime.start("com.android.internal.os.ZygoteInit", args, zygote);
        } else if (className) {
            runtime.start("com.android.internal.os.RuntimeInit", args, zygote);
        } else {
            //没有指定类名或zygote,参数错误
            return 10;
        }
    }
    
    

    根据传入参数的不同可以有两种启动方式,一个是 “com.android.internal.os.RuntimeInit”, 另一个是 ”com.android.internal.os.ZygoteInit", 对应RuntimeInit 和 ZygoteInit 两个类, 这两个类的主要区别在于Java端,可以明显看出,ZygoteInit 相比 RuntimeInit 多做了很多事情,比如说 “preload", “gc” 等等。但是在Native端,他们都做了相同的事, startVM() 和 startReg()

    在当前场景中,init.rc指定了–zygote选项,并且args有添加start-system-server值,所以接下来执行

    AndroidRuntime::start

    void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote)
    {
        static const String8 startSystemServer("start-system-server");
    
        for (size_t i = 0; i < options.size(); ++i) {
            if (options[i] == startSystemServer) {
               const int LOG_BOOT_PROGRESS_START = 3000;
            }
        }
        const char* rootDir = getenv("ANDROID_ROOT");
        if (rootDir == NULL) {
            rootDir = "/system";
            if (!hasDir("/system")) {
                return;
            }
            setenv("ANDROID_ROOT", rootDir, 1);
        }
        JniInvocation jni_invocation;
        jni_invocation.Init(NULL);
        JNIEnv* env;
        // 虚拟机创建,主要篇幅是关于虚拟机参数的设置
        if (startVm(&mJavaVM, &env, zygote) != 0) {
            return;
        }
        onVmCreated(env);
        // JNI方法注册
        if (startReg(env) < 0) {
            return;
        }
    
        jclass stringClass;
        jobjectArray strArray;
        jstring classNameStr;
    
        //等价 strArray= new String[options.size() + 1];
        stringClass = env->FindClass("java/lang/String");
        strArray = env->NewObjectArray(options.size() + 1, stringClass, NULL);
    
        //等价 strArray[0] = "com.android.internal.os.ZygoteInit"
        classNameStr = env->NewStringUTF(className);
        env->SetObjectArrayElement(strArray, 0, classNameStr);
    
        //等价 strArray[1] = "start-system-server";
        //    strArray[2] = "--abi-list=xxx";
        //其中xxx为系统响应的cpu架构类型,比如arm64-v8a.
        for (size_t i = 0; i < options.size(); ++i) {
            jstring optionsStr = env->NewStringUTF(options.itemAt(i).string());
            env->SetObjectArrayElement(strArray, i + 1, optionsStr);
        }
    
        //将"com.android.internal.os.ZygoteInit"转换为"com/android/internal/os/ZygoteInit"
        char* slashClassName = toSlashClassName(className);
        //找到Zygoteinit类
        jclass startClass = env->FindClass(slashClassName);
        if (startClass == NULL) {
            ...
        } else {
        //找到这个类后就继续找成员函数main方法的Mehtod ID
            jmethodID startMeth = env->GetStaticMethodID(startClass, "main",
                "([Ljava/lang/String;)V");
            // 通过反射调用ZygoteInit.main()方法
            env->CallStaticVoidMethod(startClass, startMeth, strArray);
        }
        //释放相应对象的内存空间
        free(slashClassName);
        mJavaVM->DetachCurrentThread();
        mJavaVM->DestroyJavaVM();
    }
    

    AndroidRuntime::startVm

    int AndroidRuntime::startVm(JavaVM** pJavaVM, JNIEnv** pEnv, bool zygote)
    {
        // JNI检测功能,用于native层调用jni函数时进行常规检测,比较弱字符串格式是否符合要求,资源是否正确释放。该功能一般用于早期系统调试或手机Eng版,对于User版往往不会开启,引用该功能比较消耗系统CPU资源,降低系统性能。
        bool checkJni = false;
        property_get("dalvik.vm.checkjni", propBuf, "");
        if (strcmp(propBuf, "true") == 0) {
            checkJni = true;
        } else if (strcmp(propBuf, "false") != 0) {
            property_get("ro.kernel.android.checkjni", propBuf, "");
            if (propBuf[0] == '1') {
                checkJni = true;
            }
        }
        if (checkJni) {
            addOption("-Xcheck:jni");
        }
    
        //虚拟机产生的trace文件,主要用于分析系统问题,路径默认为/data/anr/traces.txt
        parseRuntimeOption("dalvik.vm.stack-trace-file", stackTraceFileBuf, "-Xstacktracefile:");
    
        //对于不同的软硬件环境,这些参数往往需要调整、优化,从而使系统达到最佳性能
        parseRuntimeOption("dalvik.vm.heapstartsize", heapstartsizeOptsBuf, "-Xms", "4m");
        parseRuntimeOption("dalvik.vm.heapsize", heapsizeOptsBuf, "-Xmx", "16m");
        parseRuntimeOption("dalvik.vm.heapgrowthlimit", heapgrowthlimitOptsBuf, "-XX:HeapGrowthLimit=");
        parseRuntimeOption("dalvik.vm.heapminfree", heapminfreeOptsBuf, "-XX:HeapMinFree=");
        parseRuntimeOption("dalvik.vm.heapmaxfree", heapmaxfreeOptsBuf, "-XX:HeapMaxFree=");
        parseRuntimeOption("dalvik.vm.heaptargetutilization",
                           heaptargetutilizationOptsBuf, "-XX:HeapTargetUtilization=");
        ...
    
        //preloaded-classes文件内容是由WritePreloadedClassFile.java生成的,
        //在ZygoteInit类中会预加载工作将其中的classes提前加载到内存,以提高系统性能
        if (!hasFile("/system/etc/preloaded-classes")) {
            return -1;
        }
    
        //初始化虚拟机
        if (JNI_CreateJavaVM(pJavaVM, pEnv, &initArgs) < 0) {
            ALOGE("JNI_CreateJavaVM failed\n");
            return -1;
        }
    }
    

    AndroidRuntime::startReg

    int AndroidRuntime::startReg(JNIEnv* env)
    {
        //设置线程创建方法为javaCreateThreadEtc 
        androidSetCreateThreadFunc((android_create_thread_fn) javaCreateThreadEtc);
    
        env->PushLocalFrame(200);
        //进程JNI方法的注册
        if (register_jni_procs(gRegJNI, NELEM(gRegJNI), env) < 0) {
            env->PopLocalFrame(NULL);
            return -1;
        }
        env->PopLocalFrame(NULL);
        return 0;
    }
    

    总结一下Zygote native 进程做了哪些主要工作:

    • 创建虚拟机–startVM

    • 注册JNI函数–startReg

    • 通过JNI知道Java层的com.android.internal.os.ZygoteInit 类,调用main 函数,进入java 世界

    这就开始进入java层了

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


    ZygoteInit.main

    public static void main(String argv[]) {
        try {
            RuntimeInit.enableDdms(); //开启DDMS功能
            SamplingProfilerIntegration.start();
            boolean startSystemServer = false;
            String socketName = "zygote";
            String abiList = null;
            for (int i = 1; i < argv.length; i++) {
                if ("start-system-server".equals(argv[i])) {
                    startSystemServer = 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]);
                }
            }
            ...
    
            registerZygoteSocket(socketName); //为Zygote注册socket
            preload(); // 预加载类和资源
            SamplingProfilerIntegration.writeZygoteSnapshot();
            gcAndFinalize(); //GC操作
            if (startSystemServer) {
                startSystemServer(abiList, socketName);//启动system_server
            }
            runSelectLoop(abiList); //进入循环模式
            closeServerSocket();
        } catch (MethodAndArgsCaller caller) {
            caller.run(); //启动system_server中会讲到。
        } catch (RuntimeException ex) {
            closeServerSocket();
            throw ex;
        }
    }
    
    

    ZygoteInit.registerZygoteSocket

    private static void registerZygoteSocket(String socketName) {
        if (sServerSocket == null) {
            int fileDesc;
            final String fullSocketName = ANDROID_SOCKET_PREFIX + socketName;
            try {
                String env = System.getenv(fullSocketName);
                fileDesc = Integer.parseInt(env);
            } catch (RuntimeException ex) {
                ...
            }
    
            try {
                FileDescriptor fd = new FileDescriptor();
                fd.setInt$(fileDesc); //设置文件描述符
                sServerSocket = new LocalServerSocket(fd); //创建Socket的本地服务端
            } catch (IOException ex) {
                ...
            }
        }
    }
    

    在这里就是实例化一个LocalServerSocket,这样zygote就可以作为服务端,不断的获取其它进程发送过来的请求

    ZygoteInit.preload

    static void preload() {
        //预加载位于/system/etc/preloaded-classes文件中的类
        preloadClasses();
    
        //预加载资源,包含drawable和color资源
        preloadResources();
    
        //预加载OpenGL
        preloadOpenGL();
    
        //通过System.loadLibrary()方法,
        //预加载"android","compiler_rt","jnigraphics"这3个共享库
        preloadSharedLibraries();
    
        //预加载  文本连接符资源
        preloadTextResources();
    
        //仅用于zygote进程,用于内存共享的进程
        WebViewFactory.prepareWebViewInZygote();
    }
    

    执行Zygote进程的初始化,对于类加载,采用反射机制Class.forName()方法来加载。对于资源加载,主要是 com.android.internal.R.array.preloaded_drawables和com.android.internal.R.array.preloaded_color_state_lists,在应用程序中以com.android.internal.R.xxx开头的资源,便是此时由Zygote加载到内存的

    ZygoteInit.runSelectLoop

    private static void runSelectLoop(String abiList) throws MethodAndArgsCaller {
        ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>();
        ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();
        //sServerSocket是socket通信中的服务端,即zygote进程。保存到fds[0]
        fds.add(sServerSocket.getFileDescriptor());
        peers.add(null);
    
        while (true) {
            StructPollfd[] pollFds = new StructPollfd[fds.size()];
            for (int i = 0; i < pollFds.length; ++i) {
                pollFds[i] = new StructPollfd();
                pollFds[i].fd = fds.get(i);
                pollFds[i].events = (short) POLLIN;
            }
            try {
                 //处理轮询状态,当pollFds有事件到来则往下执行,否则阻塞在这里
                Os.poll(pollFds, -1);
            } catch (ErrnoException ex) {
                ...
            }
            
            for (int i = pollFds.length - 1; i >= 0; --i) {
                //采用I/O多路复用机制,当接收到客户端发出连接请求 或者数据处理请求到来,则往下执行;
                // 否则进入continue,跳出本次循环。
                if ((pollFds[i].revents & POLLIN) == 0) {
                    continue;
                }
                if (i == 0) {
                    //即fds[0],代表的是sServerSocket,则意味着有客户端连接请求;
                    // 则创建ZygoteConnection对象,并添加到fds。
                    ZygoteConnection newPeer = acceptCommandPeer(abiList);
                    peers.add(newPeer);
                    fds.add(newPeer.getFileDesciptor()); //添加到fds.
                } else {
                    //i>0,则代表通过socket接收来自对端的数据,并执行相应操作
                    boolean done = peers.get(i).runOnce();
                    if (done) {
                        peers.remove(i);
                        fds.remove(i); //处理完则从fds中移除该文件描述符
                    }
                }
            }
        }
    }
    
    

    ZygoteInit.acceptCommandPeer

    private static ZygoteConnection acceptCommandPeer(String abiList) {
        try {
            return new ZygoteConnection(sServerSocket.accept(), abiList);
        } catch (IOException ex) {
            ...
        }
    }
    

    ZygoteConnection.runOnce

    boolean runOnce() throws ZygoteInit.MethodAndArgsCaller {
    
        String args[];
        Arguments parsedArgs = null;
        FileDescriptor[] descriptors;
    
        try {
            //读取socket客户端发送过来的参数列表
            args = readArgumentList();
            descriptors = mSocket.getAncillaryFileDescriptors();
        } catch (IOException ex) {
            ...
            return true;
        }
        ...
    
        try {
            //将binder客户端传递过来的参数,解析成Arguments对象格式
            parsedArgs = new Arguments(args);
            ...
            pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids,
                    parsedArgs.debugFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo,
                    parsedArgs.niceName, fdsToClose, parsedArgs.instructionSet,
                    parsedArgs.appDataDir);
        } catch (Exception e) {
            ...
        }
    
        try {
            if (pid == 0) {
                //子进程执行
                IoUtils.closeQuietly(serverPipeFd);
                serverPipeFd = null;
                //进入子进程流程
                handleChildProc(parsedArgs, descriptors, childPipeFd, newStderr);
                return true;
            } else {
                //父进程执行
                IoUtils.closeQuietly(childPipeFd);
                childPipeFd = null;
                return handleParentProc(pid, descriptors, serverPipeFd, parsedArgs);
            }
        } finally {
            IoUtils.closeQuietly(childPipeFd);
            IoUtils.closeQuietly(serverPipeFd);
        }
    }
    

    接收客户端发送过来的connect()操作,Zygote作为服务端执行accept()操作。 再后面客户端调用write()写数据,Zygote进程调用read()读数据。

    没有连接请求时会进入休眠状态,当有创建新进程的连接请求时,唤醒Zygote进程,创建Socket通道ZygoteConnection,然后执行ZygoteConnection的runOnce()方法。
     

    Zygote总结:

    • 解析init.zygote.rc中的参数,创建AppRuntime并调用AppRuntime.start()方法
    • 调用AndroidRuntime的startVM()方法创建虚拟机,再调用startReg()注册JNI函数
    • 通过JNI方式调用ZygoteInit.main(),第一次进入Java世界
    • registerZygoteSocket()建立socket通道,zygote作为通信的服务端,用于响应客户端请求
    • preload()预加载通用类、drawable和color资源、openGL以及共享库以及WebView,用于提高app启动效率
    • 通过startSystemServer(),fork得力帮手system_server进程,也是Java Framework的运行载体(下面讲到system server再详细讲解)
    • 调用runSelectLoop(),随时待命,当接收到请求创建新进程请求时立即唤醒并执行相应工作


    System Server进程


    system server进程和zygote进程可以说是Android世界中的两大最重要的进程,离开其中之一基本上系统就玩完了;基本上在Java Framework中的大多数服务都是在system server进程中一个线程的方式存在的,如下:

    • EntropyService    提供伪随机数
    • PowerManagerService    电源管理服务
    • ActivityManagerService    最核心的服务之一,管理 四大组件
    • TelephonyRegistry    通过该服务注册电话模块的事件响应,比如重启、关闭、启动等
    • PackageManagerService    程序包管理服务
    • AccountManagerService    账户管理服务,是指联系人账户,而不是 Linux 系统的账户
    • ContentService    ContentProvider 服务,提供跨进程数据交换
    • BatteryService    电池管理服务
    • LightsService    自然光强度感应传感器服务
    • VibratorService    震动器服务
    • AlarmManagerService    定时器管理服务,提供定时提醒服务
    • WindowManagerService    Framework 最核心的服务之一,负责窗口管理
    • BluetoothService    蓝牙服务
    • DevicePolicyManagerService    提供一些系统级别的设置及属性
    • StatusBarManagerService    状态栏管理服务
    • ClipboardService    系统剪切板服务
    • InputMethodManagerService    输入法管理服务
    • NetStatService    网络状态服务
    • NetworkManagementService    网络管理服务
    • ConnectivityService    网络连接管理服务
    • ThrottleService    暂不清楚其作用
    • AccessibilityManagerService    辅助管理程序截获所有的用户输入,并根据这些输入给用户一些额外的反馈,起到辅助的效果
    • MountService    挂载服务,可通过该服务调用 Linux 层面的 mount 程序
    • NotificationManagerService    通知栏管理服务, Android 中的通知栏和状态栏在一起,只是界面上前者在左边,后者在右边
    • DeviceStorageMonitorService    磁盘空间状态检测服务
    • LocationManagerService    地理位置服务
    • SearchManagerService    搜索管理服务
    • DropBoxManagerService    通过该服务访问 Linux 层面的 Dropbox 程序
    • WallpaperManagerService    墙纸管理服务,墙纸不等同于桌面背景,在 View 系统内部,墙纸可以作为任何窗口的背景
    • AudioService    音频管理服务
    • BackupManagerService    系统备份服务
    • AppWidgetService    Widget 服务
    • RecognitionManagerService    身份识别服务
    • DiskStatsService    磁盘统计服务

    system server进程也是由zygote进程fork出来的,在上面的ZygoteInit.main方法中有如下代码
     

    ZygoteInit.main

    public static void main(String argv[]) {
        try {
            if (startSystemServer) {
                startSystemServer(abiList, socketName);//启动system_server
            }
        } catch (MethodAndArgsCaller caller) {
            caller.run(); //这一步很重要,接下来会讲到
        } catch (RuntimeException ex) {
            closeServerSocket();
            throw ex;
        }
    }
    

    ZygoteInit.startSystemServer

    private static boolean startSystemServer(String abiList, String socketName)
            throws MethodAndArgsCaller, RuntimeException {
        ...
        //参数准备
        String args[] = {
            "--setuid=1000",
            "--setgid=1000",
            "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1021,1032,3001,3002,3003,3006,3007",
            "--capabilities=" + capabilities + "," + capabilities,
            "--nice-name=system_server",
            "--runtime-args",
            "com.android.server.SystemServer",
        };
    
        ZygoteConnection.Arguments parsedArgs = null;
        int pid;
        try {
            //用于解析参数,生成目标格式
            parsedArgs = new ZygoteConnection.Arguments(args);
            ZygoteConnection.applyDebuggerSystemProperty(parsedArgs);
            ZygoteConnection.applyInvokeWithSystemProperty(parsedArgs);
    
            // fork子进程,该进程是system_server进程
            pid = Zygote.forkSystemServer(
                    parsedArgs.uid, parsedArgs.gid,
                    parsedArgs.gids,
                    parsedArgs.debugFlags,
                    null,
                    parsedArgs.permittedCapabilities,
                    parsedArgs.effectiveCapabilities);
        } catch (IllegalArgumentException ex) {
            throw new RuntimeException(ex);
        }
    
        //进入子进程system_server
        if (pid == 0) {
    	    //第二个zygote进程
            if (hasSecondZygote(abiList)) {
                waitForSecondaryZygote(socketName);
            }
            // 完成system_server进程剩余的工作 
            handleSystemServerProcess(parsedArgs);
        }
        return true;
    }
    
    

    这个方法先准备参数,然后fork新进程,对于有两个zygote进程情况,需等待第2个zygote创建完成

    Zygote.forkSystemServer

    public static int forkSystemServer(int uid, int gid, int[] gids, int debugFlags,
            int[][] rlimits, long permittedCapabilities, long effectiveCapabilities) {
        VM_HOOKS.preFork();
        // 调用native方法fork system_server进程
        int pid = nativeForkSystemServer(
                uid, gid, gids, debugFlags, rlimits, permittedCapabilities, effectiveCapabilities);
        if (pid == 0) {
            Trace.setTracingEnabled(true);
        }
        VM_HOOKS.postForkCommon();
        return pid;
    }
    

    nativeForkSystemServer()方法在AndroidRuntime.cpp中注册的,调用com_android_internal_os_Zygote.cpp中的register_com_android_internal_os_Zygote()方法建立native方法的映射关系,所以接下来进入如下方法

    com_android_internal_os_Zygote.nativeForkSystemServer

    static jint com_android_internal_os_Zygote_nativeForkSystemServer(
            JNIEnv* env, jclass, uid_t uid, gid_t gid, jintArray gids,
            jint debug_flags, jobjectArray rlimits, jlong permittedCapabilities,
            jlong effectiveCapabilities) {
      //fork子进程
      pid_t pid = ForkAndSpecializeCommon(env, uid, gid, gids,
                                          debug_flags, rlimits,
                                          permittedCapabilities, effectiveCapabilities,
                                          MOUNT_EXTERNAL_DEFAULT, NULL, NULL, true, NULL,
                                          NULL, NULL);
      if (pid > 0) {
          // zygote进程,检测system_server进程是否创建
          gSystemServerPid = pid;
          int status;
          if (waitpid(pid, &status, WNOHANG) == pid) {
              //当system_server进程死亡后,重启zygote进程
              RuntimeAbort(env);
          }
      }
      return pid;
    }
    

    当system_server进程创建失败时,将会重启zygote进程。这里需要注意,对于Android 5.0以上系统,有两个zygote进程,分别是zygote、zygote64两个进程,system_server的父进程,一般来说64位系统其父进程是zygote64进程

    • 当kill system_server进程后,只重启zygote64和system_server,不重启zygote;
    • 当kill zygote64进程后,只重启zygote64和system_server,也不重启zygote;
    • 当kill zygote进程,则重启zygote、zygote64以及system_server。

    com_android_internal_os_Zygote.ForkAndSpecializeCommon

    static pid_t ForkAndSpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray javaGids,
                                         jint debug_flags, jobjectArray javaRlimits,
                                         jlong permittedCapabilities, jlong effectiveCapabilities,
                                         jint mount_external,
                                         jstring java_se_info, jstring java_se_name,
                                         bool is_system_server, jintArray fdsToClose,
                                         jstring instructionSet, jstring dataDir) {
      SetSigChldHandler(); //设置子进程的signal信号处理函数
      pid_t pid = fork(); //fork子进程
      if (pid == 0) {
        //进入子进程
        DetachDescriptors(env, fdsToClose); //关闭并清除文件描述符
    
        if (!is_system_server) {
            //对于非system_server子进程,则创建进程组
            int rc = createProcessGroup(uid, getpid());
        }
        SetGids(env, javaGids); //设置设置group
        SetRLimits(env, javaRlimits); //设置资源limit
    
        int rc = setresgid(gid, gid, gid);
        rc = setresuid(uid, uid, uid);
    
        SetCapabilities(env, permittedCapabilities, effectiveCapabilities);
        SetSchedulerPolicy(env); //设置调度策略
    
         //selinux上下文
        rc = selinux_android_setcontext(uid, is_system_server, se_info_c_str, se_name_c_str);
    
        if (se_info_c_str == NULL && is_system_server) {
          se_name_c_str = "system_server";
        }
        if (se_info_c_str != NULL) {
          SetThreadName(se_name_c_str); //设置线程名为system_server,方便调试
        }
        UnsetSigChldHandler(); //设置子进程的signal信号处理函数为默认函数
        //等价于调用zygote.callPostForkChildHooks()
        env->CallStaticVoidMethod(gZygoteClass, gCallPostForkChildHooks, debug_flags,
                                  is_system_server ? NULL : instructionSet);
        ...
    
      } else if (pid > 0) {
        //进入父进程,即zygote进程
      }
      return pid;
    }
    
    int fork() {
      __bionic_atfork_run_prepare(); 
    
      pthread_internal_t* self = __get_thread();
    
      //fork期间,获取父进程pid,并使其缓存值无效
      pid_t parent_pid = self->invalidate_cached_pid();
      //系统调用
      int result = syscall(__NR_clone, FORK_FLAGS, NULL, NULL, NULL, &(self->tid));
      if (result == 0) {
        self->set_cached_pid(gettid());
        __bionic_atfork_run_child(); //fork完成执行子进程回调方法
      } else {
        self->set_cached_pid(parent_pid);
        __bionic_atfork_run_parent(); //fork完成执行父进程回调方法
      }
      return result;
    }
    

    fork

    fork()采用copy on write技术,这是linux创建进程的标准方法,调用一次,返回两次,返回值有3种类型

    1. 父进程中,fork返回新创建的子进程的pid;
    2. 子进程中,fork返回0;
    3. 当出现错误时,fork返回负数。(当进程数超过上限或者系统内存不足时会出错)

    fork()的主要工作是寻找空闲的进程号pid,然后从父进程拷贝进程信息,例如数据段和代码段,fork()后子进程要执行的代码等。 Zygote进程是所有Android进程的母体,包括system_server和各个App进程。zygote利用fork()方法生成新进程,对于新进程A复用Zygote进程本身的资源,再加上新进程A相关的资源,构成新的应用进程A


    fork之后,操作系统会复制一个与父进程完全相同的子进程,虽说是父子关系,但是在操作系统看来,他们更像兄弟关系,这2个进程共享代码空间,但是数据空间是互相独立的,子进程数据空间中的内容是父进程的完整拷贝,指令指针也完全相同,子进程拥有父进程当前运行到的位置(两进程的程序计数器pc值相同,也就是说,子进程是从fork返回处开始执行的),但有一点不同,如果fork成功,子进程中fork的返回值是0,父进程中fork的返回值是子进程的进程号,如果fork不成功,父进程会返回错误。

    可以这样想象,2个进程一直同时运行,而且步调一致,在fork之后,他们就开始分别作不同的工作,正如fork原意【分支】一样

    到此system_server进程已完成了创建的所有工作,接下来开始了system_server进程的真正工作。在前面startSystemServer()方法中,zygote进程执行完forkSystemServer()后,新创建出来的system_server进程便进入handleSystemServerProcess()方法
     

    ZygoteInit.handleSystemServerProcess

    private static void handleSystemServerProcess(
            ZygoteConnection.Arguments parsedArgs)
            throws ZygoteInit.MethodAndArgsCaller {
    
        closeServerSocket(); //关闭父进程zygote复制而来的Socket
    
        Os.umask(S_IRWXG | S_IRWXO);
    
        if (parsedArgs.niceName != null) {
            Process.setArgV0(parsedArgs.niceName); //设置当前进程名为"system_server"
        }
    
        final String systemServerClasspath = Os.getenv("SYSTEMSERVERCLASSPATH");
        if (systemServerClasspath != null) {
            //执行dex优化操作
            performSystemServerDexOpt(systemServerClasspath);
        }
    
        if (parsedArgs.invokeWith != null) {
            String[] args = parsedArgs.remainingArgs;
    
            if (systemServerClasspath != null) {
                String[] amendedArgs = new String[args.length + 2];
                amendedArgs[0] = "-cp";
                amendedArgs[1] = systemServerClasspath;
                System.arraycopy(parsedArgs.remainingArgs, 0, amendedArgs, 2, parsedArgs.remainingArgs.length);
            }
            //启动应用进程
            WrapperInit.execApplication(parsedArgs.invokeWith,
                    parsedArgs.niceName, parsedArgs.targetSdkVersion,
                    VMRuntime.getCurrentInstructionSet(), null, args);
        } else {
            ClassLoader cl = null;
            if (systemServerClasspath != null) {
                创建类加载器,并赋予当前线程
                cl = new PathClassLoader(systemServerClasspath, ClassLoader.getSystemClassLoader());
                Thread.currentThread().setContextClassLoader(cl);
            }
    
            //system_server故进入此分支
            RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs, cl);
        }
    }
    
    

    RuntimeInit.zygoteInit

    public static final void zygoteInit(int targetSdkVersion, String[] argv, ClassLoader classLoader)
            throws ZygoteInit.MethodAndArgsCaller {
    
        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "RuntimeInit");
        redirectLogStreams(); //重定向log输出
    
        commonInit(); // 通用的一些初始化
        nativeZygoteInit(); // zygote初始化 
        applicationInit(targetSdkVersion, argv, classLoader); // 应用初始化
    }
    
    private static final void commonInit() {
        // 设置默认的未捕捉异常处理方法
        Thread.setDefaultUncaughtExceptionHandler(new UncaughtHandler());
    
        // 设置市区,中国时区为"Asia/Shanghai"
        TimezoneGetter.setInstance(new TimezoneGetter() {
            @Override
            public String getId() {
                return SystemProperties.get("persist.sys.timezone");
            }
        });
        TimeZone.setDefault(null);
    
        //重置log配置
        LogManager.getLogManager().reset();
        new AndroidConfig();
    
        // 设置默认的HTTP User-agent格式( "Dalvik/1.1.0 (Linux; U; Android 6.0.1;LenovoX3c70 Build/LMY47V)"),用于 HttpURLConnection
        String userAgent = getDefaultUserAgent();
        System.setProperty("http.agent", userAgent);
    
        // 设置socket的tag,用于网络流量统计
        NetworkManagementSocketTagger.install();
    }
    
    private static void applicationInit(int targetSdkVersion, String[] argv, ClassLoader classLoader)
            throws ZygoteInit.MethodAndArgsCaller {
        //true代表应用程序退出时不调用AppRuntime.onExit(),否则会在退出前调用
        nativeSetExitWithoutCleanup(true);
    
        //设置虚拟机的内存利用率参数值为0.75
        VMRuntime.getRuntime().setTargetHeapUtilization(0.75f);
        VMRuntime.getRuntime().setTargetSdkVersion(targetSdkVersion);
    
        final Arguments args;
        try {
            args = new Arguments(argv); //解析参数
        } catch (IllegalArgumentException ex) {
            return;
        }
    
        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
    
        //调用startClass的static方法 main() 此处args.startClass为”com.android.server.SystemServer”
        invokeStaticMain(args.startClass, args.startArgs, classLoader);
    }
    
    private static void invokeStaticMain(String className, String[] argv, ClassLoader classLoader)
            throws ZygoteInit.MethodAndArgsCaller {
        Class<?> cl = Class.forName(className, true, classLoader);
        ...
    
        Method m;
        try {
            m = cl.getMethod("main", new Class[] { String[].class });
        } catch (NoSuchMethodException ex) {
            ...
        } catch (SecurityException ex) {
            ...
        }
    
        //通过抛出异常,回到ZygoteInit.main()。这样做好处是能清空栈帧,提高栈帧利用率
        throw new ZygoteInit.MethodAndArgsCaller(m, argv);
    }
    
    

    重点看最后一个方法,通过反射获取SystemServer类的main方法参数,然后抛出MethodAndArgsCaller异常;但是抛出异常后怎么弄呢,我们知道一个方法抛异常,会一直走到调用方法,直到一个方法捕获了异常,这里就是开头讲的,在ZygoteInit.main方法捕获了异常然后去执行
     

    ZygoteInit.main

    public static void main(String argv[]) {
        try {
            if (startSystemServer) {
                startSystemServer(abiList, socketName);//启动system_server
            }
        } catch (MethodAndArgsCaller caller) {
            caller.run(); //这一步很重要,接下来会讲到
        } catch (RuntimeException ex) {
            closeServerSocket();
            throw ex;
        }
    }
    

    但是为啥没有直接在startSystemServer()或者上面的方法中直接调用SystemServer类的main方法,而是通过抛异常的方式处理呢?

    我们知道,当一个函数抛出异常后,这个异常会依次传递给调用它的函数,直到这个异常被捕获,如果这个异常一直没有被处理,最终就会引起程序的崩溃。

    程序都是由一个个函数组成的(除了汇编程序),c/c++/java/…等高级语言编写的应用程序,在执行的时候,他们都拥有自己的栈空间(是一种先进后出的内存区域),用于存放函数的返回地址和函数的临时数据,每调用一个函数时,就会把函数的返回地址和相关数据压入栈中,当一个函数执行完后,就会从栈中弹出,cpu会根据函数的返回地址,执行上一个调用函数的下一条指令。

    所以,在抛出异常后,如果异常没有在当前的函数中捕获,那么当前的函数执行就会异常的退出,从应用程序的栈弹出,并将这个异常传递给上一个函数,直到异常被捕获处理,否则,就会引起程序的崩溃。

    因此,这里通过抛异常的方式启动主要是清理应用程序栈中ZygoteInit.main以上的函数栈帧,以实现当相应的main函数退出时,能直接退出整个应用程序
     

    ZygoteInit.MethodAndArgsCaller.run

    public static class MethodAndArgsCaller extends Exception
                implements Runnable {
            /** 调用的方法 在上面的方法可知是main方法 */
            private final Method mMethod;
    
            /** 参数列表 */
            private final String[] mArgs;
    
            public MethodAndArgsCaller(Method method, String[] args) {
                mMethod = method;
                mArgs = args;
            }
    
            public void run() {
                try {
                    mMethod.invoke(null, new Object[] { mArgs });
                } catch (IllegalAccessException ex) {
                    throw new RuntimeException(ex);
                } catch (InvocationTargetException ex) {
                    Throwable cause = ex.getCause();
                    if (cause instanceof RuntimeException) {
                        throw (RuntimeException) cause;
                    } else if (cause instanceof Error) {
                        throw (Error) cause;
                    }
                    throw new RuntimeException(ex);
                }
            }
        }
    

    可以看到这里根据传递过来的参数,可知此处通过反射机制调用的是SystemServer.main()方法;到此,总算是进入到了SystemServer类的main()方法

    SystemServer.main

    public static void main(String[] args) {
            new SystemServer().run();
    }
    
    private void run() {
            try {
               	//如果系统时间比1970年早,那就设置为1970
                if (System.currentTimeMillis() < EARLIEST_SUPPORTED_TIME) {
                    SystemClock.setCurrentTimeMillis(EARLIEST_SUPPORTED_TIME);
                }
    
                //变更虚拟机的库文件,对于Android 6.0默认采用的是libart.so
                SystemProperties.set("persist.sys.dalvik.vm.lib.2", VMRuntime.getRuntime().vmLibrary());
    
                //清除vm内存增长上限,由于启动过程需要较多的虚拟机内存空间
                VMRuntime.getRuntime().clearGrowthLimit();
    
                //设置内存的可能有效使用率为0.8
                VMRuntime.getRuntime().setTargetHeapUtilization(0.8f);
    
                // 针对部分设备依赖于运行时就产生指纹信息,因此需要在开机完成前已经定义
                Build.ensureFingerprintProperty();
    
                //访问环境变量前,需要明确地指定用户
                Environment.setUserRequired(true);
    
                // Within the system server, any incoming Bundles should be defused
                // to avoid throwing BadParcelableException.
                BaseBundle.setShouldDefuse(true);
    
                //确保当前系统进程的binder调用,总是运行在前台优先级(foreground priority)
                BinderInternal.disableBackgroundScheduling(true);
    
                // 增加system_server中的binder线程数
                BinderInternal.setMaxThreads(sMaxBinderThreads);
    
                // 创建主线程looper 在当前线程运行
                android.os.Process.setThreadPriority(
                    android.os.Process.THREAD_PRIORITY_FOREGROUND);
                android.os.Process.setCanSelfBackground(false);
                Looper.prepareMainLooper();
    
                //初始化android_servers库
                System.loadLibrary("android_servers");
    
                //检测上次关机过程是否失败
                performPendingShutdown();
    
                //初始化系统上下文
                //初始化系统上下文对象mSystemContext,并设置默认的主题,mSystemContext实际上是一个ContextImpl对象。
                //调用ActivityThread.systemMain()的时候,会调用ActivityThread.attach(true),而在attach()里面,则创建了Application对象,并调用了Application.onCreate()。
                createSystemContext();
    
                //创建系统服务管理
                mSystemServiceManager = new SystemServiceManager(mSystemContext);
                LocalServices.addService(SystemServiceManager.class, mSystemServiceManager);
            } finally {
                Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
            }
    
            //启动各种系统服务
            try {
    	        //引导服务
                startBootstrapServices();
                //核心服务
                startCoreServices();
                //其它服务
                startOtherServices();
            } catch (Throwable ex) {
                throw ex;
            } finally {
                Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
            }
    
            //开启消息循环
            Looper.loop();
            throw new RuntimeException("Main thread loop unexpectedly exited");
        }
    

    system server进程总结

     

    • zygote进程通过Zygote.forkSystemServer —> fork.fork()创建system server进程
    • 调用ZygoteInit.handleSystemServerProcess方法设置当前进程名为"system_server",执行dex优化操作,一些属性的初始化,设置binder线程
    • 通过抛出MethodAndArgsCaller异常,回到ZygoteInit.main(),在try catch中执行MethodAndArgsCaller.run;在这里通过反射执行SystemServer.main()方法
    • 在SystemServer.run方法中做一些设置,比如初始化系统上下文 ,创建SystemServiceManager,启动引导服务,启动核心服务,启动其他服务
    • 最后调用Looper.loop(),不断的从消息队列取出消息处理
       

     

     

     

    展开全文
  • Zygote进程的启动流程

    千次阅读 2015-09-17 09:40:14
    Zygote进程时由Android系统的第一个进程init启动起来的。init进程时在内核加载完成之后就启动起来的,它在启动的过程中,会读取根目录下的一个脚本文件init.rc,以便可以将其他需要开机启动的进程也一起启动起来。 ...

         Zygote进程时由Android系统的第一个进程init启动起来的。init进程时在内核加载完成之后就启动起来的,它在启动的过程中,会读取根目录下的一个脚本文件init.rc,以便可以将其他需要开机启动的进程也一起启动起来。

         Zygote进程在脚本文件init.rc中的启动脚本如下:

    service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
        socket zygote stream 666
         第一行表示Zygote进程是以服务的形式启动的,并且它对应的应用程序文件为/system/bin/app_process。接下来的四个选项是Zygote进程的启动参数。其中最后一个参数"--start-system-server"表示Zygote进程在启动完成之后,需要马上将System进程也启动起来。

         第二行表示Zygote进程在启动的过程中,需要在内部创建一个名称为"zygote"的Socket。这个Socket是用来执行进程间通信的,它的访问权限被设置为666,即所有用户都可以对它进行读和写。


         我们先分析Zygote是如何在启动的过程中创建一个名称为"zygote"的Socket。

         由于Zygote进程在脚本init.rc中配置了以服务的形式来启动,因此,init进程在启动时,就会调用函数service_start来启动它,如下:

    void service_start(struct service *svc, const char *dynamic_args)//svc用来描述一个即将要启动的服务,dynamic_args为NULL
    {
        ......
        pid_t pid;
        ......
        pid = fork();//init进程fork出Zygote进程
    
        if (pid == 0) {//Zygote进程
            struct socketinfo *si;
            ......
            for (si = svc->sockets; si; si = si->next) {//svc->sockets描述即将要启动的服务的Socket列表
                int socket_type = (
                        !strcmp(si->type, "stream") ? SOCK_STREAM :
                            (!strcmp(si->type, "dgram") ? SOCK_DGRAM : SOCK_SEQPACKET));
                int s = create_socket(si->name, socket_type,
                                      si->perm, si->uid, si->gid);//name为socket,socket_type为stream,创建一个Socket,返回一个描述符
                if (s >= 0) {
                    publish_socket(si->name, s);//create_socket返回的描述符最后会通过函数publish_socket发布到系统中
                }
            }
    
           ......
    
            setpgid(0, getpid());
    
           /* as requested, set our gid, supplemental gids, and uid */
            if (svc->gid) {
                setgid(svc->gid);
            }
            if (svc->nr_supp_gids) {
                setgroups(svc->nr_supp_gids, svc->supp_gids);
            }
            if (svc->uid) {//由于svc->uid为空,所有Zygote进程的uid还为0,依然是root权限
                setuid(svc->uid);
            }
    
            if (!dynamic_args) {
                if (execve(svc->args[0], (char**) svc->args, (char**) ENV) < 0) {//svc->args[0]为/system/bin/app_process,svc->args静态启动参数,注意这个数组里面有"--start-system-server"
                    ERROR("cannot execve('%s'): %s\n", svc->args[0], strerror(errno));
                }
            } else {
                ......
            }
            _exit(127);
        }
    
        ......
    }
        接着我们分析函数create_socket和public_socket的实现,以便可以了解它们是如何为Zygote进程创建一个名称为"zygote"的Socket。

        函数create_socket的实现如下所示。

    int create_socket(const char *name, int type, mode_t perm, uid_t uid, gid_t gid)
    {
        struct sockaddr_un addr;
        int fd, ret;
    
        fd = socket(PF_UNIX, type, 0);//创建一个socket,这个Socket使用文件描述符fd描述
        ......
    
        memset(&addr, 0 , sizeof(addr));
        addr.sun_family = AF_UNIX;//创建了一个类型为AF_UNIX的Socket地址addr,这个Socket地址有一个对应的设备文件,即ANDROID_SOCKET_DIR/name,如下一行代码所示
        snprintf(addr.sun_path, sizeof(addr.sun_path), ANDROID_SOCKET_DIR"/%s",//name为zygote,ANDROID_SOCKET_DIR为/dev/socket
                 name);
    
        ......
    
        ret = bind(fd, (struct sockaddr *) &addr, sizeof (addr));//bind将文件描述符fd所描述的Socket与Socket地址addr绑定起来之后,我们就可以得到一个设备文件/dev/socket/zygote
        ......
    
        chown(addr.sun_path, uid, gid);//chown设置设备文件/dev/socket/zygote的用户ID,用户组ID
        chmod(addr.sun_path, perm);//chmod设置设备文件/dev/socket/zygote的访问权限,参数perm为666,因为设备文件/dev/socket/zygote是可以被任意用户访问的。
    
        ......
    
        return fd;//返回描述符
    }
        函数publish_socket的实现如下:

    static void publish_socket(const char *name, int fd)
    {
        char key[64] = ANDROID_SOCKET_ENV_PREFIX;
        char val[64];
    
        strlcpy(key + sizeof(ANDROID_SOCKET_ENV_PREFIX) - 1,
                name,
                sizeof(key) - sizeof(ANDROID_SOCKET_ENV_PREFIX));//key值为ANDROID_SOCKET_zygote
        snprintf(val, sizeof(val), "%d", fd);//fd是一个文件描述符,指向了前面所创建的一个Socket,把fd格式化为一个字符串,并且保存在变量val中
        add_environment(key, val);//在系统中增加了一个名称为key的环境变量,并且将它的值设置为val。这就相当于将前面所创建的一个Socket的文件描述符保存在名称为"ANDROID_SOCKET_zygote"的环境变量中
    
        /* make sure we don't close-on-exec */
        fcntl(fd, F_SETFD, 0);
    }
        在下面,我们就会看到,Zygote进程在启动的过程中,会根据这个环境变量的值来创建一个Server端Socket,等到启动完成之后,再在这个Server端Socket上等待Activtiy管理服务ActivityMangerService请求它创建新的应用程序进程。


        回到service_start中,继续执行如下代码:

    if (!dynamic_args) {
                if (execve(svc->args[0], (char**) svc->args, (char**) ENV) < 0) {//svc->args[0]为/system/bin/app_process,svc->args静态启动参数,注意这个数组里面有"--start-system-server"
                    ERROR("cannot execve('%s'): %s\n", svc->args[0], strerror(errno));
                }
            }
        在Zygote进程中加载的应用程序文件为system/bin/app_process,因此,接下来我们就从这个应用程序文件的入口函数main开始分析Zygote进程的启动流程。
    int main(int argc, const char* const argv[])
    {
        // These are global variables in ProcessState.cpp
        mArgC = argc;
        mArgV = argv;
        
        mArgLen = 0;
        for (int i=0; i<argc; i++) {
            mArgLen += strlen(argv[i]) + 1;
        }
        mArgLen--;
    
        AppRuntime runtime;//创建了一个AppRuntime对象runtime
        const char *arg;
        const char *argv0;
    
        argv0 = argv[0];
    
        // Process command line arguments
        // ignore argv[0]
        argc--;
        argv++;
    
        // Everything up to '--' or first non '-' arg goes to the vm
        
        int i = runtime.addVmArguments(argc, argv);
    
        // Next arg is parent directory
        if (i < argc) {
            runtime.mParentDir = argv[i++];
        }
    
        // Next arg is startup classname or "--zygote"
        if (i < argc) {
            arg = argv[i++];
            if (0 == strcmp("--zygote", arg)) {//启动参数中有"--zygote"
                bool startSystemServer = (i < argc) ? 
                        strcmp(argv[i], "--start-system-server") == 0 : false;//startSystemServer的值等于true,表示Zygote进程在启动完成之后,需要将System进程启动起来
                setArgv0(argv0, "zygote");
                set_process_name("zygote");//设置进程名为zygote
                runtime.start("com.android.internal.os.ZygoteInit",
                    startSystemServer);
            } else {
                ......
            }
        } else {
            ......
        }
    
    }
    
        AppRuntime类的成员函数start是从其父类AndroidRuntime继承下来的,因此,接下来我们就继续分析AndroidRuntime类的成员函数start的实现。

    /*
    * Start the Android runtime.  This involves starting the virtual machine
    * and calling the "static void main(String[] args)" method in the class
    * named by "className".
    */
    void AndroidRuntime::start(const char* className, const bool startSystemServer)
    {
    	......
    
    	char* slashClassName = NULL;
    	char* cp;
    	JNIEnv* env;
    
    	......
    
    	/* start the virtual machine */
    	if (startVm(&mJavaVM, &env) != 0)
    		goto bail;
    
    	/*
    	* Register android functions.
    	*/
    	if (startReg(env) < 0) {
    		LOGE("Unable to register all android natives\n");
    		goto bail;
    	}
    
    	/*
    	* We want to call main() with a String array with arguments in it.
    	* At present we only have one argument, the class name.  Create an
    	* array to hold it.
    	*/
    	jclass stringClass;
    	jobjectArray strArray;
    	jstring classNameStr;
    	jstring startSystemServerStr;
    	stringClass = env->FindClass("java/lang/String");
    	assert(stringClass != NULL);
    	strArray = env->NewObjectArray(2, stringClass, NULL);
    	assert(strArray != NULL);
    	classNameStr = env->NewStringUTF(className);
    	assert(classNameStr != NULL);
    	env->SetObjectArrayElement(strArray, 0, classNameStr);
    	startSystemServerStr = env->NewStringUTF(startSystemServer ?
    		"true" : "false");
    	env->SetObjectArrayElement(strArray, 1, startSystemServerStr);
    
    	/*
    	* Start VM.  This thread becomes the main thread of the VM, and will
    	* not return until the VM exits.
    	*/
    	jclass startClass;
    	jmethodID startMeth;
    
    	slashClassName = strdup(className);
    	for (cp = slashClassName; *cp != '\0'; cp++)
    		if (*cp == '.')
    			*cp = '/';
    
    	startClass = env->FindClass(slashClassName);
    	if (startClass == NULL) {
    		......
    	} else {
    		startMeth = env->GetStaticMethodID(startClass, "main",
    			"([Ljava/lang/String;)V");
    		if (startMeth == NULL) {
    			......
    		} else {
    			env->CallStaticVoidMethod(startClass, startMeth, strArray);
    			......
    		}
    	}
    
    	......
    }
         startVm在Zygote进程中创建了一个虚拟机实例,然后startReg在这个虚拟机实例中注册了一系列JNI方法,这两步的执行流程可参考Dalvik虚拟机的启动过程分析Dalvik虚拟机总结

         最后调用com.android.internal.os.ZygoteInit类的静态成员函数main来进一步启动Zygote进程。env->CallStaticVoidMethod(startClass, startMeth, strArray)实际上通过Dalvik虚拟机去解释执行相关java代码,具体请参考Dalvik虚拟机的运行过程分析


         接着我们继续来分析com.android.internal.os.ZygoteInit类的静态成员函数main的实现。

    public class ZygoteInit {
    	......
    
    	public static void main(String argv[]) {
    		try {
    			......
    
    			registerZygoteSocket();//创建一个Server端Socket,这个Server端Socket是用来等待Activity管理服务ActivityManagerService请求Zygote进程创建新的应用程序进程的	
    			
    			......
    
    			......
    
    			if (argv[1].equals("true")) {
    				startSystemServer();//启动System进程,以便它可以将系统的关键服务启动起来
    			} else if (!argv[1].equals("false")) {
    				......
    			}
    
    			......
    
    			if (ZYGOTE_FORK_MODE) {//false
    				......
    			} else {
    				runSelectLoopMode();
    			}
    
    			......
    		} catch (MethodAndArgsCaller caller) {
    			......
    		} catch (RuntimeException ex) {
    			......
    		}
    	}
    
    	......
    }
        我们先来分析registerZygoteSocket,如下:

       private static void registerZygoteSocket() {
            if (sServerSocket == null) {
                int fileDesc;
                try {
                    String env = System.getenv(ANDROID_SOCKET_ENV);//获得一个名称为"ANDROID_SOCKET_zygote"的环境变量的值
                    fileDesc = Integer.parseInt(env);//将它转换位一个文件描述符,我们知道这个文件描述符是用来描述一个类型为AF_UNIX的Socket。
                } catch (RuntimeException ex) {
                    throw new RuntimeException(
                            ANDROID_SOCKET_ENV + " unset or invalid", ex);
                }
    
                try {
                    sServerSocket = new LocalServerSocket(
                            createFileDescriptor(fileDesc));//创建了一个Server端Socket,并且保存在ZygoteInit的静态成员变量sServerSocket中
                } catch (IOException ex) {
                    throw new RuntimeException(
                            "Error binding to local socket '" + fileDesc + "'", ex);
                }
            }
        }
        然后我们来分析startSystemServer,如下:

    public class ZygoteInit {
    	......
    
    	private static boolean startSystemServer()
    			throws MethodAndArgsCaller, RuntimeException {
    		/* Hardcoded command line to start the system server */
    		String args[] = {
    			"--setuid=1000",
    			"--setgid=1000",
    			"--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,3001,3002,3003",
    			"--capabilities=130104352,130104352",
    			"--runtime-init",
    			"--nice-name=system_server",
    			"com.android.server.SystemServer",
    		};
    		ZygoteConnection.Arguments parsedArgs = null;
    
    		int pid;
    
    		try {
    			parsedArgs = new ZygoteConnection.Arguments(args);
    
    			......
    
    			/* Request to fork the system server process */
    			pid = Zygote.forkSystemServer(
    				parsedArgs.uid, parsedArgs.gid,
    				parsedArgs.gids, debugFlags, null,
    				parsedArgs.permittedCapabilities,
    				parsedArgs.effectiveCapabilities);//System进程uid为1000
    		} catch (IllegalArgumentException ex) {
    			......
    		}
    
    		/* For child process */
    		if (pid == 0) {//子进程,System进程
    			handleSystemServerProcess(parsedArgs);//System进程,后续再分析
    		}
    
    		return true;
    	}
    	
    	......
    }
         首先创建了字符串数组args,用来保存System进程的启动参数。接着调用forkSystemServer来创建一个子进程,这个子进程就是Android系统的System进程。这里可以看出,Android系统的System进程的用户id和用户组id都被设置为1000,shell中显示的就是system。

         返回到com.android.internal.os.ZygoteInit类的静态成员函数main,继续分析runSelectLoopMode,如下:

    public class ZygoteInit {
    	......
    
    	private static void runSelectLoopMode() throws MethodAndArgsCaller {
    		ArrayList<FileDescriptor> fds = new ArrayList();
    		ArrayList<ZygoteConnection> peers = new ArrayList();
    		FileDescriptor[] fdArray = new FileDescriptor[4];//首先创建了一个大小为4的Socket文件描述符数组fdArray,表示Zygote进程做多能同时处理4个Socket连接	
    
    		fds.add(sServerSocket.getFileDescriptor());//将ZygoteInit类的静态成员变量sServerSocket所描述的一个Socket的文件描述符添加到Socket文件描述符列表fds中
    		peers.add(null);
    
    		int loopCount = GC_LOOP_COUNT;
    		while (true) {
    			int index;
    
    			......
    
    
    			try {
    				fdArray = fds.toArray(fdArray);//将保存在Socket文件描述符列表fds中的Socket文件描述符转移到Socket文件描述符数组fdArray中
    				index = selectReadable(fdArray);//来监控保存在这个数组中的Socket是否有数据可读。
    			} catch (IOException ex) {
    				throw new RuntimeException("Error in select()", ex);
    			}
    
    			if (index < 0) {
    				throw new RuntimeException("Error in select()");
    			} else if (index == 0) {//接收到连接,
    				ZygoteConnection newPeer = acceptCommandPeer();
    				peers.add(newPeer);
    				fds.add(newPeer.getFileDesciptor());
    			} else {//接收到Activity管理服务ActivityManangerService发送过来的创建应用程序进程请求
    				boolean done;
    				done = peers.get(index).runOnce();//来创建一个应用程序进程
    
    				if (done) {
    					peers.remove(index);
    					fds.remove(index);
    				}
    			}
    		}
    	}
    
    	......
    }      
        selectReadable来监控保存在这个数组中的Socket是否有数据可读,一个数据可读就意味着它接收到了一个连接或者一个请求。如果index为0,说明它接收到了一个连接。index大于0,说明接收到请求。

        ZygoteInit中静态函数startSystemServer中调用了Zygote.forkSystemServer,ZygoteInit中静态函数runSelectLoopMode中调用了selectReadable,都是native方法,如下:

    native public static int forkAndSpecialize(int uid, int gid, int[] gids,
                int debugFlags, int[][] rlimits);
    static native int selectReadable(FileDescriptor[] fds) throws IOException;
        我们刚刚说过了com.android.internal.os.ZygoteInit类的静态成员函数main,是Dalvik虚拟机解释执行的;那么执行到这些native方法,实际上JNI方法是直接在本地操作系统上执行的,而不是由Dalvik虚拟机解释器执行。具体请参考Dalvik虚拟机JNI方法的注册过程分析Dalvik虚拟机总结。相关直接在本地操作系统执行代码如下:

    void dvmCallMethodV(Thread* self, const Method* method, Object* obj,
        bool fromJni, JValue* pResult, va_list args)
    {
        ......
    
        if (dvmIsNativeMethod(method)) {
            TRACE_METHOD_ENTER(self, method);
            /*
             * Because we leave no space for local variables, "curFrame" points
             * directly at the method arguments.
             */
            (*method->nativeFunc)(self->curFrame, pResult, method, self);//直接去执行
            TRACE_METHOD_EXIT(self, method);
        } else {
            dvmInterpret(self, method, pResult);//解释执行
        }
    
        ......
    }

         Zygote.forkSystemServer创建了一个进程,具体请参考Dalvik虚拟机进程和线程的创建过程分析

    展开全文
  • Zygote进程浅析

    千次阅读 2018-04-20 19:35:01
    zygote是受精卵的意思,它是Android中的一个非常重要的守护进程服务(Daem Service),所有的其他Dalvik虚拟机进程都是通过zygote孵化(fork)出来的。Android应用程序是由Java语言编写的,运行在各自独立的Dalvik...
  • zygote进程启动

    2019-01-25 11:15:06
    1.init.cpp —&gt; main() main()方法主要完成一下 6 件事: klog_init() 将log写入到/dev/kmsg中 process_kernel_cmdline()解析内核启动参数 signal_handler_init()函数设置了信号处理函数 ...
  • Zygote进程简介

    千次阅读 2011-02-27 00:00:00
    关于Zygote进程与Dalvik虚拟机进程关系的简介。
  • Zygote进程详解

    千次阅读 2015-04-03 16:16:49
    Zygote进程是怎么启动的? Android系统是基于Linux内核的,而在Linux系统中,所有的进程都是init进程的子孙进程,也就是说,所有的进程都是直接或者间接地由init进程fork出来的。Zygote进程也不例外,它是在系统...
  • zygote进程认识

    2018-05-08 13:53:50
    今天开始正式一个android得项目,学习了一下zygote进程PID为1的为init进程;PPID为1的为daemon进程,PID为38的即zygote进程,她也是由init(1号进程)启动的,而PPID为38的进程则为zygote的子进程,基本为应用程序...
  • Zygote进程启动

    2020-02-21 11:12:15
    Zygote被称为孵化器,因为在Android中DVM、ART、应用程序进程以及系统服务进程(SystemServer)都是有它来创建的,而且是通过是通过fork的形式来创建应用程序进程和SystemServer,所以这些进程的内部会获取一个DVM...
  • zygote进程

    2019-05-02 17:52:09
    https://www.cnblogs.com/samchen2009/p/3294713.htmlhttps://blog.csdn.net/ctthuangcheng/article/details/42207601 转载于:https://blog.51cto.com/haidragon/2388371
  • init进程与zygote进程

    2017-11-06 11:33:41
    通过ps命令了解Android中运行的进程和android的守护...zygote进程生成系统服务器端和各种java应用程序进程。 init进程在所有系统中通常具有固定的pid值(pid=1),但启动其他进程时,不同系统赋予的pid值也有所不同。
  • Android进程-zygote进程

    2018-01-31 17:49:32
    一,zygote进程 zygote进程的父进程是init,zygote也是所有应用的父进程,也是system_server进程的父进程。   1.1 Zygote系统源码组成 1) Zygote.java(frameworks/base/core/java/com/android/internal/os/) ...
  • Android O: zygote进程分析

    千次阅读 2018-02-26 11:13:10
    本篇博客主要结合Android 8.0的代码,回顾一下zygote进程的流程。
  • Android zygote 进程的启动过程分析

    千次阅读 2019-07-11 23:58:57
    zygote进程在 Android 开发中属于比较底层的内容,然而要透彻的理解 AMS、WMS 和 IPC 等,不可避免的要先理解zogyte进程,因此本文即作为对自己的学习记录,也想分享出来和遇到同样问题的读者交流。
  • Android系统启动过程往细了说可以分为5步: Loader –》Kernel –》Native –》Framework –》Application ...Boot ROM: 当手机处于关机状态时,长按Power键开机,引导芯片开始从固化在ROM里的预设出代码开始...
  • android zygote 进程分析

    2019-02-28 16:35:58
    在 Android 系统中,所有的应用程序以及系统服务进程 SystemService 都是由 zygote 进程孕育 (fork) 出来的。 创建 java 虚拟机,加载系统资源 应用程序启动过程中负责 fork 出子进程 在 Android 应用程序启动时...
  • Zygote进程启动流程

    2020-01-17 16:49:43
    博客同步至github博客:Zygote进程启动流程 使用到的相关源码:https://github.com/JesusYoung/AndroidResourceCode9.0/tree/master 基于Android 9.0 1、Zygote进程 Zygote是在init进程启动时创建的,它又称为孵化器...

空空如也

1 2 3 4 5 ... 20
收藏数 2,345
精华内容 938
关键字:

zygote进程