IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> Zygote——Android系统中java世界的受精卵(二、Welcome To Java) -> 正文阅读

[移动开发]Zygote——Android系统中java世界的受精卵(二、Welcome To Java)

0、引言

? ? ? ? Android的底层内核是基于Linux构建而成,是在Native世界,而Android上层的应用是隶属Java世界。那么在Android系统启动过程中,系统是如何从Native孵化出Java世界的呢?这便是这篇文章的主角Zygote的主要职责。

????????本文所选Android系统版本是9.0 Pie,文中所有代码片段路径在代码块第一行已经标注。文章的目的是记录自己的学习历程与心得,不做商用或盈利,凡是学习过程中学习或引用过的大佬博文或著作都会尽力标注,在此感谢各位前辈的不吝分享。本文借鉴如下:


2、Welcome To Java

? ? ? ? 在上篇博文《Zygote——Android系统中java世界的受精卵(一、C/C++中的Zygote)》中,我们分析了,C/C++世界Zygote相关的启动代码,在结尾处,终于在ZygoteInit.main()函数执行时,进入到了Java世界。所以这边文章就接着main函数往下看,追踪Java世界中Zygote相关的内容,main()函数的代码依旧是分割开来解析 。

? 2.1、准备工作

// pie\frameworks\base\core\java\com\android\internal\os\ZygoteInit.java
public static void main(String[] argv) {
        ZygoteServer zygoteServer = null;
        //pie\libcore\dalvik\src\main\java\dalvik\system\ZygoteHooks.java
        ZygoteHooks.startZygoteNoThreadCreation();    //调用native函数,功能是确保此时没有其他线程启动
        try {
            Os.setpgid(0, 0);                         //设置pid
        } catch (ErrnoException ex) {
            throw new RuntimeException("Failed to setpgid(0,0)", ex);
        }

        Runnable caller;
        try {
            final long startTime = SystemClock.elapsedRealtime();    //系统启动到现在的时间,包含设备深度休眠的时间
            final boolean isRuntimeRestarted = "1".equals( 
                    SystemProperties.get("sys.boot_completed"));     //该属性值在设备物理重启时为空,reboot重启后为1 
            String bootTimeTag = Process.is64Bit() ? "Zygote64Timing" : "Zygote32Timing";    //设置boot时间打印TAG
            //pie\frameworks\base\core\java\android\util\TimingsTraceLog.java
            TimingsTraceLog bootTimingsTraceLog = new 
                TimingsTraceLog(bootTimeTag,Trace.TRACE_TAG_DALVIK); //通过systrace来追踪
            bootTimingsTraceLog.traceBegin("ZygoteInit");            //追踪开始,每个traceBegin()对应一个traceEnd()
            //使能DDMS(Dalvik Debug Monitor Server),注册所有已知的Java VM的处理块的监听器。
            //线程监听、内存监听、native堆内存监听、debug模式监听…
            RuntimeInit.preForkInit();    

            boolean startSystemServer = false;
            String zygoteSocketName = "zygote";
            String abiList = null;
            boolean enableLazyPreload = false;
            for (int i = 1; i < argv.length; i++) {
                if ("start-system-server".equals(argv[i])) {         //读取"start-system-server"参数
                    startSystemServer = true;
                //ro.zygote属性值为zygote64_32或zygote64_32时,会存在另外一个进程zygote_secondary,
                //zygote_secondary -Xzygote /system/bin --zygote --socket-name=zygote_secondary --enable-lazy-preload
                } else if ("--enable-lazy-preload".equals(argv[i])) {
                    enableLazyPreload = true;
                } else if (argv[i].startsWith(ABI_LIST_ARG)) {       //读取"--abi-list"参数
                    abiList = argv[i].substring(ABI_LIST_ARG.length());
                } else if (argv[i].startsWith(SOCKET_NAME_ARG)) {    //读取"--socket-name"参数
                    zygoteSocketName = argv[i].substring(SOCKET_NAME_ARG.length());
                } else {
                    throw new RuntimeException("Unknown command line argument: " + argv[i]);
                }
            }
            // PRIMARY_SOCKET_NAME = "zygote"
            final boolean isPrimaryZygote = zygoteSocketName.equals(Zygote.PRIMARY_SOCKET_NAME);
            if (!isRuntimeRestarted) {
                if (isPrimaryZygote) {
                    FrameworkStatsLog.write(FrameworkStatsLog.BOOT_TIME_EVENT_ELAPSED_TIME_REPORTED,
                            BOOT_TIME_EVENT_ELAPSED_TIME__EVENT__ZYGOTE_INIT_START,
                            startTime);    //FrameworkStatsLog.java == statslog-framework-java-gen
                //SECONDARY_SOCKET_NAME = "zygote_secondary"
                } else if (zygoteSocketName.equals(Zygote.SECONDARY_SOCKET_NAME)) {    
                    FrameworkStatsLog.write(FrameworkStatsLog.BOOT_TIME_EVENT_ELAPSED_TIME_REPORTED,
                            BOOT_TIME_EVENT_ELAPSED_TIME__EVENT__SECONDARY_ZYGOTE_INIT_START,
                            startTime);
                }
            }

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

? ? ? ? 这一部分主要是为后面的任务做准备工作:

  • ????????禁止启动其他线程;
  • ????????设置pid;
  • ????????解析C/C++层传进来的参数argv;
  • ????????设置相关日志追踪;

2.2、preload()

// pie\frameworks\base\core\java\com\android\internal\os\ZygoteInit.java
   public static void main(String[] argv) {
        …………
        if (!enableLazyPreload) {
                bootTimingsTraceLog.traceBegin("ZygotePreload");
                EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,SystemClock.uptimeMillis());
                preload(bootTimingsTraceLog);    //预加载
                EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,SystemClock.uptimeMillis());
                bootTimingsTraceLog.traceEnd();
        }
   }

