一. Zygote 简介
Zygote英文为“受精卵”,它是Android系统中十分重要的进程。在Android中Zygote负责孵化新的进程,Android的应用程序进程都是通过zygote孵化启动。Linux 创建应用程序通过写时拷贝(copy on write),先调用fork 创建子进程,执行系统调用exec。而zygote 创建应用程序,只用了fork ,没有调用exec,因为Android应用执行的是java代码。zygote fork出子进程后,子进程只要装载APK文件中的字节码就可以运行了。
zygote通过共享系统库和资源大大加快了应用的启动速度。zygote 初始化时会创建虚拟机,同时把需要的系统库和资源文件加载到内存。zygote fork出子进程后,子进程已经有了各种系统资源,只要装载APK文件中的字节码就可以运行了。
二. Zygote 进程启动过程
1. 启动流程图
2. Init启动 app_process
Zygote进程实际是由app_process进程执行,app_process进程不仅可以启动Zygote,还可以启动其他系统进程。
1.)Init 启动app_process
init 启动 app_process进程服务
Zygote进程由用户的第一个进程Init进程以service的方式启动。在init.c 中则通过import的方式引入文件:import /init.${ro.zygote}.rc,其中ro.zygote 可能的取值:zygote32, zygote32_64, zygote64, zygote64_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 media
onrestart restart netd
2.)启动可执行文件时传递的参数格式
app_process 源码目录frameworks/base/cmds/app_process/app_main.cpp
启动app_process 需要传递一些参数,app_process启动参数格式:app_process [虚拟机参数] 运行目录 参数 [Java类]
虚拟机参数:以符号’-‘ 开头。启动dalvik 虚拟机时传递给虚拟机,用来区分要在虚拟机中运行的类是Zygote,还是在Zygote中运行的其他Android 应用程序。
运行目录:程序的运行目录,通常是/system/bin。(要运行的app_process程序所在的目录)
参数:以符号’—-‘ 开头。参数’--zygote’ 表示要启动zygote进程,参数’--application’ 表示要以普通进程的方式执行java 代码。
Java 类:将要执行的java 类,必须有一个静态方法main。使用参数’—-Zygote’ 时不会执行这个类,而是固定执行ZygoteInit类。
3. app_process main方法主要代码流程
1)创建AppRuntime对象,并保存参数。继承了系统的AndroidRuntime类。AndroidRuntime主要作用是创建和初始化虚拟机
int main(int argc, char* const argv[])
{
if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) < 0) {
if (errno != EINVAL) {
LOG_ALWAYS_FATAL(“PR_SET_NO_NEW_PRIVS failed: %s”, strerror(errno));
return 12;
}
}
AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv)); // 代码(1)
argc—;
argv++;
// As an exception to the above rule, anything in "spaced commands"
// goes to the vm even though it has a space in it.
const char* spaced_commands[] = { "-cp", "-classpath" };
// Allow "spaced commands" to be succeeded by exactly 1 argument (regardless of -s).
bool known_command = false;
int i;
for (i = 0; i < argc; i++) {
if (known_command == true) { //代码(2)
runtime.addOption(strdup(argv[i]));
// 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
ALOGV("app_process main add known option '%s'", argv[i]);
known_command = false;
continue;
}
for (int j = 0; j < static_cast<int>(sizeof(spaced_commands) / sizeof(spaced_commands[0])); ++j) {
if (strcmp(argv[i], spaced_commands[j]) == 0) {
known_command = true;
ALOGV("app_process main found known command '%s'", argv[i]);
}
}
if (argv[i][0] != ‘-‘) { //代码(3)
break;
}
if (argv[i][1] == ‘-‘ && argv[i][2] == 0) { //代码(4)
++i; //skip —-.
break;
}
runtime.addOption(strdup(argv[i])); //代码(5)
}
...
}
代码(1): 创建AppRuntime 对象
代码(2): 这段代码处理以上定义的app_process参数规则的例外情况。在spaced_commands 数组中保存的命令的参数会保存在AppRuntime中,同样会传给虚拟机。
代码(3): 表示如果参数的第一个字母 不是以’-’ 开头(以’-’ 开头表示是虚拟机参数) 结束循环,因为本循环目的是获取虚拟机参数并存储。
代码(4): 表示跳过前缀为"--"的参数。根据app_process参数的定义,前缀为"--"的是app_process启动运行参数
代码(5): 保存获取的参数到AppRuntime 对象中
以上代码主要创建AppRuntime对象,并解析传给app_process的参数,将和虚拟机相关的参数保存到AppRuntime对象中。
2.)解析app_process启动参数
...
// 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++];
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;
}
}
解析app_process启动使用的参数。如果启动的是zyogte进程,则strcmp(arg, “--zygote”) == 0,zygote = true ,并niceName固定设置为静态常量ZYGOTE_NICE_NAME。ZYGOTE_NICE_NAME值为zygote64或者zygote,根据不同的系统有不同的取值。niceName会被设置为虚拟机进程的名称。
3.) 解析准备传给ZygoteInit类或者RuntimeInit类的参数
Vector<String8> args;
if (!className.isEmpty()) { //说明启动的是非zygote 的java类
// 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);
if (!LOG_NDEBUG) {
String8 restOfArgs;
char* const* argv_new = argv + i;
int argc_new = argc - i;
for (int k = 0; k < argc_new; ++k) {
restOfArgs.append("\"");
restOfArgs.append(argv_new[k]);
restOfArgs.append("\" ");
}
ALOGV("Class name = %s, args = %s", className.string(), restOfArgs.string());
}
} else {// zygote 模式
// 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]));
}
}
如果启动的是zygote模式则className是空值。如果解析的参数中存在className,则说明启动的是非zygote的java类。
startSystemServer为true 则设置将“start-system-server”字符串加入到参数列表args中。
在zygote模式下,本段代码将“start-system-server”,abiFlag,以及所有剩余参数保存到容器args中,并最终会传给ZygoteInit的main方法。
4.) 设置进程名称
if (!niceName.isEmpty()) {
runtime.setArgv0(niceName.string(), true /* setProcName */);
}
将上面代码获取的niceName设置到AppRuntime中。最终将本进程名称设置为niceName指定的值。
5.) 启动ZygoteInit类
如果启动参数带有”--zygote“,执行ZygoteInit类。所以zygote进程最终执行的java类是ZygoteInit类。ZygoteInit类执行后会进入等待socket事件的无限循环,创建并启动新应用程序。
以下代码可以看到 app_process 除了可以启动Zygote进程,也可以使用它执行系统的Java类
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.");
}
由于ZygoteInit是java代码,所以AndroidRuntime类的start方法在执行ZygoteInit类之前需要做一件很重要的事,初始化整个Java运行环境。
4. AndroidRuntime类的start方法做了哪些事
1.) 启动虚拟机
void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote)
{
...
/* start the virtual machine */
JniInvocation jni_invocation;
jni_invocation.Init(NULL);
JNIEnv* env;
if (startVm(&mJavaVM, &env, zygote) != 0) {
return;
}
onVmCreated(env);
...
}
startVm方法中会根据传入的参数,创建虚拟机并启动虚拟机。如果返回0表示虚拟机创建成功,-1表示创建失败。
其中参数&env为JNIEnv类的接口指针(JNIEnv**),方便访问虚拟机。
2.)调用onVmCreated()
onVmCreated是虚函数,实际调用的是子类AppRuntime 中的重载函数
如果是zygote,则此方法直接返回,不做任何处理
virtual void onVmCreated(JNIEnv* env)
{
if (mClassName.isEmpty()) {
return; // Zygote. Nothing to do here.
}
/*
* This is a little awkward because the JNI FindClass call uses the
* class loader associated with the native method we're executing in.
* If called in onStarted (from RuntimeInit.finishInit because we're
* launching "am", for example), FindClass would see that we're calling
* from a boot class' native method, and so wouldn't look for the class
* we're trying to look up in CLASSPATH. Unfortunately it needs to,
* because the "am" classes are not boot classes.
*
* The easiest fix is to call FindClass here, early on before we start
* executing boot class Java code and thereby deny ourselves access to
* non-boot classes.
*/
char* slashClassName = toSlashClassName(mClassName.string());
mClass = env->FindClass(slashClassName);
if (mClass == NULL) {
ALOGE("ERROR: could not find class '%s'\n", mClassName.string());
}
free(slashClassName);
mClass = reinterpret_cast<jclass>(env->NewGlobalRef(mClass));
}
3.) 注册android系统的JNI函数
/*
* Register android functions.
*/
if (startReg(env) < 0) {
ALOGE("Unable to register all android natives\n");
return;
}
startReg通过调用register_jni_procs() 函数将全局数组gRegJNI中的JNI本地函数注册到虚拟机中。
/*AndroidRuntime 全局数组*/
static const RegJNIRec gRegJNI[] = {
REG_JNI(register_com_android_internal_os_RuntimeInit),
REG_JNI(register_com_android_internal_os_ZygoteInit_nativeZygoteInit),
REG_JNI(register_android_os_SystemClock),
REG_JNI(register_android_util_EventLog),
REG_JNI(register_android_util_Log),
REG_JNI(register_android_util_MemoryIntArray),
REG_JNI(register_android_util_PathParser),
REG_JNI(register_android_util_StatsLog),
REG_JNI(register_android_util_StatsLogInternal),
REG_JNI(register_android_app_admin_SecurityLog),
REG_JNI(register_android_content_AssetManager),
....
}
4.) 准备调用Java类的main函数的参数
/*
* 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
strArray = env->NewObjectArray(options.size() + 1, stringClass, NULL);
assert(strArray != NULL);
classNameStr = env->NewStringUTF(className);
assert(classNameStr != NULL);
// 将classNameStr字符串设置到数组里,即传递过来的参数“com.android.internal.os.ZygoteInit”
env->SetObjectArrayElement(strArray, 0, classNameStr);
// 将传递过来的参数列表中的剩下的参数全部设置到strArray数组中
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);
}
如果当前启动的是zygote,那么strArray数组中设置的classNameStr为“com.android.internal.os.ZygoteInit”,其他为app_process解析后传入start方法中的,如“--abi-list=xxx”,“start-system-server”等。
5.)调用ZygoteInit的main方法
/*
* Start VM. This thread becomes the main thread of the VM, and will
* not return until the VM exits.
*/
char* slashClassName = toSlashClassName(className != NULL ? className : "");
jclass startClass = env->FindClass(slashClassName);
if (startClass == NULL) {
ALOGE("JavaVM unable to locate class '%s'\n", slashClassName);
/* keep going */
} else {
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 {
env->CallStaticVoidMethod(startClass, startMeth, strArray);
#if 0
if (env->ExceptionCheck())
threadExitUncaughtException(env);
#endif
}
}
toSlashClassName的作用是将类名中的’.’ 替换成’/'。先通过env->FindClass(slashClassName),找到系统中加载的ZygoteInit类。然后找到main方法的jmethodID,如果不为空,则执行ZygoteInit类的main方法,并将数组strArray作为main函数的参数传入ZygoteInit中。至此,Zygote的初始化过程将转到java层代码。
总结,zygote进程中,AndroidRuntime的start方法主要工作:创建启动虚拟机,注册系统JNI,执行ZygoteInit类的main方法,进入java运行环境。
5. ZygoteInit类main方法的执行过程
ZygoteInit main 方法主要工作有以下几个方面:
1.)解析传递给main函数调用的参数
2.)加载加载Android Application Framework 使用的类与资源
// 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();
}
正常情况下enableLazyPreload为false,调用preload方法。在preload方法中加载类和资源。分别会调用preloadClasses()和preloadResources()方法。
下面是preload方法主要代码。
static void preload(TimingsTraceLog bootTimingsTraceLog) {
...
preloadClasses();
...
preloadResources();
...
nativePreloadAppProcessHALs();
...
maybePreloadGraphicsDriver();
...
preloadSharedLibraries();
preloadTextResources();
// Ask the WebViewFactory to do any initialization that must run in the zygote process,
// for memory sharing purposes.
WebViewFactory.prepareWebViewInZygote();
endPreload();
...
}
preloadClasses方法加载类到虚拟机。Android将所有需要预加载的Java类存放在文本文件"preload-classes"中。PRELOADED_CLASSES=“/system/etc/preloaded-classes”。preloadClasses主要工作:读取preload-classes文件,使用Class.forName加载类。
private static void preloadClasses() {
final VMRuntime runtime = VMRuntime.getRuntime();
InputStream is;
try {
is = new FileInputStream(PRELOADED_CLASSES);
} catch (FileNotFoundException e) {
Log.e(TAG, "Couldn't find " + PRELOADED_CLASSES + ".");
return;
}
...
try {
BufferedReader br = new BufferedReader(new InputStreamReader(is), Zygote.SOCKET_BUFFER_SIZE);
int count = 0;
String line;
while ((line = br.readLine()) != null) {
// Skip comments and blank lines.
line = line.trim();
if (line.startsWith("#") || line.equals("")) {
continue;
}
Trace.traceBegin(Trace.TRACE_TAG_DALVIK, line);
try {
if (false) {
Log.v(TAG, "Preloading " + line + "...");
}
// Load and explicitly initialize the given class. Use
// Class.forName(String, boolean, ClassLoader) to avoid repeated stack lookups
// (to derive the caller's class-loader). Use true to force initialization, and
// null for the boot classpath class-loader (could as well cache the
// class-loader of this class in a variable).
Class.forName(line, true, null);
count++;
} catch (ClassNotFoundException e) {
...
}
...
} finally {
IoUtils.closeQuietly(is);
// Restore default.
runtime.setTargetHeapUtilization(defaultUtilization);
// Fill in dex caches with classes, fields, and methods brought in by preloading.
Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "PreloadDexCaches");
runtime.preloadDexCaches();
Trace.traceEnd(Trace.TRACE_TAG_DALVIK);
// Bring back root. We'll need it later if we're in the zygote.
if (droppedPriviliges) {
try {
Os.setreuid(ROOT_UID, ROOT_UID);
Os.setregid(ROOT_GID, ROOT_GID);
} catch (ErrnoException ex) {
throw new RuntimeException("Failed to restore root", ex);
}
}
}
}
preloadResources加载系统资源
private static void preloadResources() {
final VMRuntime runtime = VMRuntime.getRuntime();
try {
mResources = Resources.getSystem();
mResources.startPreloading();
if (PRELOAD_RESOURCES) {
...
TypedArray ar = mResources.obtainTypedArray(com.android.internal.R.array.preloaded_drawables);
int N = preloadDrawables(ar);
ar.recycle();
...
ar = mResources.obtainTypedArray(com.android.internal.R.array.preloaded_color_state_lists);
N = preloadColorStateLists(ar);
ar.recycle();
Log.i(TAG, "...preloaded " + N + " resources in " + (SystemClock.uptimeMillis() - startTime) + "ms.");
if (mResources.getBoolean(com.android.internal.R.bool.config_freeformWindowManagement)) {
startTime = SystemClock.uptimeMillis();
ar = mResources.obtainTypedArray(com.android.internal.R.array.preloaded_freeform_multi_window_drawables);
N = preloadDrawables(ar);
ar.recycle();
Log.i(TAG, "...preloaded " + N + " resource in " + (SystemClock.uptimeMillis() - startTime) + "ms.");
}
}
mResources.finishPreloading();
} catch (RuntimeException e) {
Log.w(TAG, "Failure preloading resources", e);
}
}
通过preloadDrawables和preloadColorStateLists加载了Framework的drawable资源和状态颜色定义资源。
除了类和资源之外preload方法还加载共享库preloadSharedLibraries,文本资源preloadTextResources,WebViewFactory初始化工作等。
3.) 创建Zygote的LocalServerSocket,用于接收启动应用程序的消息。
...
Zygote.initNativeState(isPrimaryZygote);
ZygoteHooks.stopZygoteNoThreadCreation();
zygoteServer = new ZygoteServer(isPrimaryZygote);
...
在ZygoteServer构造方法中调用Zygote.createManagedSocketFromInitSocket方法创建LocalServerSocket,并将其保存在变量mZygoteSocket中。
以下是ZygoteServer的构造方法
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);
}
fetchUsapPoolPolicyProps();
mUsapPoolSupported = true;
}
以下是Zygote.createManagedSocketFromInitSocket方法代码,在这里获取系统中的文件描述符,绑定套接字生成LocalServerSocket对象。用于接收socket信息。
static LocalServerSocket createManagedSocketFromInitSocket(String socketName) {
int fileDesc;
final String fullSocketName = ANDROID_SOCKET_PREFIX + socketName;
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);
}
}
4.)调用forkSystemServer启动SystemServer进程
...
if (startSystemServer) {
Runnable r = forkSystemServer(abiList, zygoteSocketName, zygoteServer);
// {@code r == null} in the parent (zygote) process, and {@code r != null} in the
// child (system_server) process.
if (r != null) {
r.run();
return;
}
}
...
forkSystemServer方法调用了Zygote.forkSystemServer方法,而Zygote.forkSystemServer最终调用native方法nativeForkSystemServer来启动SystemServer进程。forkSystemServer方法返回一个Runnable 对象,如果当前是父进程则r为空。如果是子进程,则运行r.run();
4.调用runSelectLoop方法,进入监听和接收消息的循环。
....
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.
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类main函数的的最后,调用zygoteServer.runSelectLoop(abiList) 方法,zygote进入监听和处理启动应用程序的请求循环。如果当前是zygote进程,则循环永不退出,zygoteServer.runSelectLoop(abiList) 永不返回,一直处于无限循环中,如果是zygote fork出的子进程,zygoteServer.runSelectLoop(abiList) 返回后caller 不为空,最后执行caller的run方法。
至此,Zygote进程启动完成,接下来等待启动应用程序的请求,fork出应用程序进程并启动。
三. Zygote 启动应用程序
zygote 如何启动应用程序的?
1.)发送启动信息给zygote
Android 启动一个新进程是通过ActivityManagerService中调用startProcessLocket方法完成的。startProcessLocket准备好参数后,最终调用Process类的start方法。start方法调用ZygoteProcess类的startViaZygote方法。如下代码:
startResult = Process.start(entryPoint,
app.processName, uid, uid, gids, runtimeFlags, mountExternal,
app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,
app.info.dataDir, invokeWith, app.info.packageName,
new String[] {PROC_START_SEQ_IDENT + app.startSeq});
private Process.ProcessStartResult startViaZygote(@NonNull final String processClass,
@Nullable final String niceName,
final int uid, final int gid,
@Nullable final int[] gids,
int runtimeFlags, int mountExternal,
int targetSdkVersion,
@Nullable String seInfo,
@NonNull String abi,
@Nullable String instructionSet,
@Nullable String appDataDir,
@Nullable String invokeWith,
boolean startChildZygote,
@Nullable String packageName,
boolean useUsapPool,
@Nullable String[] extraArgs)
throws ZygoteStartFailedEx {
ArrayList<String> argsForZygote = new ArrayList<>();
// --runtime-args, --setuid=, --setgid=,
// and --setgroups= must go first
argsForZygote.add("--runtime-args");
argsForZygote.add("--setuid=" + uid);
argsForZygote.add("--setgid=" + gid);
argsForZygote.add("--runtime-flags=" + runtimeFlags);
if (mountExternal == Zygote.MOUNT_EXTERNAL_DEFAULT) {
argsForZygote.add("--mount-external-default");
} else if (mountExternal == Zygote.MOUNT_EXTERNAL_READ) {
argsForZygote.add("--mount-external-read");
} else if (mountExternal == Zygote.MOUNT_EXTERNAL_WRITE) {
argsForZygote.add("--mount-external-write");
} else if (mountExternal == Zygote.MOUNT_EXTERNAL_FULL) {
argsForZygote.add("--mount-external-full");
} else if (mountExternal == Zygote.MOUNT_EXTERNAL_INSTALLER) {
argsForZygote.add("--mount-external-installer");
} else if (mountExternal == Zygote.MOUNT_EXTERNAL_LEGACY) {
argsForZygote.add("--mount-external-legacy");
}
argsForZygote.add("--target-sdk-version=" + targetSdkVersion);
// --setgroups is a comma-separated list
if (gids != null && gids.length > 0) {
StringBuilder sb = new StringBuilder();
sb.append("--setgroups=");
int sz = gids.length;
for (int i = 0; i < sz; i++) {
if (i != 0) {
sb.append(',');
}
sb.append(gids[i]);
}
argsForZygote.add(sb.toString());
}
if (niceName != null) {
argsForZygote.add("--nice-name=" + niceName);
}
if (seInfo != null) {
argsForZygote.add("--seinfo=" + seInfo);
}
if (instructionSet != null) {
argsForZygote.add("--instruction-set=" + instructionSet);
}
if (appDataDir != null) {
argsForZygote.add("--app-data-dir=" + appDataDir);
}
if (invokeWith != null) {
argsForZygote.add("--invoke-with");
argsForZygote.add(invokeWith);
}
if (startChildZygote) {
argsForZygote.add("--start-child-zygote");
}
if (packageName != null) {
argsForZygote.add("--package-name=" + packageName);
}
argsForZygote.add(processClass);
if (extraArgs != null) {
Collections.addAll(argsForZygote, extraArgs);
}
synchronized(mLock) {
// The USAP pool can not be used if the application will not use the systems graphics
// driver. If that driver is requested use the Zygote application start path.
return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi), useUsapPool, argsForZygote);
}
}
zygoteSendArgsAndGetResult第一个参数调用openZygoteSocketIfNeeded方法,并返回ZygoteState对象,openZygoteSocketIfNeeded方法最终通过ZygoteState.connect创建链接用于通信的LocalSocket,并保存于primaryZygoteState类中,这个primaryZygoteState会被openZygoteSocketIfNeeded方法返回给zygoteSendArgsAndGetResult作为一个参数。
private void attemptConnectionToPrimaryZygote() throws IOException {
if (primaryZygoteState == null || primaryZygoteState.isClosed()) {
primaryZygoteState = ZygoteState.connect(mZygoteSocketAddress, mUsapPoolSocketAddress);
maybeSetApiBlacklistExemptions(primaryZygoteState, false);
maybeSetHiddenApiAccessLogSampleRate(primaryZygoteState);
maybeSetHiddenApiAccessStatslogSampleRate(primaryZygoteState);
}
}
//创建socket代码
static ZygoteState connect(@NonNull LocalSocketAddress zygoteSocketAddress, @Nullable LocalSocketAddress usapSocketAddress) throws IOException {
DataInputStream zygoteInputStream;
BufferedWriter zygoteOutputWriter;
final LocalSocket zygoteSessionSocket = new LocalSocket();
if (zygoteSocketAddress == null) {
throw new IllegalArgumentException("zygoteSocketAddress can't be null");
}
try {
zygoteSessionSocket.connect(zygoteSocketAddress);
zygoteInputStream = new DataInputStream(zygoteSessionSocket.getInputStream());
zygoteOutputWriter = new BufferedWriter(new OutputStreamWriter(zygoteSessionSocket.getOutputStream()),
Zygote.SOCKET_BUFFER_SIZE);
} catch (IOException ex) {
try {
zygoteSessionSocket.close();
} catch (IOException ignore) { }
throw ex;
}
return new ZygoteState(zygoteSocketAddress, usapSocketAddress, zygoteSessionSocket, zygoteInputStream, zygoteOutputWriter, getAbiList(zygoteOutputWriter, zygoteInputStream));
}
// 创建socket 地址代码
public ZygoteProcess() {
mZygoteSocketAddress =
new LocalSocketAddress(Zygote.PRIMARY_SOCKET_NAME, LocalSocketAddress.Namespace.RESERVED);
...
}
zygoteSendArgsAndGetResult方法内部会调用attemptZygoteSendArgsAndGetResult,在这个方法中将参数写入到前面创建的LocalSocket中。这时就将信息发送给了zygote。
private Process.ProcessStartResult attemptZygoteSendArgsAndGetResult(ZygoteState zygoteState, String msgStr) throws ZygoteStartFailedEx {
try {
final BufferedWriter zygoteWriter = zygoteState.mZygoteOutputWriter;
final DataInputStream zygoteInputStream = zygoteState.mZygoteInputStream;
zygoteWriter.write(msgStr);
zygoteWriter.flush();
// Always read the entire result from the input stream to avoid leaving
// bytes in the stream for future process starts to accidentally stumble
// upon.
Process.ProcessStartResult result = new Process.ProcessStartResult();
result.pid = zygoteInputStream.readInt();
result.usingWrapper = zygoteInputStream.readBoolean();
if (result.pid < 0) {
throw new ZygoteStartFailedEx("fork() failed");
}
return result;
} catch (IOException ex) {
zygoteState.close();
Log.e(LOG_TAG, "IO Exception while communicating with Zygote - " + ex.toString());
throw new ZygoteStartFailedEx(ex);
}
}
2.)zygote进程处理启动请求
首先在zygoteServer.runSelectLoop方法中监听Socket请求,在acceptCommandPeer方法中等待socket链接,并生成ZygoteConnection
/**
* 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<FileDescriptor> socketFDs = new ArrayList<FileDescriptor>();
ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();
socketFDs.add(mZygoteSocket.getFileDescriptor());
peers.add(null);
while (true) {
fetchUsapPoolPolicyPropsWithMinInterval();
int[] usapPipeFDs = null;
StructPollfd[] pollFDs = null;
...
/*
* For reasons of correctness the USAP pool pipe and event FDs
* must be processed before the session and server sockets. This
* is to ensure that the USAP pool accounting information is
* accurate when handling other requests like API blacklist
* exemptions.
*/
int pollIndex = 0;
for (FileDescriptor socketFD : socketFDs) {
pollFDs[pollIndex] = new StructPollfd();
pollFDs[pollIndex].fd = socketFD;
pollFDs[pollIndex].events = (short) POLLIN;
++pollIndex;
}
final int usapPoolEventFDIndex = pollIndex;
...
boolean usapPoolFDRead = false;
while (--pollIndex >= 0) {
if ((pollFDs[pollIndex].revents & POLLIN) == 0) {
continue;
}
if (pollIndex == 0) {
// Zygote server socket
ZygoteConnection newPeer = acceptCommandPeer(abiList);
peers.add(newPeer);
socketFDs.add(newPeer.getFileDescriptor());
} else if (pollIndex < usapPoolEventFDIndex) {
// Session socket accepted from the Zygote server socket
try {
ZygoteConnection connection = peers.get(pollIndex);
final Runnable command = connection.processOneCommand(this);
// TODO (chriswailes): Is this extra check necessary?
if (mIsForkChild) {
// We're in the child. We should always have a command to run at this
// stage if processOneCommand hasn't called "exec".
if (command == null) {
throw new IllegalStateException("command == null");
}
return command;
} else {
// We're in the server - we should never have any commands to run.
if (command != null) {
throw new IllegalStateException("command != null");
}
// We don't know whether the remote side of the socket was closed or
// not until we attempt to read from it from processOneCommand. This
// shows up as a regular POLLIN event in our regular processing loop.
if (connection.isClosedByPeer()) {
connection.closeSocket();
peers.remove(pollIndex);
socketFDs.remove(pollIndex);
}
}
} catch (Exception e) {
if (!mIsForkChild) {
// We're in the server so any exception here is one that has taken place
// pre-fork while processing commands or reading / writing from the
// control socket. Make a loud noise about any such exceptions so that
// we know exactly what failed and why.
Slog.e(TAG, "Exception executing zygote command: ", e);
// Make sure the socket is closed so that the other end knows
// immediately that something has gone wrong and doesn't time out
// waiting for a response.
ZygoteConnection conn = peers.remove(pollIndex);
conn.closeSocket();
socketFDs.remove(pollIndex);
} else {
// We're in the child so any exception caught here has happened post
// fork and before we execute ActivityThread.main (or any other main()
// method). Log the details of the exception and bring down the process.
Log.e(TAG, "Caught post-fork exception in child process.", e);
throw e;
}
} finally {
// Reset the child flag, in the event that the child process is a child-
// zygote. The flag will not be consulted this loop pass after the Runnable
// is returned.
mIsForkChild = false;
}
} else {
// Either the USAP pool event FD or a USAP reporting pipe.
... }
}
...
}
}
调用mZygoteSocket.accept()直到有socket 链接请求进入,然后唤醒进程创建ZygoteConnection类,这个类保存了读写socket的流。
调用acceptCommandPeer来和客户端建立一个socket链接。然后把这个socket加入监听数组中,等待这个socket上的命令的到来。
/**
* Waits for and accepts a single command connection. Throws
* RuntimeException on failure.
*/
private ZygoteConnection acceptCommandPeer(String abiList) {
try {
return createNewConnection(mZygoteSocket.accept(), abiList);
} catch (IOException ex) {
throw new RuntimeException("IOException during accept()", ex);
}
}
protected ZygoteConnection createNewConnection(LocalSocket socket, String abiList) throws IOException {
return new ZygoteConnection(socket, abiList);
}
当socket接收到数据后会执行ZygoteConnection类的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.
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.
if (args == null) {
isEof = true;
return null;
}
int pid = -1;
FileDescriptor childPipeFd = null;
FileDescriptor serverPipeFd = null;
parsedArgs = new ZygoteArguments(args);
...
Zygote.applyUidSecurityPolicy(parsedArgs, peer);
Zygote.applyInvokeWithSecurityPolicy(parsedArgs, peer);
Zygote.applyDebuggerSystemProperty(parsedArgs);
Zygote.applyInvokeWithSystemProperty(parsedArgs);
...
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();
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.
IoUtils.closeQuietly(childPipeFd);
childPipeFd = null;
handleParentProc(pid, descriptors, serverPipeFd);
return null;
}
} finally {
IoUtils.closeQuietly(childPipeFd);
IoUtils.closeQuietly(serverPipeFd);
}
}
processOneCommand首先调用Zygote.readArgumentList(mSocketReader),读取参数行,并按照格式解析出来保存到args数组中。再参数进行检查。
检查无误后调用Zygote.forkAndSpecialize方法fork子进程。在Zygote.forkAndSpecialize方法中调用native方法nativeForkAndSpecialize来完成fork工作。
fork 出子进程后,调用handleChildProc方法完成子进程的初始化工作。
handleChildProc关闭监听socket和从Zygote中继承的文件描述符,设置进程名称,成功则返回Runnable对象。注意当前是子进程则pid==0 调用handleChildProc,当前是zygote进程则pid 不为0,调用handleParentProc方法。也就是当运行完fork之后,代码会分别运行2个分支,子进程执行pid == 0 分支,zygote进程执行else分支。
handleChildProc最终调用RuntimeInit类的findStaticMain方法。
/**
* Invokes a static "main(argv[]) method on class "className".
* Converts various failing exceptions into RuntimeExceptions, with
* the assumption that they will then cause the VM instance to exit.
*
* @param className Fully-qualified class name
* @param argv Argument vector for main()
* @param classLoader the classLoader to load {@className} with
*/
protected static Runnable findStaticMain(String className, String[] argv, ClassLoader classLoader) {
Class<?> cl;
try {
cl = Class.forName(className, true, classLoader);
} catch (ClassNotFoundException ex) {
throw new RuntimeException("Missing class when invoking static main " + className, ex);
}
Method m;
try {
m = cl.getMethod("main", new Class[] { String[].class });
} catch (NoSuchMethodException ex) {
throw new RuntimeException("Missing static main on " + className, ex);
} catch (SecurityException ex) {
throw new RuntimeException("Problem getting static main on " + className, ex);
}
int modifiers = m.getModifiers();
if (! (Modifier.isStatic(modifiers) && Modifier.isPublic(modifiers))) {
throw new RuntimeException("Main method is not public and static on " + className);
}
/*
* This throw gets caught in ZygoteInit.main(), which responds
* by invoking the exception's run() method. This arrangement
* clears up all the stack frames that were required in setting
* up the process.
*/
return new MethodAndArgsCaller(m, argv);
}
findStaticMain方法首先加载子进程要启动的java类到虚拟机中。然后找到该类的main方法的Method对象m。再将m和解析的参数argv以参数的形式传递给生成的MethodAndArgsCaller类的对象,MethodAndArgsCaller是Runnable子类。
子进程最终从zygoteServer.runSelectLoop方法的无限循环中退出后,执行caller.run()进入子进程运行换行
// loops forever in the 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();
}
调用caller.run()其实调用的是子类MethodAndArgsCaller的run方法
public void run() {
try {
mMethod.invoke(null, new Object[] { mArgs });
} catch (IllegalAccessException ex) {
throw new RuntimeException(ex);
} catch (InvocationTargetException ex) {
Throwable cause = ex.getCause();
if (cause instanceof RuntimeException) {
throw (RuntimeException) cause;
} else if (cause instanceof Error) {
throw (Error) cause;
}
throw new RuntimeException(ex);
}
}
在caller.run方法中只是执行了前面传入的main方法的Method对象。这才开始真正调用ActivityThread的main方法。
至此zygote启动应用程序完成,应用进入其本身的启动流程。
总结:
流程图
-
监听socket等待处理socket链接请求
-
处理socket请求,解析参数
-
fork子进程,将应用程序的启动类加载到子进程中,并执行main方法
四. 源代码路径
以上代码基于Android10.0源码
app_process:frameworks/base/cmds/app_process/app_main.cpp
AndroidRuntime:frameworks/base/core/jni/AndroidRuntime.cpp
ActivityManagerServic:frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
ZygoteProcess:frameworks/base/core/java/android/os/ZygoteProcess.java
ZygoteInit:frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
ZygoteConnection: frameworks/base/core/java/com/android/internal/os/ZygoteConnection.java