Android系统启动之init进程启动+Zygote进程启动分析

news2024/11/18 19:55:05

一、基础概念理解

init进程

        Android系统所有进程的祖先,是Android系统内核初始化完毕后,进入用户空间启动的第一个进程。

Android虚拟机

        Dalvik虚拟机是谷歌自己设计的用于Android平台的虚拟机。Android4.4同时提供了Dalvik和ART虚拟机。Android5.0以后,Dalvik虚拟机彻底被删除,ART虚拟机取而代之。

Zygote

        中文翻译为“受精卵、结合子”

        Zygote是Android系统中,负责孵化所有其他应用进程的一个进程,Android系统是基于Linux内核的系统,所以Zygote进程是由Linux启动的用户级init进程创建的,Zygote是init进程的子进程,Zygote是一个java进程,负责启动Android虚拟机(Dalvik、ART)。

二、Android系统启动过程

第一步:BootLoader

        BootLoader是在操作系统内核运行之前运行。可以初始化硬件设备、建立内存空间映射图,从而将系统的软硬件环境带到一个合适状态,以便为最终调用操作系统内核准备好正确的环境。

第二步:Kernel

        Kernel指的是操作系统内核Linux初始化及启动。

第三步:init进程启动

        init进程是Android内核初始化之后创建并启动的第一个进程,是所有进程的父进程,init进程首先调用/system/core/init/init.cpp的main方法,该方法做了两件事:

(1),搭建系统运行环境,创建相关目录,设置相关路径和属性;

(2),解析rc配置文件,执行rc配置文件所要求的动作和命令

三、Zygote进程启动

1,init如何启动Zygote服务

(1)解析init.rc

        init.cpp的main方法中其中有一句代码parser.ParseConfig("/init.rc");用来读取rc配置并执行init.rc位于/system/core/rootdir/init.rc

7 import /init.environ.rc

8 import /system/etc/init/hw/init.usb.rc

9 import /init.${ro.hardware}.rc

10 import /vendor/etc/init/hw/init.${ro.hardware}.rc

11 import /system/etc/init/hw/init.usb.configfs.rc

12 import /system/etc/init/hw/init.${ro.zygote}.rc

...

946 # It is recommended to put unnecessary data/ initialization from post-fs-data

947 # to start-zygote in device's init.rc to unblock zygote start.

948 on zygote-start && property:ro.crypto.state=unencrypted

949 wait_for_prop odsign.verification.done 1

950 # A/B update verifier that marks a successful boot.

951 exec_start update_verifier_nonencrypted

952 start statsd

953 start netd

954 start zygote

955 start zygote_secondary

956

957 on zygote-start && property:ro.crypto.state=unsupported

958 wait_for_prop odsign.verification.done 1

959 # A/B update verifier that marks a successful boot.

960 exec_start update_verifier_nonencrypted

961 start statsd

962 start netd

963 start zygote

964 start zygote_secondary

965

966 on zygote-start && property:ro.crypto.state=encrypted && property:ro.crypto.type=file

967 wait_for_prop odsign.verification.done 1

968 # A/B update verifier that marks a successful boot.

969 exec_start update_verifier_nonencrypted

970 start statsd

971 start netd

972 start zygote

973 start zygote_secondary

/init.${ro.zygote}.rc会根据硬件实际的配置,选择导入32位还是64位。在Android12上有这几个选择:init.zygote32.rc,init.zygote64.rc,init.zygote64_32.rc

(2)启动Zygote服务

start zygote是启动Zygote服务的方式,所以Zygote服务就会被启动

Zygote服务就是下面配置文件中的服务【service zygote】

比如设备是64位的,则init启动的就是/system/core/rootdir/init.zygote64.rc配置文件中的【service zygote】

1 service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server

2 class main

3 socket zygote stream 660 root system

4 onrestart write /sys/android_power/request_state wake

5 onrestart write /sys/power/state on

6 onrestart restart audioserver

7 onrestart restart cameraserver

8 onrestart restart media

9 onrestart restart netd

10 writepid /dev/cpuset/foreground/tasks

综上所述,Zygote进程是Init进程通过解析init.rc过程中又去解析了init.zygote64.rc或者init.zygote32.rc配置文件,以Service的方式创建并启动

2,Zygote服务启动后,做了什么

上面的zygote service配置中,有一个重要选项/system/bin/app_process64,通过执行app_process来进入zygote进程。

app_process主要作用是解析启动参数,然后根据启动参数选择不同的启动模式

执行 /system/bin/app_process64命令之后,程序就会执行到/frameworks/base/cmds/app_process/,该目录下面就是可执行文件,该路径下有app_main.cpp,最终执行的就是app_main.cpp的main方法:

/system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server

上面标红的是调用app_main.cpp的main()方法的入参,使用中间的空格符切割一下,得到5个值如下:

  1. /system/bin/app_process64
  2. -Xzygote
  3. /system/bin
  4. --zygote
  5. --start-system-server

下面的main()函数两个入参,int argc,char* const argv[],其中argc是传入参数的数目,这里应该等于5,argv是传入参数的值,就是上面这5个切割后的字符串

int main(int argc, char* const argv[])
{
    ...
//argc=5
//                 argv[0]="/system/bin/app_process64"
//                 argv[1]="-Xzygote"
//                 argv[2]="/system/bin"
//                 argv[3]="--zygote"
//                 argv[4]="--start-system-server"

 argv[0]="/system/bin/app_process64"被传入runtime
//AppRuntime继承自AndroidRuntime,
//这里创建AppRuntime对象,main方法的操作都是通过这个runtime完成的
    AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));
    argc--;//执行此语句块后,argc=4
    argv++;//argv[0]被忽略
//    argc=4
//                 argv[1]="-Xzygote"
//                 argv[2]="/system/bin"
//                 argv[3]="--zygote"
//                 argv[4]="--start-system-server"

    int i;
    for (i = 0; i < argc; i++) {
        if (argv[i][0] != '-') {//很明显遍历到argv[2]="/system/bin"时候直接break
            break;
        }
        if (argv[i][1] == '-' && argv[i][2] == 0) {
            ++i; // Skip --.
            break;
        }
        //只有argv[1]="-Xzygote"会走到这一步,再往后遍历直接break了
        runtime.addOption(strdup(argv[i]));
    }