? ? ? ? 这里的预加载是指将Java类、资源文件、图像资源等公共资源在zygote启动的时候就进行加载。这样一来,根据fork的copy-on-write机制,其他由zygote fork出来的进程在使用这些资源的时候就不需要再次加载了,而是直接使用。所以这是一种牺牲系统开机时间,来提高系统应用运行时的运行效率的手段。????????

//pie\frameworks\base\core\java\com\android\internal\os\ZygoteInit.java
    static void preload(TimingsTraceLog bootTimingsTraceLog) {
        Log.d(TAG, "begin preload");
        bootTimingsTraceLog.traceBegin("BeginPreload");
        beginPreload();                          //ZygoteHooks.onBeginPreload();
        bootTimingsTraceLog.traceEnd();          //BeginPreload
        bootTimingsTraceLog.traceBegin("PreloadClasses");
        preloadClasses();                        //预加载一些类
        bootTimingsTraceLog.traceEnd();          //PreloadClasses
        bootTimingsTraceLog.traceBegin("CacheNonBootClasspathClassLoaders");
        //加载一些应用程序使用但不能放入引导类路径的jar包库,这些库过去是引导类路径的一部分,但必须删除。
        //由于向后兼容性的原因,旧的系统应用程序仍然会使用它们,因此它们被缓存在这里以保持性能特征
        cacheNonBootClasspathClassLoaders();    
        bootTimingsTraceLog.traceEnd();          //CacheNonBootClasspathClassLoaders
        bootTimingsTraceLog.traceBegin("PreloadResources");
        preloadResources();                      //加载常用资源,以便它们可以跨进程共享,比如apk开发常用到的color、drawable等资源
        bootTimingsTraceLog.traceEnd();          //PreloadResources
        Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "PreloadAppProcessHALs");
        nativePreloadAppProcessHALs();           //一些被大多数app进程加载的内容,需要通过HAL来添加(native)
        Trace.traceEnd(Trace.TRACE_TAG_DALVIK);
        Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "PreloadGraphicsDriver");
        maybePreloadGraphicsDriver();            //根据属性ro.zygote.disable_gl_preload来判断是否禁止预加载图像驱动相关内容(native)
        Trace.traceEnd(Trace.TRACE_TAG_DALVIK);
        preloadSharedLibraries();                //加载几个共享库:libandroid.so、libcompiler_rt.so、libjnigraphics.so                          
        preloadTextResources();                  //启动字体缓存,设置Typeface              
        WebViewFactory.prepareWebViewInZygote(); //为了内存共享,WebViewFactory执行所有必须在zygote进程中运行的初始化
        endPreload();
        warmUpJcaProviders();                    //注册AndroidKeyStoreProvider并预热已经注册的provider
        Log.d(TAG, "end preload");

        sPreloadComplete = true;
    }

