一、前言
说到Zygote进程,就不可避免的提到init进程。init作为Linux的第一个进程,有着无与伦比的作用。它主要是启动系统的关键服务并且守护关键服务。这里的系统关键服务指的是Android系统的关键服务,比如媒体,通话等。即便关键进程被杀死,init进程也会把它复活出来。其中的关键之处就在于init进程会加载一个名为init.rc的文件。
我们想了解init进程就不可避免的去看源码,init的源码就位于/system/core/init/init.cpp 和 main.cpp中。这里推荐一个网站Android源码查看这是谷歌官方提供的源码查看网站。
我们可以在init.cpp中找到这样一个函数,它就会去解析init.rc里面的内容。
static void LoadBootScripts(ActionManager& action_manager, ServiceList& service_list) {
Parser parser = CreateParser(action_manager, service_list);
std::string bootscript = GetProperty("ro.boot.init_rc", "");
if (bootscript.empty()) {
parser.ParseConfig("/system/etc/init/hw/init.rc");
if (!parser.ParseConfig("/system/etc/init")) {
late_import_paths.emplace_back("/system/etc/init");
}
parser.ParseConfig("/system_ext/etc/init");
if (!parser.ParseConfig("/vendor/etc/init")) {
late_import_paths.emplace_back("/vendor/etc/init");
}
if (!parser.ParseConfig("/odm/etc/init")) {
late_import_paths.emplace_back("/odm/etc/init");
}
if (!parser.ParseConfig("/product/etc/init")) {
late_import_paths.emplace_back("/product/etc/init");
}
} else {
parser.ParseConfig(bootscript);
}
}
那我们可以在哪里找到init.rc文件呢,我们可以在/system/core/rootdir/init.rc找到。下面浅看一下init.rc的内容吧。
# Copyright (C) 2012 The Android Open Source Project
#
# IMPORTANT: Do not create world writable files or directories.
# This is a common source of Android security bugs.
#
import /init.environ.rc
import /system/etc/init/hw/init.usb.rc
import /init.${ro.hardware}.rc
import /vendor/etc/init/hw/init.${ro.hardware}.rc
import /system/etc/init/hw/init.usb.configfs.rc
import /system/etc/init/hw/init.${ro.zygote}.rc
# Cgroups are mounted right before early-init using list from /etc/cgroups.json
on early-init
# Disable sysrq from keyboard
write /proc/sys/kernel/sysrq 0
# Android doesn't need kernel module autoloading, and it causes SELinux
# denials. So disable it by setting modprobe to the empty string. Note: to
# explicitly set a sysctl to an empty string, a trailing newline is needed.
write /proc/sys/kernel/modprobe \n
# Set the security context of /adb_keys if present.
restorecon /adb_keys
# Set the security context of /postinstall if present.
restorecon /postinstall
mkdir /acct/uid
# memory.pressure_level used by lmkd
chown root system /dev/memcg/memory.pressure_level
chmod 0040 /dev/memcg/memory.pressure_level
# app mem cgroups, used by activity manager, lmkd and zygote
mkdir /dev/memcg/apps/ 0755 system system
# cgroup for system_server and surfaceflinger
mkdir /dev/memcg/system 0550 system system
# symlink the Android specific /dev/tun to Linux expected /dev/net/tun
mkdir /dev/net 0755 root root
symlink ../tun /dev/net/tun
...省略部分代码
大家可以看到其实init.rc并不是一个程序代码文件,更像是一个脚本文件,其实也可以理解成脚本文件,它会运行Linux命令来启动相关服务。
我们需要注意的是import /system/etc/init/hw/init.${ro.zygote}.rc 这句话,它的意思是会根据系统去加载不同的init.zygote文件。我们可以在相同的目录下发现init.zygote64.rc和init.zygote32.rc两个文件。浅看一看内容,以init.zygote64.rc为例。
service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server
class main
priority -20
user root
group root readproc reserved_disk
socket zygote stream 660 root system
socket usap_pool_primary stream 660 root system
onrestart exec_background - system system -- /system/bin/vdc volume abort_fuse
onrestart write /sys/power/state on
onrestart restart audioserver
onrestart restart cameraserver
onrestart restart media
onrestart restart media.tuner
onrestart restart netd
onrestart restart wificond
task_profiles ProcessCapacityHigh
critical window=${zygote.critical_window.minute:-off} target=zygote-fatal
它会通过service命令来启动一个位于/system/bin/app_process64的服务,而后面的则是带的一些参数。既然这里出现了zygote那么是不是和zygote进程有关呢。
二、Zygote进程的启动
前面说到init进程会加载init.rc文件并且通过命令启动app_process服务。那么我们的源码在哪呢。app_process的源码在frameworks/base/cmds/app_process/app_main.cpp这个路径下。既然这个是一个程序文件,那么程序的入口就是main函数了。
int main (int argc, char* const argv[]) 后面的就是argv就是携带的参数 --zygote --start-system-server
如果你们跟着源码在看的话,就会想到那么zygote进程到底是如何启动的呢。
其实我们的zygote进程已经开始执行了。
我们再看main函数中具体的代码。
while (i < argc) {
const char* arg = argv[i++];
if (strcmp(arg, "--zygote") == 0) {
zygote = true;
niceName = ZYGOTE_NICE_NAME;
} else if (strcmp(arg, "--start-system-server") == 0) {
startSystemServer = true;
} else if (strcmp(arg, "--application") == 0) {
application = true;
} else if (strncmp(arg, "--nice-name=", 12) == 0) {
niceName.setTo(arg + 12);
} else if (strncmp(arg, "--", 2) != 0) {
className.setTo(arg);
break;
} else {
--i;
break;
}
}
大家可以看到我们第一个参数就是–zygote所以zygote变量被赋值为true,第二次循环startSystemServer就会被赋值为true。当然niceName也被赋值了。
static const char ZYGOTE_NICE_NAME[] = "zygote";
if (!niceName.isEmpty()) {
runtime.setArgv0(niceName.string(), true );
}
由上述源码可知,在这段代码执行过后,当前的进程名字就被改为了zygote。我们一直期待的zygote进程就出现了。
if (zygote) {
runtime.start("com.android.internal.os.ZygoteInit", args, zygote);
} else if (className) {
runtime.start("com.android.internal.os.RuntimeInit", args, zygote);
} else {
fprintf(stderr, "Error: no class name or --zygote supplied.\n");
app_usage();
LOG_ALWAYS_FATAL("app_process: no class name or --zygote supplied.");
}
那么上述的一段代码又是作为什么使用的呢?
三、Zygote进程的作用
前面说到如果zygote这个变量为true的话,就会执行runtime.start("com.android.internal.os.ZygoteInit", args, zygote); 这句话回去执行相应包下的zygoteInit这个类。我们浅看一下。老样子还是找到它的main方法。
public static void main(String[] argv) {
ZygoteServer zygoteServer = null;
ZygoteHooks.startZygoteNoThreadCreation();
try {
Os.setpgid(0, 0);
} 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"));
String bootTimeTag = Process.is64Bit() ? "Zygote64Timing" : "Zygote32Timing";
TimingsTraceLog bootTimingsTraceLog = new TimingsTraceLog(bootTimeTag,
Trace.TRACE_TAG_DALVIK);
bootTimingsTraceLog.traceBegin("ZygoteInit");
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])) {
startSystemServer = true;
} else if ("--enable-lazy-preload".equals(argv[i])) {
enableLazyPreload = true;
} else if (argv[i].startsWith(ABI_LIST_ARG)) {
abiList = argv[i].substring(ABI_LIST_ARG.length());
} else if (argv[i].startsWith(SOCKET_NAME_ARG)) {
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 (!isRuntimeRestarted) {
if (isPrimaryZygote) {
FrameworkStatsLog.write(FrameworkStatsLog.BOOT_TIME_EVENT_ELAPSED_TIME_REPORTED,
BOOT_TIME_EVENT_ELAPSED_TIME__EVENT__ZYGOTE_INIT_START,
startTime);
} 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.");
}
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();
}
bootTimingsTraceLog.traceBegin("PostZygoteInitGC");
gcAndFinalize();
bootTimingsTraceLog.traceEnd();
bootTimingsTraceLog.traceEnd();
Zygote.initNativeState(isPrimaryZygote);
ZygoteHooks.stopZygoteNoThreadCreation();
zygoteServer = new ZygoteServer(isPrimaryZygote);
if (startSystemServer) {
Runnable r = forkSystemServer(abiList, zygoteSocketName, zygoteServer);
if (r != null) {
r.run();
return;
}
}
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();
}
}
if (caller != null) {
caller.run();
}
}
这么一大堆代码,看着是不是很让人头疼,但是我们可以有重点的去看这段代码。如main方法下面的第一行代码就说明zygote进程内部实例化了一个Server,这个Server是什么呢。我们点进ZygoteServer会发现里面有个LocalServerSocket变量,没错这个server就是地地道道的SocketServer。这个Socket有啥作用呢,我们等到后面再说。
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();
}
我们继续向下看会看到这样的一段代码,在经过之前的代码判断之后,会走到If里面 ,会调用到preload方法。再看看这个方法里面会做什么吧。
static void preload(TimingsTraceLog bootTimingsTraceLog) {
Log.d(TAG, "begin preload");
bootTimingsTraceLog.traceBegin("BeginPreload");
beginPreload();
bootTimingsTraceLog.traceEnd();
bootTimingsTraceLog.traceBegin("PreloadClasses");
preloadClasses();
bootTimingsTraceLog.traceEnd();
bootTimingsTraceLog.traceBegin("CacheNonBootClasspathClassLoaders");
cacheNonBootClasspathClassLoaders();
bootTimingsTraceLog.traceEnd();
bootTimingsTraceLog.traceBegin("PreloadResources");
preloadResources();
bootTimingsTraceLog.traceEnd();
Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "PreloadAppProcessHALs");
nativePreloadAppProcessHALs();
Trace.traceEnd(Trace.TRACE_TAG_DALVIK);
Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "PreloadGraphicsDriver");
maybePreloadGraphicsDriver();
Trace.traceEnd(Trace.TRACE_TAG_DALVIK);
preloadSharedLibraries();
preloadTextResources();
WebViewFactory.prepareWebViewInZygote();
endPreload();
warmUpJcaProviders();
Log.d(TAG, "end preload");
sPreloadComplete = true;
}
这个方法里面所作的就是加载Framework使用的类与资源,如preloadClass、preloadResources等。因为所有的app启动都会加载相应的类,但是每个app的activity类都是继承了Android的activity,那么不可能每次app加载的时候都会去重新加载一遍Android的类和资源。这时候zygote进程的提前预加载的好处就体现出来了,可以加快app的启动速度,因为app所需要的Android类已经加载好了。
让我们把目光接着往下移动。
if (startSystemServer) {
Runnable r = forkSystemServer(abiList, zygoteSocketName, zygoteServer);
if (r != null) {
r.run();
return;
}
}
我们就会看到最重要的部分。zygote进程fork出了SystemServer进程。对Android源码有所了解的同学可能会知道,SystemServer进程会启动各种重要的服务,如AMS、PMS等。
当有新的APP需要启动时,AMS就会通过Socket告知zygote进程为APP创建一个新的进程。这就是zygote进程里面维护一个SocketServer的作用。
那么到此,zygote的进程就初步了解完成了。
|