码迷,mamicode.com
首页 > 移动开发 > 详细

Android源码分析--Zygote进程分析

时间:2015-03-06 19:14:47      阅读:279      评论:0      收藏:0      [点我收藏+]

标签:源码   android   系统   

众所周知,Android系统中存在着两个完全不同的世界:
1. Java世界,Google所提供的SDK就主要是针对这个世界的,在这个世界中运行的程序都是基于Dalvik虚拟机的Java程序。
2. native世界,也就是利用C或C++语言开发的程序。

那么问题来了,Android系统具体是如何将这两个世界联系起来的,这就是关系到本篇博文所讲的Zygote进程。Android是基于Linux内核构建的,这样Android最早进入的也就是native世界。Linux系统启动的第一个进程是init进程,Android系统中最早启动的进程也是init进程,接下来init进程根据init.rc文件中的配置选项创建了Zygote进程。

Zygote名字的来历

Zygote进程的名字最初时并不是“zygote”,而是“app_process”,这个名字是在Android.mk文件中指定的,但在运行过程中app_process通过Linux下pctrl系统调用把名字换成了“zygote”。其所对应的源文件是App_main.cpp。

App_main.cpp分析

(源码位置:frameworks\base\cmds\app_process\app_main.cpp)
被执行的方法是App_main.cpp中的main方法,该方法比较简单,它首先为虚拟机添加了一些参数,接下来解析了运行时的参数,如果我们的参数设定为执行Zygote进程,则会将bool值zygote置为true,接下来调用了AppRuntime中的start方法。

int main(int argc, char* const argv[])
{
    ........
    // 两个全局变量被定义在ProcessState.cpp中
    mArgC = argc;
    mArgV = argv;

    mArgLen = 0;
    for (int i=0; i<argc; i++) {
        mArgLen += strlen(argv[i]) + 1;
    }
    mArgLen--;

    AppRuntime runtime;
    const char* 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);

    // 接下来解析一些运行时参数
    bool zygote = false;
    bool startSystemServer = false;
    bool application = false;
    const char* parentDir = NULL;
    const char* niceName = NULL;
    const char* className = NULL;
    while (i < argc) {
        const char* arg = argv[i++];
        if (!parentDir) {
            parentDir = arg;
        } else if (strcmp(arg, "--zygote") == 0) {
            zygote = true;
            niceName = "zygote";
        } else if (strcmp(arg, "--start-system-server") == 0) {
            startSystemServer = true;
        } else if (strcmp(arg, "--application") == 0) {
            application = true;
        } else if (strncmp(arg, "--nice-name=", 12) == 0) {
            niceName = arg + 12;
        } else {
            className = arg;
            break;
        }
    }

    if (niceName && *niceName) {
        setArgv0(argv0, niceName);
        //在这里将进程的名称更换为zygote
        set_process_name(niceName);
    }

    runtime.mParentDir = parentDir;

    if (zygote) {
        // 调用AppRuntime的start方法以执行名称为ZygoteInit的类其中的main方法。
        // argv的参数为"--zygote" "--start-system-server",则startSystemServer为true
        runtime.start("com.android.internal.os.ZygoteInit", startSystemServer ? "start-system-server" : "");
    } else if (className) {

        runtime.mClassName = className;
        runtime.mArgC = argc - i;
        runtime.mArgV = argv + i;
        runtime.start("com.android.internal.os.RuntimeInit",
                application ? "application" : "tool");
    } else {
        fprintf(stderr, "Error: no class name or --zygote supplied.\n");
        app_usage();
        LOG_ALWAYS_FATAL("app_process: no class name or --zygote supplied.");
        return 10;
    }
}

AppRuntime中start方法分析

在App_main的main方法中我们最终进入到AppRuntime的start方法中去,接下来分析一下AppRuntime中的start方法,该类的实现和定义均在app_main.cpp中。