? ? ? ? 其中的preloadClasses()函数是去加载目标设备目录树中,/system/etc/preloaded-classes这个文件中每行一个全限定名格式的类(#开头的注释行和空白行则自动跳过)。该文件是由文件frameworks\base\tools\preload\WritePreloadedClassFile.java自动生成,其对于哪些类需要预加载有明确的说明:

/*
* pie\frameworks\base\tools\preload\WritePreloadedClassFile.java
* The set of classes to preload. We preload a class if:
* a) it's loaded in the bootclasspath (i.e., is a system class)                1、即系统类
* b) it takes > MIN_LOAD_TIME_MICROS = 1250 us to load, and                    2、加载时长超过1250ms的类
* c) it's loaded by more than one process, or it's loaded by anapplication     3、不止一个进程会去加载的类
*/

2.3、gcAndFinalize()

//pie\frameworks\base\core\java\com\android\internal\os\ZygoteInit.java
    public static void main(String[] argv) {
            …………
            bootTimingsTraceLog.traceBegin("PostZygoteInitGC");
            // 调用ZygoteHooks.gcAndFinalize(),通过runFinalizationSync()可以在没有HeapWorker线程的Zygote中调用finalizers,
            //以运行几个特殊的gc来尝试清理几代软可及和最终可及的对象,以及任何其他垃圾。
            gcAndFinalize();
            bootTimingsTraceLog.traceEnd(); // PostZygoteInitGC
            bootTimingsTraceLog.traceEnd(); // 对应bootTimingsTraceLog.traceBegin("ZygoteInit")   
            Zygote.initNativeState(isPrimaryZygote);    //初始化zygote的native状态(native方法)
            ZygoteHooks.stopZygoteNoThreadCreation();   //可以启动其他线程了,对应前面的ZygoteHooks.startZygoteNoThreadCreation();
            …………
    }

? ? ? ? gcAndFinalize()方法主要就是在预加载动作之后、后续从zygote fork其他进程的动作之前,进行的一次垃圾回收。这里需要补充看一下上面这个代码段中的Zygote.initNativeState()方法:

// pie\frameworks\base\core\java\com\android\internal\os\Zygote.java
    static void initNativeState(boolean isPrimary) {
        nativeInitNativeState(isPrimary);
    }

// pie\frameworks\base\core\jni\com_android_internal_os_Zygote.cpp
static void com_android_internal_os_Zygote_nativeInitNativeState(JNIEnv* env, jclass, jboolean is_primary) {
  gZygoteSocketFD = android_get_control_socket(is_primary ? "zygote" : "zygote_secondary");    //获取socket的句柄fd
  if (gZygoteSocketFD >= 0) {
    ALOGV("Zygote:zygoteSocketFD = %d", gZygoteSocketFD);
  } else {
    ALOGE("Unable to fetch Zygote socket file descriptor");
  }
  gUsapPoolSocketFD = android_get_control_socket(is_primary ? "usap_pool_primary" : "usap_pool_secondary");
  if (gUsapPoolSocketFD >= 0) {
    ALOGV("Zygote:usapPoolSocketFD = %d", gUsapPoolSocketFD);
  } else {
    ALOGE("Unable to fetch USAP pool socket file descriptor");
  }
  //创建套接字,该套接字将被用来发送未经请求的消息到system_server,该套接字将在派生子进程后被关闭
  initUnsolSocketToSystemServer();    

  gIsSecurityEnforced = security_getenforce();    //根据selinux策略,普通apk是禁止security_getenforce的,
  selinux_android_seapp_context_init();           //所以在zygote fork之前初始化并缓存该策略值

  //Zygote进程在fork每个子进程之前首先卸载根存储空间,因为Zygote进程不使用根存储空间,所以取消对其下面的挂载名称空间的共享。
  //每个fork的子进程(包括SystemServer)只挂载它们自己的根存储空间,在MountEmulatedStorage方法中不需要卸载存储操作。
  UnmountStorageOnInit(env);

  if (!SetTaskProfiles(0, {})) {    //加载必须的performance profile信息
    zygote::ZygoteFailure(env, "zygote", nullptr, "Zygote SetTaskProfiles failed");
  }
}

? ? ? ? 该函数的功能概括来讲做了这四件事:

  • ????????从环境变量中获取socket句柄fd;
  • ????????初始化安全属性;
  • ????????卸载适当的存储;
  • ????????加载必要的性能概要信息;

? ? ? ? 还有需要说明一下的是代码里出现的USAP(Unspecialized App Process),是指在android高版本里提出来的一种zygote fork子进程的机制。通过prefork的方式提前创建好一批进程,当有应用启动时,直接将已经创建好的进程分配给它,从而省去了fork的动作,从而可以提升性能。详情参考《Android Framework | 一种新型的应用启动机制:USAP》

2.4、?forkSystemServer()

? ? ? ? 前面的三个小节做好准备工作后,下面就要开始做zygote比较重要的的一个任务了,那就是fork出system_server进程:

//pie\frameworks\base\core\java\com\android\internal\os\ZygoteInit.java
    public static void main(String[] argv) {
            …………
            zygoteServer = new ZygoteServer(isPrimaryZygote);    //创建zygote的ServerSocket
            if (startSystemServer) {
                Runnable r = forkSystemServer(abiList, zygoteSocketName, zygoteServer);
                if (r != null) {    //{r == null} in the parent process, and {r != null} in the child process
                    r.run();    //通过反射机制执行SystemServer.java的main()函数
                    return;
                }
            }
            …………
    }

? ? ? ? 这里先是通过ZygoteServer类的构造函数,去创建zygote的LocalServerSocket:

//pie\frameworks\base\core\java\com\android\internal\os\ZygoteServer.java
ZygoteServer(boolean isPrimaryZygote) {
        mUsapPoolEventFD = Zygote.getUsapPoolEventFD();

        if (isPrimaryZygote) {
            mZygoteSocket = Zygote.createManagedSocketFromInitSocket(Zygote.PRIMARY_SOCKET_NAME);
            mUsapPoolSocket = Zygote.createManagedSocketFromInitSocket(Zygote.USAP_POOL_PRIMARY_SOCKET_NAME);
        } else {
            mZygoteSocket =Zygote.createManagedSocketFromInitSocket(Zygote.SECONDARY_SOCKET_NAME);
            mUsapPoolSocket = Zygote.createManagedSocketFromInitSocket(Zygote.USAP_POOL_SECONDARY_SOCKET_NAME);
        }
        mUsapPoolSupported = true;
        fetchUsapPoolPolicyProps();    //TODO
    }

// pie\frameworks\base\core\java\com\android\internal\os\Zygote.java
    static LocalServerSocket createManagedSocketFromInitSocket(String socketName) {
        int fileDesc;
        final String fullSocketName = ANDROID_SOCKET_PREFIX + socketName;    // "ANDROID_SOCKET_zygote"

        try {
            String env = System.getenv(fullSocketName);
            fileDesc = Integer.parseInt(env);
        } catch (RuntimeException ex) {
            throw new RuntimeException("Socket unset or invalid: " + fullSocketName, ex);
        }

        try {
            FileDescriptor fd = new FileDescriptor();
            fd.setInt$(fileDesc);
            return new LocalServerSocket(fd);
        } catch (IOException ex) {
            throw new RuntimeException(
                "Error building socket from file descriptor: " + fileDesc, ex);
        }
    }

????????可以看出createManagedSocketFromInitSocket()函数首先是根据socket默认前缀?"ANDROID_SOCKET_"和该socket名称"zygote",拼接成环境变量的key = "ANDROID_SOCKET_zygote" ,然后以该key值从环境变量中获取目标socket的文件描述符fd。(这个环境变量的键值在init阶段解析init.zygote.rc、读取并启动zygote这个service下面的socket(socket zygote stream 660 root system),在目标设备创建/dev/socket/zygote 这个文件时,就已经以"ANDROID_SOCKET_zygote"为键,创建该socket的文件描述符fd为值,存储到环境变量中了。)这里获取到目标socket的文件描述符后,就用其创建了LocalServerSocket。

????????以上这些准备好了之后,就要做forkSystemServer这个重要的动作了,鉴于该函数挺长,所以依然分割开来解析。

? ? ? ? 2.4.1、参数准备

// pie\frameworks\base\core\java\com\android\internal\os\ZygoteInit.java
private static Runnable forkSystemServer(String abiList, String socketName,
            ZygoteServer zygoteServer) {
        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_PTRACE,
                OsConstants.CAP_SYS_TIME,
                OsConstants.CAP_SYS_TTY_CONFIG,
                OsConstants.CAP_WAKE_ALARM,
                OsConstants.CAP_BLOCK_SUSPEND
        );
        StructCapUserHeader header = new StructCapUserHeader(OsConstants._LINUX_CAPABILITY_VERSION_3, 0);
        StructCapUserData[] data;
        try {
            data = Os.capget(header);
        } catch (ErrnoException ex) {
            throw new RuntimeException("Failed to capget()", ex);
        }
        capabilities &= ((long) data[0].effective) | (((long) data[1].effective) << 32);

        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,3011",
                "--capabilities=" + capabilities + "," + capabilities,
                "--nice-name=system_server",
                "--runtime-args",
                "--target-sdk-version=" + VMRuntime.SDK_VERSION_CUR_DEVELOPMENT,
                "com.android.server.SystemServer",
        };
        …………
}