//上一步又使用了一个参数argv[1]="-Xzygote"。忽略掉,所以代码走到这里还剩下三个参数
//    argc=3
//                 argv[2]="/system/bin"
//                 argv[3]="--zygote"
//                 argv[4]="--start-system-server"
    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) {
            // argv[3]="--zygote"满足条件,zygote=true,表示当前进程是zygote
            zygote = true;
            //static const char ZYGOTE_NICE_NAME[] = "zygote64";
            //static const char ZYGOTE_NICE_NAME[] = "zygote";
            niceName = ZYGOTE_NICE_NAME;//设置niceName为zygote64或者zygote
        } else if (strcmp(arg, "--start-system-server") == 0) {
            // argv[4]="--start-system-server",这里说明需要启动System Server
            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;
        }
    }
    
    //设置后面调用ZygoteInit.java的main方法或者RuntimeInit.java的Main方法的参数
    //这里的参数先是传给了Runtime的start方法,start方法里面又将其转成Java参数的
     Vector<String8> args;
    if (!className.isEmpty()) {
        //非Zygote模式,这种情况可能是application模式或者tool模式
        args.add(application ? String8("application") : String8("tool"));
        runtime.setClassNameAndArgs(className, argc - i, argv + i);
    } else {
       //Zygote模式,这里可以证明后续调用ZygoteInit的main方法,会启动System Server服务
        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);
        args.add(abiFlag);
    
        // In zygote mode, pass all remaining arguments to the zygote
        // main() method.
        for (; i < argc; ++i) {
            args.add(String8(argv[i]));
        }
    }
   //niceName在参数解析时被设置。此处变更了app_process启动的进程名为zygote。
    if (!niceName.isEmpty()) {
        runtime.setArgv0(niceName.string());
        set_process_name(niceName.string());
    }
    //runtime.start启动Android运行环境
    if (zygote) {
        //com.android.internal.os.ZygoteInit是Android Java运行时环境的初始化类,
            runtime.start("com.android.internal.os.ZygoteInit", args, zygote);
    } else if (className) {
        //非Zygote模式,则执行RuntimeInit.java的main方法
        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;
    }
}

app_main.cpp的main方法,主要做了三件事儿:

  1. 初始化AndroidRuntime;
  2. 解析main函数的参数,判断当前是不是Zygote模式;
  3. 根据是否是Zygote模式,调用AndroidRuntime的start方法传入不同的参数

app_process是c++本地程序,源码目录为 frameworks/base/cmds/app_process/

app_process是可以执行java代码的命令(因为它启动了一个java虚拟机),它有两种启动模式:

1.zygote 模式:通常情况下,在–start-system-server启动参数的配置下,app_process启动之后,直接fork system_server 子进程,拉起整个android系统,之后用来孵化apk进程

2.非zygote模式:分两种子模式

(1).application模式:这种模式是zygote 创建进程后通过shell来重新加载app_process命令再执行的

(2).tool模式:这个模式主要是用来执行调试命令(如am\pm\wm等等)

AppRuntime继承自AndroidRuntime,AndroidRuntime的start方法,我们暂且先看下它的注释吧:

启动Android运行时。这涉及到启动虚拟机并在类中调用“static void main(String[] args)”方法由“className”命名。

传递给main函数两个参数,类名和指定的选项字符串。

/frameworks/base/core/jni/AndroidRuntime.cpp的start方法

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;
    //startVm  创建、启动虚拟机,并且设置相关参数。Dalvik或者ART虚拟机
    if (startVm(&mJavaVM, &env, zygote, primary_zygote) != 0) {
        return;
    }
    onVmCreated(env);
      /*
     *向虚拟机注册Android JNI native函数,(系统so库,用户自定义so库,加载函数等)
     */
    if (startReg(env) < 0) {
        ALOGE("Unable to register all android natives\n");
        return;
    }
    
    //给接下来要调用的java main方法准备参数
    //非常经典的在Native层创建Java层对象的操作:
    //创建一个java.lang.String的数组对象
    //并根据传入的参数对数组对象逐个元素进行赋值
    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);
    }

  ....
  //找到传进来的类的main方法,比如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 {
            //通过JNI技术调用main方法
            env->CallStaticVoidMethod(startClass, startMeth, strArray);

#if 0
            if (env->ExceptionCheck())
                threadExitUncaughtException(env);
#endif
        }
    }
   ...
}

综上所述,AndroidRuntime.star方法,主要做了三件事儿:

  1. 创建、启动了Android虚拟机;
  2. 向虚拟机注册了Android JNI native函数;
  3. 利用JNI技术调用了参数传进来的className对应类的main()函数。

如果不考虑非Zygote模式,那么Zygote服务的启动,执行app_main.cpp的main方法

而app_main.cpp的main方法做了四件事:

  1. 创建、启动了Android虚拟机;
  2. 向虚拟机注册了Android JNI native函数;
  3. 准备Java类的main方法的参数
  4. 利用JNI技术调用了ZygoteInit的main()方法。

下面就要分析ZygoteInit了

3,执行ZygoteInit.java的main方法

ZygoteInit:负责Zygote进程Java层的初始化工作