//传入参数为"com.android.internal.os.ZygoteInit","start-system-server"
void AndroidRuntime::start(const char* className, const char* options)
{
    ALOGD("\n>>>>>> AndroidRuntime START %s <<<<<<\n",
            className != NULL ? className : "(unknown)");

    /*
     * ‘startSystemServer == true‘ 我们在这里打印出启动引导事件
     */
    if (strcmp(options, "start-system-server") == 0) {
        /* 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)));
    }
    //如果环境变量中没有ANDROID_ROOT则设置该环境变量
    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);
    }

    /* 开启虚拟机 */
    JniInvocation jni_invocation;
    jni_invocation.Init(NULL);
    JNIEnv* env;
    if (startVm(&mJavaVM, &env) != 0) {
        return;
    }
    onVmCreated(env);

    /*
     * 注册一些jni函数
     */
    if (startReg(env) < 0) {
        ALOGE("Unable to register all android natives\n");
        return;
    }

    /*
     * 接下来通过jni调用,调用ZygoteInit的main方法,并设置好传递参数
     */
    jclass stringClass;
    jobjectArray strArray;
    jstring classNameStr;
    jstring optionsStr;

    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);
    optionsStr = env->NewStringUTF(options);
    env->SetObjectArrayElement(strArray, 1, optionsStr);

    /*
     * 该线程将会成为虚拟机的主线程,并且伴随虚拟机一直存在
     */
    char* slashClassName = toSlashClassName(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 {
        //调用Java类中的静态main方法
            env->CallStaticVoidMethod(startClass, startMeth, strArray);
        .......
    }
    free(slashClassName);
    ......
}

我们来总结一下start方法的工作:
1. 设置ANDROID_ROOT环境变量
2. 调用AndroidRuntime类中的startVM方法创建虚拟机
3. 调用startReg函数注册JNI函数
4. 通过jni调用调用Java类ZygoteInit的main方法
至此,我们已经进入了Java的世界。

进入Java世界

通过上面的分析,我们的程序已经来到了Java类ZygoteInit的静态main方法中,该类被定义在frameworks\base\core\java\com\android\internal\os\ZygoteInit.java中。接下来我们看看她的工作:

    public static void main(String argv[]) {
        try {
            // 开始配置Zygote进程的初始化工作
            SamplingProfilerIntegration.start();

            //建立IPC通信的服务端
            registerZygoteSocket();
            EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,
                SystemClock.uptimeMillis());
            //预加载类和资源
            preload();
            EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,
                SystemClock.uptimeMillis());

            // 结束配置Zygote的初始化
            SamplingProfilerIntegration.writeZygoteSnapshot();

            // 进行一次垃圾回收
            gc();

            // 禁用跟踪
            Trace.setTracingEnabled(false);

            // If requested, start system server directly from Zygote
            if (argv.length != 2) {
                throw new RuntimeException(argv[0] + USAGE_STRING);
            }

            if (argv[1].equals("start-system-server")) {
                startSystemServer();//启动system_server进程
            } else if (!argv[1].equals("")) {
                throw new RuntimeException(argv[0] + USAGE_STRING);
            }

            Log.i(TAG, "Accepting command socket connections");

            runSelectLoop();//处理客户连接和客户请求

            closeServerSocket();//关闭服务端
        } catch (MethodAndArgsCaller caller) {
            caller.run();
        } catch (RuntimeException ex) {
            Log.e(TAG, "Zygote died with exception", ex);
            closeServerSocket();
            throw ex;
        }
    }

总结一下:
1. 调用registerZygoteSocket注册IPC通信服务端的socket
2. preload预加载类和资源
3. startSystemServer启动system_server
4. runSelectLoop处理客户连接和客户请求
在这里zygote进程建立了一个子进程system_server,该进程是framework的核心,并且和Zygote保持相同的生命周期。但是,system_server的作用将在runSelectLoop中体现出来。

runSelectLoop分析

在前面我们知道runSelectLoop被用来处理客户连接和客户请求,接下来我们来看看这个方法。

    private static void runSelectLoop() 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使用多路复用I/O模型
                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) {
                ZygoteConnection newPeer = acceptCommandPeer();
                peers.add(newPeer);
                fds.add(newPeer.getFileDesciptor());
            } else {
                boolean done;
                done = peers.get(index).runOnce();

                if (done) {
                    peers.remove(index);
                    fds.remove(index);
                }
            }
        }
    }

在这段程序中我们可以发现每一次客户的连接中,客户是由ZygoteConnection对象来表示,客户的请求是由ZygoteConnection的runOnce方法来处理。

至此,我们对Zygote进程的分析以及结束,它运行起漫长的runSelectLoop方法就沉沉的睡去,接下来的重要任务将在system_server进程中处理执行。
参考书目:深入理解Android 卷I

Android源码分析--Zygote进程分析

标签:源码   android   系统   

原文地址:http://blog.csdn.net/smbroe/article/details/44099591

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!