? ? ? ? 这里主要做的工作就是为后面fork出system_server进程准备启动参数。首先是通过posixCapabilitiesAsBits()函数配置一个long类型的(POSIX?capability)能力参数(说人话就是配置system_server进程可以拥有的能力或权限,即能做哪些事),然后和其他命令行参数一起组成启动system_server所需要传入的字符串数组类型的参数args。

? ? ? ? 其中的OsConstants类位于pie\libcore\luni\src\main\java\android\system\OsConstants.java中,这个类把CAP_KILL这些静态常量都设置为0,源码注释:A hack to avoid these constants being inlined by javac......because we want to initialize them at runtime.大概意思就是说,这样做是不想在静态编译(javac)的时候这些常量被内联进去,而是想借用native方法在运行时去初始化。具体操作就是在该Java类的静态块里面调用了一个native接口,该native接口在运行时才会通过GetStaticFieldID()和SetStaticIntField()函数去给这些静态常量设置具体的值。该native方法位于pie\libcore\luni\src\main\native\android_system_OsConstants.cpp中,而这些值的具体定义是在<linux/capability.h>中,而这个文件位于pie\bionic\libc\kernel\uapi\linux\capability.h。这些原文件中对每个数值定义都有详细的说明注释,有兴趣可以看看这些注释。看明白这些数值的的定义范围,返回来就看得懂函数posixCapabilitiesAsBits()通过传入的不定参数,对system_server进程能力(Capabilities)的配置过程了:

/**
*kitkak\frameworks\base\core\java\com\android\internal\os\ZygoteInit.java
* Gets the bit array representation of the provided list of POSIX capabilities.
*/
private static long posixCapabilitiesAsBits(int... capabilities) {
    long result = 0;
    for (int capability : capabilities) {
        if ((capability < 0) || (capability > OsConstants.CAP_LAST_CAP)) {
            throw new IllegalArgumentException(String.valueOf(capability));
        }
        result |= (1L << capability);
    }
    return result;
}

????????其无非就是通过位操作,将目标long类型整数的二进制形式中,能力(Capabilities)使能所代表的位置为1而已。比如不定参数的第一个常量CAP_KILL的数值为5,则代码将long类型的1有符号左移五位,其他不同的数值也是类似左移不同的位数,最终通过 |= 操作整合出目标数值。

? ? ? ? 2.4.2、参数解析与标识置位

