Android源码阅读---zygote(app_process)进程

Android源码阅读—zygote(app_process)进程

1. app_processpe的启动

app_process也是由init 进程创建的, 它对应的bin文件在目录/system/bin下面,然后看看它的编译文件和配置文件frameworks/base/cmds/app_process/Android.mk

LOCAL_PATH:= $(call my-dir)
# This is a list of libraries that need to be included in order to avoid bad apps. This prevents a library from having a mismatch when resolving new/delete from an app shared library.
app_process_common_shared_libs := \
    libwilhelm \

include $(CLEAR_VARS)

LOCAL_SRC_FILES:= \
    app_main.cpp

LOCAL_LDFLAGS := -Wl,--version-script,art/sigchainlib/version-script.txt -Wl,--export-dynamic

LOCAL_SHARED_LIBRARIES := \
    libdl \
    libcutils \
    libutils \
    liblog \
    libbinder \
    libnativeloader \
    libandroid_runtime \
    $(app_process_common_shared_libs) \

LOCAL_WHOLE_STATIC_LIBRARIES := libsigchain

LOCAL_MODULE:= app_process
LOCAL_MULTILIB := both
LOCAL_MODULE_STEM_32 := app_process32
LOCAL_MODULE_STEM_64 := app_process64
LOCAL_CFLAGS += -Wall -Werror -Wunused -Wunreachable-code
include $(BUILD_EXECUTABLE)
# Create a symlink from app_process to app_process32 or 64 depending on the target configuration.
include $(BUILD_SYSTEM)/executable_prefer_symlink.mk
# Build a variant of app_process binary linked with ASan runtime.
# ARM-only at the moment.
ifeq ($(TARGET_ARCH),arm)
include $(CLEAR_VARS)

LOCAL_SRC_FILES:= \
    app_main.cpp

LOCAL_SHARED_LIBRARIES := \
    libcutils \
    libutils \
    liblog \
    libbinder \
    libandroid_runtime \
    $(app_process_common_shared_libs) \

LOCAL_WHOLE_STATIC_LIBRARIES := libsigchain

LOCAL_LDFLAGS := -ldl -Wl,--version-script,art/sigchainlib/version-script.txt -Wl,--export-dynamic
LOCAL_CPPFLAGS := -std=c++11

LOCAL_MODULE := app_process__asan
LOCAL_MULTILIB := both
LOCAL_MODULE_STEM_32 := app_process32
LOCAL_MODULE_STEM_64 := app_process64

LOCAL_SANITIZE := address
LOCAL_CLANG := true
LOCAL_MODULE_PATH := $(TARGET_OUT_EXECUTABLES)/asan

LOCAL_CFLAGS += -Wall -Werror -Wunused -Wunreachable-code

include $(BUILD_EXECUTABLE)

endif # ifeq($(TARGET_ARCH),arm)

从上面的编译文件中可以看出,它会同时编译32位和64位的2个版本,然后它对应的配置文件则在目录system/core/rootdir/,首先看看存32位的配置文件

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 audioserver
    onrestart restart cameraserver
    onrestart restart media
    onrestart restart netd
    writepid /dev/cpuset/foreground/tasks

文件中,声明了它作为一个系统级服务,名字为zygote,对应的可执行文件路径/system/bin/app_process,以及相关参数,class为main,只要action块中有命令class_start main就会启动它,同时服务audioserver、cameraserver、media、netd终止,都会重启它。
在看看配置文件system/core/rootdir/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

在该配置中声明了2个service块,名称分别是zygote和zygote_secondary,既可以支持32位程序又可以支持64位程序。
而在init.rc中有如下语句,它定义了zygote服务的启动时机

on nonencrypted
    # A/B update verifier that marks a successful boot.
    exec - root cache -- /system/bin/update_verifier nonencrypted
    class_start main
    class_start late_start

on property:vold.decrypt=trigger_reset_main
    class_reset main

on property:vold.decrypt=trigger_restart_min_framework
    # A/B update verifier that marks a successful boot.
    exec - root cache -- /system/bin/update_verifier trigger_restart_min_framework
    class_start main

on property:vold.decrypt=trigger_restart_framework
    # A/B update verifier that marks a successful boot.
    exec - root cache -- /system/bin/update_verifier trigger_restart_framework
    class_start main
    class_start late_start

on property:vold.decrypt=trigger_shutdown_framework
    class_reset late_start
    class_reset main

2. main函数流程

