android源码阅读-----zygote进程

来源:互联网 发布:amd优化什么意思 编辑:程序博客网 时间:2024/06/07 06:56

android源码阅读—–Zygote进程

Zygote进程简介:

    zygote进程是安卓中非常重要的一个进程,与init进程 SystemServ进程共同支撑着Android环境。    Zygote进程与一般进程的区别是:

一般进程fork出子进程之后,会继续调用系统的exec,将一个新的可执行文件的内容替换当前的进程的代码段,数据段,堆和栈段,然后zogte只调用的了fork,没有调用exec,这是因为Android中执行的是java代码,java代码所执行的环境要求是一样的,就是虚拟机

    这也是Zygote进程初始化时会创建虚拟机,同时把需要的系统类库和资源文件加载到内存,当他fork出子进程的时候 子进程也集成了能正常工作的虚拟机和各种资源文件,然后子进程把apk文件的字节码装载进去运行就行了,app的启动时间会少很多
Zgote vm resorce lib …

————————————————————

Child vm resorce lib … APK字节码

跟继承类似,子进程拥有父进程的资源

Zygote进程的初始化

前篇博客有说到,init进程运行的时候会加载init.rc,根据里面的配置来fork一些进程等,有兴趣的童鞋可以去翻,里面分为两种类型,action 和 service Zygote进程就是以service的方式启动的,在5.0系统中,zygote的启动发生了一些变化,以前是直接写在init.rc的代码块中的,现在则通过import的方式引用过来了

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

上面可以看到,init.rc并不是直接引用哪个固定的文件,而是根据ro.zyote的内容来引入不同的文件。这个主要是因为从5.0开始Android开始支持64位的编译(喜大普奔),所以zygote也会有32和64位版本的区别,在init.rc同一目录下,有这么四个文件

init.zygote32_64.rcinit.zygote32.rcinit.zygote64_32.rcinit.zygote64.rc

从这里看出 android支持四种运行模式, 纯32位,纯64位,32为主、64为辅,64为主,32为辅

init.zygote32_64.rc

service zygote /system/bin/app_process32 -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 media    onrestart restart netdservice zygote_secondary /system/bin/app_process64 -Xzygote /system/bin --zygote --socket-name=zygote_secondary    class main    socket zygote_secondary stream 660 root system    onrestart restart zygote

上面的代码有过敲命令行的童鞋应该了解怎么回事了,他执行的是app_process32 sencondary执行的是64位的,这就好理解了。