// pie\frameworks\base\core\java\com\android\internal\os\ZygoteInit.java
private static Runnable forkSystemServer(String abiList, String socketName,
            ZygoteServer zygoteServer) {
        …………
        ZygoteArguments parsedArgs;
        int pid;
        try {
            //将args存储到zygote命令缓冲区中,这个ZygoteCommandBuffer是一个用于Zygote命令的本机可访问的缓冲区。
            //设计支持重复fork的应用程序,而不干预内存分配,从而保持zygote内存尽可能稳定
            ZygoteCommandBuffer commandBuffer = new ZygoteCommandBuffer(args);
            try {   //单例模式解析参数
                parsedArgs = ZygoteArguments.getInstance(commandBuffer);
            } catch (EOFException e) {
                throw new AssertionError("Unexpected argument error for forking system server", e);
            }
            commandBuffer.close();    //及时释放本地资源,避免命令重复调用
            Zygote.applyDebuggerSystemProperty(parsedArgs);
            Zygote.applyInvokeWithSystemProperty(parsedArgs); //--invoke-with=?

            if (Zygote.nativeSupportsMemoryTagging()) {
                /* The system server has ASYNC MTE by default, in order to allow system services to specify 
                 * their own MTE level later, as you can't re-enable MTE once it's disabled. */
                String mode = SystemProperties.get("arm64.memtag.process.system_server", "async");
                if (mode.equals("async")) {
                    parsedArgs.mRuntimeFlags |= Zygote.MEMORY_TAG_LEVEL_ASYNC;
                } else if (mode.equals("sync")) {
                    parsedArgs.mRuntimeFlags |= Zygote.MEMORY_TAG_LEVEL_SYNC;
                } else if (!mode.equals("off")) {
                    // When we have an invalid memory tag level, keep the current level.
                    parsedArgs.mRuntimeFlags |= Zygote.nativeCurrentTaggingLevel();
                    Slog.e(TAG, "Unknown memory tag level for the system server: \"" + mode + "\"");
                }
            } else if (Zygote.nativeSupportsTaggedPointers()) {
                //Enable pointer tagging in the system server. Hardware support for this is present in all ARMv8 CPUs
                parsedArgs.mRuntimeFlags |= Zygote.MEMORY_TAG_LEVEL_TBI;
            }
            /* Enable gwp-asan on the system server with a small probability. This is the same
             * policy as applied to native processes and system apps. */
            parsedArgs.mRuntimeFlags |= Zygote.GWP_ASAN_LEVEL_LOTTERY;

            if (shouldProfileSystemServer()) {
                parsedArgs.mRuntimeFlags |= Zygote.PROFILE_SYSTEM_SERVER;
            }
        …………   
}

????????这里主要是先将2.4.1部分准备的参数args存储到ZygoteCommandBuffer这个命令缓冲区中,然后通过ZygoteArguments.getInstance()接口,获取单例模式的ZygoteArguments类的实例。之后ZygoteArguments类的构造函数调用parseArgs()函数对这些zygote命令参数进行解析,最后根据一些配置对参数解析出来的结果对象parsedArgs的mRuntimeFlags成员进行标识位置位。

? ? ? ?获取单例模式的ZygoteArguments的实例时,在构造函数中调用parseArgs()去解析参数的过程:

//pie\frameworks\base\core\java\com\android\internal\os\ZygoteArguments.java
    private ZygoteArguments(ZygoteCommandBuffer args, int argCount)
            throws IllegalArgumentException, EOFException {
        parseArgs(args, argCount);
    }

    public static ZygoteArguments getInstance(ZygoteCommandBuffer args)
            throws IllegalArgumentException, EOFException {
        int argCount = args.getCount();
        return argCount == 0 ? null : new ZygoteArguments(args, argCount);
    }

? ? ? ? 2.4.3、真正的fork动作

// pie\frameworks\base\core\java\com\android\internal\os\ZygoteInit.java
    private static Runnable forkSystemServer(String abiList, String socketName,
            ZygoteServer zygoteServer) {
        …………
        int pid;
        try {
            …………
            pid = Zygote.forkSystemServer(
                    parsedArgs.mUid, parsedArgs.mGid,
                    parsedArgs.mGids,
                    parsedArgs.mRuntimeFlags,
                    null,
                    parsedArgs.mPermittedCapabilities,
                    parsedArgs.mEffectiveCapabilities);
        } catch (IllegalArgumentException ex) {
            throw new RuntimeException(ex);
        }
        …………
    }

? ? ? ? ?这里直接去找Zygote.forkSystemServer()方法:

//pie\frameworks\base\core\java\com\android\internal\os\Zygote.java
    static int forkSystemServer(int uid, int gid, int[] gids, int runtimeFlags,
            int[][] rlimits, long permittedCapabilities, long effectiveCapabilities) {
        ZygoteHooks.preFork();    //停掉守护线程,停掉当前进程的所有的线程,zygote每次fork前调用

        int pid = nativeForkSystemServer(
                uid, gid, gids, runtimeFlags, rlimits,
                permittedCapabilities, effectiveCapabilities);

        Thread.currentThread().setPriority(Thread.NORM_PRIORITY);    //设置当前线程优先级
        
        //每次调用preFork()后,都会在子进程上调用postForkChild(),
        //并且都会在父进程和子进程上调用postForkCommon(),
        //子进程调用postForkCommon()在postForkCommon()之后
        ZygoteHooks.postForkCommon();
        return pid;
    }

? ? ? ? 这里做了fork前的准备后,主要就是通过jni去调用了nativeForkSystemServer()函数:

//pie\frameworks\base\core\jni\com_android_internal_os_Zygote.cpp
static jint com_android_internal_os_Zygote_nativeForkSystemServer(
        JNIEnv* env, jclass, uid_t uid, gid_t gid, jintArray gids,
        jint runtime_flags, jobjectArray rlimits, jlong permitted_capabilities,
        jlong effective_capabilities) {
  //初始化USAP相关的一个vector
  std::vector<int> fds_to_close(MakeUsapPipeReadFDVector()), fds_to_ignore(fds_to_close);
  fds_to_close.push_back(gUsapPoolSocketFD);

  if (gUsapPoolEventFD != -1) {
    fds_to_close.push_back(gUsapPoolEventFD);
    fds_to_ignore.push_back(gUsapPoolEventFD);
  }

  if (gSystemServerSocketFd != -1) {
      fds_to_close.push_back(gSystemServerSocketFd);
      fds_to_ignore.push_back(gSystemServerSocketFd);
  }

  pid_t pid = zygote::ForkCommon(env, true, fds_to_close, fds_to_ignore, true);    //fork动作
  if (pid == 0) {
      /在子进程中进行一些system_server相关配置,有兴趣的话去详细看看
      SpecializeCommon(env, uid, gid, gids, runtime_flags, rlimits,
                       permitted_capabilities, effective_capabilities,
                       MOUNT_EXTERNAL_DEFAULT, nullptr, nullptr, true, false, 
                       nullptr, nullptr, false, nullptr, false, false);
  } else if (pid > 0) {
      ALOGI("System server process %d has been created", pid);
      gSystemServerPid = pid;
      int status;
      //在父进程zygote中使用waitpid()函数以及WNOHANG这个选项,监控子进程的结束情况,
      //监控到system_server进程结束时,需要重启zygote。
      //waitpid()函数参考https://www.cnblogs.com/zhaihongliangblogger/p/6367041.html
      if (waitpid(pid, &status, WNOHANG) == pid) {
          ALOGE("System server process %d has died. Restarting Zygote!", pid);
          RuntimeAbort(env, __LINE__, "System server process has died. Restarting Zygote!");
      }

      if (UsePerAppMemcg()) {    //检测是否挂载了memcg
          if (!SetTaskProfiles(pid, std::vector<std::string>{"SystemMemoryProcess"})) {
              ALOGE("couldn't add process %d into system memcg group", pid);
          }
      }
  }
  return pid;
}

????????这里重点就是通过ForkCommon()函数fork子进程,然后通过SpecializeCommon()函数对子进程做一些配置。这里主要来看一下ForkCommon()函数的fork过程:

// pie\frameworks\base\jni\com_android_internal_os_Zygote.cpp
pid_t zygote::ForkCommon(JNIEnv* env, bool is_system_server,
                         const std::vector<int>& fds_to_close,
                         const std::vector<int>& fds_to_ignore,
                         bool is_priority_fork,
                         bool purge) {
  SetSignalHandlers();    //为zygote管理子进程配置信号SIGCHLD/SIGHUP
  //指定ZygoteFailure函数,其用来向runtime报告致命错误
  auto fail_fn = std::bind(zygote::ZygoteFailure, env, is_system_server ? "system_server" : "zygote", nullptr, _1);

  //在fork期间临时阻塞SIGCHLD。SIGCHLD处理程序可能会记录日志,
  BlockSignal(SIGCHLD, fail_fn); //这将导致我们关闭的日志fd被重新打开。会导致失败,因为不允许列出fd
  __android_log_close();         //在开始计算文件描述符列表之前,关闭所有与日志记录相关的fd
  AStatsSocket_close();

  if (gOpenFdTable == nullptr) { //如果这是zygote的第一次fork,则创建一个打开的FD表,验证文件受支持的类型和允许列表
    gOpenFdTable = FileDescriptorTable::Create(fds_to_ignore, fail_fn);
  } else {    //如果不是,则检查打开的文件是否没有更改,不希望并且未来会禁止打开新的文件。
    gOpenFdTable->Restat(fds_to_ignore, fail_fn);    //目前的做法是,如果通过了上面的Create检测,则允许打开新的文件
  }
  android_fdsan_error_level fdsan_error_level = android_fdsan_get_error_level();

  if (purge) {           //清除未使用的本机内存,以减少与子进程的错误共享。通过减少与子进程共享的libc_malloc区域的大小,  
    mallopt(M_PURGE, 0); //当malloc在fork之后调整它所管理的每个页面上的元数据时,可以减少转换到私有脏状态的页面数量
  }

  pid_t pid = fork();    //核心的fork动作
  if (pid == 0) {        //子进程
    if (is_priority_fork) {
      setpriority(PRIO_PROCESS, 0, PROCESS_PRIORITY_MAX);
    } else {
      setpriority(PRIO_PROCESS, 0, PROCESS_PRIORITY_MIN);
    }

    PreApplicationInit();
    DetachDescriptors(env, fds_to_close, fail_fn);    //通过dup3()函数清除那些需要立即关闭的文件描述符
    ClearUsapTable();                                 //清除USAP进程表
    gOpenFdTable->ReopenOrDetach(fail_fn);            //重新打开所有剩余的打开的文件描述符,这样它们就不会通过fork与zygote共享
    android_fdsan_set_error_level(fdsan_error_level);
    gSystemServerSocketFd = -1;
  } else {               //父进程
    ALOGD("Forked child process %d", pid);
  }

  UnblockSignal(SIGCHLD, fail_fn);                    //fork结束后打开阻塞,对应上面的BlockSignal()
  return pid;
}

? ? ? ? ?2.4.4、fork后的扫尾工作

// pie\frameworks\base\core\java\com\android\internal\os\ZygoteInit.java
    private static Runnable forkSystemServer(String abiList, String socketName,
            ZygoteServer zygoteServer) {
        …………
        //由于fork()函数完成任务后返回的位置不确定,如果在子进程中,fork函数返回0;
        //如果在父进程中,fork返回新创建子进程的进程ID
        if (pid == 0) {    
            if (hasSecondZygote(abiList)) {            //通过比较设备ABI列表和受精卵列表来确定这一点,
                waitForSecondaryZygote(socketName);    //如果这个受精卵支持该设备支持的所有abi,就不会有另一个受精卵
            }

            zygoteServer.closeServerSocket();    //fork出来的子进程中不会用到zygoteServer这个socket,所以要关掉
            return handleSystemServerProcess(parsedArgs);    //做一些fork system_server的扫尾工作
        }

        return null;
    }

? ? ? ? ?在上一小节的native fork动作结束返回后,这里需要通过handleSystemServerProcess()方法来做一些system_server进程的收尾动作:

// pie\frameworks\base\core\java\com\android\internal\os\ZygoteInit.java
private static Runnable handleSystemServerProcess(ZygoteArguments parsedArgs) {
        Os.umask(S_IRWXG | S_IRWXO);    //进程权限设置为0077,这样新文件和目录将默认为所有者权限
        if (parsedArgs.mNiceName != null) {    //参数准备部分的"--nice-name=system_server"
            Process.setArgV0(parsedArgs.mNiceName);    //进程名设置为system_server
        }
        //环境变量SYSTEMSERVERCLASSPATH=/system/framework/services.jar:
        //                        /system/framework/ethernet-service.jar:
        //                        /system/framework/wifi-service.jar:…………
        final String systemServerClasspath = Os.getenv("SYSTEMSERVERCLASSPATH");
        if (systemServerClasspath != null) {
            if (shouldProfileSystemServer() && (Build.IS_USERDEBUG || Build.IS_ENG)) {
                try {
                    Log.d(TAG, "Preparing system server profile");
                    prepareSystemServerProfile(systemServerClasspath);    //debug或eng模式下准备system_server的profile文件
                } catch (Exception e) {
                    Log.wtf(TAG, "Failed to set up system server profile", e);
                }
            }
        }

        if (parsedArgs.mInvokeWith != null) {    //TODO
            String[] args = parsedArgs.mRemainingArgs;
            if (systemServerClasspath != null) {
                String[] amendedArgs = new String[args.length + 2];
                amendedArgs[0] = "-cp";
                amendedArgs[1] = systemServerClasspath;
                System.arraycopy(args, 0, amendedArgs, 2, args.length);
                args = amendedArgs;
            }

            WrapperInit.execApplication(parsedArgs.mInvokeWith, parsedArgs.mNiceName, parsedArgs.mTargetSdkVersion,
                                        VMRuntime.getCurrentInstructionSet(), null, args);
            throw new IllegalStateException("Unexpected return from WrapperInit.execApplication");
        } else {    //一般system_server走这个分支
            ClassLoader cl = getOrCreateSystemServerClassLoader(); //为system_server创建类加载器
            if (cl != null) {
                Thread.currentThread().setContextClassLoader(cl);  //为当前线程设置上下文类加载器
            }
            return ZygoteInit.zygoteInit(parsedArgs.mTargetSdkVersion, parsedArgs.mDisabledCompatChanges,
                                         parsedArgs.mRemainingArgs, cl);
        }
    }

????????继续追踪ZygoteInit.zygoteInit() 方法:

// pie\frameworks\base\core\java\com\android\internal\os\ZygoteInit.java
    public static Runnable zygoteInit(int targetSdkVersion, long[] disabledCompatChanges,
            String[] argv, ClassLoader classLoader) {
        if (RuntimeInit.DEBUG) {
            Slog.d(RuntimeInit.TAG, "RuntimeInit: Starting application from zygote");
        }

        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ZygoteInit");
        RuntimeInit.redirectLogStreams();    //将java的system.out和system.err log输出流重定向到AndroidPrintStream
        RuntimeInit.commonInit(); //设置log配置、通过persist.sys.timezone的属性值设置时区、设置默认的HTTP User-agent格式到http.agent属性    
        //通过JNI调用AndroidRuntime的成员gCurRuntime(即app_process.cpp中)的onZygoteInit()函数,
        ZygoteInit.nativeZygoteInit();     //主要完成创建binder的工作
        return RuntimeInit.applicationInit(targetSdkVersion, disabledCompatChanges, argv, classLoader);
    }

? ? ? ? 追踪RuntimeInit.applicationInit()方法:

// pie\frameworks\base\core\java\com\android\internal\os\RuntimeInit.java
    protected static Runnable applicationInit(int targetSdkVersion, long[] disabledCompatChanges, String[] argv, ClassLoader classLoader) {
        …………
        //从前面准备的参数中解析出"com.android.server.SystemServer"赋值给args.startClass
        final Arguments args = new Arguments(argv);
        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);    //对应上面ZygoteInit的traceBegin()
        //有了类的全限定名,通过反射机制找到SystemServer.java的main()方法
        return findStaticMain(args.startClass, args.startArgs, classLoader);
    }


    protected static Runnable findStaticMain(String className, String[] argv, ClassLoader classLoader) {
        …………    //省略通过反射机制寻找main方法的过程
        return new MethodAndArgsCaller(m, argv);
    }

    //将main方法封装到Runnable实例中返回,最终返回给2.4节一开始的Runnable r,然后通过r.run()执行该main方法
    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() {
            try {
                mMethod.invoke(null, new Object[] { mArgs });
            } catch (IllegalAccessException ex) {
              …………
            }
        }
    }