public static void main(String argv[]) {
    //创建Zygote服务管理类,用来注册Socket监听
    ZygoteServer zygoteServer = new ZygoteServer();
    //这里主要目的是拦截创建线程,
    //调用了这句代码以后,标记着Zygote进程开始Java层的初始化工作
    //如果此时创建线程会产生错误
    ZygoteHooks.startZygoteNoThreadCreation();
    // 将Zygote设置进他自己的进程组
    try {
        //将参数pid指定进程所属的组识别码设为参数pgid指定的组识别码。
        //Os.setpgid(int pid, int pgid)
        //pid=0表示设置当前进程所在的组的进程组pgid
        //pgid=0表示当前进程的PID为进程组pgid
        Os.setpgid(0, 0);
    } catch (ErrnoException ex) {
        throw new RuntimeException("Failed to setpgid(0,0)", ex);
    }
    final Runnable caller;
    try {
        // Report Zygote start time to tron unless it is a runtime restart
    
    ...日志打印
    
        //启动DDMS虚拟机监控调试服务
        RuntimeInit.enableDdms();
        //参数解析
        boolean startSystemServer = false;
        String socketName = "zygote";
        String abiList = null;
        boolean enableLazyPreload = false;
        for (int i = 1; i < argv.length; i++) {
            if ("start-system-server".equals(argv[i])) {
                //开启系统服务,这个参数是传进来的
                startSystemServer = true;
            } else if ("--enable-lazy-preload".equals(argv[i])) {
                enableLazyPreload = true;
            } else if (argv[i].startsWith(ABI_LIST_ARG)) {
                //abi类型,"--abi-list="这个参数也是传经来的
                abiList = argv[i].substring(ABI_LIST_ARG.length());
            } else if (argv[i].startsWith(SOCKET_NAME_ARG)) {
                //解析Socket name
                socketName = argv[i].substring(SOCKET_NAME_ARG.length());
            } else {//未知参数
                throw new RuntimeException("Unknown command line argument: " + argv[i]);
            }
        }
        //没有指定ABI参数会抛异常
        if (abiList == null) {
            throw new RuntimeException("No ABI list supplied.");
        }
        //注册Zygote的Socket服务端,用来监听接收启动应用程序的消息,这里的IPC不是Binder通信
        zygoteServer.registerServerSocketFromEnv(socketName);
        // In some configurations, we avoid preloading resources and classes eagerly.
        // In such cases, we will preload things prior to our first fork.
        if (!enableLazyPreload) {//没有延迟加载
        ...
            //执行预加载操作,包括系统预加载类,FrameWork资源,OpenGL资源
            preload(bootTimingsTraceLog);
        ...
        } else {//有延迟加载
            //重置线程优先级,设置为默认的Thread.NORM_PRIORITY
            Zygote.resetNicePriority();
        }
        ...
        //运行几个指定的GC,尝试清除几代的软引用和可达的对象,以及任何其他垃圾。
        //这只在fork()之前有用。强制进行了一次垃圾收集
        gcAndFinalize();
        ...
        //在fork之前调用一些安全初始化操作
        Zygote.nativeSecurityInit();
        //将整体的的存储目录/storage卸载,取而代之的是挂载临时目录,
        //这个动作和Android的沙箱(隔离存储)有关
        Zygote.nativeUnmountStorageOnInit();
        //呼应前面的ZygoteHooks.startZygoteNoThreadCreation()方法
        //告诉虚拟机,现在可以创建县城了
        ZygoteHooks.stopZygoteNoThreadCreation();
        if (startSystemServer) {//启动systemServer进程
            //这里的forkSystemServer方法导致进程进程发生了fork,也就是孵化裂变
            //从Zygote进程变成了Zygote和systemserver两个进程,fork会导致堆栈段的复制
            //进程会切换执行,涉及到CPU的切换,上下文的切换导致两个进程代码执行都停留在fork函数
            //两个进程都执行到fork函数等待返回,因此fork函数我们看代码是两次返回。
            //实际上fork函数的两次返回,是在两个进程中进行的:
            //先是在父进程中返回了被fork出来的子进程的pid
            //CPU执行切换到子进程之后因为在没有fork子进程,所以返回了0
            Runnable r = forkSystemServer(abiList, socketName, zygoteServer);
            //如果r=null,说明当前代码在Zygote进程中执行,直接跳过
            if (r != null) {
                //如果r!=null,说明当前代码在子进程(systemserver)中执行
                //启动进程后返回
                //因为Runnable的run方法实际上包装了SystemServer的main方法,所以这里会运行main方法
                r.run();
                return;
            }
        }
       //走到这一步,代码没有返回,说明这里的代码是在Zygote进程中执行的,
       //因为如果是孵化的子进程的话,走不到这一步代码就return了
       //此处进入一个无限循环,处理Zygote Socket接收到的数据,
        caller = zygoteServer.runSelectLoop(abiList);
    } catch (Throwable ex) {
        Log.e(TAG, "System zygote died with exception", ex);
        throw ex;
    } finally {
        //关闭释放Sockte连接
        //这里的代码主要是给子进程调用的,因为Zygote进程在runSelectLoop中无限循环阻塞了,
        //正常情况不会执行到这
        //子进程是由Zygote这个父进程fork出来的,所以也会附带有Socket连接,
        //但是子进程不需要Zygote的Socket服务,这里保证关闭
        zygoteServer.closeServerSocket();
    }
    //我们在子进程中并退出了select循环。继续执行命令。
    if (caller != null) {
        caller.run();
    }
}

(1)registerServerSocketFromEnv注册Zygote的Socket服务

void registerServerSocketFromEnv(String socketName) {
...
        //这里的socketName来源于上面的main函数zygote
        //所以最终fullSocketName=ANDROID_SOCKET_zygote
        final String fullSocketName = ANDROID_SOCKET_PREFIX + socketName;
...
            //找到名称为ANDROID_SOCKET_zygote的环境变量
            String env = System.getenv(fullSocketName);
            fileDesc = Integer.parseInt(env);
      ...
            FileDescriptor fd = new FileDescriptor();
            fd.setInt$(fileDesc);
            //创建一个本地socket服务,赋值给全局变量mServerSocket
            mServerSocket = new LocalServerSocket(fd);
      ...
}

注意上面的这句代码:

String env = System.getenv(fullSocketName);

        获取进程中名字为ANDROID_SOCKET_zygote的环境变量,那么这个环境变量是什么时候写进去的呢?我们前面分析/system/core/rootdir/init.rc时候讲到,他会解析/system/core/rootdir/init.zygote64.rc这个配置文件,init.zygote64.rc里面有这样一句socket zygote stream 660 root system,init进程在解析到这句配置的时候,会创建一个Socket fileDesc(简称socket fd)也就进程独有的文件描述符并且与ANDROID_SOCKET_zygote这个名字绑定,然后将socket名字(ANDROID_SOCKET_zygote)和socket fd注册到init进程的环境变量里面。其他进程都是init进程的子进程,可以通过System.getenv("ANDROID_SOCKET_zygote")获取到这个环境变量。

我们感兴趣的可以看下某 socket fd长什么样子?如下:

root@ubuntu:~# ll /proc/1583/fd

total 0

lrwx------ 1 root root 64 Jul 19 12:37 7 -> socket:[18892]

lrwx------ 1 root root 64 Jul 19 12:37 8 -> socket:[18893]

LocalSocket是Google为我们带来的,比Java的socket效率更高,没有经过协议栈,是Android自己实现的类似共享内存一样的东西,在传输大量数据的时候就需要用到。

(2)preload预加载

        Android的Java进程都是通过Zygote进程fork的,Zygote通过预加载类和资源可以加快子进程的执行速度和内存优化,因为预加载的类和资源比较多,所以开机时也需要重点关注preload的耗时。

static void preload(TimingsTraceLog bootTimingsTraceLog) {
    //设置软引用保护,避免在预加载期间创建的引用被GC回收
    beginIcuCachePinning();
    //预加载系统类
    //读取设备本地/system/etc/preloaded-classes文件,解析该文件,
    //通过反射技术加载文件中声明的所有类,不同的手机厂商定义的类数量有差异,
    //有时需要加载数千个类,这也是设备启动慢的原因之一
    //Android12中preloaded-classes的源码在/frameworks/base/config/preloaded-classes
    preloadClasses();
    //预加载系统资源
    //com.android.internal.R.array.preloaded_drawables
    //com.android.internal.R.array.preloaded_color_state_lists
    //Android系统有一个framework-res.apk包,这些系统资源就是存在这个当中
    //Android应用可以使用这些公共资源
    preloadResources();
    //调用native方法加载HAL(硬件抽象层)代码
    //所谓HAL硬件抽象层
    nativePreloadAppProcessHALs();
    加载OpenGL资源
    preloadOpenGL();
    //加载一些so库:libandroid.so、libcompiler_rt.so、libjnigraphics.so
    preloadSharedLibraries();
    //加载字体资源
    preloadTextResources();
    //要求WebViewFactory所有初始化必须在Zygote进程中进行
    WebViewFactory.prepareWebViewInZygote();
    //与前面的beginIcuCachePinning()呼应,取消软引用保护
    endIcuCachePinning();
    //初始化JCA相关参数
    warmUpJcaProviders();

    sPreloadComplete = true;
}

        Zygote进程启动时候预加载了不少资源,那么后续Zygote在fork新进程的时候,采用了COW(copy-on-write)技术,即写时拷贝技术。当App通过fork创建的时候,为了节省开销、加快应用启动,Zygote fork子进程不进行内存复制,而是共享Zygote进程预加载的系统类和系统资源,只有当子进程需要修改共享资源时,才会将共享内存复制到自己的进程内做修改。