从前面的编译文件中可以知道,该进程主要使用的是文件app_main.cpp,该进程的入口就是app_main.cpp的main函数:

int main(int argc, char* const argv[])
{
    if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) < 0) {
        // Older kernels don't understand PR_SET_NO_NEW_PRIVS and return EINVAL. Don't die on such kernels.
        if (errno != EINVAL) {
            LOG_ALWAYS_FATAL("PR_SET_NO_NEW_PRIVS failed: %s", strerror(errno));
            return 12;
        }
    }

    AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));
    // Process command line arguments ignore argv[0]
    argc--;
    argv++;

/*
/system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server --socket-name=zygote
-Xzygote
zygote=true,startSystemServer=true,application=false,niceName=zygote64,className= 


/system/bin/app_process32 -Xzygote /system/bin --zygote --socket-name=zygote_secondary
-Xzygote 
zygote=true,startSystemServer=false,application=false,niceName=zygote,className=
--abi-list=armeabi-v7a,armeabi --socket-name=zygote_secondary
*/

    // 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]));
    }
/*for 循环后,i=1,runtime.mOptions=[-Xzygote ]*/

    // 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;
        } 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=true,startSystemServer=true,application=false,niceName=zygote64,className= */
    Vector<String8> args;
    if (!className.isEmpty()) {
        // We're not in zygote mode, the only argument we need to pass
        // to RuntimeInit is the application argument.
        //
        // The Remainder of args get passed to startup class main(). Make
        // copies of them before we overwrite them with the process name.
        args.add(application ? String8("application") : String8("tool"));
        runtime.setClassNameAndArgs(className, argc - i, argv + i);
    } else {
        // We're in zygote mode.
        maybeCreateDalvikCache();/*给kInstructionSet赋值*/ 
        if (startSystemServer) {
            args.add(String8("start-system-server"));
        }
/*public static final int PROP_VALUE_MAX = 91;*/
        char prop[PROP_VALUE_MAX];/*声明一个char数组*/
        if (property_get(ABI_LIST_PROPERTY, prop, NULL) == 0) {/*将系统属性值"ro.product.cpu.abilist[xx]"的值存入prop中*/
            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.abilist[xx] */
        args.add(abiFlag);

        // In zygote mode, pass all remaining arguments to the zygote main() method.
        for (; i < argc; ++i) {
            args.add(String8(argv[i]));
        }
    }
/*此时args中存的值为start-system-server --abi-list=arm64-v8a --socket-name=zygote*/
    if (!niceName.isEmpty()) {
        runtime.setArgv0(niceName.string());
        set_process_name(niceName.string());
    }

    if (zygote) {/*zygote为ture ,走这个流程*/
        runtime.start("com.android.internal.os.ZygoteInit", args, zygote);
    } else if (className) {
        runtime.start("com.android.internal.os.RuntimeInit", args, zygote);
    } 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;
    }
}

整个main函数主要做了:

  • 参数处理,server块通过命令start_class启动app_process,然后还会传入几个参数,main函数前部分逻辑都是在处理传入的这些参数,如根据是否 带有参数"–zygote"决定是否走zygote 启动流程。
  • 开启虚拟机,启动对应的java程序
Created with Raphaël 2.2.0 命令启动 app_process进程 参数处理 开启虚拟机 进入java环境

3. 创建java运行环境

接下来将会开启java虚拟机,开始start函数,它的实现是在runtime对象的父类AndroidRuntime中

/*
 * 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.
 */
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) {/*创建一个java虚拟机*/
        return;
    }
    onVmCreated(env);

    /*
     * Register android functions.
     */
    if (startReg(env) < 0) {/*为虚拟机注册JNI方法*/
        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");/*获得java的String类*/
    assert(stringClass != NULL);
    strArray = env->NewObjectArray(options.size() + 1, stringClass, NULL);/*创建一个数组 strArray =new String[options.size() + 1];*/
    assert(strArray != NULL);
    classNameStr = env->NewStringUTF(className); /*String classNameStr ="com.android.internal.os.ZygoteInit";*/
    assert(classNameStr != NULL);
    env->SetObjectArrayElement(strArray, 0, classNameStr);/*将classNameStr填入数组strArray 中*/

    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);/*strArray ={"com.android.internal.os.ZygoteInit","start-system-server"," --abi-list=arm64-v8a ","--socket-name=zygote"};*/
    }

    /*
     * Start VM. This thread becomes the main thread of the VM, and will not return until the VM exits.
     */
    char* slashClassName = toSlashClassName(className);/*将com.android.internal.os.ZygoteInit转换为com/android/internal/os/ZygoteInit*/
    jclass startClass = env->FindClass(slashClassName);/*通过jni 获得com/android/internal/os/ZygoteInit类*/
    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");/*再拿到com/android/internal/os/ZygoteInit类的main函数*/
        if (startMeth == NULL) {
            ALOGE("JavaVM unable to find main() in '%s'\n", className);
            /* keep going */
        } else {
            env->CallStaticVoidMethod(startClass, startMeth, strArray);/*同样通过JNI开始运行com/android/internal/os/ZygoteInit类的main函数*/
        }
    }
    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");
}