? ? ? ? 总结一下2.4.4小节主要做了:

  1. ????????对fork出来的新进程的权限设定;
  2. ????????进程命名为system_server;
  3. ????????创建类加载器加载system_server的java类;
  4. ? ? ? ? 通过反射机制找到SystemServer.java的main函数,并封装到Runnable r;
  5. ? ? ? ? 方法return到2.4节一开始,通过r.run()执行该main方法,以启动SystsmServer;

2.5、runSelectLoop()

? ? ? ? zygote除了fork出system_server进程这个任务外,还有一个重要的任务,那就是接收AMS(ActivityManagerService)发来创建java层应用程序的请求,fork出一个个进程,并在新进程中执行该请求中相关应用程序的main方法。上层的一个个应用程序就是这样通过zygote创建而来,因为应用程序都是由zygote孕育而来,所以就不难理解zygote(受精卵)的名称的由来了。我们继续往下看看它是如何完成这一任务的:

// pie\frameworks\base\core\java\com\android\internal\os\ZygoteInit.java
    public static void main(String[] argv) {
        …………
        Runnable caller;
        try {
            …………
            Log.i(TAG, "Accepting command socket connections");
            caller = zygoteServer.runSelectLoop(abiList);
        } catch (Throwable ex) {
            Log.e(TAG, "System zygote died with fatal exception", ex);
            throw ex;
        } finally {
            if (zygoteServer != null) {
                zygoteServer.closeServerSocket();    //zygote挂掉的时候关闭ServerSocket
            }
        }

        if (caller != null) {
            caller.run();
        }
    }

