声明
- 前阶段在项目中涉及到了Android系统定制任务,Android系统定制前提要知道Android系统是如何启动的。
- 本文参考了一些书籍的若干章节,比如《Android进阶解密-第2章-Android系统启动》、《深入理解Android虚拟机-第8/9/10章-init进程详解/Dalvik VM的进程系统/Dalvik VM运作流程详解》、《深入理解Android系统-第6/7/8章-init启动进程详解/Zygote进程详解/System进程详解》等
- 本文使用的代码是LineageOS的cm-14.1,对应Android 7.1.2,可以参考我的另一篇博客:cm-14.1 Android系统启动过程分析(1)-如何下载Nexus5的LineageOS14.1(cm-14.1)系统源码并编译、刷机
- 很多代码注释待详细写
0 写在前面的
Android系统中主要有三个重要的进程系统:
- Zygote进程:被称为孵化进程,功能和Linux中的fork类似,不同的是它在Android系统中用来产生Java层的子进程;
- System进程:系统进程,是Android Framework所在的进程,用于启动Android系统。核心进程为Zygote进程fork出来的system_server,由system_server再去启动Framework层各个系统服务;
- 应用程序进程:每个Android应用程序运行时都有自己的进程;
1 Zygote是什么
Android系统是基于Linux内核搭建起来的开放系统,那么它也是遵循Linux操作系统的基本原理:即所有的进程都是由init进程fork出来的。Zygote进程也是由init进程根据解析的init.rc相关命令启动起来的。之所以Zygote进程在Android系统中处于重要位置,是因为它是Android系统中第一个Java进程、也是Framework系统服务的祖先,Zygote正是通常所说的Java运行环境(DVM/ART)。
Zygote创建了第一个Java虚拟机,并且创建进程system server,这是绝大多数系统服务的守护进程。之后为每一个应用程序创建一个相应的Activity进程。具体步骤如下:
- 创建AppRuntime对象,并且调用该对象的start,由AppRuntime 来控制后续的活动。
- 调用startVM创建Java虚拟机,由startReg来注册JNI函数。
- 通过JNI调用com.androidinternal.os.Zygotelnit类的main函数,开始进入 Java 世界。
- 调用registerZygoteSocket()、preload() 两个函数,响应其他应用程序。
- 通过调用startSystemServer()分裂一个子进程system_server来提供服务。
- 调用runSelectLoopMode()函数。
Zygote启动新应用的过程如图所示Zygote Service接受启动新程序的请求,通过调用Zygote loop函数,使用fork机制为这个程序设置一个启动进程,通过该进程启动程序。同时,通过COW(Copy on Write)方式对运行在内存中的进程实现最大程度的复用,并通过库共享有效地降低内存的使用量(footprint)。
Zygote在Android系统中是一个C/S架构,其他进程作为客户端向Zygote发出fork请求,当Zygote接收到命令后就fork出一个Activity进程。
用adb连接Nexus5手机,执行ps命令可观察各个系统进程的PID及PPID:
USER PID PPID VSIZE RSS WCHAN PC NAME
root 1 0 7916 1388 sys_epoll_ 00000000 S /init
root 2 0 0 0 kthreadd 00000000 S kthreadd
...省略n行...
root 227 1 1559616 68852 poll_sched 00000000 S zygote
...省略n行...
system 806 227 1825696 136184 sys_epoll_ 00000000 S system_server
u0_a64 973 227 993120 48228 sys_epoll_ 00000000 S com.android.inputmethod.latin
u0_a33 987 227 1087016 106116 sys_epoll_ 00000000 S com.android.systemui
media_rw 992 157 8388 1852 inotify_re 00000000 S /system/bin/sdcard
u0_a1 1083 227 978064 37988 sys_epoll_ 00000000 S org.cyanogenmod.cmaudio.service
wifi 1124 1 7660 3164 poll_sched 00000000 S /system/bin/wpa_supplicant
u0_a7 1408 227 977836 38748 sys_epoll_ 00000000 S com.android.cellbroadcastreceiver
u0_a34 1465 227 977348 36624 sys_epoll_ 00000000 S org.cyanogenmod.weather.provider
u0_a10 1525 227 976332 37348 sys_epoll_ 00000000 S android.ext.services
root 1542 1 11392 1444 futex_wait 00000000 S /system/bin/mpdecision
u0_a47 1595 227 984276 42372 sys_epoll_ 00000000 S com.android.deskclock
u0_a31 1637 227 977884 37928 sys_epoll_ 00000000 S org.cyanogenmod.weatherservice
u0_a58 1642 227 982704 39360 sys_epoll_ 00000000 S com.android.printspooler
u0_a3 1658 227 981108 39668 sys_epoll_ 00000000 S org.cyanogenmod.audiofx
nfc 1673 227 1002016 47588 sys_epoll_ 00000000 S com.android.nfc
radio 1692 227 979008 38340 sys_epoll_ 00000000 S com.redbend.vdmc
u0_a9 1720 227 986664 50868 sys_epoll_ 00000000 S android.process.media
system 1736 227 977416 37228 sys_epoll_ 00000000 S com.android.keychain
u0_a60 1764 227 977408 36920 sys_epoll_ 00000000 S com.android.smspush
u0_a30 1779 227 1073396 88992 sys_epoll_ 00000000 S com.cyanogenmod.trebuchet
u0_a52 1832 227 979260 39432 sys_epoll_ 00000000 S com.cyanogenmod.lockclock
system 1854 227 986712 46544 sys_epoll_ 00000000 S org.cyanogenmod.cmparts
u0_a43 1883 227 995504 50448 sys_epoll_ 00000000 S com.android.calculator2
u0_a16 1909 227 993656 42248 sys_epoll_ 00000000 S com.android.dialer
u0_a41 1937 227 991976 41420 sys_epoll_ 00000000 S com.android.calendar
u0_a5 1954 227 977320 37408 sys_epoll_ 00000000 S com.android.carrierconfig
u0_a2 1971 227 987116 47844 sys_epoll_ 00000000 S android.process.acore
u0_a54 2009 227 993892 45456 sys_epoll_ 00000000 S com.android.email
u0_a4 2026 227 982520 40928 sys_epoll_ 00000000 S com.android.providers.calendar
u0_a56 2760 227 977208 36528 sys_epoll_ 00000000 S com.qualcomm.timeservice
u0_a67 2803 227 1109540 86768 sys_epoll_ 00000000 S com.alibaba.android.rimet:channel
shell 2951 212 3632 1312 sys_rt_sig b6e5839c S /system/bin/sh
shell 2978 2951 4576 1304 0 b6bff1e8 R ps
其中,Zygote进程的PID为227,PPID为1;system_server进程的PID为806,PPID为227;
Zygote启动之初进程名字叫app_process,Zygote启动之后Linux系统下的pctrl系统会调用app_process,将其名称换成zygote。
2 Zygote启动脚本
init.rc脚本最前面就import了zygote相关的rc文件:
#对于Nexus5来说,${ro.zygote}的值为zygote32
import /init.${ro.zygote}.rc
在源码目录~/LineageOS/system/core/rootdir中有四个zygote相关的rc文件,分别是:
init.zygote32.rc
init.zygote64.rc
init.zygote32_64.rc
init.zygote64_32.rc
Android5.0以后是支持64位程序的,Zygote也就有了32和64的差别,这里利用ro.zygote值得不同进而选择启动不同的Zygote进程。
2.1 init.zygote32.rc文件
支持纯32位程序,init.zygote32.rc文件内容为:
service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
class main
socket zygote stream 660 root system
onrestart write /sys/android_power/request_state wake
onrestart write /sys/power/state on
onrestart restart audioserver
onrestart restart cameraserver
onrestart restart media
onrestart restart netd
writepid /dev/cpuset/foreground/tasks
根据其中的onrestart可知,如果audioserver、cameraserver、media、netd等进程终止了,就需要重启。
2.2 init.zygote32_64.rc文件
支持32位程序和64位程序,init.zygote32_64.rc文件内容为:
service zygote /system/bin/app_process32 -Xzygote /system/bin --zygote --start-system-server --socket-name=zygote
class main
socket zygote stream 660 root system
onrestart write /sys/android_power/request_state wake
onrestart write /sys/power/state on
onrestart restart audioserver
onrestart restart cameraserver
onrestart restart media
onrestart restart netd
writepid /dev/cpuset/foreground/tasks
service zygote_secondary /system/bin/app_process64 -Xzygote /system/bin --zygote --socket-name=zygote_secondary
class main
socket zygote_secondary stream 660 root system
onrestart restart zygote
writepid /dev/cpuset/foreground/tasks
脚本中要启动Zygote进程,一个名称为zygote,执行程序为app_process32,作为主模式;另一个名为zygote_secondary,执行程序为app_process64,作为辅助模型。
在我的上篇文章:cm-14.1 Android系统启动过程分析(4)-init进程的启动、rc脚本解析、zygote启动、属性服务中的【3.2.1 解析Zygote节】中介绍了Zygote进程是如何被init进程启动起来的。
3 Zygote进程启动过程分析
先借鉴一张图来看看启动过程时序图:
3.1 入口函数main()
通过上面我们知道Zygote进程要执行的程序便是app_process了,它位于frameworks/base/cmds/app_process/app_main.cpp文件中,入口函数是main。
int main(int argc, char* const argv[])
{
if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) < 0) {
// Older kernels don't understand PR_SET_NO_NEW_PRIVS and return
// EINVAL. Don't die on such kernels.
if (errno != EINVAL) {
LOG_ALWAYS_FATAL("PR_SET_NO_NEW_PRIVS failed: %s", strerror(errno));
return 12;
}
}
AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));
// Process command line arguments
// ignore 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.
int i;
for (i = 0; i < argc; i++) {
if (argv[i][0] != '-') {
break;
}
if (argv[i][1] == '-' && argv[i][2] == 0) {
++i; // Skip --.
break;
}
runtime.addOption(strdup(argv[i]));
}
// Parse runtime arguments. Stop at first unrecognized option.
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++];
//Zygote进程是通过fork自身来创建创建子进程的,这样Zygote进程以及它的子进程都可以进入app_main.cpp的main函数,因此main函数为了区分当前运行在哪个进程,会判断arg中是否包含了参数“--zygote”,如果包含则说明main运行在Zygote进程中,将zygote设置为true;
if (strcmp(arg, "--zygote") == 0) {
zygote = true;
niceName = ZYGOTE_NICE_NAME;
//判断参数arg是否包含“--start-system-server”,如果包含则说明main运行在SystemServer进程中,并将startSystemServer设置为true
} 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;
}
}
Vector<String8> args;
if (!className.isEmpty()) {
// We're not in zygote mode, the only argument we need to pass
// to RuntimeInit is the application argument.
//
// The Remainder of args get passed to startup class main(). Make
// copies of them before we overwrite them with the process name.
args.add(application ? String8("application") : String8("tool"));
runtime.setClassNameAndArgs(className, argc - i, argv + i);
} else {
// We're in zygote mode.
maybeCreateDalvikCache();
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]));
}
}
if (!niceName.isEmpty()) {
runtime.setArgv0(niceName.string());
set_process_name(niceName.string());
}
//若zygote为true,说明当前运行在Zygote进程中,调用AppRuntime的start函数
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.");
return 10;
}
}
3.2 启动函数创建一个虚拟机实例,进入Java世界
若zygote为true,说明当前运行在Zygote进程中,调用AppRuntime的start函数,AppRuntime的start方法在源码目录:~/LineageOS/frameworks/base/core/jni/AndroidRuntime.cpp
/*
* Start the Android runtime. This involves starting the virtual machine
* and calling the "static void main(String[] args)" method in the class
* named by "className".
*
* Passes the main function two arguments, the class name and the specified
* options string.
*/
void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote)
{
ALOGD(">>>>>> START %s uid %d <<<<<<\n",
className != NULL ? className : "(unknown)", getuid());
static const String8 startSystemServer("start-system-server");
/*
* 'startSystemServer == true' means runtime is obsolete and not run from
* init.rc anymore, so we print out the boot start event here.
*/
for (size_t i = 0; i < options.size(); ++i) {
if (options[i] == startSystemServer) {
/* track our progress through the boot sequence */
const int LOG_BOOT_PROGRESS_START = 3000;
LOG_EVENT_LONG(LOG_BOOT_PROGRESS_START, ns2ms(systemTime(SYSTEM_TIME_MONOTONIC)));
}
}
const char* rootDir = getenv("ANDROID_ROOT");
if (rootDir == NULL) {
rootDir = "/system";
if (!hasDir("/system")) {
LOG_FATAL("No root directory specified, and /android does not exist.");
return;
}
setenv("ANDROID_ROOT", rootDir, 1);
}
//const char* kernelHack = getenv("LD_ASSUME_KERNEL");
//ALOGD("Found LD_ASSUME_KERNEL='%s'\n", kernelHack);
/* start the virtual machine */
JniInvocation jni_invocation;
jni_invocation.Init(NULL);
//创建一个虚拟机实例
JNIEnv* env;
//启动Java虚拟机;
if (startVm(&mJavaVM, &env, zygote) != 0) {
return;
}
onVmCreated(env);
/*
* Register android functions.
*/
//为Java虚拟机注册JNI方法;
if (startReg(env) < 0) {
ALOGE("Unable to register all android natives\n");
return;
}
/*
* We want to call main() with a String array with arguments in it.
* At present we have two arguments, the class name and an option string.
* Create an array to hold them.
*/
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);
//从app_main的main函数得知className为com.android.internal.os.ZygoteInit;
classNameStr = env->NewStringUTF(className);
assert(classNameStr != NULL);
env->SetObjectArrayElement(strArray, 0, classNameStr);
for (size_t i = 0; i < options.size(); ++i) {
jstring optionsStr = env->NewStringUTF(options.itemAt(i).string());
assert(optionsStr != NULL);
env->SetObjectArrayElement(strArray, i + 1, optionsStr);
}
/*
* Start VM. This thread becomes the main thread of the VM, and will
* not return until the VM exits.
*/
//将className的.替换为“/”;
char* slashClassName = toSlashClassName(className);
//找到ZygoteInit
jclass startClass = env->FindClass(slashClassName);
if (startClass == NULL) {
ALOGE("JavaVM unable to locate class '%s'\n", slashClassName);
/* keep going */
} else {
//找到ZygoteInit的main方法;
jmethodID startMeth = env->GetStaticMethodID(startClass, "main",
"([Ljava/lang/String;)V");
if (startMeth == NULL) {
ALOGE("JavaVM unable to find main() in '%s'\n", className);
/* keep going */
} else {
//通过JNI调用类com.android.internal.os.ZygoteInit的静态成员main()方法来启动Zygote进程;
env->CallStaticVoidMethod(startClass, startMeth, strArray);
#if 0
if (env->ExceptionCheck())
threadExitUncaughtException(env);
#endif
}
}
free(slashClassName);
ALOGD("Shutting down VM\n");
if (mJavaVM->DetachCurrentThread() != JNI_OK)
ALOGW("Warning: unable to detach main thread\n");
if (mJavaVM->DestroyJavaVM() != 0)
ALOGW("Warning: VM did not shut down cleanly\n");
}
最终,Zygote进程成功通过JNI调用从Native层的app_process进入Java框架层的ZygotInit,真正进入了Java代码的世界!!
打开源码目录:~/LineageOS/frameworks/base/core/java/com/android/internal/os/ZygoteInit.java,查看其main方法:
public static void main(String argv[]) {
// Mark zygote start. This ensures that thread creation will throw
// an error.
ZygoteHooks.startZygoteNoThreadCreation();
try {
Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "ZygoteInit");
RuntimeInit.enableDdms();
// Start profiling the zygote initialization.
SamplingProfilerIntegration.start();
boolean startSystemServer = false;
String socketName = "zygote";
String abiList = null;
for (int i = 1; i < argv.length; i++) {
if ("start-system-server".equals(argv[i])) {
startSystemServer = 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)) {
socketName = argv[i].substring(SOCKET_NAME_ARG.length());
} else {
throw new RuntimeException("Unknown command line argument: " + argv[i]);
}
}
if (abiList == null) {
throw new RuntimeException("No ABI list supplied.");
}
//创建一个Server端的Socket,socketname的值为“zygote”,用于等待AMS请求Zygote来创建新的应用程序进程;
registerZygoteSocket(socketName);
Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "ZygotePreload");
EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,
SystemClock.uptimeMillis());
//预加载类和资源;
preload();
EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,
SystemClock.uptimeMillis());
Trace.traceEnd(Trace.TRACE_TAG_DALVIK);
// Finish profiling the zygote initialization.
SamplingProfilerIntegration.writeZygoteSnapshot();
// Do an initial gc to clean up after startup
Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "PostZygoteInitGC");
gcAndFinalize();
Trace.traceEnd(Trace.TRACE_TAG_DALVIK);
Trace.traceEnd(Trace.TRACE_TAG_DALVIK);
// Disable tracing so that forked processes do not inherit stale tracing tags from
// Zygote.
Trace.setTracingEnabled(false);
// Zygote process unmounts root storage spaces.
Zygote.nativeUnmountStorageOnInit();
ZygoteHooks.stopZygoteNoThreadCreation();
if (startSystemServer) {
//启动SystemServer进程,Java层的系统服务线程将会由它启动起来
startSystemServer(abiList, socketName);
}
Log.i(TAG, "Accepting command socket connections");
//进入无限循环,在前面创建的Socket接口中等待ActivityManagerService请求,以创建新的应用程序进程;至于AMS如何与Zygote链接的等我分析AMS时再详细描述!
runSelectLoop(abiList);
closeServerSocket();
} catch (MethodAndArgsCaller caller) {
caller.run();
} catch (Throwable ex) {
Log.e(TAG, "Zygote died with exception", ex);
closeServerSocket();
throw ex;
}
}
ZygoteInit的main方法主要完成4件事情:
- 创建一个Server端的Socket;
- 预加载类和资源;
- 启动SystemServer进程;
- 等待AMS请求创建新的应用程序进程;
3.3 registerZygoteSocket方法
进入源码目录:~/LineageOS/frameworks/base/core/java/com/android/internal/os/ZygoteInit.java,查看其registerZygoteSocket方法:
/**
* Registers a server socket for zygote command connections
*
* @throws RuntimeException when open fails
*/
private static void registerZygoteSocket(String socketName) {
if (sServerSocket == null) {
int fileDesc;
//拼接Socket的名称,为"ANDROID_SOCKET_+zygote";
final String fullSocketName = ANDROID_SOCKET_PREFIX + socketName;
try {
//得到Socket的环境变量的值,将fullSocketName转换为环境变量的值;
String env = System.getenv(fullSocketName);
//将Socket环境变量的值转换为文件描述符的参数;
fileDesc = Integer.parseInt(env);
} catch (RuntimeException ex) {
throw new RuntimeException(fullSocketName + " unset or invalid", ex);
}
try {
//创建文件描述符
FileDescriptor fd = new FileDescriptor();
//传入此前转换的文件操作符参数;
fd.setInt$(fileDesc);
//创建服务器端Socket,并将文件操作符作为参数传进去;Zygote进程将SystemServer进程启动后,就会在这个服务器端的Socket上等待AMS请求Zygote进程来创建新的应用程序进程;
sServerSocket = new LocalServerSocket(fd);
} catch (IOException ex) {
throw new RuntimeException(
"Error binding to local socket '" + fileDesc + "'", ex);
}
}
}
Zygote进程将SystemServer进程启动后,就会在这个服务器端的Socket上等待AMS请求Zygote进程来创建新的应用程序进程;
3.4 启动SystemServer进程
进入源码目录:~/LineageOS/frameworks/base/core/java/com/android/internal/os/ZygoteInit.java,查看其startSystemServer方法:
/**
* Prepare the arguments and fork for the system server process.
*/
private static boolean startSystemServer(String abiList, String socketName)
throws MethodAndArgsCaller, RuntimeException {
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
);
/* Containers run without this capability, so avoid setting it in that case */
if (!SystemProperties.getBoolean(PROPERTY_RUNNING_IN_CONTAINER, false)) {
capabilities |= posixCapabilitiesAsBits(OsConstants.CAP_BLOCK_SUSPEND);
}
/* Hardcoded command line to start the system server */
//创建args数组,用来保存启动SystemServer的启动参数;其中可看到SystemServer进程的用户id和用户组id被设置为1000,并且拥有用户组1001-1010、1018、1021、1032、3001-3010的权限;进程名为system_server,启动的类名为:com.android.server.SystemServer;
String args[] = {
"--setuid=1000",
"--setgid=1000",
"--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1021,1032,3001,3002,3003,3006,3007,3009,3010",
"--capabilities=" + capabilities + "," + capabilities,
"--nice-name=system_server",
"--runtime-args",
"com.android.server.SystemServer",
};
ZygoteConnection.Arguments parsedArgs = null;
int pid;
try {
//将args数组封装成Arguments对象并提供给forkSystemServer使用;
parsedArgs = new ZygoteConnection.Arguments(args);
ZygoteConnection.applyDebuggerSystemProperty(parsedArgs);
ZygoteConnection.applyInvokeWithSystemProperty(parsedArgs);
/* Request to fork the system server process */
//调用ZygoteInit的forkSystemServer方法(native层调用的是nativeForkSystemServer方法,最终通过fork函数),创建一个子进程,也就是SystemServer进程;
pid = Zygote.forkSystemServer(
parsedArgs.uid, parsedArgs.gid,
parsedArgs.gids,
parsedArgs.debugFlags,
null,
parsedArgs.permittedCapabilities,
parsedArgs.effectiveCapabilities);
} catch (IllegalArgumentException ex) {
throw new RuntimeException(ex);
}
/* For child process */
//当前代码逻辑运行在子进程中;
if (pid == 0) {
if (hasSecondZygote(abiList)) {
waitForSecondaryZygote(socketName);
}
//处理SystemServer进程;
handleSystemServerProcess(parsedArgs);
}
return true;
}
这样就去启动SystemServer进程了,SystemServer进程的启动过程参考:cm-14.1 Android系统启动过程分析(6)-SystemServer进程启动过程。
3.5 runSelectLoop方法
进入源码目录:~/LineageOS/frameworks/base/core/java/com/android/internal/os/ZygoteInit.java,查看其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.
*
* @throws MethodAndArgsCaller in a child process when a main() should
* be executed.
*/
private static void runSelectLoop(String abiList) throws MethodAndArgsCaller {
ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>();
ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();
//sServerSocket即在registerZygoteSocket方法中创建的服务器端Socket,调用sServerSocket.getFileDescriptor()函数来获得该Socket的fd字段的值并添加到fd列表fds中;
fds.add(sServerSocket.getFileDescriptor());
peers.add(null);
//无限循环等待AMS请求Zygote进程创建新的应用程序进程;
while (true) {
StructPollfd[] pollFds = new StructPollfd[fds.size()];
//通过遍历fds存储的信息转移到pollFds数组中;
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.poll(pollFds, -1);
} catch (ErrnoException ex) {
throw new RuntimeException("poll failed", ex);
}
//对pollFds进行遍历,如果i==0说明服务器端Socket与客户端连接上了,也就是当前Zygote进程和AMS建立了连接;
for (int i = pollFds.length - 1; i >= 0; --i) {
if ((pollFds[i].revents & POLLIN) == 0) {
continue;
}
if (i == 0) {
//acceptCommandPeer方法得到ZygoteConnection类并添加到Socket连接列表peers中,然后将该ZygoteConnection的fd添加到fds中,以便可以接收到AMS发送过来的请求;
ZygoteConnection newPeer = acceptCommandPeer(abiList);
peers.add(newPeer);
fds.add(newPeer.getFileDesciptor());
} else {
//调用ZygoteConnection的runOnce函数来创建一个新的应用程序进程,并在成功创建后将这个连接从Socket连接列表peers和fd列表fds中清除;
boolean done = peers.get(i).runOnce();
if (done) {
peers.remove(i);
fds.remove(i);
}
}
}
}
}
3.6 Zygote进程启动总结
Zygote进程启动共做了以下几波操作:
- 创建AppRuntime并调用其start方法,启动Zygote进程;
- 创建Java虚拟机并为Java虚拟机注册JNI方法;
- 通过JNI调用ZygoteInit的main函数进入Zygote的Java框架层;
- 通过registerZygoteSocket方法创建服务器端Socket,并通过runSelectLoop方法等待AMS的请求来创建新的应用程序进程;
- 启动SystemServer进程;
4 Zygote背后的逻辑
读到这里你可能不禁要问:不就是启动一个新的 App 嘛,有必要搞得这么复杂吗?还真有必要!因为这样做有不少好处,还不止是在一个方面,这些好处体现在两个方面。
- 应用启动所需的时间会被大大缩短:
不论是哪个 App,所有的虚拟机都必须按照某种一样的而且是确定的方式初始化。加载 App 的类只不过是这个操作的最后一步罢了,但是这一操作产生的实际开销却主要是花在加载大量构成了 Android 各种丰富的框架的运行时类上的。如果你把 App 的加载想象成一场长跑赛,那么使用 Zygote 让 Android 可以在临近终点时才突然插进比赛,只用跑最后一个冲刺即可一一这样就省去了前面加载各种库的时间,耗时当然会相对短很多。 - 优化共享内存:
因为所有的虚拟机都是从 Zygote 这里 fork0出来的,所以它们无疑能够享受到由内核实现的内存共享的优势。特别是,尽管每个 app_process 的实例都有它自己的虚拟内存,但这些内存中的大部分是只读的(因为其中存放的是类的实现代码),在物理内存中只需保留一份,让各个进程共享就够了。而内存的其他部分 (存储的是类的数据,读写)也只要在绝对必要的时候才需要分配一些内存页来存储这些数据[这种技术叫“写时复制”(copy-on-write)]。因此,大多数 Android 应用都和其他应用(其中还包括system server,它是第一个真正的完整虚拟机的实例)共享了80%~90%的内存。这种被最大化了的内存使用方式,使得即使是在那些拥有物理内存相对较少的设备中仍可以“塞”进不少应用。这是 Zygote 特有的设计,这一设计使得它在Java跌倒的地方获得成功。
所有的虚拟机都是从 Zygote 这里 fork()出来的,这种优化也不是没有缺点:所有的应用都是从同一个进程fork()出来的,这会有效地破坏地址空间布局随机化(ASLR,Address)----而这一技术却又是对抗代码注入攻击的重要安全手段。换句话说,需求量大的战胜了需求量小的,对性能的渴求压倒了安全需求。
在使用ART(Android RunTime,Android 运行时)后,Zygote 甚至变得更有效了,因为所有预加载类也都已经经过预编译了。