所以总结下,该函数主要做了:

  1. 创建一个java虚拟机
  2. 注册JNI方法
  3. 构造参数 argv
  4. 通过JNI开始运行com.android.internal.os.ZygoteInit类的main函数

至此,进程的逻辑从c/c++层开始转到java层的运行逻辑了,并且运行start函数的线程将作为java层运行逻辑的主线程并在java虚拟机运行结束后回到该方法中

4. ZygoteInit类主函数

在运行start函数之前,是不能运行java代码的,而在该函数中,通过JNI开始调用java代码了, 所以从现在开始视角从c++转为了java。然后看看在刚开始运行java代码具体做了哪些工作:

    public static void main(String argv[]) {
/*String argv[] ={"com.android.internal.os.ZygoteInit","start-system-server"," --abi-list=arm64-v8a ","--socket-name=zygote"};*/
        // Mark zygote start. This ensures that thread creation will throw an error.
        ZygoteHooks.startZygoteNoThreadCreation();

        try {
            Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "ZygoteInit");
            RuntimeInit.enableDdms();
            // 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());/*给abiList赋值为arm64-v8a*/
                } else if (argv[i].startsWith(SOCKET_NAME_ARG)) {
                    socketName = argv[i].substring(SOCKET_NAME_ARG.length());/*给socketName 赋值为zygote*/
                } else {
                    throw new RuntimeException("Unknown command line argument: " + argv[i]);
                }
            }

            if (abiList == null) {
                throw new RuntimeException("No ABI list supplied.");
            }

            registerZygoteSocket(socketName);/*注册一个socket*/
            Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "ZygotePreload");
            EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,SystemClock.uptimeMillis());
            preload();  /*预加载类和资源*/
            EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,SystemClock.uptimeMillis());
            Trace.traceEnd(Trace.TRACE_TAG_DALVIK);

            // Finish profiling the zygote initialization.
            SamplingProfilerIntegration.writeZygoteSnapshot();

            // Do an initial gc to clean up after startup
            Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "PostZygoteInitGC");
            gcAndFinalize();
            Trace.traceEnd(Trace.TRACE_TAG_DALVIK);
            Trace.traceEnd(Trace.TRACE_TAG_DALVIK);
            // Disable tracing so that forked processes do not inherit stale tracing tags from Zygote.
            Trace.setTracingEnabled(false);

            // Zygote process unmounts root storage spaces.
            Zygote.nativeUnmountStorageOnInit();
            ZygoteHooks.stopZygoteNoThreadCreation();

            if (startSystemServer) {
                startSystemServer(abiList, socketName);/*启动 systemServer*/
            }

            Log.i(TAG, "Accepting command socket connections");
            runSelectLoop(abiList);/*等待AMS请求*/
            closeServerSocket();
        } catch (MethodAndArgsCaller caller) {
            caller.run();
        } catch (Throwable ex) {
            Log.e(TAG, "Zygote died with exception", ex);
            closeServerSocket();
            throw ex;
        }
    }

在该main函数中主要做了如下几个事:

  1. 创建一个socket,它将做为一个server监听其他进程请求
  2. 预加载类和资源
  3. 启动systemserver
  4. 等待AMS请求
Created with Raphaël 2.2.0 已经处于java运行环境中 创建一个socket,等待其他进程连接请求 预加载类和资源 启动一个子进程,运行systemserver 进入loop循环,等待&&处理 连接socket的请求 zygote进程奔溃,否则不退出

