开机启动 Zygote 进程

Android - 开机启动 Zygote 进程

相关源码文件:

/system/core/rootdir/init.rc
/frameworks/base/cmds/app_process/App_main.cpp
/frameworks/base/core/jni/AndroidRuntime.cpp
/frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
/frameworks/base/core/java/com/android/internal/os/ZygoteConnection.java

Zygote 进程是由 init 进程通过解析 init.rc 文件而创建的。

service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
    class main
    socket zygote stream 660 root system
    onrestart write /sys/android_power/request_state wake
    onrestart write /sys/power/state on
    onrestart restart media
    onrestart restart netd

对应找到 /frameworks/base/cmds/app_process/app_main.cpp 源码文件中的 main 方法

int main(int argc, char* const argv[])
{
    // AppRuntime 继承 AndoirdRuntime
    AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));
    // 过滤第一个参数
    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.
    // 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;
        }
    }

    ...
    //设置进程名
    if (!niceName.isEmpty()) {
        runtime.setArgv0(niceName.string());
        set_process_name(niceName.string());
    }
    // 如果 zygote ,AndroidRuntime 执行 com.android.internal.os.ZygoteInit 
    // 看上面解析的脚本参数执行的是这里。
    if (zygote) {
        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;
    }
}

上面首先是解析参数,然后来到 /frameworks/base/core/jni/AndroidRuntime.cpp中的 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"
 // options ={"start-system-server", "--abi-list=xxxcpu架构类型"}
void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote)
{
    ... 
    // 创建一个虚拟机的实例
    /* start the virtual machine */
    JniInvocation jni_invocation;
    jni_invocation.Init(NULL);
    JNIEnv* env;
    if (startVm(&mJavaVM, &env, zygote) != 0) { //开启java虚拟机
        return;
    }
    onVmCreated(env);

    // JNI 方法注册
    /*
     * Register android functions.
     */
    if (startReg(env) < 0) {
        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;

    // 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=系统响应的cpu架构类型";
    for (size_t i = 0; i < options.size(); ++i) {
        jstring optionsStr = env->NewStringUTF(options.itemAt(i).string());
        env->SetObjectArrayElement(strArray, i + 1, optionsStr);
    }

    // slashClassName = "com/android/internal/os/ZygoteInit"
    char* slashClassName = toSlashClassName(className);//转成java的路径
    jclass startClass = env->FindClass(slashClassName);//找这个类名com/android/internal/os/ZygoteInit
    if (startClass == NULL) {
        ALOGE("JavaVM unable to locate class '%s'\n", slashClassName);
        /* keep going */
    } else {
        // 获取 ZygoteInit.java 的 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.java 的 main 方法,从 Native 世界进入 Java 世界
            env->CallStaticVoidMethod(startClass, startMeth, strArray);
        }
    }
    ...
}

Java 代码是跑在 Java 虚拟机上的,而 Java 与 native 通信采用的是 JNI ,从这里我们就开始进入 Java 世界,ZygoteInit.java

//argv参数如下:
//strArray[0] = "com.android.internal.os.ZygoteInit"
//strArray[1] = "start-system-server"
//strArray[2] = "--abi-list=系统响应的cpu架构类型"
public static void main(String argv[]) {
    try {
        // 解析参数
        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]);
            }
        }
        ...
        // 为 Zygote 注册 socket 用于通信
        registerZygoteSocket(socketName);
        // 预加载类和资源
        preload(); 
        // 启动 system_server
        if (startSystemServer) {
            startSystemServer(abiList, socketName);
        }
        // 进入循环模式,等待孵化进程
        runSelectLoop(abiList); 
        closeServerSocket();
    } catch (MethodAndArgsCaller caller) {
        caller.run();
    } catch (RuntimeException ex) {
        closeServerSocket();
        throw ex;
    }
}

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);
            // 创建 Socket 的本地服务端
            sServerSocket = new LocalServerSocket(fd); 
        } catch (IOException ex) {
            ...
        }
    }
}

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

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 {
        ...
        // 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);
    }

    //  pid == 0 代表子进程,也就是 system_server 进程
    if (pid == 0) {
        // 执行初始化 system_server 进程
        handleSystemServerProcess(parsedArgs);
    }
    return true;
}

