继上一篇介绍语法后,接下来详细看看init进程解析init.rc后启动的一些关键的系统服务进程,其中最重要的有ServiceManager、Zygote和SystemServer。
一、Android的“DNS服务器”--------ServiceManager
ServiceManager是Binder机制中的“DNS服务器”,负责域名(某Binder服务在ServiceManager注册时提供的名称) 到IP地址(有底层Binder驱动分配的值)的解析。
在高通8155 LA.1.1 中 ServiceManager是在init.rc里由init进程启动。如下:
on init #init事件.......略 # Start logd before any other services run to ensure we capture all of their logs. # 在任何其他服务运行之前启动 logd 以确保我们捕获它们的所有日志。 start logd # 这个命令将启动一个服务 logd ,如果它没有处于运行状态的话 # Start essential services. # 启动基本服务。 start servicemanager # 这个命令将启动一个服务 servicemanager ,如果它没有处于运行状态的话 start hwservicemanager # 这个命令将启动一个服务 hwservicemanager ,如果它没有处于运行状态的话 start vndservicemanager # 这个命令将启动一个服务 vndservicemanager ,如果它没有处于运行状态的话 ......略
有servicemanager文件可看出,servicemanager是一个 Linux程序的执行文件。它在设备中的存储路径是“/system/bin/servicemanager”(需要进入root才能查询到,如下图),源码路径则是“frameworks/native/cmds/servicemanager”。
servicemanager的启动描述则在servicemanager.rc文件里,.rc文件位于“frameworks/native/cmds/servicemanager/servicemanager.rc”。高通8155的LA.1.1基线代码对于servicemanager的描述和启动的位置分在两个不同的.rc文件。servicemanager.rc具体启动描述内容如下:
service servicemanager /system/bin/servicemanager class core animation #所属类是 core 和 animation user system #在启动服务前将用户切换至 system ,默认是root group system readproc #在启动服务前将用户组切换至 system 和 readproc critical #表明这是对设备至关重要的一个服务,如果4分钟内退出超过4次,则设备将重启进入恢复模式 onrestart restart healthd #当servicemanager重启时,重启 healthd 进程 onrestart restart zygote #当servicemanager重启时,重启 zygote 进程 onrestart restart audioserver #当servicemanager重启时,重启 audioserver 进程 onrestart restart media #当servicemanager重启时,重启 media 进程 onrestart restart surfaceflinger #当servicemanager重启时,重启 surfaceflinger 进程 onrestart restart inputflinger #当servicemanager重启时,重启 inputflinger 进程 onrestart restart drm #当servicemanager重启时,重启 drm 进程 onrestart restart cameraserver #当servicemanager重启时,重启 cameraserver 进程 onrestart restart keystore #当servicemanager重启时,重启 keystore 进程 onrestart restart gatekeeperd #当servicemanager重启时,重启 gatekeeperd 进程 onrestart restart thermalservice #当servicemanager重启时,重启 thermalservice 进程 writepid /dev/cpuset/system-background/tasks # 当fork一个子进程时,写子进程的pid到一个给定的文件。是给cgroup/cpuset使用 #设置服务进程的关闭行为。如果未指定此选项,则在关闭过程中通过使用SIGTERM和SIGKILL终止服务。 #shutdown_behavior为"critical"时,服务在关闭期间不会被杀死,直到关闭超时为止。 #当服务进程关闭超时时,即使标记为"shutdown critical"的服务也将被杀死。 #当shutdown行为启动时,标有"shutdown critical"的服务未运行时,它将启动。 shutdown critical #服务在关闭期间不会被杀死,直到关闭超时为止
由servicemanager.rc可看出,servicemanager所属class是core,其它同类的系统进程包括ueventd、console(/system/bin/sh)、adbd等。根据core组的特性,这些进程会同时被启动或停止。另外,critical选项说明它是系统的关键进程,意味着如果进程不幸在4分钟异常退出4次,则设备将重启进入还原模式。每当servicemanager重启时,其它关键进程也会被重启,如:healthd、zygote、audioserver、media、surfaceflinger、inputflinger、drm、cameraserver、keystore、gatekeeperd、thermalservice等。
二、Zygote—“孕育”新的线程和进程
Zygote这个词的字面意思时“受精卵”,因而可以“孕育”出一个“新生命”。在Android中大多数应用进程和系统进程都是通过Zygote来生成的。下面具体分析Zygote时如何启动的。
同servicemanager类似,Zygote也是由init解析rc脚本时启动的。在早期的Android版本中Zygote的启动命令是直接被写在init.rc中。但随着硬件等的不断升级换代,Android系统不得不面对32位和64位机器同时存在的状况,因而,对Zygote的启动也需要根据不同的情况区分对待,在高通平台中,在init.rc中加载Zygote的脚本描述如下:
import /init.environ.rcimport /init.usb.rcimport /init.${ro.hardware}.rcimport /vendor/etc/init/hw/init.${ro.hardware}.rcimport /init.usb.configfs.rcimport /init.${ro.zygote}.rc
根据系统属性ro.zygote的具体值,init.rc中加载不同的描述zygote的rc脚本,zygote的描述脚本包含“init.zygote32_64.rc”、“init.zygote32.rc”、“init.zygote64_32.rc”、“init.zygote64.rc”,具体文件如下:(目录:system/core/rootdir)
其中zygote32和zygote64分别对应32位和64位机器的情况,而zygote32_64和zygote64_32,则是Primary Arch和Secondary Arch的组合。
组合介绍如下:
路径:device/qcom/msmnile_au/BoardConfig.mk
BoardConfig.mk用于指定目标平台相关的不少属性,咱们能够在这个脚本中同时指定Primary和Secondary的CPU Arch和ABI:
与Primary Arch相关的变量有TARGET_ARCH、TARGET_ARCH_VARIANT、TARGET_CPU_VARIANT等,具体范例以下:
TARGET_ARCH := arm64TARGET_ARCH_VARIANT := armv8-aTARGET_CPU_ABI := arm64-v8aTARGET_CPU_ABI2 :=TARGET_CPU_VARIANT := generic
与Secondary Arch相关的变量有TARGET_2ND_ARCH、TARGET_2ND_ARCH_VARIANT、TARGET_2ND_CPU_VARIANT等,具体范例以下:
TARGET_2ND_ARCH := armTARGET_2ND_ARCH_VARIANT := armv7-a-neonTARGET_2ND_CPU_ABI := armeabi-v7aTARGET_2ND_CPU_ABI2 := armeabiTARGET_2ND_CPU_VARIANT := cortex-a9
所以,由BoardConfig.mk可知,高通8155的LA.1.1基线中的“init.rc“-》“import /init.${ro.zygote}.rc“-》ro.zygote的值为“zygote64_32”,即Primary Arch为64,Secondary Arch为32。接下来详细看zygote64_32的内容,如下:
service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server --socket-name=zygote class main #所属类是 main priority -20 #设置服务进程的优先级.优先级取值范围为-20~19,默认是0.可以通过setpriority()设置 user root #在启动服务前将用户切换至 root ,默认是 root group root readproc reserved_disk #在启动服务前将用户组切换至 root 和 readproc 和 reserved_disk socket zygote stream 660 root system #创建一个名为 /dev/socket/zygote 的unix domian socket ,然后将它的fd值传给启动它的进程,有效的值为 stream (dgram,stream,seqpacket),权限 660 用户 root ,用户组 system socket usap_pool_primary stream 660 root system #创建一个名为 /dev/socket/usap_pool_primary 的unix domian socket ,然后将它的fd值传给启动它的进程,有效的值为 stream (dgram,stream,seqpacket),权限 660 用户 root ,用户组 system onrestart write /sys/android_power/request_state wake #当 zygote 重启时,写 wake 到 /sys/android_power/request_state onrestart write /sys/power/state on #当 zygote 重启时,写 on 到 /sys/power/state onrestart restart audioserver #当 zygote 重启时,重启 audioserver 进程 onrestart restart cameraserver #当 zygote 重启时,重启 cameraserver 进程 onrestart restart media #当 zygote 重启时,重启 media 进程 onrestart restart netd #当 zygote 重启时,重启 netd 进程 onrestart restart wificond #当 zygote 重启时,重启 wificond 进程 writepid /dev/cpuset/foreground/tasks # 当fork一个子进程时,写子进程的pid到一个给定的文件。是给cgroup/cpuset使用service zygote_secondary /system/bin/app_process32 -Xzygote /system/bin --zygote --socket-name=zygote_secondary --enable-lazy-preload class main #所属类是 main priority -20 #设置服务进程的优先级.优先级取值范围为-20~19,默认是0.可以通过setpriority()设置 user root #在启动服务前将用户切换至 root ,默认是 root group root readproc reserved_disk #在启动服务前将用户组切换至 root 和 readproc 和 reserved_disk socket zygote_secondary stream 660 root system #创建一个名为 /dev/socket/zygote_secondary 的unix domian socket ,然后将它的fd值传给启动它的进程,有效的值为 stream (dgram,stream,seqpacket),权限 660 用户 root ,用户组 system socket usap_pool_secondary stream 660 root system #创建一个名为 /dev/socket/usap_pool_secondary 的unix domian socket ,然后将它的fd值传给启动它的进程,有效的值为 stream (dgram,stream,seqpacket),权限 660 用户 root ,用户组 system onrestart restart zygote #当 zygote_secondary 重启时,重启 zygote 进程 writepid /dev/cpuset/foreground/tasks # 当fork一个子进程时,写子进程的pid到一个给定的文件。是给cgroup/cpuset使用
从上面这段脚本描述可以看出:
存在两个服务 zygote 和 zygote_secondary;
zygote的path:/system/bin/app_process64
zygote_secondary的path:/system/bin/app_process32
zygote的Arguments:-Xzygote /system/bin --zygote --start-system-server --socket-name=zygote
zygote_secondary的Arguments:-Xzygote /system/bin --zygote --socket-name=zygote_secondary --enable-lazy-preload
zygote和zygote_secondary所属class都为main,而不是core。同class的系统进程有netd、debuggerd、rild等。从两者的路径可以看出,它们所在的程序名分别叫“ app_process64” 和 “ app_process32”,而不像ServiceManager一样在一个独立的程序中。通过指定–zygote 参数,app_process可以识别出用户是否需要启动zygote。那么app_process又是什么东东呢?app_process的源码路径在:frameworks/base/cmds/app_process中,先看看其Android.mk的内容,如下:
LOCAL_PATH:= $(call my-dir)app_process_common_shared_libs := libandroid_runtime libbinder libcutils libdl libhidlbase liblog libnativeloader libutils # This is a list of libraries that need to be included in order to avoid# bad apps、This prevents a library from having a mismatch when resolving# new/delete from an app shared library.# See b/21032018 for more details.# 这是为了避免不良应用程序需要包含的库列表。 这可以防止库在从应用程序共享库中解析新/删除时出现不匹配。# 详情请参阅 b/21032018。app_process_common_shared_libs += libwilhelm app_process_common_static_libs := libsigchain app_process_src_files := app_main.cpp app_process_cflags := -Wall -Werror -Wunused -Wunreachable-codeapp_process_ldflags_32 := -Wl,--version-script,art/sigchainlib/version-script32.txt -Wl,--export-dynamicapp_process_ldflags_64 := -Wl,--version-script,art/sigchainlib/version-script64.txt -Wl,--export-dynamicinclude $(CLEAR_VARS)LOCAL_SRC_FILES:= $(app_process_src_files)LOCAL_LDFLAGS_32 := $(app_process_ldflags_32) #32位程序的ld标志LOCAL_LDFLAGS_64 := $(app_process_ldflags_64) #64位程序的ld标志LOCAL_SHARED_LIBRARIES := $(app_process_common_shared_libs) #共享库LOCAL_WHOLE_STATIC_LIBRARIES := $(app_process_common_static_libs) #静态库LOCAL_MODULE:= app_process #模块名称LOCAL_MULTILIB := both #用于针对的硬件平台架构,可选项:"both":同时 "32":针对32 "64":针对64 " ":由系统根据其它变量决定LOCAL_MODULE_STEM_32 := app_process32 #指定32位系统下的应用程序LOCAL_MODULE_STEM_64 := app_process64 #指定64位系统下的应用程序LOCAL_CFLAGS += $(app_process_cflags)# In SANITIZE_LITE mode, we create the sanitized binary in a separate location (but reuse# the same module)、Using the same module also works around an issue with make: binaries# that depend on sanitized libraries will be relinked, even if they set LOCAL_SANITIZE := never.## Also pull in the asanwrapper helper.# 在 SANITIZE_LITE 模式下,我们在单独的位置创建经过清理的二进制文件(但重用相同的模块)。 # 使用相同的模块也可以解决 make 的问题:依赖于已清理库的二进制文件将被重新链接,即使它们设置 LOCAL_SANITIZE := never。# 同时引入 asanwrapper 助手。ifeq ($(SANITIZE_LITE),true)LOCAL_MODULE_PATH := $(TARGET_OUT_EXECUTABLES)/asanLOCAL_REQUIRED_MODULES := asanwrapperendifinclude $(BUILD_EXECUTABLE)# Create a symlink from app_process to app_process32 or 64# depending on the target configuration.# 根据目标配置创建从 app_process 到 app_process32 或 64 的符号链接。ifneq ($(SANITIZE_LITE),true)include $(BUILD_SYSTEM)/executable_prefer_symlink.mkendif
从上面的描述可看到,app_process其实扮演的类似一个外壳,实际是去调用 app_process64 或app_process32程序。那么app_process具体内容有哪些呢?下面分析app_process.cpp中的main主函数的实现,内容如下:
int main(int argc, char* const argv[]){ if (!LOG_NDEBUG) { String8 argv_String; for (int i = 0; i < argc; ++i) { argv_String.append("""); argv_String.append(argv[i]); argv_String.append("" "); } ALOGV("app_process main with argv: %s", argv_String.string()); } //Android运行时环境 AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv)); // Process command line arguments 处理命令行参数 // ignore argv[0] 忽略 argv[0] argc--; argv++; // Everything up to '--' or first non '-' arg goes to the vm. // // The first argument after the VM args is the "parent dir", which // is currently unused. // // After the parent dir, we expect one or more the following internal // arguments : // // --zygote : Start in zygote mode // --start-system-server : Start the system server. // --application : Start in application (stand alone, non zygote) mode. // --nice-name : The nice name for this process. // // For non zygote starts, these arguments will be followed by // the main class name、All remaining arguments are passed to // the main method of this class. // // For zygote starts, all remaining arguments are passed to the zygote. // main function. // // Note that we must copy argument string values since we will rewrite the // entire argument block when we apply the nice name to argv0. // // As an exception to the above rule, anything in "spaced commands" // goes to the vm even though it has a space in it. // 直到 '--' 或第一个非 '-' arg 的所有内容都进入 vm。 // VM args 后面的第一个参数是“父目录”,目前未使用。 // 在父目录之后,我们期望一个或多个以下内部参数: // --zygote : 以 zygote 模式启动 // --start-system-server : 启动系统服务器。 // --application : 以应用程序(独立,非 zygote)模式启动。 // --nice-name : 这个进程的好名字。 // 对于非 zygote 启动,这些参数后跟主类名。所有剩余的参数都传递给这个类的 main 方法。 // 对于 zygote 启动,所有剩余的参数都传递给 zygote。 // 主功能。 // 请注意,我们必须复制参数字符串值,因为当我们将 nice 名称应用于 argv0 时,我们将重写整个参数块。 // 作为上述规则的一个例外,“间隔命令”中的任何内容都会进入 vm,即使其中有空格。 const char* spaced_commands[] = { "-cp", "-classpath" }; // Allow "spaced commands" to be succeeded by exactly 1 argument (regardless of -s). // 允许“间隔命令”通过恰好 1 个参数(不管 -s)。 bool known_command = false; int i; for (i = 0; i < argc; i++) { if (known_command == true) { //判断参数是否存在 runtime.addOption(strdup(argv[i])); //将参数传给runtime // The static analyzer gets upset that we don't ever free the above // string、Since the allocation is from main, leaking it doesn't seem // problematic、NOLINTNEXTLINE // 静态分析器对我们没有释放上面的字符串感到不安。 由于分配来自 main,因此泄漏它似乎没有问题。 NOLINTNEXTLINE ALOGV("app_process main add known option '%s'", argv[i]); known_command = false; continue; } for (int j = 0; j < static_cast
这个函数用于解析启动app_process时传入的参数,具体参数如下:
–zygote:表示当前进行用于承载zygote
–start-system-server:是否需要启动system server
–application:启动进入独立的程序模式
–nice-name:此进程的“别名”
对于非zygote的情况下,在上述参数的末尾会跟上main class的名称,而后的其它参数则属于这个class的主函数传入的参数;
对于zygote的情况,所有参数则会作为它的主函数传入参数使用;
在前面的 init.zegote64_32.rc中指定了 “–zygote“选项,因而app_process接下来将启动“com.android.internal.os.ZygoteInit ”,并传入“start-system-server”。之后ZygoteInit会运行于Java虚拟机上,那为什么呢?
原因就是runtime这个变量,它实际上是一个AndroidRuntime对象,其start函数源码如下:
void AndroidRuntime::start(const char* className, const Vector
对于虚拟机的具体启动和运行过程,等作者学习了后续在出相关文章讲解。
按照正常的启动流程,VM成功启动,并进入ZygoteInit执行;ZygoteInit执行源码如下:
public static void main(String argv[]) { ZygoteServer zygoteServer = null; // Mark zygote start、This ensures that thread creation will throw // an error. // 标记zygote开始。 这确保线程创建将引发错误。 ZygoteHooks.startZygoteNoThreadCreation(); // Zygote goes into its own process group. // Zygote 进入它自己的进程组。 try { Os.setpgid(0, 0); } catch (ErrnoException ex) { throw new RuntimeException("Failed to setpgid(0,0)", ex); } Runnable caller; try { // Report Zygote start time to tron unless it is a runtime restart // 向 tron 报告 Zygote 启动时间,除非是运行时重启 if (!"1".equals(SystemProperties.get("sys.boot_completed"))) { MetricsLogger.histogram(null, "boot_zygote_init", (int) SystemClock.elapsedRealtime()); } String bootTimetag = Process.is64Bit() ? "Zygote64Timing" : "Zygote32Timing"; TimingsTraceLog bootTimingsTraceLog = new TimingsTraceLog(bootTimetag, Trace.TRACE_TAG_DALVIK); bootTimingsTraceLog.traceBegin("ZygoteInit"); RuntimeInit.enableDdms(); 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])) { startSystemServer = true; //标记,需要启动 SystemServer } else if ("--enable-lazy-preload".equals(argv[i])) { enableLazyPreload = true; //标记, 使能 LazyPreload } else if (argv[i].startsWith(ABI_LIST_ARG)) { //abi列表参数 abiList = argv[i].substring(ABI_LIST_ARG.length()); } else if (argv[i].startsWith(SOCKET_NAME_ARG)) { //socket名参数 zygoteSocketName = argv[i].substring(SOCKET_NAME_ARG.length()); } else { throw new RuntimeException("Unknown command line argument: " + argv[i]); } } final boolean isPrimaryZygote = zygoteSocketName.equals(Zygote.PRIMARY_SOCKET_NAME); if (abiList == null) { throw new RuntimeException("No ABI list supplied."); } // 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); //预加载资源 EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END, SystemClock.uptimeMillis()); bootTimingsTraceLog.traceEnd(); // ZygotePreload } else { Zygote.resetNicePriority(); } // Do an initial gc to clean up after startup // 启动后执行初始 gc 清理 bootTimingsTraceLog.traceBegin("PostZygoteInitGC"); gcAndFinalize(); bootTimingsTraceLog.traceEnd(); // PostZygoteInitGC bootTimingsTraceLog.traceEnd(); // ZygoteInit // Disable tracing so that forked processes do not inherit stale tracing tags from // Zygote. // 禁用跟踪,以便分叉的进程不会从 Zygote 继承陈旧的跟踪标记。 Trace.setTracingEnabled(false, 0); Zygote.initNativeState(isPrimaryZygote); ZygoteHooks.stopZygoteNoThreadCreation(); zygoteServer = new ZygoteServer(isPrimaryZygote); if (startSystemServer) { //启动一个 SystemServer 进程 Runnable r = forkSystemServer(abiList, zygoteSocketName, zygoteServer); // {@code r == null} in the parent (zygote) process, and {@code r != null} in the // child (system_server) process. // {@code r == null} 在父 (zygote) 进程中,{@code r != null} 在子 (system_server) 进程中。 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. // select 循环在 fork 之后的子进程中尽早返回,并在 zygote 中永远循环。 caller = zygoteServer.runSelectLoop(abiList); } catch (Throwable ex) { Log.e(TAG, "System zygote died with exception", ex); throw ex; } finally { if (zygoteServer != null) { zygoteServer.closeServerSocket(); } } // We're in the child process and have exited the select loop、Proceed to execute the // command. if (caller != null) { caller.run(); } }
ZygoteInit的主函数主要完成以下几点:
—Socket—
zygote是一个孵化器,一旦有新程序需要运行时,系统会通过这个socket(完整名称为:zygote 、Zygote.PRIMARY_SOCKET_NAME))第一时间通知“总管事”Zygote,并由它负责实际的进程孵化过程。
—Preload预加载资源—
通过enableLazyPreload判断是否预加载资源。加载虚拟机运行时所需的资源,包括:
preloadClasses();
cacheNonBootClasspathClassLoaders();
preloadResources();
nativePreloadAppProcessHALs();
maybePreloadGraphicsDriver();
preloadSharedLibraries();
preloadTextResources();
从对应的名称可看出每个preload函数的作用。以preloadClasses为例,它负责加载和初始化常用的一些classes。这些需要预加载的classes被记录在"out/target/product/msmnile_au/system/etc/preloaded-classes"中,在高通8155的LA.1.1中如下所示:
# Preloaded-classes filter file for phones.# Classes in this file will be allocated into the boot image, and forcibly initialized in# the zygote during initialization、This is a trade-off, using virtual address space to share# common heap between apps.# This file has been derived for mainline phone (and tablet) usage.#android.R$styleableandroid.accessibilityservice.AccessibilityServiceInfo$1android.accessibilityservice.AccessibilityServiceInfoandroid.accounts.Account$1android.accounts.Accountandroid.accounts.AccountManager$10android.accounts.AccountManager$11android.accounts.AccountManager$18android.accounts.AccountManager$1android.accounts.AccountManager$20android.accounts.AccountManager$2android.accounts.AccountManager$AmsTask$1android.accounts.AccountManager$AmsTask$Responseandroid.accounts.AccountManager$AmsTaskandroid.accounts.AccountManager$baseFutureTask$1android.accounts.AccountManager$baseFutureTask$Response....略
从输出文件中可以看出preloaded-classes中包含多达上千个classes,而且包括了libcore里面的重要基础资源,如:android.system、android.util等。另外,这个记录表通过“frameworks/base/tools/preload/WritePreloadedClassFile.java”生成。
—启动System Server—
如果app_process的调用参数中带有“start-system-server”,那么此时就会通过“forkSystemServer”来启动“SystemServer”。
Zygote在前期主要担当启动系统服务的工作,后期则又负责“程序孵化”的任务。但是Zygote只在init.rc中被启动一次,它又是如何协调这两者的工作关系呢?从前面的过程中,大致推断,上述中的“forkSystemServer”应该会新建一个专门的进程来承载系统服务的运行,而后app_process所在的进程转化为Zygote的“孵化器”守护进程。那么具体如何呢?接下来分析“forkSystemServer”的内容,如下:
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", "--capabilities=" + capabilities + "," + capabilities, "--nice-name=system_server", "--runtime-args", "--target-sdk-version=" + VMRuntime.SDK_VERSION_CUR_DEVELOPMENT, "com.android.server.SystemServer", }; ZygoteArguments parsedArgs = null; int pid; try { parsedArgs = new ZygoteArguments(args); Zygote.applyDebuggerSystemProperty(parsedArgs); Zygote.applyInvokeWithSystemProperty(parsedArgs); boolean profileSystemServer = SystemProperties.getBoolean( "dalvik.vm.profilesystemserver", false); if (profileSystemServer) { parsedArgs.mRuntimeFlags |= Zygote.PROFILE_SYSTEM_SERVER; } pid = Zygote.forkSystemServer( //此处fork一个新的进程(子进程) parsedArgs.mUid, parsedArgs.mGid, parsedArgs.mGids, parsedArgs.mRuntimeFlags, null, parsedArgs.mPermittedCapabilities, parsedArgs.mEffectiveCapabilities); } catch (IllegalArgumentException ex) { throw new RuntimeException(ex); } if (pid == 0) { //子进程,即System Server所承载进程 if (hasSecondZygote(abiList)) { waitForSecondaryZygote(socketName); } zygoteServer.closeServerSocket(); return handleSystemServerProcess(parsedArgs); //启动各个 System Server } return null; }
上述代码段中又出现了我们熟悉的fork流程,forkSystemServer在内部利用UNIX的fork机制创建了一个新的进程;而这个“新生儿”(即pid=0分支)会在随后的执行过程中通过“handleSystemServerProcess”来启动各种支撑系统运行的 System Server。
在跟踪 System Server的具体启动过程之前,先来为Zygote接下来的工作做个分析,与我们之前所见的fork处理流程不同的是,ZygoteInit.java-》main()-》forkSystemServer()函数中并没有为父进程专门开辟一个代码分支,因而这个函数最后会通过return handleSystemServerProcess(parsedArgs) 返回到ZygoteInit.java-》main()中。在main()接着就是语句:
caller = zygoteServer.runSelectLoop(abiList);
从runSelectLoop的函数名可猜到,这很可能会是一个“死循环”,除非Zygote退出或者出现异常才会跳出循环,runSelectLoop函数内容如下:
** * 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
从上述程序可看到,runSelectLoop函数的主体部分确实是一和while循环,它将作为zygoted 守护体存在。因为zygote此时运行在虚拟机环境中,所以需要处理USAP 池的分配与管理的问题。
在mZygoteSocket.getFileDescriptor()获取的是Server socket的文件描述符,并添加到 ArrayList
try { Os.poll(pollFDs, -1); //判断 当前轮训到的 pollFDs中的socketFD 是否处于可读状态 } catch (ErrnoException ex) { throw new RuntimeException("poll failed", ex); }
当pollFDs中的socketFD指示的某个文件有可读数据时,pollFDs的revents成员的值会被修改。
pollIndex表示当前轮训的第几个socket,从最大值开始轮训。pollIndex大于或等于0时进入循环。
首先判断当前socket的事件 是否 时进入轮训状态,是的话进入重新循环,否则继续运行下面的判断。
if ((pollFDs[pollIndex].revents & POLLIN) == 0) { //轮训 continue; }
pollIndex = 0
此时表示有新的客户端连接,需要通过“ZygoteConnection newPeer = acceptCommandPeer(abiList);”接受来自客户端的连接,产生一个新的ZygoteConnection,然后分别更新peers和socketFDs,为了保证这两个列表中的对象序列号保存一致,可以看到peer在初始化时专门添加了一个null,对应的是Zygote Server Socket 这个“监听者”。
pollIndex < usapPoolEventFDIndex
usapPoolEventFDIndex是记录了socketFDs的数量的。此时说明已经建立Socket连接中有来自客户端的数据需要处理,完成具体工作的是connection.processoneCommand(this),该函数具体内容如下:
Runnable processOneCommand(ZygoteServer zygoteServer) { String args[]; ZygoteArguments parsedArgs = null; FileDescriptor[] descriptors; try { args = Zygote.readArgumentList(mSocketReader); // TODO (chriswailes): Remove this and add an assert. // TODO (chriswailes): 删除它并添加一个断言。 descriptors = mSocket.getAncillaryFileDescriptors(); } catch (IOException ex) { throw new IllegalStateException("IOException on command socket", ex); } // readArgumentList returns null only when it has reached EOF with no available // data to read、This will only happen when the remote socket has disconnected. // readArgumentList 仅在到达 EOF 且没有可读取的数据时才返回 null。 这只会在远程套接字断开连接时发生。 if (args == null) { isEof = true; return null; } int pid = -1; FileDescriptor childPipeFd = null; FileDescriptor serverPipeFd = null; parsedArgs = new ZygoteArguments(args); if (parsedArgs.mAbiListQuery) { handleAbiListQuery(); return null; } if (parsedArgs.mPidQuery) { handlePidQuery(); return null; } if (parsedArgs.mUsapPoolStatusSpecified) { return handleUsapPoolStatusChange(zygoteServer, parsedArgs.mUsapPoolEnabled); } if (parsedArgs.mPreloadDefault) { handlePreload(); return null; } if (parsedArgs.mPreloadPackage != null) { handlePreloadPackage(parsedArgs.mPreloadPackage, parsedArgs.mPreloadPackageLibs, parsedArgs.mPreloadPackageLibFileName, parsedArgs.mPreloadPackageCacheKey); return null; } if (canPreloadApp() && parsedArgs.mPreloadApp != null) { byte[] rawParcelData = base64.getDecoder().decode(parsedArgs.mPreloadApp); Parcel appInfoParcel = Parcel.obtain(); appInfoParcel.unmarshall(rawParcelData, 0, rawParcelData.length); appInfoParcel.setDataPosition(0); ApplicationInfo appInfo = ApplicationInfo.CREATOR.createFromParcel(appInfoParcel); appInfoParcel.recycle(); if (appInfo != null) { handlePreloadApp(appInfo); } else { throw new IllegalArgumentException("Failed to deserialize --preload-app"); } return null; } if (parsedArgs.mApiBlacklistExemptions != null) { return handleApiBlacklistExemptions(zygoteServer, parsedArgs.mApiBlacklistExemptions); } if (parsedArgs.mHiddenApiAccessLogSampleRate != -1 || parsedArgs.mHiddenApiAccessStatslogSampleRate != -1) { return handleHiddenApiAccessLogSampleRate(zygoteServer, parsedArgs.mHiddenApiAccessLogSampleRate, parsedArgs.mHiddenApiAccessStatslogSampleRate); } if (parsedArgs.mPermittedCapabilities != 0 || parsedArgs.mEffectiveCapabilities != 0) { throw new ZygoteSecurityException("Client may not specify capabilities: " + "permitted=0x" + Long.toHexString(parsedArgs.mPermittedCapabilities) + ", effective=0x" + Long.toHexString(parsedArgs.mEffectiveCapabilities)); } Zygote.applyUidSecurityPolicy(parsedArgs, peer); Zygote.applyInvokeWithSecurityPolicy(parsedArgs, peer); Zygote.applyDebuggerSystemProperty(parsedArgs); Zygote.applyInvokeWithSystemProperty(parsedArgs); int[][] rlimits = null; if (parsedArgs.mRLimits != null) { rlimits = parsedArgs.mRLimits.toArray(Zygote.INT_ARRAY_2D); } int[] fdsToIgnore = null; if (parsedArgs.mInvokeWith != null) { try { FileDescriptor[] pipeFds = Os.pipe2(O_CLOEXEC); childPipeFd = pipeFds[1]; serverPipeFd = pipeFds[0]; Os.fcntlInt(childPipeFd, F_SETFD, 0); fdsToIgnore = new int[]{childPipeFd.getInt$(), serverPipeFd.getInt$()}; } catch (ErrnoException errnoEx) { throw new IllegalStateException("Unable to set up pipe for invoke-with", errnoEx); } } int [] fdsToClose = { -1, -1 }; FileDescriptor fd = mSocket.getFileDescriptor(); if (fd != null) { fdsToClose[0] = fd.getInt$(); } fd = zygoteServer.getZygoteSocketFileDescriptor(); if (fd != null) { fdsToClose[1] = fd.getInt$(); } fd = null; pid = Zygote.forkAndSpecialize(parsedArgs.mUid, parsedArgs.mGid, parsedArgs.mGids, parsedArgs.mRuntimeFlags, rlimits, parsedArgs.mMountExternal, parsedArgs.mSeInfo, parsedArgs.mNiceName, fdsToClose, fdsToIgnore, parsedArgs.mStartChildZygote, parsedArgs.mInstructionSet, parsedArgs.mAppDataDir, parsedArgs.mTargetSdkVersion); try { if (pid == 0) { // in child //在子进程 zygoteServer.setForkChild(); //mIsForkChild 值为true zygoteServer.closeServerSocket(); IoUtils.closeQuietly(serverPipeFd); serverPipeFd = null; return handleChildProc(parsedArgs, descriptors, childPipeFd, parsedArgs.mStartChildZygote); } else { // In the parent、A pid < 0 indicates a failure and will be handled in // handleParentProc. // 在父级中。 pid < 0 表示失败,将在 handleParentProc 中处理。 IoUtils.closeQuietly(childPipeFd); childPipeFd = null; handleParentProc(pid, descriptors, serverPipeFd); return null; } } finally { IoUtils.closeQuietly(childPipeFd); IoUtils.closeQuietly(serverPipeFd); } }
函数processOneCommand比较长,其中重点内容是函数的后面部分,我们重点关注两点:
创建承载应用程序的新进程
这个是在意料之中的,zygote需要为每个新启动的应用程序生成自己独立的进程。不过processOneCommand中并没有直接使用fork来父进程的“收尾”工作
执行完上述的任务后,父进程还需要做一些清尾工作才算“大功告成”。包括:将子进程加入进程组;正确关闭文件;调用方返回结果值等。
Specialize的字面意思是“专门化”,表达了“forkAndSpecialize”在“孵化”的同时也把它转变为Android应用程序的目标。函数forkAndSpecialize的处理分为3个阶段,即 preFork、nativeForkAndSpecialize以及postForkCommon。函数内容如下:
public static int forkAndSpecialize(int uid, int gid, int[] gids, int runtimeFlags, int[][] rlimits, int mountExternal, String seInfo, String niceName, int[] fdsToClose, int[] fdsToIgnore, boolean startChildZygote, String instructionSet, String appDataDir, int targetSdkVersion) { ZygoteHooks.preFork(); // Resets nice priority for zygote process. // 重置 zygote 进程的优先级。 resetNicePriority(); int pid = nativeForkAndSpecialize( uid, gid, gids, runtimeFlags, rlimits, mountExternal, seInfo, niceName, fdsToClose, fdsToIgnore, startChildZygote, instructionSet, appDataDir); // Enable tracing as soon as possible for the child process. // 尽快为子进程启用跟踪。 if (pid == 0) { Zygote.disableExecuteOnly(targetSdkVersion); Trace.setTracingEnabled(true, runtimeFlags); // Note that this event ends at the end of handleChildProc, // 注意这个事件在handleChildProc结束时结束, Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "PostFork"); } ZygoteHooks.postForkCommon(); return pid; }
preFork分析
preFork在Zygote中对应的实现如下:
static jlong ZygoteHooks_nativePreFork(JNIEnv* env, jclass) { Runtime* runtime = Runtime::Current(); CHECK(runtime->IsZygote()) << "runtime instance not started with -Xzygote"; runtime->PreZygoteFork(); // Grab thread before fork potentially makes Thread::pthread_key_self_ unusable. // 在 fork 之前抓取线程可能会使 Thread::pthread_key_self_ 不可用。 return reinterpret_cast
这里的Runtime实例具体而言指的是 Zygote进程中的运行环境(后续如果讲解虚拟机时在详细讲解)。而runtime->PreZygoteFork()又会间接调用Heap::PreZygoteFrok,从而完成堆栈空间的初始化。
函数nativeForkAndSpecialize是一个native方法。具体对应的实现是com_android_internal_os_Zygote_nativeForkAndSpecialize,后者有进一步调用了 ForkCommon 和 SpecializeCommon。
com_android_internal_os_Zygote_nativeForkAndSpecialize 函数内容如下:
static jint com_android_internal_os_Zygote_nativeForkAndSpecialize( JNIEnv* env, jclass, jint uid, jint gid, jintArray gids, jint runtime_flags, jobjectArray rlimits, jint mount_external, jstring se_info, jstring nice_name, jintArray managed_fds_to_close, jintArray managed_fds_to_ignore, jboolean is_child_zygote, jstring instruction_set, jstring app_data_dir) { jlong capabilities = CalculateCapabilities(env, uid, gid, gids, is_child_zygote); if (UNLIKELY(managed_fds_to_close == nullptr)) { ZygoteFailure(env, "zygote", nice_name, "Zygote received a null fds_to_close vector."); } std::vector
ForkCommon函数的内容如下:
// Utility routine to fork a process from the zygote.// 从 zygote 派生一个进程的实用程序。static pid_t ForkCommon(JNIEnv* env, bool is_system_server, const std::vector
SpecializeCommon的内容如下:
// Utility routine to specialize a zygote child process.// 用于专门化 zygote 子进程的实用程序。static void SpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray gids, jint runtime_flags, jobjectArray rlimits, jlong permitted_capabilities, jlong effective_capabilities, jint mount_external, jstring managed_se_info, jstring managed_nice_name, bool is_system_server, bool is_child_zygote, jstring managed_instruction_set, jstring managed_app_data_dir) { const char* process_name = is_system_server ? "system_server" : "zygote"; auto fail_fn = std::bind(ZygoteFailure, env, process_name, managed_nice_name, _1); auto extract_fn = std::bind(ExtractJString, env, process_name, managed_nice_name, _1); auto se_info = extract_fn(managed_se_info); auto nice_name = extract_fn(managed_nice_name); auto instruction_set = extract_fn(managed_instruction_set); auto app_data_dir = extract_fn(managed_app_data_dir); // Keep capabilities across UID change, unless we're staying root. // 保持跨 UID 更改的功能,除非我们保持 root。 if (uid != 0) { EnableKeepCapabilities(fail_fn); } SetInheritable(permitted_capabilities, fail_fn); DropCapabilitiesBoundingSet(fail_fn); bool use_native_bridge = !is_system_server && instruction_set.has_value() && android::NativeBridgeAvailable() && android::NeedsNativeBridge(instruction_set.value().c_str()); if (use_native_bridge && !app_data_dir.has_value()) { // The app_data_dir variable should never be empty if we need to use a // native bridge、 In general, app_data_dir will never be empty for normal // applications、 It can only happen in special cases (for isolated // processes which are not associated with any app)、 These are launched by // the framework and should not be emulated anyway. // 如果我们需要使用本地网桥,app_data_dir 变量永远不应该为空。 // 通常,对于普通应用程序,app_data_dir 永远不会为空。 // 它只能在特殊情况下发生(对于与任何应用程序无关的隔离进程)。 // 这些是由框架启动的,无论如何都不应该被模拟。 use_native_bridge = false; ALOGW("Native bridge will not be used because managed_app_data_dir == nullptr."); } MountEmulatedStorage(uid, mount_external, use_native_bridge, fail_fn); // If this zygote isn't root, it won't be able to create a process group, // since the directory is owned by root. // 如果这个 zygote 不是 root,它将无法创建进程组,因为该目录是由 root 拥有的。 if (!is_system_server && getuid() == 0) { const int rc = createProcessGroup(uid, getpid()); if (rc == -EROFS) { ALOGW("createProcessGroup failed, kernel missing CONFIG_CGROUP_CPUACCT?"); } else if (rc != 0) { ALOGE("createProcessGroup(%d, %d) failed: %s", uid, 0, strerror(-rc)); } } SetGids(env, gids, is_child_zygote, fail_fn); SetRLimits(env, rlimits, fail_fn); if (use_native_bridge) { // Due to the logic behind use_native_bridge we know that both app_data_dir // and instruction_set contain values. // 由于 use_native_bridge 背后的逻辑,我们知道 app_data_dir 和 instruction_set 都包含值。 android::PreInitializeNativeBridge(app_data_dir.value().c_str(), instruction_set.value().c_str()); } if (setresgid(gid, gid, gid) == -1) { fail_fn(CREATE_ERROR("setresgid(%d) failed: %s", gid, strerror(errno))); } // Must be called when the new process still has CAP_SYS_ADMIN, in this case, // before changing uid from 0, which clears capabilities、 The other // alternative is to call prctl(PR_SET_NO_NEW_PRIVS, 1) afterward, but that // breaks SELinux domain transition (see b/71859146)、 As the result, // privileged syscalls used below still need to be accessible in app process. // 必须在新进程仍有 CAP_SYS_ADMIN 时调用,在这种情况下,在将 uid 从 0 更改为清除功能之前。 // 另一种选择是在之后调用 prctl(PR_SET_NO_NEW_PRIVS, 1),但这会中断 SELinux 域转换(参见 b/71859146)。 // 因此,下面使用的特权系统调用仍然需要在应用程序进程中访问。 SetUpSeccompFilter(uid, is_child_zygote); if (setresuid(uid, uid, uid) == -1) { fail_fn(CREATE_ERROR("setresuid(%d) failed: %s", uid, strerror(errno))); } // The "dumpable" flag of a process, which controls core dump generation, is // overwritten by the value in /proc/sys/fs/suid_dumpable when the effective // user or group ID changes、See proc(5) for possible values、In most cases, // the value is 0, so core dumps are disabled for zygote children、However, // when running in a Chrome OS container, the value is already set to 2, // which allows the external crash reporter to collect all core dumps、Since // only system crashes are interested, core dump is disabled for app // processes、This also ensures compliance with CTS. // 当有效用户或组 ID 更改时,控制核心转储生成的进程的“dumpable”标志被 /proc/sys/fs/suid_dumpable 中的值覆盖。 // 有关可能的值,请参见 proc(5)。 在大多数情况下,该值为 0,因此对 zygote 子项禁用核心转储。 // 但是,在 Chrome OS 容器中运行时,该值已设置为 2,这允许外部崩溃报告器收集所有核心转储。 // 由于只对系统崩溃感兴趣,因此对应用程序进程禁用核心转储。 这也确保符合 CTS。 int dumpable = prctl(PR_GET_DUMPABLE); if (dumpable == -1) { ALOGE("prctl(PR_GET_DUMPABLE) failed: %s", strerror(errno)); RuntimeAbort(env, __LINE__, "prctl(PR_GET_DUMPABLE) failed"); } if (dumpable == 2 && uid >= AID_APP) { if (prctl(PR_SET_DUMPABLE, 0, 0, 0, 0) == -1) { ALOGE("prctl(PR_SET_DUMPABLE, 0) failed: %s", strerror(errno)); RuntimeAbort(env, __LINE__, "prctl(PR_SET_DUMPABLE, 0) failed"); } } // Set process properties to enable debugging if required. // 如果需要,设置进程属性以启用调试。 if ((runtime_flags & RuntimeFlags::DEBUG_ENABLE_JDWP) != 0) { EnableDebugger(); } if ((runtime_flags & RuntimeFlags::PROFILE_FROM_SHELL) != 0) { // simpleperf needs the process to be dumpable to profile it. // simpleperf 需要进程可转储以对其进行分析。 if (prctl(PR_SET_DUMPABLE, 1, 0, 0, 0) == -1) { ALOGE("prctl(PR_SET_DUMPABLE) failed: %s", strerror(errno)); RuntimeAbort(env, __LINE__, "prctl(PR_SET_DUMPABLE, 1) failed"); } } if (NeedsNoRandomizeWorkaround()) { // Work around ARM kernel ASLR lossage (http://b/5817320). // 解决 ARM 内核 ASLR 丢失问题 (http://b/5817320)。 int old_personality = personality(0xffffffff); int new_personality = personality(old_personality | ADDR_NO_RANDOMIZE); if (new_personality == -1) { ALOGW("personality(%d) failed: %s", new_personality, strerror(errno)); } } SetCapabilities(permitted_capabilities, effective_capabilities, permitted_capabilities, fail_fn); SetSchedulerPolicy(fail_fn); __android_log_close(); stats_log_close(); const char* se_info_ptr = se_info.has_value() ? se_info.value().c_str() : nullptr; const char* nice_name_ptr = nice_name.has_value() ? nice_name.value().c_str() : nullptr; if (selinux_android_setcontext(uid, is_system_server, se_info_ptr, nice_name_ptr) == -1) { fail_fn(CREATE_ERROR("selinux_android_setcontext(%d, %d, "%s", "%s") failed", uid, is_system_server, se_info_ptr, nice_name_ptr)); } // Make it easier to debug audit logs by setting the main thread's name to the // nice name rather than "app_process". // 通过将主线程的名称设置为好听的名称而不是“app_process”,可以更轻松地调试审计日志。 if (nice_name.has_value()) { SetThreadName(nice_name.value()); } else if (is_system_server) { SetThreadName("system_server"); } // Unset the SIGCHLD handler, but keep ignoring SIGHUP (rationale in SetSignalHandlers). // 取消设置 SIGCHLD 处理程序,但继续忽略 SIGHUP(SetSignalHandlers 中的基本原理)。 UnsetChldSignalHandler(); if (is_system_server) { env->CallStaticVoidMethod(gZygoteClass, gCallPostForkSystemServerHooks); if (env->ExceptionCheck()) { fail_fn("Error calling post fork system server hooks."); } // Prefetch the classloader for the system server、This is done early to // allow a tie-down of the proper system server selinux domain. // 预取系统服务器的类加载器。 这是尽早完成以允许绑定适当的系统服务器 selinux 域。 env->CallStaticVoidMethod(gZygoteInitClass, gCreateSystemServerClassLoader); if (env->ExceptionCheck()) { // Be robust here、The Java code will attempt to create the classloader // at a later point (but may not have rights to use AoT artifacts). // 这里要健壮。 Java 代码稍后将尝试创建类加载器(但可能无权使用 AoT 工件)。 env->ExceptionClear(); } // TODO(oth): Remove hardcoded label here (b/117874058). // TODO(oth):在此处删除硬编码标签 (b/117874058)。 static const char* kSystemServerLabel = "u:r:system_server:s0"; if (selinux_android_setcon(kSystemServerLabel) != 0) { fail_fn(CREATE_ERROR("selinux_android_setcon(%s)", kSystemServerLabel)); } } env->CallStaticVoidMethod(gZygoteClass, gCallPostForkChildHooks, runtime_flags, is_system_server, is_child_zygote, managed_instruction_set); if (env->ExceptionCheck()) { fail_fn("Error calling post fork hooks."); }}
首先在ForkCommon函数内,会先fork一个新进程,并在pid=0这一分支中为孵化出的进程完成一系列初始化操作,而后在SpecializeCommon函数内执行CallStaticVoidMethod函数。CallStaticVoidMethod函数的参数 gZygoteClass对应的是“com/android/internal/os/Zygote”,而gCallPostForkChildHooks则是Zygote这个类中的成员函数callPostForkChildHooks,从名称可看出其是用于执行孵化后的一些处理工作。
ForkCommon和SpecializeCommon都没有涉及与应用程序相关的具体业务,这部分由 “frameworks/base/core/java/com/android/internal/os/ZygoteConnection.java”->processOneCommand中的handleChildProc()来完成。
函数handleChildProc的内容如下:
private Runnable handleChildProc(ZygoteArguments parsedArgs, FileDescriptor[] descriptors, FileDescriptor pipeFd, boolean isZygote) { closeSocket(); if (descriptors != null) { try { Os.dup2(descriptors[0], STDIN_FILENO); Os.dup2(descriptors[1], STDOUT_FILENO); Os.dup2(descriptors[2], STDERR_FILENO); for (FileDescriptor fd: descriptors) { IoUtils.closeQuietly(fd); } } catch (ErrnoException ex) { Log.e(TAG, "Error reopening stdio", ex); } } if (parsedArgs.mNiceName != null) { //存在子进程的别名 Process.setArgV0(parsedArgs.mNiceName); //设置子进程的别名 } // End of the postFork event. // postFork 事件结束。 Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); if (parsedArgs.mInvokeWith != null) { WrapperInit.execApplication(parsedArgs.mInvokeWith, // 执行应用程序,正常情况下不返回 parsedArgs.mNiceName, parsedArgs.mTargetSdkVersion, VMRuntime.getCurrentInstructionSet(), pipeFd, parsedArgs.mRemainingArgs); // Should not get here. // 不应该到这里。 throw new IllegalStateException("WrapperInit.execApplication unexpectedly returned"); //WrapperInit.execApplication 意外返回 } else { //否则重新初始化zygote if (!isZygote) { return ZygoteInit.zygoteInit(parsedArgs.mTargetSdkVersion, parsedArgs.mRemainingArgs, null ); } else { return ZygoteInit.childZygoteInit(parsedArgs.mTargetSdkVersion, parsedArgs.mRemainingArgs, null ); } } }
这个函数的任务是,处理参数后调用WrapperInit.execApplication(),执行应用程序。Android系统中所有应用程序理论上都是由zygote启动的, 从前面的分析来看,不难发现zygote会为新启动的应用程序fork一个进程。不过和传统的内核中的fork+exec的作法不同的地方是,Zygote中并不会执行exec()。在这种情况下就会造成一些障碍,比如无法使用valgrind来监控程序的内存泄漏情况。android系统提供了一种Wrapper实现,并通过parsedArgs.mInvokeWith 来加以控制。有兴趣的读者可查阅相关资料。
在高通的这个基线代码中execApplication函数主要是分析参数后,调用shell执行运行程序的命令。execApplication的内容如下:
public static void execApplication(String invokeWith, String niceName, int targetSdkVersion, String instructionSet, FileDescriptor pipeFd, String[] args) { StringBuilder command = new StringBuilder(invokeWith); final String appProcess; if (VMRuntime.is64BitInstructionSet(instructionSet)) { appProcess = "/system/bin/app_process64"; } else { appProcess = "/system/bin/app_process32"; } command.append(' '); command.append(appProcess); // Generate bare minimum of debug information to be able to backtrace through JITed code. // We assume that if the invoke wrapper is used, backtraces are desirable: // * The wrap.sh script can only be used by debuggable apps, which would enable this flag // without the script anyway (the fork-zygote path)、 So this makes the two consistent. // * The wrap.* property can only be used on userdebug builds and is likely to be used by // developers (e.g、enable debug-malloc), in which case backtraces are also useful. // 生成最少的调试信息,以便能够通过 JITed 代码进行回溯。 // 我们假设如果使用调用包装器,则需要回溯: wrap.sh 脚本只能由可调试的应用程序使用, // 这将在没有脚本的情况下启用此标志(fork-zygote 路径)。 所以这使得两者一致。 // wrap.* 属性只能在 userdebug 构建中使用,并且很可能被开发人员使用(例如启用 debug-malloc),在这种情况下回溯也很有用。 command.append(" -Xcompiler-option --generate-mini-debug-info"); command.append(" /system/bin --application"); if (niceName != null) { command.append(" '--nice-name=").append(niceName).append("'"); } command.append(" com.android.internal.os.WrapperInit "); command.append(pipeFd != null ? pipeFd.getInt$() : 0); command.append(' '); command.append(targetSdkVersion); Zygote.appendQuotedShellArgs(command, args); preserveCapabilities(); Zygote.execShell(command.toString()); }
在前面的handleChildProc这个函数中,会有一些会参数的处理,详细的了解需要对应用程序的启动由一个全局的认识。所以可以穿插阅读其它有关文档文章(后续作者也会持续更新)。这里假设运行的流程已经到了ActivityManagerService。
由于文章篇幅太长,本部分先讲解到这。后面文章将紧接这部分讲解分析流程。