4.1 registerZygoteSocket

    /**
     * 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;/*此处将名字拼成ANDROID_SOCKET_zygote*/
            try {
                String env = System.getenv(fullSocketName);/*获得socket的环境变量值*/
                fileDesc = Integer.parseInt(env);
            } catch (RuntimeException ex) {
                throw new RuntimeException(fullSocketName + " unset or invalid", ex);
            }
            try {
                FileDescriptor fd = new FileDescriptor();
                fd.setInt$(fileDesc);
                sServerSocket = new LocalServerSocket(fd);
            } catch (IOException ex) {
                throw new RuntimeException(
                        "Error binding to local socket '" + fileDesc + "'", ex);
            }
        }
    }

这里会创建一个socket(它实际上是一个UNIX DOmain Socket),只要有新程序运行,系统就会通过该socket通知到app_process进程(zygote进程)。

4.2 preload

    static void preload() {
        Log.d(TAG, "begin preload");
        Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "BeginIcuCachePinning");
        beginIcuCachePinning();
        Trace.traceEnd(Trace.TRACE_TAG_DALVIK);
        Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "PreloadClasses");
        preloadClasses();
        Trace.traceEnd(Trace.TRACE_TAG_DALVIK);
        Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "PreloadResources");
        preloadResources();
        Trace.traceEnd(Trace.TRACE_TAG_DALVIK);
        Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "PreloadOpenGL");
        preloadOpenGL();
        Trace.traceEnd(Trace.TRACE_TAG_DALVIK);
        preloadSharedLibraries();
        preloadTextResources();
        // Ask the WebViewFactory to do any initialization that must run in the zygote process, for memory sharing purposes.
        WebViewFactory.prepareWebViewInZygote();
        endIcuCachePinning();
        warmUpJcaProviders();
        Log.d(TAG, "end preload");
    }

从各个方法的名字上就可以看出,它预加载了常用的类、资源文件、图形图像相关的openGL、共享类库等。

4.3 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_IPC_LOCK,
            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
        );
        /* Containers run without this capability, so avoid setting it in that case */
        if (!SystemProperties.getBoolean(PROPERTY_RUNNING_IN_CONTAINER, false)) {
            capabilities |= posixCapabilitiesAsBits(OsConstants.CAP_BLOCK_SUSPEND);
        }
        /* 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,1021,1032,3001,3002,3003,3006,3007,3009,3010",
            "--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);
            /* Request to fork the system server process */
            pid = Zygote.forkSystemServer( parsedArgs.uid, parsedArgs.gid, parsedArgs.gids,parsedArgs.debugFlags, null,parsedArgs.permittedCapabilities,parsedArgs.effectiveCapabilities);/*单独创建一个进程来运行 systemserver*/
        } catch (IllegalArgumentException ex) {
            throw new RuntimeException(ex);
        }

        /* For child process */
        if (pid == 0) {
            if (hasSecondZygote(abiList)) {
                waitForSecondaryZygote(socketName);
            }
            handleSystemServerProcess(parsedArgs);
        }
        return true;
    }

该方法中主要做了:

  • 初始化开启 systemServer需要的参数
  • fork一个单独的进程
  • handleSystemServerProcess启动创建的进程

4.3 runSelectLoop

从名字上可以看出它会是一个死循环,也就是除非app_process进程(zygote进程)退出或者出现异常,否则不会跳出该循环。

    /**
     * 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>();

        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;
                }
                if (i == 0) {/*情况二:有新的连接接入, 通过方法acceptCommandPeer拿到连接对象并将该连接的文件描述符存入数组*/
                    ZygoteConnection newPeer = acceptCommandPeer(abiList);
                    peers.add(newPeer);
                    fds.add(newPeer.getFileDesciptor());
                } else {/*情况三:有新的请求传入
                    boolean done = peers.get(i).runOnce();
                    if (done) {/*如果连接中的请求处理完毕 将这个连接和对应的文件描述符移除*/
                        peers.remove(i);
                        fds.remove(i);
                    }
                }
            }
        }
    }