app_process位于frameworks/base/cmds/app_process/app_main.cpp main函数如下,代码有些长,不过自己加了一点关键性的注释,希望能耐着性子看一下

         static const char ABI_LIST_PROPERTY[] = "ro.product.cpu.abilist32";        static const char ZYGOTE_NICE_NAME[] = "zygote";    int main(int argc, char* const argv[])    {         ......        AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));        // Process command line arguments        // ignore argv[0]        argc--;        argv++;    // Everything up to '--' or first non '-' arg goes to the vm.    //    // The first argument after the VM args is the "parent dir", which    // is currently unused.    //    // After the parent dir, we expect one or more the following internal    // arguments :    //    // --zygote : Start in zygote mode    // --start-system-server : Start the system server.    // --application : Start in application (stand alone, non zygote) mode.    // --nice-name : The nice name for this process.    //    // For non zygote starts, these arguments will be followed by    // the main class name. All remaining arguments are passed to    // the main method of this class.    //    // For zygote starts, all remaining arguments are passed to the zygote.    // main function.    //    // Note that we must copy argument string values since we will rewrite the    // entire argument block when we apply the nice name to argv0.    int i;    for (i = 0; i < argc; i++) {        if (argv[i][0] != '-') {            break;        }        if (argv[i][1] == '-' && argv[i][2] == 0) {            ++i; // Skip --.            break;        }        runtime.addOption(strdup(argv[i]));}    // Parse runtime arguments.  Stop at first unrecognized option.    bool zygote = false;    bool startSystemServer = false;    bool application = false;    String8 niceName;    String8 className;    ++i;  // Skip unused "parent dir" argument.    while (i < argc) {        const char* arg = argv[i++];        if (strcmp(arg, "--zygote") == 0) {            zygote = true;            niceName = ZYGOTE_NICE_NAME;//"zygote"        } else if (strcmp(arg, "--start-system-server") == 0) {            startSystemServer = true;        } else if (strcmp(arg, "--application") == 0) {            ......        } else if (strncmp(arg, "--nice-name=", 12) == 0) {            ......        } else if (strncmp(arg, "--", 2) != 0) {            ......        } else {            --i;            break;        }    }    Vector<String8> args;//该参数接下来要传入AndroidRuntime.start函数    if (!className.isEmpty()) {        ......    } else {        // We're in zygote mode.        maybeCreateDalvikCache();        if (startSystemServer) {            args.add(String8("start-system-server"));        }        char prop[PROP_VALUE_MAX];        if (property_get(ABI_LIST_PROPERTY, prop, NULL) == 0) {            LOG_ALWAYS_FATAL("app_process: Unable to determine ABI list from property %s.",                ABI_LIST_PROPERTY);            return 11;        }        String8 abiFlag("--abi-list=");        abiFlag.append(prop);//"--abi-list=ro.product.cpu.abilist32"        args.add(abiFlag);        // In zygote mode, pass all remaining arguments to the zygote        // main() method.        for (; i < argc; ++i) {            args.add(String8(argv[i]));        }    }    if (!niceName.isEmpty()) {        runtime.setArgv0(niceName.string());        set_process_name(niceName.string());//将进程名修改成"zygote"    }    if (zygote) {        runtime.start("com.android.internal.os.ZygoteInit", args);    } else if (className) {        runtime.start("com.android.internal.os.RuntimeInit", args);    } else {        ......    }}

这个函数的主要功能就是:

  • 解析init.rc里面的参数传到AndroidRuntime里面
  • 修改进程的名字为zygote,
  • 调用AndroidRuntime的start函数;