????????runSelectLoop()方法冗长,有太多USAP相关的操作,我们这里省略相关内容,只看核心操作:

// pie\frameworks\base\core\java\com\android\internal\os\ZygoteServer.java
Runnable runSelectLoop(String abiList) {
        ArrayList<FileDescriptor> socketFDs = new ArrayList<>();
        ArrayList<ZygoteConnection> peers = new ArrayList<>();
        socketFDs.add(mZygoteSocket.getFileDescriptor());    //先将server socket加入到这个socketFDs列表
        peers.add(null);

        while (true) {    //间隔时间持续轮询
            …………
            int[] usapPipeFDs = null;
            StructPollfd[] pollFDs;
            pollFDs = new StructPollfd[socketFDs.size()];    //每轮循环,都重新创建需要监听的pollFDs
            int pollIndex = 0;
            for (FileDescriptor socketFD : socketFDs) {
                pollFDs[pollIndex] = new StructPollfd();
                pollFDs[pollIndex].fd = socketFD;
                pollFDs[pollIndex].events = (short) POLLIN;    //关注poll事件到来
                ++pollIndex;
            }
            …………
            int pollTimeoutMs;//设置poll轮询时延间隔 
            int pollReturnValue;
            try {
                pollReturnValue = Os.poll(pollFDs, pollTimeoutMs);
            …………

            if (pollReturnValue == 0) {    …………
            } else {
                while (--pollIndex >= 0) {
                    if ((pollFDs[pollIndex].revents & POLLIN) == 0) {
                        continue;
                    }

                    if (pollIndex == 0) {    //server socket最先加入fds, 因此这里是server socket收到数据
                        ZygoteConnection newPeer = acceptCommandPeer(abiList);    //收到新的建立通信的请求,建立通信连接
                        peers.add(newPeer);  //加入到peers和fds, 即下一次也开始监听
                        socketFDs.add(newPeer.getFileDescriptor());
                    } else if (pollIndex < usapPoolEventFDIndex) {    //说明接收到AMS通过socket发送过来创建应用程序的请求
                        try {
                            //有socket连接时创建ZygoteConnection对象,并添加到pollFDs
                            ZygoteConnection connection = peers.get(pollIndex);
                            boolean multipleForksOK = !isUsapPoolEnabled()
                                    && ZygoteHooks.isIndefiniteThreadSuspensionSafe();
                            final Runnable command =
                                    connection.processCommand(this, multipleForksOK);    //完成创建子进程的请求
                            if (mIsForkChild) {
                                if (command == null) {
                                    throw new IllegalStateException("command == null");
                                }
                                return command;    //依然是提供Runnable接口,通过反射机制执行目标应用程序的main方法
                            } else {
                                if (command != null) {
                                    throw new IllegalStateException("command != null");
                                }
                                //处理完后,关闭socket连接,并从peers和socketFDs列表中移除
                                if (connection.isClosedByPeer()) {    
                                    connection.closeSocket();
                                    peers.remove(pollIndex);
                                    socketFDs.remove(pollIndex);
                                }
                            }
                        } catch (Exception e) {
                            …………
    }

? ? ? ? 这里大概意思就是,循环间隔一段时间轮询连接socket消息,看是否有AMS客户端发过来创建应用程序的请求,有的话则通过pie\frameworks\base\core\java\com\android\internal\os\ZygoteConnection.processCommand()方法创建进程并启动目标应用程序。我们只需要直到这里是接收AMS创建应用程序的请求,完成目标应用程序创建与启动的就好。详细细节我后面学习到AMS之后,单独写一篇文章来追踪AMS与zygote之间通过socket通信,创建应用程序的过程吧。

3、结语

? ? ? ? 总结来说,zygote在开机过程中,其先是启动虚拟机、注册JNI函数、进入java世界,然后fork出system_server进程,之后作为守护进程监听并处理创建普通应用程序的工作。调用流程图原图请见:| ProcessOn

  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2021-10-27 12:56:47  更:2021-10-27 12:57:31 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 1:03:24-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码