然后看看 ,如果连接中有请求时,runOnce方法如何处理的

    /**
     * Reads one start command from the command socket. If successful, a child is forked and a {@link ZygoteInit.MethodAndArgsCaller} exception is thrown in that child while in the parent process, the method returns normally. On failure, the child is not spawned and messages are printed to the log and stderr. Returns a boolean status value indicating whether an end-of-file on the command socket has been encountered.
     *
     * @return false if command socket should continue to be read from, or true if an end-of-file has been encountered.
     * @throws ZygoteInit.MethodAndArgsCaller trampoline to invoke main() method in child process
     */
    boolean runOnce() throws ZygoteInit.MethodAndArgsCaller {
        String args[];
        Arguments parsedArgs = null;
        FileDescriptor[] descriptors;

        try {
            args = readArgumentList();/*读取socket传来的参数*/
            descriptors = mSocket.getAncillaryFileDescriptors();
        } catch (IOException ex) {
            Log.w(TAG, "IOException on command socket " + ex.getMessage());
            closeSocket();
            return true;
        }

        if (args == null) {
            // EOF reached.
            closeSocket();
            return true;
        }

        /** the stderr of the most recent request, if avail */
        PrintStream newStderr = null;

        if (descriptors != null && descriptors.length >= 3) {
            newStderr = new PrintStream(
                    new FileOutputStream(descriptors[2]));
        }

        int pid = -1;
        FileDescriptor childPipeFd = null;
        FileDescriptor serverPipeFd = null;

        try {
            parsedArgs = new Arguments(args);/*将参数打包成Arguments对象*/
            if (parsedArgs.abiListQuery) {
                return handleAbiListQuery();
            }
            if (parsedArgs.permittedCapabilities != 0 || parsedArgs.effectiveCapabilities != 0) {
                throw new ZygoteSecurityException("Client may not specify capabilities: " +"permitted=0x" + Long.toHexString(parsedArgs.permittedCapabilities) +", effective=0x" + Long.toHexString(parsedArgs.effectiveCapabilities));
            }
/*权限相关的检查??*/
            applyUidSecurityPolicy(parsedArgs, peer);
            applyInvokeWithSecurityPolicy(parsedArgs, peer);
            applyDebuggerSystemProperty(parsedArgs);
            applyInvokeWithSystemProperty(parsedArgs);

            int[][] rlimits = null;

            if (parsedArgs.rlimits != null) {
                rlimits = parsedArgs.rlimits.toArray(intArray2d);
            }

            if (parsedArgs.invokeWith != null) {
                FileDescriptor[] pipeFds = Os.pipe2(O_CLOEXEC);
                childPipeFd = pipeFds[1];
                serverPipeFd = pipeFds[0];
                Os.fcntlInt(childPipeFd, F_SETFD, 0);
            }

            /**
             * In order to avoid leaking descriptors to the Zygote child, the native code must close the two Zygote socket descriptors in the child process before it switches from Zygote-root to the UID and privileges of the application being launched.
             *
             * In order to avoid "bad file descriptor" errors when the two LocalSocket objects are closed, the Posix file descriptors are released via a dup2() call which closes the socket and substitutes an open descriptor to /dev/null.
             */

            int [] fdsToClose = { -1, -1 };

            FileDescriptor fd = mSocket.getFileDescriptor();

            if (fd != null) {
                fdsToClose[0] = fd.getInt$();
            }

            fd = ZygoteInit.getServerSocketFileDescriptor();

            if (fd != null) {
                fdsToClose[1] = fd.getInt$();
            }

            fd = null;

            pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids, parsedArgs.debugFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo, parsedArgs.niceName, fdsToClose, parsedArgs.instructionSet,parsedArgs.appDataDir);   /*此处会创建一个新的进程*/
        } catch (ErrnoException ex) {
            logAndPrintError(newStderr, "Exception creating pipe", ex);
        } catch (IllegalArgumentException ex) {
            logAndPrintError(newStderr, "Invalid zygote arguments", ex);
        } catch (ZygoteSecurityException ex) {
            logAndPrintError(newStderr,
                    "Zygote security policy prevents request: ", ex);
        }

        try {
            if (pid == 0) {
                // in child              /*在子进程中运行如下代码*/
                IoUtils.closeQuietly(serverPipeFd);
                serverPipeFd = null;
                handleChildProc(parsedArgs, descriptors, childPipeFd, newStderr);
                // should never get here, the child is expected to either throw ZygoteInit.MethodAndArgsCaller or exec().
                return true;
            } else {
                // in parent...pid of < 0 means failure
                IoUtils.closeQuietly(childPipeFd);
                childPipeFd = null;
                return handleParentProc(pid, descriptors, serverPipeFd, parsedArgs);
            }
        } finally {
            IoUtils.closeQuietly(childPipeFd);
            IoUtils.closeQuietly(serverPipeFd);
        }
    }
  1. forkAndSpecialize,为新启动的应用创建一个新的进程
    /**
     * Forks a new VM instance. The current VM must have been started with the -Xzygote flag. <b>NOTE: new instance keeps all root capabilities. The new process is expected to call capset()</b>.
     *
     * @param uid the UNIX uid that the new process should setuid() to after fork()ing and and before spawning any threads.
     * @param gid the UNIX gid that the new process should setgid() to after fork()ing and and before spawning any threads.
     * @param gids null-ok; a list of UNIX gids that the new process should setgroups() to after fork and before spawning any threads.
     * @param debugFlags bit flags that enable debugging features.
     * @param rlimits null-ok an array of rlimit tuples, with the second dimension having a length of 3 and representing (resource, rlim_cur, rlim_max). These are set via the posix setrlimit(2) call.
     * @param seInfo null-ok a string specifying SELinux information for the new process.
     * @param niceName null-ok a string specifying the process name.
     * @param fdsToClose an array of ints, holding one or more POSIX
     * file descriptor numbers that are to be closed by the child
     * (and replaced by /dev/null) after forking. An integer value
     * of -1 in any entry in the array means "ignore this one".
     * @param instructionSet null-ok the instruction set to use.
     * @param appDataDir null-ok the data directory of the app.
     *
     * @return 0 if this is the child, pid of the child if this is the parent, or -1 on error.
     */
    public static int forkAndSpecialize(int uid, int gid, int[] gids, int debugFlags, int[][] rlimits, int mountExternal, String seInfo, String niceName, int[] fdsToClose,String instructionSet, String appDataDir) {
        VM_HOOKS.preFork();
        int pid = nativeForkAndSpecialize(uid, gid, gids, debugFlags, rlimits, mountExternal, seInfo, niceName, fdsToClose,instructionSet, appDataDir);
        // Enable tracing as soon as possible for the child process.
        if (pid == 0) {
            Trace.setTracingEnabled(true);
            // Note that this event ends at the end of handleChildProc,
            Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "PostFork");
        }
        VM_HOOKS.postForkCommon();
        return pid;
}

    native private static int nativeForkAndSpecialize(int uid, int gid, int[] gids,int debugFlags,int[][] rlimits, int mountExternal, String seInfo, String niceName, int[] fdsToClose,String instructionSet, String appDataDir);