/**    AppRuntime 是内部类,继承AndroidRuntime**/    class AppRuntime : public AndroidRuntime{public:    AppRuntime(char* argBlockStart, const size_t argBlockLength)        : AndroidRuntime(argBlockStart, argBlockLength)        , mClass(NULL)    {    }

AppRuntime是一个内部类,就在app_main里面,继承了AndroidRuntime ,它位于 \frameworks\base\core\jni\AndroidRuntime.cpp文件中

static AndroidRuntime* gCurRuntime = NULL;AndroidRuntime::AndroidRuntime(char* argBlockStart, const size_t argBlockLength) :        mExitWithoutCleanup(false),        mArgBlockStart(argBlockStart),        mArgBlockLength(argBlockLength){    SkGraphics::Init();    // There is also a global font cache, but its budget is specified in code    // see SkFontHost_android.cpp    // Pre-allocate enough space to hold a fair number of options.    mOptions.setCapacity(20);    assert(gCurRuntime == NULL);        // one per process    gCurRuntime = this;}

这个gCurRuntime静态变量指向它本身,下面有个这样的方法

AndroidRuntime* AndroidRuntime::getRuntime(){    return gCurRuntime;}

接下来就该执行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". * * Passes the main function two arguments, the class name and the specified * options string. */  //这里的className为"com.android.internal.os.ZygoteInit"void AndroidRuntime::start(const char* className, const Vector<String8>& options){    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)));        }    }    //这里将rootDir的目录设置为/system,ANDROID_ROOT为/system    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) != 0) {在这里打开了java虚拟机        return;    }    onVmCreated(env);    /*     * Register android functions.     */    if (startReg(env) < 0) {  //在这个不经意的一行代码中,注册了jni函数,原话是这样的Register android native functions with the VM.        ALOGE("Unable to register all android natives\n");        return;    }    /*     * We want to call main() with a String array with arguments in it.     * At present we have two arguments, the class name and an option string.     * Create an array to hold them.     */    jclass stringClass;    jobjectArray strArray;    jstring classNameStr;    stringClass = env->FindClass("java/lang/String");    assert(stringClass != NULL);    strArray = env->NewObjectArray(options.size() + 1, stringClass, NULL);    assert(strArray != NULL);    classNameStr = env->NewStringUTF(className);    assert(classNameStr != NULL);    env->SetObjectArrayElement(strArray, 0, classNameStr);    for (size_t i = 0; i < options.size(); ++i) {        jstring optionsStr = env->NewStringUTF(options.itemAt(i).string());        assert(optionsStr != NULL);        env->SetObjectArrayElement(strArray, i + 1, optionsStr);    }    /*     * Start VM.  This thread becomes the main thread of the VM, and will     * not return until the VM exits.     */    char* slashClassName = toSlashClassName(className);    jclass startClass = env->FindClass(slashClassName);    if (startClass == NULL) {        ALOGE("JavaVM unable to locate class '%s'\n", slashClassName);        /* keep going */    } else {    //获取"com.android.internal.os.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);#if 0            if (env->ExceptionCheck())                threadExitUncaughtException(env);#endif        }    }    free(slashClassName);    ALOGD("Shutting down VM\n");    if (mJavaVM->DetachCurrentThread() != JNI_OK)        ALOGW("Warning: unable to detach main thread\n");    if (mJavaVM->DestroyJavaVM() != 0)        ALOGW("Warning: VM did not shut down cleanly\n");}

综上所述 AndroidRuntime.start函数主要做了三个工作:

  • 启动虚拟机 调用AndroidRuntime.startVm启动虚拟机

  • 注册jni函数 调用AndroidRuntime.startReg注册jni函数

  • 调用ZygoteInit.main函数

下面咱们跑到ZygoteInit.java 下面 (我的天,终于跑到java上面去了,累死了)
目录:\frameworks\base\core\Java\com\android\internal\os\ZygoteInit.java

public static void main(String argv[]) {        try {            // Start profiling the zygote initialization.            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]);                }            }            if (abiList == null) {                throw new RuntimeException("No ABI list supplied.");            }            //注册Zygote的Socket监听端口,用来接收应用程序启动的消息            registerZygoteSocket(socketName);            EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,                SystemClock.uptimeMillis());                //装载系统资源            preload();            EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,                SystemClock.uptimeMillis());            // Finish profiling the zygote initialization.            SamplingProfilerIntegration.writeZygoteSnapshot();            // Do an initial gc to clean up after startup            gc();            // Disable tracing so that forked processes do not inherit stale tracing tags from            // Zygote.            Trace.setTracingEnabled(false);            //启动SystemServer进程            if (startSystemServer) {                startSystemServer(abiList, socketName);            }            Log.i(TAG, "Accepting command socket connections");            //进入监听和接收消息的循环            runSelectLoop(abiList);            closeServerSocket();        } catch (MethodAndArgsCaller caller) {            caller.run();        } catch (RuntimeException ex) {            Log.e(TAG, "Zygote died with exception", ex);            closeServerSocket();            throw ex;        }    }

ZygoteInit.main主要做了三项工作:

  1. 调用registerZygoteSocket,注册zygote的socket。
  2. 调用startSystemServer,启动SystemServer。
  3. 调用runSelectLoop,zygote无限循环等待创建进程的请求

咱来一个个的分析 。。 首先是socket,registerZygoteSocket是ZygoteInit的一个方法

    /**     * Registers a server socket for zygote command connections     *     * @throws RuntimeException when open fails     */    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) {                throw new RuntimeException(fullSocketName + " unset or invalid", ex);            }            try {                sServerSocket = new LocalServerSocket(                        createFileDescriptor(fileDesc));            } catch (IOException ex) {                throw new RuntimeException(                        "Error binding to local socket '" + fileDesc + "'", ex);            }        }    }