(3)forkSystemServer孵化systemserver进程并启动

SystemServer是Android基本服务的提供者,是Android系统运行的最基本需求,所有Service运行在一个叫system_server的进程中,system_server为Android系统提供了各种Service。system_server进程是Android Java虚拟机中第一个进程,可以说整个Android系统的业务都是system_server展开的。

forkSystemServer方法,为孵化SystemServer进程准备参数,并且fork出systemServer进程

        注意,forkSystemServer方法因为是fork新的进程出来,新进程代码也会执行到forkSystemServer方法,这就会导致Zygote进程、system_server进程一起从fork函数返回。如果方法是在Zygote进程中执行的,则返回被fork出的SystemServer进程的Runnable对象;如果方法是在SystemServer进程中执行的,则因为其没有继续fork子进程,所以没有需要执行的Runnable任务,返回null

private static Runnable forkSystemServer(String abiList, String socketName,
        ZygoteServer zygoteServer) {
    ...
    //参数准备
    String args[] = {
        "--setuid=1000",
        "--setgid=1000",
        "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1021,1023,1024,1032,1065,3001,3002,3003,3006,3007,3009,3010",
        "--capabilities=" + capabilities + "," + capabilities,
        "--nice-name=system_server",
        "--runtime-args",
        "--target-sdk-version=" + VMRuntime.SDK_VERSION_CUR_DEVELOPMENT,
        "com.android.server.SystemServer",
    };
    ZygoteConnection.Arguments parsedArgs = null;

    int pid;

    try {
        //参数解析,生成目标函数
        parsedArgs = new ZygoteConnection.Arguments(args);
        ZygoteConnection.applyDebuggerSystemProperty(parsedArgs);
        ZygoteConnection.applyInvokeWithSystemProperty(parsedArgs);

        boolean profileSystemServer = SystemProperties.getBoolean(
                "dalvik.vm.profilesystemserver", false);
        if (profileSystemServer) {
            parsedArgs.runtimeFlags |= Zygote.PROFILE_SYSTEM_SERVER;
        }
        //这里是重点,fork出system_server进程,并运行system_server进程
        //fork动作会产生一个新的与Zygote一样的新的进程,并且云心新进程,
        //这样就导致了Zygote进程与system_server两个进程CPU执行权切换,
        //两个进程都停留在fork方法等待返回,两个fork方法是在两个进程中运行的,自然分别有对应返回值。
        //当fork方法运行在Zygote进程中时候,则返回其fork出子进程的pid,也就是system_server的pid;
        //当fork方法运行在system_server进程中时候,因为其没有继续fork的子进程,所以返回0
        pid = Zygote.forkSystemServer(
                parsedArgs.uid, parsedArgs.gid,
                parsedArgs.gids,
                parsedArgs.runtimeFlags,
                null,
                parsedArgs.permittedCapabilities,
                parsedArgs.effectiveCapabilities);
    } catch (IllegalArgumentException ex) {
        throw new RuntimeException(ex);
    }

    /* For child process */
    if (pid == 0) {
        //走到这里说明当前代码运行在system_Server进程当中
        if (hasSecondZygote(abiList)) {
            //如果设备同时配置了两个Zygote进程,那么这里等待第二个Zygote进程
            //这里主要是一些设备配置了init.zygote32_64.rc或者init.zygote64_32.rc
            //这样就会启动两个Zygote进程,一个为主,一个为次
            waitForSecondaryZygote(socketName);
        }
        //子进程是由Zygote孵化出来的,所以也具备了zygoteServer的Socket服务
        //但是子进程用不到,所以直接关闭
        zygoteServer.closeServerSocket();
        //handleSystemServerProcess方法的作用:
        //利用反射技术找到SystemServer的main函数,并将这个函数包装到Runnable的run方法中
        //返回包装后的Runnable对象
        return handleSystemServerProcess(parsedArgs);
    }
    return null;
}

(4)zygoteServer.runSelectLoop进入循环阻塞等待for新进程的请求

        Zygote进程会启动一个Socket本地服务,等待Socket客户端连接请求,当新的App启动的时候,就会请求zygote server服务fork新的进程。

        zygoteServer.runSelectLoop会进入循环阻塞等待,等待处理启动新应用的请求,一旦收到请求会fork新的进程出来。

        与上面的forkSystemServer一个道理,Zygote在fork新的进程,就会造成新老进程的runSelectLoop方法都执行但是返回值不同。当在子进程中时,会跳出runSelectLoop的循环,返回Runnable对象,也就是说在子进程中是不存在阻塞的,Zygote进程会保持阻塞监控新的连接请求

Runnable runSelectLoop(String abiList) {
    ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>();
    ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();
    //执行完下面这句代码,表示fds中只有一个元素,那就是mServerSocket
    fds.add(mServerSocket.getFileDescriptor());
    peers.add(null);
    while (true) {
        //每次循环都会动态创建新的pollFds
        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.pull是Linux系统的一个处理文件描述符的方法,等待文件描述符上的某个事件,I/O服用机制
            //监听pollFds数组中的事件,当pollFds有事件到来就往下执行
            //这里的-1表示当没有事件到来时一直阻塞,
            Os.poll(pollFds, -1);
        } catch (ErrnoException ex) {
            throw new RuntimeException("poll failed", ex);
        }
        //代码走到这里说明上面的poll阻塞方法有返回了,也就是pollFds有数据到来了
        for (int i = pollFds.length - 1; i >= 0; --i) {
            if ((pollFds[i].revents & POLLIN) == 0) {
                //采用I/O多路复用机制,当接收到客户端发出连接请求 或者数据处理请求到来,则往下执行;
                //否则进入continue,跳出本次循环。
                continue;
            }
            if (i == 0) {
                //fds[0]是mServerSocket
                //Socket服务端是LocalServerSocket,Socket客户端应该是LocalSocket
                //acceptCommandPeer方法就是给mServerSocket创建了一个与之连接的LocalSocket客户端
               //ZygoteConnection内部分装了LocalSocket客户端
                ZygoteConnection newPeer = acceptCommandPeer(abiList);
                peers.add(newPeer);
                //将通信对象添加到fds
                fds.add(newPeer.getFileDesciptor());
            } else {
                //这里就是遍历到了上面新添加的Socket通信对象
                try {
                    ZygoteConnection connection = peers.get(i);
                    //processOneCommand会读取参数并且fork新的子进程及相关操作
                    //因为这里最终会是fork操作,所以同样的会造成父进程子进程都运行这段代码
                    //当在子进程中运行,则command不为空,Zygote中command为空
                    final Runnable command = connection.processOneCommand(this);
                    if (mIsForkChild) {
                        //已经fork了子进程,并且当前代码运行在子进程
                        if (command == null) {
                            //保证fork子进程后必须有command返回
                            throw new IllegalStateException("command == null");
                        }
                        //在子进程中,返回command
                        return command;
                    } else {
                        if (command != null) {
                            //保证父进程不能存在command
                            throw new IllegalStateException("command != null");
                        }
                        //Zygote进程,完成了子进程的fork后,应该关闭本次的Socket连接,并清除该连接
                        if (connection.isClosedByPeer()) {
                            connection.closeSocket();
                            peers.remove(i);
                            fds.remove(i);
                        }
                    }
                } catch (Exception e) {
                    if (!mIsForkChild) {
                        //发生异常后清除操作
                        ZygoteConnection conn = peers.remove(i);
                        conn.closeSocket();

                        fds.remove(i);
                    } else {
                        Log.e(TAG, "Caught post-fork exception in child process.", e);
                        throw e;
                    }
                } finally {
                    //每次处理完客户端请求后,保证mIsForkChild为false
                    mIsForkChild = false;
                }
            }
        }
    }
}