首先,

  1. handleChildProc,开始执行应用自己的代码
    /**
     * Handles post-fork setup of child proc, closing sockets as appropriate, reopen stdio as appropriate, and ultimately throwing MethodAndArgsCaller if successful or returning if failed.
     *
     * @param parsedArgs non-null; zygote args
     * @param descriptors null-ok; new file descriptors for stdio if available.
     * @param pipeFd null-ok; pipe for communication back to Zygote.
     * @param newStderr null-ok; stream to use for stderr until stdio is reopened.
     *
     * @throws ZygoteInit.MethodAndArgsCaller on success to trampoline to code that invokes static main.
     */
    private void handleChildProc(Arguments parsedArgs, FileDescriptor[] descriptors, FileDescriptor pipeFd, PrintStream newStderr) throws ZygoteInit.MethodAndArgsCaller {
        /*
         * By the time we get here, the native code has closed the two actual Zygote socket connections, and substituted /dev/null in their place. The LocalSocket objects still need to be closed properly.
         */
        closeSocket();
        ZygoteInit.closeServerSocket();
        if (descriptors != null) {
            try {
                Os.dup2(descriptors[0], STDIN_FILENO);
                Os.dup2(descriptors[1], STDOUT_FILENO);
                Os.dup2(descriptors[2], STDERR_FILENO);
                for (FileDescriptor fd: descriptors) {
                    IoUtils.closeQuietly(fd);
                }
                newStderr = System.err;
            } catch (ErrnoException ex) {
                Log.e(TAG, "Error reopening stdio", ex);
            }
        }
        if (parsedArgs.niceName != null) {/*为子进程设置名字*/
            Process.setArgV0(parsedArgs.niceName);
        }
        // End of the postFork event.
        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
        if (parsedArgs.invokeWith != null) {
            WrapperInit.execApplication(parsedArgs.invokeWith,parsedArgs.niceName, parsedArgs.targetSdkVersion,VMRuntime.getCurrentInstructionSet(), pipeFd, parsedArgs.remainingArgs);
        } else {
            RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion,parsedArgs.remainingArgs, null /* classLoader */);
        }
    }

在这里插入图片描述

发布了38 篇原创文章 · 获赞 14 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/cw102055234/article/details/104988604
今日推荐