系统相关
首页 > 系统相关> > Android系统启动流程(2) —— 解析Zygote进程启动过程

Android系统启动流程(2) —— 解析Zygote进程启动过程

作者:互联网

相关文章

Android系统启动流程(1)  ——  解析init进程启动过程

Zygote 进程启动过程

       在Android系统中,所有的应用程序进程以及系统服务进程SystemServer都是由zygote进程孕育(fork)出来的,这也许就是为什么要把它称为Zygote(受精卵)的原因吧。由于zygote进程在Android系统中有着如此重要的地位,本文将详细分析它的启动过程。

    1. Zygote简介

       在Android系统中,DVM(Dalvik虚拟机)、应用程序进程以及运行系统的关键服务的SystemServer进程都是由zygote进程来创建的,我们也将它称为孵化器。它通过fock(复制进程)的形式来创建应用程序进程和SystemServer进程,由于zygote进程在启动时会创建DVM,因此通过fock而创建的应用程序进程和SystemServer进程可以在内部获取一个DVM的实例拷贝。
       关于init启动zygote我们在上一篇文章已经提到了,这里就不赘述了,这篇文章主要分析Android8.1系统的zygote进程的启动流程。

     2. Zygote启动脚本

        在init.rc文件中采用了Import类型语句来引入Zygote启动脚本,这些启动脚本都是由Android初始化语言(Android Init Language)来编写的,引入Zygote脚本代码如下:

system/core/init/init.cpp

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

       在init.rc中通过属性ro.zygote的值来引入不同的zygote启动脚本的。从Android5.0开始,Android开始支持64位程序,Zygote也就有了32位和64位的区别了,所以在这里用 ro.zygote 属性来控制使用不同的 Zygote 启动脚本,从而也就启动了不同版本zygote进程, ro.zygote 属性的取值有以下4种:

      这些 Zygote 启动脚本都放 system/core/rootdir 目录中。        

     1. init.zygote32.rc

      表示支持纯 32 位程序, init.zygote32.rc 文件内容如下所示:

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

       根据 Service类型语句的格式,可以得知 Zygote 进程名称为zygote ,执行程序为 app _process, class name为main ,如果 audioserver cameraserver、 media、netd、wificond 进程终止了,就需要进行 restart (重启 )。

      2. init.zygote32_64.rc

       表示既支持 32 位程序也支持64位程序, init.zygote32_64.rc 文件内容如下所示:

service zygote /system/bin/app_process32 -Xzygote /system/bin --zygote --start-system-server --socket-name=zygote
    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

service zygote_secondary /system/bin/app_process64 -Xzygote /system/bin --zygote --socket-name=zygote_secondary
    class main
    priority -20
    user root
    group root readproc
    socket zygote_secondary stream 660 root system
    onrestart restart zygote
    writepid /dev/cpuset/foreground/tasks
       脚本中有两个Service类型语句,说明会启动两个zygote 进程, 第一个名称为 zygote,执行程序为 app_process32 ,作为主模式 ;第二个名称为 zygote_secondary,执行程序为 app _process64 ,作为辅模式。

     3. init.zygote64.rc

      表示支持纯 64 位程序, init.zygote64.rc 文件内容如下所示:

service zygote /system/bin/app_process64 -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

       根据 Service类型语句的格式,可以得知 Zygote 进程名称为zygote ,执行程序为 app _process64, class name为main ,如果 audioserver cameraserver、 media、netd、wificond 进程终止了,就需要进行 restart (重启 )。

      4. init.zygote64_32.rc

       表示既支持 32 位程序也支持64位程序, init.zygote64_32.rc 文件内容如下所示:

service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server --socket-name=zygote
    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

service zygote_secondary /system/bin/app_process32 -Xzygote /system/bin --zygote --socket-name=zygote_secondary --enable-lazy-preload
    class main
    priority -20
    user root
    group root readproc
    socket zygote_secondary stream 660 root system
    onrestart restart zygote
    writepid /dev/cpuset/foreground/tasks

       脚本中有两个Service类型语句,说明会启动两个zygote 进程, 第一个名称为 zygote,执行程序为 app_process64 ,作为主模式 ;第二个名称为 zygote_secondary,执行程序为 app _process ,作为辅模式。

    3. Zygote 进程启动过程介绍

       在init启动zygote进程是主要是调用App_mian.cpp的main函数中的AppRuntime的start方法来启动zygote进程的,那我们就从App_main.cpp的main函数开始分析,代码如下:

frameworks/base/cmds/app_process/App_main.cpp