下面看下connection.processOneCommand(this)方法的源码

Runnable processOneCommand(ZygoteServer zygoteServer) {
    String args[];
    Arguments parsedArgs = null;
    FileDescriptor[] descriptors;
    try {
        //读取参数
        args = readArgumentList();
        descriptors = mSocket.getAncillaryFileDescriptors();
    } catch (IOException ex) {
        throw new IllegalStateException("IOException on command socket", ex);
    }
    ...
    //解析参数
    parsedArgs = new Arguments(args);
    if (parsedArgs.abiListQuery) {
        handleAbiListQuery();
        return null;
    }
    if (parsedArgs.preloadDefault) {
        handlePreload();
        return null;
    }
    if (parsedArgs.preloadPackage != null) {
        handlePreloadPackage(parsedArgs.preloadPackage, parsedArgs.preloadPackageLibs,
                parsedArgs.preloadPackageLibFileName, parsedArgs.preloadPackageCacheKey);
        return null;
    }
    if (parsedArgs.apiBlacklistExemptions != null) {
        handleApiBlacklistExemptions(parsedArgs.apiBlacklistExemptions);
        return null;
    }
    if (parsedArgs.hiddenApiAccessLogSampleRate != -1) {
        handleHiddenApiAccessLogSampleRate(parsedArgs.hiddenApiAccessLogSampleRate);
        return null;
    }
    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));
    }
    //参数检查和设置
     // 检查客户端手有权限指定进程的用户ID、组ID
     // 如果是 root 进程,可以任意指定
     // 如果是 sys 进程,需要在ro.factorytest值 > 0时可以指定
    applyUidSecurityPolicy(parsedArgs, peer);
    // 判断是否具有invoke-with的执行权限
    applyInvokeWithSecurityPolicy(parsedArgs, peer);
    // 如果ro.debuggable是1的话,启动JDWP协议
    applyDebuggerSystemProperty(parsedArgs);
     // 如果ro.debuggable是1的话,启动JDWP协议
    applyInvokeWithSystemProperty(parsedArgs);
    ...
    //fork子进程,fork方法孵化子进程后,与Zygote进程都会运行并返回值
    //当前代码运行在Zygote进程中时,返回的pid就是fork得到的子进程的pid
    //当前代码如果运行在子进程中,则pid=0
    pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids,
            parsedArgs.runtimeFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo,
            parsedArgs.niceName, fdsToClose, fdsToIgnore, parsedArgs.startChildZygote,
            parsedArgs.instructionSet, parsedArgs.appDataDir);
    try {
        if (pid == 0) {
            //当前处于子进程中
            zygoteServer.setForkChild();
            //子进程由Zygote进程fork出来,所以也具备了zygoteServer,但是不需要,所以关闭
            zygoteServer.closeServerSocket();
            IoUtils.closeQuietly(serverPipeFd);
            serverPipeFd = null;
            //在子进程中完成子进程的初始化工作
            return handleChildProc(parsedArgs, descriptors, childPipeFd,
                    parsedArgs.startChildZygote);
        } else {
            //fork完子进程后,父进程中处理一些关闭及清理的工作
            IoUtils.closeQuietly(childPipeFd);
            childPipeFd = null;
            handleParentProc(pid, descriptors, serverPipeFd);
            return null;
        }
    } finally {
        IoUtils.closeQuietly(childPipeFd);
        IoUtils.closeQuietly(serverPipeFd);
    }
}

我们来看下fork出子进程之后,子进程是如何完成初始化的操作的,handleChildProc方法源码如下

private Runnable handleChildProc(Arguments parsedArgs, FileDescriptor[] descriptors,
        FileDescriptor pipeFd, boolean isZygote) {
    //关闭本次操作的Socket连接
    closeSocket();
   ...
    if (parsedArgs.invokeWith != null) {
        //启动参数有--invoke-with
        WrapperInit.execApplication(parsedArgs.invokeWith,
                parsedArgs.niceName, parsedArgs.targetSdkVersion,
                VMRuntime.getCurrentInstructionSet(),
                pipeFd, parsedArgs.remainingArgs);

        // Should not get here.
        throw new IllegalStateException("WrapperInit.execApplication unexpectedly returned");
    } else {//通常情况下--invoke-with参数为空,所以代码会进入这里
        if (!isZygote) {
            //很显然当前是在子进程运行而非Zygote进程中,所以代码执行这里
            return ZygoteInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs,
                    null /* classLoader */);
        } else {
            return ZygoteInit.childZygoteInit(parsedArgs.targetSdkVersion,
                    parsedArgs.remainingArgs, null /* classLoader */);
        }
    }
}

我们进入ZygoteInit.zygoteInit方法

public static Runnable zygoteInit(int targetSdkVersion, long[] disabledCompatChanges,
        String[] argv, ClassLoader classLoader) {
    ...
    //一些通用的简单初始化
    RuntimeInit.commonInit();
    //调用了一个本地native方法,最终调用了我们前面提到的AndroidRuntime的子类AppRuntime的onZygoteInit()方法
    //初始化binder的使用环境
    ZygoteInit.nativeZygoteInit();
    //这里最终调用了RuntimeInit.findStaticMain方法
    return RuntimeInit.applicationInit(targetSdkVersion, disabledCompatChanges, argv,
            classLoader);
}

我们先来看一下AppRuntime的onZygoteInit()方法的源码,源码在app_main.cpp的AppRuntime下面

virtual void onZygoteInit(){
    sp<ProcessState> proc = ProcessState::self();
    ALOGV("App process: starting thread pool.\n");
    proc->startThreadPool();
}

这个onZygoteInit主要就是用来初始化Binder的使用环境

我们最后看下RuntimeInit.findStaticMain方法,其实这个方法在前面forkSystemServer中也用过这个方法,findStaticMain方法,会将参数传入的className通过反射的技术,找到其main方法,并且包装到Runnable的run方法中返回