private static void runSelectLoop(String abiList) throws MethodAndArgsCaller {
    ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>();
    ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();
    // sServerSocket 是 registerZygoteSocket 中创建的,即 zygote 进程。保存到 fds[0]
    fds.add(sServerSocket.getFileDescriptor());
    peers.add(null);

    while (true) {
        // 给 pollFds 设置参数,fds.size 是 1 ,也就是说 pollFds 里面只有 sServerSocket.getFileDescriptor() 
        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) {
            if (i == 0) {
                // 即fds[0],代表的是 sServerSocket,则意味着有客户端连接请求;
                // 则创建 ZygoteConnection 对象,并添加到 fds。
                ZygoteConnection newPeer = acceptCommandPeer(abiList);
                peers.add(newPeer);
                //添加到 fds.
                fds.add(newPeer.getFileDesciptor()); 
            } else {
                // i>0,则代表通过 socket 接收来自对端的数据,并执行相应操作
                boolean done = peers.get(i).runOnce();
                if (done) {
                    peers.remove(i);
                    // 处理完则从fds中移除该文件描述符
                    fds.remove(i); 
                }
            }
        }
    }
}

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);
        ...
        // fork 创建一个新的进程
        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) {
            // pid == 0 执行子进程的逻辑
            IoUtils.closeQuietly(serverPipeFd);
            serverPipeFd = null;
            // 进入子进程流程
            handleChildProc(parsedArgs, descriptors, childPipeFd, newStderr);
            return true;
        } else {
            // pid>0 执行父进程的逻辑
            IoUtils.closeQuietly(childPipeFd);
            childPipeFd = null;
            return handleParentProc(pid, descriptors, serverPipeFd, parsedArgs);
        }
    } finally {
        IoUtils.closeQuietly(childPipeFd);
        IoUtils.closeQuietly(serverPipeFd);
    }
}

最后再来总结一下:Zygote 进程是由 init 进程解析 init.rc 脚本创建的,其具体的执行源码是在 App_main.main 方法,首先会创建一个虚拟机实例,然后注册 JNI 方法,最后通过 JNI 调用进入 Java 世界来到 ZygoteInit.main 方法。在 Java 世界中我们会为 Zygote 注册 socket 用于进程间通信,预加载一些通用的类和资源,启动 system_server 进程,循环等待孵化创建新的进程。
在这里插入图片描述在这里插入图片描述
zygote中开启了虚拟机,预加载了一些常用的类及系统资源,加载了一些必要的so库,创建了socket。
通过zygote孵化进程,比如点击qq,这时候就会通过socket发送给zygote,zygote通过fork就会创建一个qq进程。
注意:fork 有一个 copyonwrite 技术可以复用父进程的资源,好处就是不需要再去额外的花费时间去加载资源。但是不好的地方:进程一创建他的内存就比较大。
frok 原理:读时共享写时复制(创建一个进程,复制父进程的 mm 结构体,页的属性是可读)

如下所示:
zygote孵化进程时,会将其pcb控制块的mm结构体复制给孵化的子进程,使其具有可读属性,所以fork父子进程具有读时共享,写时复制特点。
在这里插入图片描述
问题一:
应用开发为什么要用多进程:QQ音乐(9个进程),获取更多资源,进程之间相互不影响,为了有更好的体验,因为在oncreate中尽量业务单一,这样启动快,多个业务就用多个进程的oncreate。
在这里插入图片描述
问题二:
Zygote 为什么要预加载这么多资源,有没有办法优化这些资源的加载?
如下:这里加载资源都是单线程逐步执行,我们可以通过开辟多个线程来加快速度。

static void preload() {
        Log.d(TAG, "begin preload");
        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");
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值