int main(int argc, char* const argv[])
{
    
    AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));
    
    ...

    while (i < argc) {
        const char* arg = argv[i++];
        if (strcmp(arg, "--zygote") == 0) { // ... 1
            // 如果当前运行在zygote进程中,则将zygote设置为true
            zygote = true; // ... 2
            niceName = ZYGOTE_NICE_NAME;
        } else if (strcmp(arg, "--start-system-server") == 0) { // ... 3
            // 如果当前运行在SystemServer进程中,则将startSystemServer设置为true
            startSystemServer = true; // ... 4
        } 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(), true /* setProcName */);
    }

    // 如果运行在zygote进程中
    if (zygote) { // ... 5
        runtime.start("com.android.internal.os.ZygoteInit", args, zygote); // ... 6
    } 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.");
    }
}

       由于zygote进程都是通过fock自身来创建子进程的,所以zygote进程以及它的子进程都可以进入App_main.cpp的main函数,因此main函数中为了区分当前运行在哪个进程中,会在注释1处判断参数 arg中是否包含了“--zygote”,如果包含了则说明main函数是运行在 zygote 进程中的并在注释2处将 zygote设置为ture,同理在注释3处判断参数arg中是否包含了“--start-system-server”,如果包含了则说明 main 函数是运行在SystemServer进程中的并在注释4处将 startSystemServer设置为true。

      在注释5处,如果zygote为true,就说明当前运行在zygote进程中,就会调用注释6处的runtime的start函数,runtime指的就是AppRuntime,AppRuntime声明也在App_main.cpp中,它继承AndroidRuntime,但是AppRuntime并没有重写start函数,也就是说我们调用start函数其实调用的就是AndroidRuntime的start函数,如下所示:

frameworks/base/cmds/app_process/App_main.cpp

class AppRuntime : public AndroidRuntime
         接下来我们分析AndroidRuntime中的start函数,代码如下:   frameworks/base/core/jni/AndroidRuntime.cpp
/*
 * 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)
{
    ...

    /* start the virtual machine */
    JniInvocation jni_invocation;
    jni_invocation.Init(NULL);
    JNIEnv* env;
    // 启动java虚拟机
    if (startVm(&mJavaVM, &env, zygote) != 0) { // ... 1
        return;
    }
    onVmCreated(env);

    /*
     * Register android functions.
     * 为java虚拟机注册JNI方法
     */
    if (startReg(env) < 0) { // ... 2
        ALOGE("Unable to register all android natives\n");
        return;
    }
     
    ... 

  
    stringClass = env->FindClass("java/lang/String");
    assert(stringClass != NULL);
    strArray = env->NewObjectArray(options.size() + 1, stringClass, NULL);
    assert(strArray != NULL);

    // 从App_main的main函数得知,className为com.android.internal.os.ZygoteInit
    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.
     */

    // 将className的"."替换为"/"
    char* slashClassName = toSlashClassName(className != NULL ? className : ""); // .. 4
    // 找到ZygoteInit
    jclass startClass = env->FindClass(slashClassName); // ... 5
    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"); // ... 6
        if (startMeth == NULL) {
            ALOGE("JavaVM unable to find main() in '%s'\n", className);
            /* keep going */
        } else {
            // 通过JNI调用ZygoteInit的main方法
            env->CallStaticVoidMethod(startClass, startMeth, strArray); // ... 7

#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");
}
       在注释1处调sartVm函数来创建 Java 虚拟机,在注释2处调用 startReg 函数为 Java 虚拟机注册 JNI 方法。注释3处的 className 的值是传进来的参数,它的值为“com.android.internal.os.ZygoteInit”。在注释4处通过toSlashClassName函数,将 className 的“.”为“/”,替换后的值为 "com/android/intemal/os/Zygotelnit"并赋值给 slashClassName ,接着在注释5处根据 slashClassName 找到 Zygotelnit,找到了Zygotelnit 之后在注释6处再去查找它的main方法。最终会在注释7处通过 JNI 调用 Zygotelnit的main 方法,这里为何要使用JNI?因为 Zygotelnit的main方法是由 Java 语言编写的,当前的运行逻辑在Native 中,这就需要通过 JNI 调用 Java 。这样 Zygote 就从 Native 层进入了 Java 框架层。        在我们通过 JNI 调用 Zygotelnit的main 方法后, Zygote 便进入了 Java框架层, 此前没有任何代码进入 Java 框架层的,换句话说是 Zygote 开创了 Java 框架层。接下来我们看ZygoteInit.java的mian方法,代码如下:   frameworks/base/core/java/com/android/internal/os/Zygotelnit.java