protected static Runnable findStaticMain(String className, String[] argv,
        ClassLoader classLoader) {
    Class<?> cl;

    try {
        cl = Class.forName(className, true, classLoader);
    } catch (ClassNotFoundException ex) {
        throw new RuntimeException(
                "Missing class when invoking static main " + className,
                ex);
    }
    Method m;
    try {
        m = cl.getMethod("main", new Class[] { String[].class });
    } catch (NoSuchMethodException ex) {
        throw new RuntimeException(
                "Missing static main on " + className, ex);
    } catch (SecurityException ex) {
        throw new RuntimeException(
                "Problem getting static main on " + className, ex);
    }
    ...
    return new MethodAndArgsCaller(m, argv);
}
static class MethodAndArgsCaller implements Runnable {
    private final Method mMethod;
    private final String[] mArgs;
    public MethodAndArgsCaller(Method method, String[] args) {
        mMethod = method;
        mArgs = args;
    }
    public void run() {
    ...
            mMethod.invoke(null, new Object[] { mArgs });
     ...
    }
}

        而我们这里,handleChildProc方法,最终返回的MethodAndArgsCaller(Runnable的子类),实际上是利用反射技术将android.app.ActivityThread的main()方法封装到Runnable的run()方法里面。而ActivityThread的main方法正式整个App入口。

(5)caller.run()子进程调用App启动入口方法ActivityThread.main

我们回顾一下ZygoteInit.main方法的最后处理逻辑

public static void main(String argv[]) {
    ...
    final Runnable caller;
    try {
      ...
        if (startSystemServer) {//启动systemServer进程
            Runnable r = forkSystemServer(abiList, socketName, zygoteServer);
            if (r != null) {
                r.run();
                return;
            }
        }
        //如果当前代码运行在Zygote进程,则返回null
        //如果当前代码运行在子进程,则返回caller
        caller = zygoteServer.runSelectLoop(abiList);
    } catch (Throwable ex) {
        Log.e(TAG, "System zygote died with exception", ex);
        throw ex;
    } finally {
        zygoteServer.closeServerSocket();
    }
    //根据前面的讲解,我们能够知道Zygote在fork进程时会发生两个进程各自运行同一处代码,
    //根据桑上面的runSelectLoop方法会将Zygote进程处于阻塞状态,无限循环等待Socket客户端
    //发起请求,比如App的启动会出发zygoteServer与Zocket客户端连接,然后fork出App的进程
    //当代码运行在App进程(子进程)中时,将会跳出阻塞,返回caller,Zygote父进程继续保持
    //阻塞监听。
    if (caller != null) {
        //执行到这一步,我们可以确定当前代码运行在子进程,此处的run方法运行的就是ActivityThread
        //的main方法。
        caller.run();
    }
}

4,Android如何利用Zygote启动一个新进程

        Android启动一个新的进程都是在ActivityManagerService(简称AMS)中完成的,可能会有很多原因导致系统启动一个新的进程,最终在AMS中都是通过调用startProcess()方法来实现。

        通过查看ActivityManagerService.startProcess的源码,找到了关键的代码,最终调用了ZygoteProcess类的一个私有方法startViaZygote()方法,我们重点看下startViaZygote的关键代码

private Process.ProcessStartResult startViaZygote(final String processClass,
                                                  final String niceName,
                                                  final int uid, final int gid,
                                                  final int[] gids,
                                                  int runtimeFlags, int mountExternal,
                                                  int targetSdkVersion,
                                                  String seInfo,
                                                  String abi,
                                                  String instructionSet,
                                                  String appDataDir,
                                                  String invokeWith,
                                                  boolean startChildZygote,
                                                  String[] extraArgs)
                                                  throws ZygoteStartFailedEx {
    ArrayList<String> argsForZygote = new ArrayList<String>();
    // --runtime-args, --setuid=, --setgid=,
    // and --setgroups= must go first
    argsForZygote.add("--runtime-args");
    argsForZygote.add("--setuid=" + uid);
    argsForZygote.add("--setgid=" + gid);
    argsForZygote.add("--runtime-flags=" + runtimeFlags);
    if (mountExternal == Zygote.MOUNT_EXTERNAL_DEFAULT) {
        argsForZygote.add("--mount-external-default");
    } else if (mountExternal == Zygote.MOUNT_EXTERNAL_READ) {
        argsForZygote.add("--mount-external-read");
    } else if (mountExternal == Zygote.MOUNT_EXTERNAL_WRITE) {
        argsForZygote.add("--mount-external-write");
    }
    argsForZygote.add("--target-sdk-version=" + targetSdkVersion);
    // --setgroups is a comma-separated list
    if (gids != null && gids.length > 0) {
        StringBuilder sb = new StringBuilder();
        sb.append("--setgroups=");
        int sz = gids.length;
        for (int i = 0; i < sz; i++) {
            if (i != 0) {
                sb.append(',');
            }
            sb.append(gids[i]);
        }
        argsForZygote.add(sb.toString());
    }
    if (niceName != null) {
        argsForZygote.add("--nice-name=" + niceName);
    }
    if (seInfo != null) {
        argsForZygote.add("--seinfo=" + seInfo);
    }
    if (instructionSet != null) {
        argsForZygote.add("--instruction-set=" + instructionSet);
    }
    if (appDataDir != null) {
        argsForZygote.add("--app-data-dir=" + appDataDir);
    }
    if (invokeWith != null) {
        argsForZygote.add("--invoke-with");
        argsForZygote.add(invokeWith);
    }
    if (startChildZygote) {
        argsForZygote.add("--start-child-zygote");
    }
    argsForZygote.add(processClass);
    if (extraArgs != null) {
        for (String arg : extraArgs) {
            argsForZygote.add(arg);
        }
    }
    //关键代码就是这一句
    //1,openZygoteSocketIfNeeded会创建与Zygote进程ServerSocket的连接
    //2,zygoteSendArgsAndGetResult会将进程启动的参数发送给Zygote进程,fork出新进程后会将进程的pid返回
    synchronized(mLock) {
        return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi), argsForZygote);
    }
}

openZygoteSocketIfNeeded方法源码

private ZygoteState openZygoteSocketIfNeeded(String abi) throws ZygoteStartFailedEx {
    Preconditions.checkState(Thread.holdsLock(mLock), "ZygoteProcess lock not held");

    if (primaryZygoteState == null || primaryZygoteState.isClosed()) {
        try {
            //与Zygote的Socket服务建立连接
            primaryZygoteState = ZygoteState.connect(mSocket);
        } catch (IOException ioe) {
            throw new ZygoteStartFailedEx("Error connecting to primary zygote", ioe);
        }
      ...
    }
   ...
    if (secondaryZygoteState == null || secondaryZygoteState.isClosed()) {
        try {
            //针对一些设备配置了init.zygote32_64.rc或者init.zygote64_32.rc
            //需要与另一个Zygote的Socket服务建立连接
            secondaryZygoteState = ZygoteState.connect(mSecondarySocket);
        } catch (IOException ioe) {
            throw new ZygoteStartFailedEx("Error connecting to secondary zygote", ioe);
        }
  ...
    }
...
}

ZygoteState的connect方法