这里根据zygote的socket的文件描述符创建了LocalServerSocket对象并保存在zygoteInit的类型LocalServerSocket的静态成员变量sServerSocket中,若又想反过来获得zygote的socket的文件描述符,只要调用LocalServerSocket.getFileDescriptor即可。具体的细节不去深入的分析了,有点复杂,有兴趣的童鞋可以自己去网上查找一些资料。

然后是调用startSystemServer

 /**     * Prepare the arguments and fork for the system server process.     */    private static boolean startSystemServer(String abiList, String socketName)            throws MethodAndArgsCaller, RuntimeException {        long capabilities = posixCapabilitiesAsBits(            OsConstants.CAP_BLOCK_SUSPEND,            OsConstants.CAP_KILL,            OsConstants.CAP_NET_ADMIN,            OsConstants.CAP_NET_BIND_SERVICE,            OsConstants.CAP_NET_BROADCAST,            OsConstants.CAP_NET_RAW,            OsConstants.CAP_SYS_MODULE,            OsConstants.CAP_SYS_NICE,            OsConstants.CAP_SYS_RESOURCE,            OsConstants.CAP_SYS_TIME,            OsConstants.CAP_SYS_TTY_CONFIG        );        /* 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,1032,3001,3002,3003,3006,3007",            "--capabilities=" + capabilities + "," + capabilities,            "--runtime-init",            "--nice-name=system_server",            "com.android.server.SystemServer",        };        ZygoteConnection.Arguments parsedArgs = null;        int pid;        try {            parsedArgs = new ZygoteConnection.Arguments(args);            ZygoteConnection.applyDebuggerSystemProperty(parsedArgs);            ZygoteConnection.applyInvokeWithSystemProperty(parsedArgs);            /* Request to fork the system server process */            //对zygote进程进行fork,得到的子进程就是SystemServer进程,返回的子进程pid为0            pid = Zygote.forkSystemServer(                    parsedArgs.uid, parsedArgs.gid,                    parsedArgs.gids,                    parsedArgs.debugFlags,                    null,                    parsedArgs.permittedCapabilities,                    parsedArgs.effectiveCapabilities);        } catch (IllegalArgumentException ex) {            throw new RuntimeException(ex);        }        /* For child process */        if (pid == 0) {            if (hasSecondZygote(abiList)) {                waitForSecondaryZygote(socketName);            }            handleSystemServerProcess(parsedArgs);        }        return true;    }

这边就比较有意思了,开头说了 SystemServer也是安卓世界中非常重要的一部分。 同过fork,来fork出SystemServer进程,代码首先通过ZygoteConnection来解析出将来创建SystemServer进程时所需的参数。除了能够解析参数外,ZygoteConnection另外一个功能就是记录zygote的socket套接字连接。

在创建好SysteServer进程后,在SystemServer进程中调用handleSystemServerProcess处理,处理时会调用RuntimeInit的zygoteInit方法

/** * Main entry point for runtime initialization.  Not for * public consumption. * @hide */public class RuntimeInit {    ......    /**     * The main function called when started through the zygote process. This     * could be unified with main(), if the native code in nativeFinishInit()     * were rationalized with Zygote startup.<p>     * @param targetSdkVersion target SDK version     * @param argv arg strings     */    public static final void zygoteInit(int targetSdkVersion, String[] argv, ClassLoader classLoader)            throws ZygoteInit.MethodAndArgsCaller {        if (DEBUG) Slog.d(TAG, "RuntimeInit: Starting application from zygote");        redirectLogStreams();        commonInit();//常规的初始化        nativeZygoteInit();//bind通信机制的准备工作        applicationInit(targetSdkVersion, argv, classLoader);    }    ......    private static void applicationInit(int targetSdkVersion, String[] argv, ClassLoader classLoader)            throws ZygoteInit.MethodAndArgsCaller {        // If the application calls System.exit(), terminate the process        // immediately without running any shutdown hooks.  It is not possible to        // shutdown an Android application gracefully.  Among other things, the        // Android runtime shutdown hooks close the Binder driver, which can cause        // leftover running threads to crash before the process actually exits.        nativeSetExitWithoutCleanup(true);        // We want to be fairly aggressive about heap utilization, to avoid        // holding on to a lot of memory that isn't needed.        VMRuntime.getRuntime().setTargetHeapUtilization(0.75f);        VMRuntime.getRuntime().setTargetSdkVersion(targetSdkVersion);        final Arguments args;        try {            args = new Arguments(argv);        } catch (IllegalArgumentException ex) {            Slog.e(TAG, ex.getMessage());            // let the process exit            return;        }        // Remaining arguments are passed to the start class's static main        invokeStaticMain(args.startClass, args.startArgs, classLoader);//args.startClass为"com.android.server.SystemServer"    }}

为了大家方便我就把两段代码放一起了,最后发现,调用invokeStaticMain执行了SystemServer.main ,SystemServer就启动完成, 然后执行ZygoteInit.runSelectLoop函数

 /**     * Runs the zygote process's select loop. Accepts new connections as     * they happen, and reads commands from connections one spawn-request's     * worth at a time.     *     * @throws MethodAndArgsCaller in a child process when a main() should     * be executed.     */    private static void runSelectLoop(String abiList) throws MethodAndArgsCaller {        ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>();        ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();        FileDescriptor[] fdArray = new FileDescriptor[4];        fds.add(sServerSocket.getFileDescriptor());        peers.add(null);        int loopCount = GC_LOOP_COUNT;        while (true) {            int index;            /*             * Call gc() before we block in select().             * It's work that has to be done anyway, and it's better             * to avoid making every child do it.  It will also             * madvise() any free memory as a side-effect.             *             * Don't call it every time, because walking the entire             * heap is a lot of overhead to free a few hundred bytes.             */            if (loopCount <= 0) {                gc();                loopCount = GC_LOOP_COUNT;            } else {                loopCount--;            }            try {                fdArray = fds.toArray(fdArray);                //selectReadable是一个native函数,内部调用select等待客户端连接,客户端连接上之后就会返回。                 //返回值:                 //<0:  内部发生错误                 //=0:  该客户端第一次连接到服务端                 //>0:  客户端与服务端已经建立连接,并开始发送数据                 index = selectReadable(fdArray);            } catch (IOException ex) {                throw new RuntimeException("Error in select()", ex);            }            if (index < 0) {                throw new RuntimeException("Error in select()");            } else if (index == 0) {//客户端第一次请求服务端,服务端调用accept与客户端建立连接。客户端在zygote中以ZygoteConnection对象表示。                ZygoteConnection newPeer = acceptCommandPeer(abiList);                peers.add(newPeer);                fds.add(newPeer.getFileDescriptor());            } else {//返回>0,表明发送数据的客户端的index,peers.get(index)取得发送数据客户端的ZygoteConnection对象,之后调用runOnce  函数处理具体的请求。                boolean done;                done = peers.get(index).runOnce();                //请求处理完成之后,移除与该客户端的连接                if (done) {                    peers.remove(index);                    fds.remove(index);                }            }        }    }

runSelectLoop函数的逻辑比较简单,主要有两点:
1、 处理客户端的连接和请求。其中客户端在zygote进程中使用ZygoteConnection对象表示。
2、 客户的请求有ZygoteConnection的runOnce来处理。

总结

Zygote进程一手创建了整个安卓的java世界,他创建了第一个虚拟机,打通了native和java,fork了framework的核心进程--SystemServer:AppRuntime.start------->AndroidRunrime.startVm------>AndroidRunrime.startReg------->ZygoteInit.java main(JAVA)--->ZygoteInit.java registerZygoteSocket()(响应所有子进程的请求)------>  ZygoteInit.java preload(加载各种资源)-------->ZygoteInit.java  startSystemServer(fork出进程为java服务)----->ZygoteInit.java  runSelectLoop让自己无限等待,接受子进程的请求便工作 

接下来会分析Zygote如何启动应用程序,希望大家持续关注,你们的关注就是我前进的动力,有什么不足的地方,大家可以直接在我评论里说出,谢谢。

0 0
原创粉丝点击