public static void main(String argv[]) {
        ZygoteServer zygoteServer = new ZygoteServer()
        ...

        String socketName = "zygote";
 
        ...       

        try {
             
            ...

            // 创建一个Server端的Socket,socketName的值为"zygote"
            zygoteServer.registerServerSocket(socketName); // ... 1
            // In some configurations, we avoid preloading resources and classes eagerly.
            // In such cases, we will preload things prior to our first fork.
            if (!enableLazyPreload) {
                bootTimingsTraceLog.traceBegin("ZygotePreload");
                EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,
                    SystemClock.uptimeMillis());

                // 预加载类和资源
                preload(bootTimingsTraceLog); // ... 2

                EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,
                    SystemClock.uptimeMillis());
                bootTimingsTraceLog.traceEnd(); // ZygotePreload
            } else {
                Zygote.resetNicePriority();
            }

            ...

            if (startSystemServer) {
                // 启动SystemServer进程
                Runnable r = forkSystemServer(abiList, socketName, zygoteServer);

                // {@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.
            // 等待AMS请求
            caller = zygoteServer.runSelectLoop(abiList); // 4
        } 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();
        }
    }

       在注释1处通过registerServerSocket 方法来创建 Server 端的 Socket ,这个name 为“zygote”的 Socket 用于等待 ActivityManagerService 请求 Zygote 来创建新的应用程序进程,后续会出AMS相关的文章解析AMS,这里就先不做介绍了。在注释2处预加载类和资源。在注释3处启动 SystemServer进程,这样系统的服务也会由 SystemServer进程启动起来。在注释4处调用 zygoteServer.runSelectLoop 方法来等待 AMS 请求创建新的应用程序进程。由此得知, Zygotelnit的main方法主要做了4件事:

       (1)创建一个 Server 端的 Socket        (2)预加载类和资源。        (3)启动 SystemServer进程。        (4)等待 AMS 请求创建新的应用程序进程。          其中第二件事预加载类和资源这里不做介绍,有兴趣的读者可以查看源码,这里会对其他的主要事件进行分析。

      1 . registerZygoteSocket

       首先我们来查看 ZygoteServer的registerZygoteSocket 方法做了什么,代码如下所示:

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

    /**
     * Registers a server socket for zygote command connections
     *
     * @throws RuntimeException when open fails
     */
    void registerServerSocket(String socketName) {
        if (mServerSocket == null) {
            int fileDesc;
            // 拼接Socket的名称
            final String fullSocketName = ANDROID_SOCKET_PREFIX + socketName; 
            try {
                // 获取Socket的环境变量的值
                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);
                // 创建服务器端Socket
                mServerSocket = new LocalServerSocket(fd); // ... 1
            } catch (IOException ex) {
                throw new RuntimeException(
                        "Error binding to local socket '" + fileDesc + "'", ex);
            }
        }
    }
       注释1处用来创建LocalServerSocket,也就是服务器端的Socket。当zygote进程将SystemServer进程启动之后,就会在这个服务器端的Socket上来等待ActivityManagerService请求zygote进程来创建新的应用程序进程。

      2. 启动SystemServer进程

       接下来查看 forkSystemServer方法, 代码如下所示:

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

    /**
     * Prepare the arguments and forks for the system server process.
     *
     * Returns an {@code Runnable} that provides an entrypoint into system_server code in the
     * child process, and {@code null} in the parent.
     */
    private static Runnable forkSystemServer(String abiList, String socketName,
            ZygoteServer zygoteServer) {
        
        ... 
 
        /* Hardcoded command line to start the system server */

        // 创建 args 数组,这个数组用来保存启动SystemServer进程的启动参数
        String args[] = {
            "--setuid=1000",
            "--setgid=1000",
            "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1021,1023,1032,3001,3002,3003,3006,3007,3009,3010",
            "--capabilities=" + capabilities + "," + capabilities,
            "--nice-name=system_server",
            "--runtime-args",
            "com.android.server.SystemServer",
        };  // ... 1
 
        ZygoteConnection.Arguments parsedArgs = null;

        int pid;

        try {
            parsedArgs = new ZygoteConnection.Arguments(args); // ... 2
            ZygoteConnection.applyDebuggerSystemProperty(parsedArgs);
            ZygoteConnection.applyInvokeWithSystemProperty(parsedArgs);

            /* Request to fork the system server process */
            // 创建system_server进程
            pid = Zygote.forkSystemServer(
                    parsedArgs.uid, parsedArgs.gid,
                    parsedArgs.gids,
                    parsedArgs.debugFlags,
                    null,
                    parsedArgs.permittedCapabilities,
                    parsedArgs.effectiveCapabilities); // ... 3
        } catch (IllegalArgumentException ex) {
            throw new RuntimeException(ex);
        }

        /* For child process */
        // 当前代码逻辑运行在子进程中
        if (pid == 0) {
            if (hasSecondZygote(abiList)) {
                waitForSecondaryZygote(socketName);
            }

            zygoteServer.closeServerSocket();
            // 处理system_server进程
            return handleSystemServerProcess(parsedArgs); // ... 4
        }

        return null;
    }

       注释1处的代码用来创建 args 数组,这个数组用来保存启动SystemServer 进程的启动参数,其中可以看出SystemServer 进程的用户id 和用户组 id 被设置为1000 ,并且拥有用户组 1001~1010、1018、1021、1032 、3001~3010 的权限;进程名为 system_server ;启动的类名 com.android server.SystemServer 。在注释2处将 args 数组封装成 Arguments 对象并供注释3处的 forkSystemServer 函数调用 。在注释3处调用 Zygote.forkSystemServer 方法, 其内部会调用 nativeForkSystemServer 这个 Native 方怯, nativeForkSystemServer方法最终会通过fork函数在当前进程创建一个子进程,也就是SystemServer 进程,如果forkSystemServer 方法返回的 pid 的值为0 ,就表示当前的代码运行在新创建的子进程中, 则执行注释4处的 handleSystemServerProcess 来处理 SystemServer 进程。

      3. runSelectloop

       启动Systemserver 进程后,会执行ZygoteServer的runSelectLoop 方法来等待AMS的请求,代码如下所示:

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