public static ZygoteState connect(LocalSocketAddress address) throws IOException {
     ...
    final LocalSocket zygoteSocket = new LocalSocket();
    ...
    try {
        zygoteSocket.connect(address);
...
    } catch (IOException ex) {
        try {
            zygoteSocket.close();
        } catch (IOException ignore) {
        }
        throw ex;
    }
...
    return new ZygoteState(zygoteSocket, zygoteInputStream, zygoteWriter,
            Arrays.asList(abiListString.split(",")));
}

zygoteSendArgsAndGetResult方法源码

private static Process.ProcessStartResult zygoteSendArgsAndGetResult(
        ZygoteState zygoteState, ArrayList<String> args)
        throws ZygoteStartFailedEx {
 ...
        //输出流,参数写入给Zygote
        final BufferedWriter writer = zygoteState.writer;
        //输入流,从Zygote进程读取fork得到的新进程
        final DataInputStream inputStream = zygoteState.inputStream;
        
        writer.write(Integer.toString(args.size()));
        writer.newLine();
        for (int i = 0; i < sz; i++) {
            String arg = args.get(i);
            writer.write(arg);
            writer.newLine();
        }
        //App启动参数写入发送
        writer.flush();
        
        //fork子进程后读取新的进程
        Process.ProcessStartResult result = new Process.ProcessStartResult();
        result.pid = inputStream.readInt();
        result.usingWrapper = inputStream.readBoolean();
        ...
        return result;
    } catch (IOException ex) {
        zygoteState.close();
        throw new ZygoteStartFailedEx(ex);
    }
}

四、总结

Android系统启动流程,前两步我们简单说明下

1,BootLoader

BootLoader是在操作系统内核运行之前运行。可以初始化硬件设备、建立内存空间映射图,从而将系统的软硬件环境带到一个合适状态,以便为最终调用操作系统内核准备好正确的环境;

2,Kernel

Kernel指的是操作系统内核Linux初始化及启动;

3,init进程启动

硬件初始化、内核初始化及启动之后,init将会启动

init进程启动先调用了init.cpp中的main()方法,init.cpp的main()方法中有这样一句代码:parser.ParseConfig("/init.rc"),解析init.rc文件,init.rc文件中有zygote start等启动zygote的命令,而且有导入zygote配置的语句import /system/etc/init/hw/init.${ro.zygote}.rc,$(ro.zygote).rc这个引用具体会指向设备具体的配置文件,配置文件按照不同的硬件厂商目前有3种:

init.zygote32.rc、init.zygote32_64.rc、init.zygote64.rc,这三种文件决定了启动32位还是64位的Zygote服务。不过这几个文件中第一行配置就是service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server这一句,service zygote意思是Zygote进程是以Service服务的方式启动,所以会先启动一个Zygote service服务,/system/bin/app_process64表示回去执行app_process,最终会去执行app_main.cpp中的main方法,并且会将下面的参数传给app_main.cpp的main方法:

  1. /system/bin/app_process64
  2. -Xzygote
  3. /system/bin
  4. --zygote
  5. --start-system-server

app_main.cpp的main方法,主要干了三件事:

  1. 初始化AndroidRuntime的子类:AppRuntime;
  2. 解析main函数的参数,判断当前是不是Zygote模式;
  3. 根据是否是Zygote模式,调用AndroidRuntime的start方法传入不同的参数

AndroidRuntime的start方法主要做三件事

  1. 创建、启动了Android虚拟机;
  2. 向虚拟机注册了Android JNI native函数;
  3. 利用JNI技术调用了参数传进来的className对应类的main()函数

        我们上面的分析,传给start方法的className是ZygoteInit,所以最终会调用ZygoteInit的main方法

        我的理解是Zygote进程在上面的init解析init.zygote.rc配置文件后,以service的方式启动了。所以在调用ZygoteInit.java的main方法之前,Zygote进程已经启动了

        ZygoteInit的main方法是通过Zygote进程去调用的,总结一下ZygoteInit.java的main方法做了什么:

  1. ZygoteHooks.startZygoteNoThreadCreation()拦截线程创建;
  2. Os.setpgid(0, 0)将Zygote设置进他自己的进程组;
  3. RuntimeInit.enableDdms()启动DDMS虚拟机监控调试服务;
  4. 解析AndroidRuntime传进来的参数;
  5. zygoteServer.registerServerSocketFromEnv(socketName)创建注册本地LocalServerSocket服务,用来与后面的客户端LocalSocket通信,注意这里并不是Binder通信;
  6. preload预加载,包括预加载系统类、Framwork资源、OpenGL等;
  7. gcAndFinalize在执行fork之前,做一次GC垃圾回收;
  8. Zygote.nativeSecurityInit()在fork之前调用一些安全初始化操作;
  9. Zygote.nativeUnmountStorageOnInit()将整体的的存储目录/storage卸载,取而代之的是挂载临时目录,这个动作和Android的沙箱(隔离存储)有关;
  10. ZygoteHooks.stopZygoteNoThreadCreation()呼应前面的ZygoteHooks.startZygoteNoThreadCreation()方法告诉虚拟机,现在可以创建线程了;
  11.  Runnable r = forkSystemServer fork出system_server进程。如果当前代码执行在system_server进程中,则返回的Runnable不为空,继续执行run方法之后return,这里的run方法就是SystemServer的main方法;如果当前代码执行在Zygote进程中,则Runnable为空,跳过run方法。
  12. caller = zygoteServer.runSelectLoop,当前代码执行在Zygote进程中则代码进入阻塞无线循环,等待并且等待Socket发起的请求,如果有新的进程要创建启动,则Zygote会fork出新的进程。此时,如果代码运行在Zygote进程中,则继续保持阻塞,等待下一次请求;如果代码运行在子进程,则return跳出runSelectLoop方法,返回caller,意味着子进程跳出阻塞。
  13. caller.run();这是main方法的最后一步,只有跳出阻塞的子进程才会走到这一步,这里的run方法与上面的forkSystemServer原理一样,都是利用反射技术,将某一个类的main方法封装到Runnable的run方法中,这里封装的是ActivityThread的main方法。

五、题外,为什么Zygote进程与其子进程的通信采用的是Socket而非Binder

(133条消息) android中AMS通知Zygote去fork进程为什么使用socket而不使用binder?_失落夏天的博客-CSDN博客_安卓socke zygote

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1066286.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

重庆建筑模板厂家:选择桉木模板,智慧之选

随着城市化进程的不断加速&#xff0c;建筑业也呈现出蓬勃发展的势头。而作为建筑过程中不可或缺的材料之一&#xff0c;建筑模板的选择将直接影响到工程质量和工期。在重庆这样一个气候多变、地形复杂的地区&#xff0c;如何选择适合当地情况的建筑模板显得尤为重要。 一、常规…

《第一行代码Andorid》阅读笔记-第六章

第六章 内容提供器 在上一章中我们学了Android数据持久化的技术&#xff0c;包括文件存储、SharedPreferences存储以及数据库存储。使用这些持久化技术所保存的数据都只能在当前应用程序中访问。 虽然文件和SharedPreferences存储中提供了MODE_WORLD_READABLE和MODE_WORLD_WRI…