/**
     * 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.
     */
    Runnable runSelectLoop(String abiList) {
        ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>();
        ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();

        fds.add(mServerSocket.getFileDescriptor()); // ... 1
        peers.add(null);

        // 无线循环等待AMS的请求
        while (true) {
            StructPollfd[] pollFds = new StructPollfd[fds.size()];
            for (int i = 0; i < pollFds.length; ++i) { // ... 2
                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) { // ... 3
                if ((pollFds[i].revents & POLLIN) == 0) {
                    continue;
                }

                if (i == 0) {
                    ZygoteConnection newPeer = acceptCommandPeer(abiList); // ... 4
                    peers.add(newPeer);
                    fds.add(newPeer.getFileDesciptor());
                } else {
                    try {
                        ZygoteConnection connection = peers.get(i);
                        final Runnable command = connection.processOneCommand(this); // ... 5

                        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) {
                        if (!mIsForkChild) {
                            // We're in the server so any exception here is one that has taken place
                            // pre-fork while processing commands or reading / writing from the
                            // control socket. Make a loud noise about any such exceptions so that
                            // we know exactly what failed and why.

                            Slog.e(TAG, "Exception executing zygote command: ", e);

                            // Make sure the socket is closed so that the other end knows immediately
                            // that something has gone wrong and doesn't time out waiting for a
                            // response.
                            ZygoteConnection conn = peers.remove(i);
                            conn.closeSocket();

                            fds.remove(i);
                        } else {
                            // We're in the child so any exception caught here has happened post
                            // fork and before we execute ActivityThread.main (or any other main()
                            // method). Log the details of the exception and bring down the process.
                            Log.e(TAG, "Caught post-fork exception in child process.", e);
                            throw e;
                        }
                    }
                }
            }
        }
    }
}
       注释1处的 mServerSocket 就是我们在 registerZygoteSocket 函数中创建的服务器端 Socket ,调用 mServerSocket.getFileDescriptor方法用来获得该Socket的fd字段的值并添加到fd的列表fds中。接下来无限循环用来等待 AMS 请求 Zygote 进程创建新的应用程序进程。 在注释2处通过遍历将 fds 存储的信息转移到 pollFds 数组中。在注释3处对pollFds数组进行遍历,如果 i==0 ,说明服务器端 Socket 与客户端连接上了,换句话说就是,当前 Zygote 进程与 AMS 立了连接。在注释4处通过acceptCommandPeer 方法得到 ZygoteConnection 类并添加到 Socket 连接列表peers 中,接着将该ZygoteConnection 的fd添加到fd列表 fds 中,以便可以接收到 AMS 发送过来的请求。 如果i的值不等于0 ,则说明 AMS向Zygote 进程发送了一个创建应用进程的请求,则在注释5处调用ZygoteConnection的processOneCommand函数来创建一个新的应用程序进程,并在成功创建后将这个连接从Socket 连接列表 peers fd列表 fds 中清除。

     4. Zygote 进程启动总结

       在init进程中通过 AppRuntime 类并调用其 start 方法,启动 Zygote 进程。        Zygote 进程启动共做了如下几件事情:        (1)创建 Java 虚拟机并为 Java 虚拟机注册 JNI 方法        (2)通过JNI调用 Zygotelnit的main 函数进入Zygote的Java框架层。        (3)通过registerZygoteSocket方法创建服务器端 Socket ,并通过 runSelectLoop 方法等 AMS 的请求来创建新的应用程序进程。        (4)启动 SystemServer进程。

标签:...,系统启动,system,zygote,Zygote,进程,onrestart,Android,main
来源: https://blog.csdn.net/lixiong0713/article/details/106692582