电脑系统一键重装Win10操作方法教程

如果我们的电脑系统遇到了运行变慢、感染病毒等问题&#xff0c;这时候我们就可以进行系统的重装&#xff0c;这样来解决遇到的系统问题。特别多的用户都想知道一键重装Win10系统的详细步骤&#xff0c;下面小编就给大家带来最详细的操作方法介绍哦&#xff0c;帮助大家轻松完成…

【Vue基础-数字大屏】地图

一、阿里云数据可视化平台 地图数据https://datav.aliyun.com/portal/school/atlas/area_selector 二、操作步骤 1、打开阿里云数据可视化平台&#xff0c;复制中国地图数据链接 2、在浏览器中打开中国地图数据链接&#xff0c;复制json数据 3、在assets静态目录下创建mapDa…

大数据获客是什么?有什么用?

随着企业部分业务线上化、目标用户下沉&#xff0c;风控体系也在迭代&#xff0c;依靠大数据、人工智能进行风控成为行业共识。另一方面&#xff0c;随着线上线下获客成本日益增长&#xff0c;各机构逐渐转向用户精细化经营&#xff0c;精准营销受到各企业机构重视。大数据精准…

基于SSM的大学生创新创业平台竞赛管理子系统设计与实现

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SSM 前端&#xff1a;采用JSP技术开发 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#x…

维修派工单,为什么要使用维修派工单

维修派工单是一种至关重要的管理工具&#xff0c;主要用于分配维修人员对设备进行维护和维修。根据派工单&#xff0c;可以快速清晰地分配维修任务&#xff0c;掌握设备维护的进度和效果&#xff0c;提升设备维护的效率和效果。  良好的维修工单应具有清晰的格式&#xff0c;…

具有隔离功能,1Mbps,高速 CAN 总线收发器:SIT1050ISO

SIT1050ISO 是一款电容隔离的 CAN 转发器&#xff0c; ISO11898 标准的技术规范&#xff0c;含有多个由二氧化 硅&#xff08; SiO2 &#xff09;绝缘隔栅分开的逻辑输入和输出缓冲器&#xff0c;具有在总线与 CAN 协议控制器之间进行差分 信号传输的能力。 产品特点&a…

智慧电力运维系统助力实现配电室无人值守

随着科技的快速发展&#xff0c;电力行业也在变革&#xff0c;不断追求高效、安全和可靠的供电服务。传统的电力运维模式存在成本高、人工操作和监控存在一定的局限性和安全隐患&#xff0c;已无法满足现代电力企业的需求&#xff0c;电力企业需要更加智能化、高效化、安全化&a…

SSL证书是什么?1分钟get

在当今互联网世界中&#xff0c;保护数据的完整性和隐私性至关重要&#xff0c;由此&#xff0c;在网络数据安全保护领域&#xff0c;作为保护网络传输数据安全的SSL证书越来越频繁出现。那么你知道SSL证书是什么&#xff1f;SSL证书有哪些类型&#xff1f;SSL证书有什么用吗&a…

SAP从入门到放弃系列之QM目录类别、代码组、选择集维护

目录 一、概念相关内容1.1 目录类别1.2 代码组和代码1.3 选择集和选择集代码 二、系统操作相关内容 一、概念相关内容 1.1 目录类别 目录类别是对定性数据的一种归纳&#xff0c;描述了业务的主题。根据PA的教材中表述&#xff0c;目录类型 0 - 9 和 A - O 由 SAP 定义&#…

在全志XR806开发板使用编码器进行调光

XR806识别编码器和PWM输出 基于FreeRTOS开发&#xff0c;旋转编码器移植了Arduino Rotary库&#xff0c;注意这个库是GPL协议的&#xff0c;使用效果不错&#xff0c;首先奉上源码链接。 之前做过一个LED调光的项目&#xff08;https://oshwhub.com/czx951002/ChargeablePWMDim…

操作系统迁移难?Alibaba Cloud Linux 支持跨版本升级 | 龙蜥技术

背景 阿里云服务器迁移中心 SMC 操作系统迁移推出 Alibaba Cloud Linux 2 到 Alibaba Cloud Linux 3 的操作系统跨版本升级的功能。可以通过 SMC 控制台将 Alibaba Cloud Linux 2 一键原地升级为 Alibaba Cloud Linux 3。 Alibaba Cloud Linux 2 将会在 2024 年 3 月 31 日结…

ChatGPT是如何产生心智的?

一、前言 - ChatGPT真的产生心智了吗&#xff1f; 来自斯坦福大学的最新研究结论&#xff0c;一经发出就造成了学术圈的轰动&#xff0c;“原本认为是人类独有的心智理论&#xff08;Theory of Mind&#xff0c;ToM&#xff09;&#xff0c;已经出现在ChatGPT背后的AI模型上”…

ScheduledExecutorService的坑

参考文献 调度服务 ScheduledExecutorService 经常卡顿问题的排查及解决方法-腾讯云开发者社区-腾讯云 场景 一个安顿广播程序使用的ScheduledExecutorService来定时执行任务&#xff0c;当有一个任务出现异常后就会卡住&#xff0c;不会继续执行后续的任务。 解决方案 查找定…

完美解决 flex 实现一行三个,显示多行,左对齐

效果图 代码 <body><section class"content"><div class"item">元素</div><div class"item">元素</div><div class"item">元素</div><div class"item">元素</di…

121-宏免杀

CS生成宏&上线 生成宏 1.cs生成宏&#xff0c;如下图操作 2.点击复制宏代码&#xff0c;保存下来 cs上线 注&#xff1a;如下操作使用的是word&#xff0c;同样的操作也适用于Excel 1.新建一个word文档&#xff0c;使用word打开。点击文件—— 2.更多——选项—— 3.自定义…

如何自学(黑客)网络安全技术————(详细分析学习思路)方法

前言 前几天发布了一篇 网络安全&#xff08;黑客&#xff09;自学 没想到收到了许多人的私信想要学习网安黑客技术&#xff01;却不知道从哪里开始学起&#xff01;怎么学&#xff1f;如何学&#xff1f; 今天给大家分享一下&#xff0c;很多人上来就说想学习黑客&#xff0c…

电脑PC端有哪些好用的记笔记工具

在日常学习中&#xff0c;想要学好每一门学科&#xff0c;必定离不开使用笔记软件记录&#xff0c;如何高效记录学习笔记呢&#xff1f;电脑PC端记录学习笔记用哪一款工具比较好呢&#xff1f;今天给大家推荐一款功能比较齐全的多平台记笔记工具——敬业签。 学生们通常不仅在…

抖捧自动直播市场火热,实体行业如何实现高效开播?

在AI数字人热度之后&#xff0c;最近抖捧场景自动直播开始火遍全网&#xff0c;因为操作简单成本极低&#xff0c;只需要一部手机放在店里&#xff0c;就可以高效开播&#xff0c;深受广大实体行业老板的认可&#xff0c;那么抖捧实景自动直播的方式&#xff0c;具体是怎么实现…