Zygote进程分析
zygote的启动流程
从init的启动流程中得知,init进程会通过解析init.rc文件执行tigger中的nonecrypted 找到文件对应的main方法。具体文件名称为:/framework/base/cmds/app_process/app_main.cpp
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());
}
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.
//
// 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) {
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] != '-') {
break;
}
if (argv[i][1] == '-' && argv[i][2] == 0) {
++i; // Skip --.
break;
}
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 option '%s'", argv[i]);
}
// Parse runtime arguments. Stop at first unrecognized option.
//如果zygote为true则代表即将创建该进程
//如果startSystemServer为true则代表创建zygote时也会创建systemServer
//系统正常启动都会将这两个boolean 默认给到true
//init.zygote32.rc 启动zygote服务的指令行:service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
//因为rc文件启动main后携带了--zygote --start-system-server 这两个参数
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; //将zygote变量设置为true,名称是:zygote
niceName = ZYGOTE_NICE_NAME;
} else if (strcmp(arg, "--start-system-server") == 0) {
startSystemServer = true; //将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);
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 {
// We're in zygote mode.
//进入创建zygote模式
//创建/data/dalvik-cache,为后续会创建Dalvik虚拟机做准备
maybeCreateDalvikCache();
//将"start-system-server"放入启动的参数args中
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.
//将所有剩余参数传递给args,例如application或tool或start-system-server或abi
//这些启动参数将会传递到其他进程中,后续取出参数决定是否启动systemServer等操作
for (; i < argc; ++i) {
args.add(String8(argv[i]));
}
}
if (!niceName.isEmpty()) {
runtime.setArgv0(niceName.string(), true /* setProcName */);
}
//zygote变量为true,将创建zygote,该args启动参数会包含start-system-server
//调用runntime(AppRunntime)的start来启动zygote,将args传入,因为args包含了启动systemServer的标志
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.");
}
}
从代码中得知,app_main.cpp的main方法先解析init.zygote32.rc携带的参数service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server 根据参数 --zygote --start-system-server 值来判断是否创建zygote 同时创建systemserver。通过通过调用runtime.start方法来启动zygote。通过代码得知runtime类是 AppRuntime,并没有start但是AppRuntime的父类AndroidRuntime有start方法,所以得知在app_main.cpp文件里面调用的是AndroidRuntime的start方法。代码路径:\frameworks\base\core\java\com\android\internal\os/ZygoteInit.java 代码如下:
void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote)
{
ALOGD(">>>>>> START %s uid %d <<<<<<\n",
className != NULL ? className : "(unknown)", getuid());
//默认会启动systemServer
static const String8 startSystemServer("start-system-server");
// Whether this is the primary zygote, meaning the zygote which will fork system server.
//是否私有,如果systemServer会被创建时,将设置为私有
bool primary_zygote = false;
/*
* '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) {
//options就是传递过来的args,默认是包含了start-system-server
if (options[i] == startSystemServer) {
primary_zygote = true;
/* 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)));
}
}
//获取环境变量,这里第一次执行时默认为空,所以rootDir不存在
// 将直接拿到/system作为rootDir并设置环境变量
const char* rootDir = getenv("ANDROID_ROOT");
if (rootDir == NULL) {
rootDir = "/system";
if (!hasDir("/system")) {
LOG_FATAL("No root directory specified, and /system does not exist.");
return;
}
setenv("ANDROID_ROOT", rootDir, 1);
}
const char* artRootDir = getenv("ANDROID_ART_ROOT");
if (artRootDir == NULL) {
LOG_FATAL("No ART directory specified with ANDROID_ART_ROOT environment variable.");
return;
}
const char* i18nRootDir = getenv("ANDROID_I18N_ROOT");
if (i18nRootDir == NULL) {
LOG_FATAL("No runtime directory specified with ANDROID_I18N_ROOT environment variable.");
return;
}
const char* tzdataRootDir = getenv("ANDROID_TZDATA_ROOT");
if (tzdataRootDir == NULL) {
LOG_FATAL("No tz data directory specified with ANDROID_TZDATA_ROOT environment variable.");
return;
}
//const char* kernelHack = getenv("LD_ASSUME_KERNEL");
//ALOGD("Found LD_ASSUME_KERNEL='%s'\n", kernelHack);
/* start the virtual machine */
//这里就开始启动虚拟机了
//jni功能初始化
JniInvocation jni_invocation;
jni_invocation.Init(NULL);
JNIEnv* env;
//创建dalvik虚拟机 ,虚拟机运行在进程里面,虚拟机这块代码实现了内存管理这个功能
//进程是程序运行的最小的内存空间
if (startVm(&mJavaVM, &env, zygote, primary_zygote) != 0) {
return;
}
onVmCreated(env);
/*
* Register android functions.
*/
//调用startReg函数用来为dvm注册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;
//通过反射拿到string类型
stringClass = env->FindClass("java/lang/String");
assert(stringClass != NULL);
//options就是app_main.cpp传递过来的args,包含start-system-server
//将options转换为array list对象
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);
//将数据转换给java 类型的array数组
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.
*/
//启动com.android.internal.os.ZygoteInit,该线程为jvm的主进程,在vm退出之前不会返回
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 {
//通过反射的方式,找到zygoteInit的main函数
// 若获取到内容则执行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 {
// 通过JNI调用ZygoteInit的main函数,将args(strArray)传递到java层
// 因为ZygoteInit的main函数是Java编写的,因此需要通过JNI调用
// 所以这里继续跟到java层面:ZygoteInit.java
env->CallStaticVoidMethod(startClass, startMeth, strArray);
#if 0
if (env->ExceptionCheck())
threadExitUncaughtException(env);
#endif
}
}
// 若执行到这里,则会结束zygote创建,关闭jvm,释放字符串所占空间
free(slashClassName);
//虚拟机崩溃或退出的时候才会执行到这里
ALOGD("Shutting down VM\n");
//将当前线程从虚拟机可见的线程集中分离
if (mJavaVM->DetachCurrentThread() != JNI_OK)
ALOGW("Warning: unable to detach main thread\n");
if (mJavaVM->DestroyJavaVM() != 0)//销毁前面创建额jvm
ALOGW("Warning: VM did not shut down cleanly\n");
}
从代码中得知,start方法主要做了:启动虚拟机,注册jni,通过反射的方法找到zygoteInit类的main方法去创建systemServer,创建完成后关闭虚拟机释放字符串所占空间。所以我们先来看zygoteInit的main方法里面做了哪些事情:代码如下:
@UnsupportedAppUsage
public static void main(String[] argv) {
ZygoteServer zygoteServer = null;
// Mark zygote start. This ensures that thread creation will throw
// an error.
//调用native函数,功能是确保此时没有其他线程启动
ZygoteHooks.startZygoteNoThreadCreation();
// Zygote goes into its own process group.
try {
//设置zygote自己的用户组pid
Os.setpgid(0, 0);
} catch (ErrnoException ex) {
throw new RuntimeException("Failed to setpgid(0,0)", ex);
}
Runnable caller;
try {
//读取系统是否已经启动完成
// Store now for StatsLogging later.
//系统启动到现在的时间,包含设备深度休眠的时间
final long startTime = SystemClock.elapsedRealtime();
//该属性值在设备物理重启时为空,reboot重启后为1
final boolean isRuntimeRestarted = "1".equals(
SystemProperties.get("sys.boot_completed"));
//将行为写入trace log 标记目前正处于ZygoteInit阶段 ,设置boot时间打印log
String bootTimeTag = Process.is64Bit() ? "Zygote64Timing" : "Zygote32Timing";
//通过systrace来追踪
TimingsTraceLog bootTimingsTraceLog = new TimingsTraceLog(bootTimeTag,
Trace.TRACE_TAG_DALVIK);
//追踪开始,每个traceBegin()对应一个traceEnd()
bootTimingsTraceLog.traceBegin("ZygoteInit");
//使能DDMS,注册所有已知的Java vm 的处理块的监听器
//线程监听、内存监听、native堆内存监听、debug模式监听
RuntimeInit.preForkInit();
boolean startSystemServer = false;
//zygote进程就是一个socket,名称就叫做zygote
String zygoteSocketName = "zygote";
String abiList = null;
boolean enableLazyPreload = false;
for (int i = 1; i < argv.length; i++) {
//从AndroidRuntime.cpp中传递上来,已经包含了start-system-server
//所以startSystemServer= true
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]);
}
}
//为true,是私有zygote
final boolean isPrimaryZygote = zygoteSocketName.equals(Zygote.PRIMARY_SOCKET_NAME);
if (!isRuntimeRestarted) {
if (isPrimaryZygote) {
FrameworkStatsLog.write(FrameworkStatsLog.BOOT_TIME_EVENT_ELAPSED_TIME_REPORTED,
BOOT_TIME_EVENT_ELAPSED_TIME__EVENT__ZYGOTE_INIT_START,
startTime);
} 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.");
}
// 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());
//预加载
//这里的预加载是指将java类、资源文件、图像资源等公共资源在zygote启动的时候就进行加载。
//这样一来,根据fork的copy-on-write机制,其他由zygote fork出来的进程在使用这些资源的时候就不需要
//再次加载了,而是直接使用。所以这是一种牺牲系统开机时间,来提高系统应用运行时的运行效率的手段
preload(bootTimingsTraceLog);
EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,
SystemClock.uptimeMillis());
bootTimingsTraceLog.traceEnd(); // ZygotePreload
}
// Do an initial gc to clean up after startup
bootTimingsTraceLog.traceBegin("PostZygoteInitGC");
gcAndFinalize();
bootTimingsTraceLog.traceEnd(); // PostZygoteInitGC
bootTimingsTraceLog.traceEnd(); // ZygoteInit
//初始化socket,从环境中获取套接字FD(ANDROID_SOCKET_ZYGOTE)
//若获取不到则创建一个用于和systemServer通信的socket,当systemServer fork出来后socket进程将关闭
Zygote.initNativeState(isPrimaryZygote);
ZygoteHooks.stopZygoteNoThreadCreation();
//根据环境变量(LocalServerSocket)获取zygote文件描述符并重新创建一个socket,可以从这里看到zygote其实就是一个
//name为"zygote"的socket用来等待ActivityManagerService来请求zygote来fork出新的应用程序进程
//所以ActivityManagerService 里启动应用程序(APP),都是由该zygote socket进行处理并fork出的子进程
zygoteServer = new ZygoteServer(isPrimaryZygote);
//默认为true,将启动systemServer
if (startSystemServer) {
//zygote就是一个孵化器,所以这里直接fork出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.
//让SystemServer子进程运行起来
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.
//让zygote socket(注意不是systemServer zygote)循环运行
//等待client 进程来请求调用,请求创建子进程(fork 出子进程(例如等待AMS的请求))
caller = zygoteServer.runSelectLoop(abiList);
} catch (Throwable ex) {
Log.e(TAG, "System zygote died with fatal exception", ex);
throw ex;
} finally {
if (zygoteServer != null) {
//停止关于systemServer的socket,保留和AMS通信的socket
//在initNativeState阶段创建了一个和sysemServer通信的socket
//接着拿到systemServer socket文件描述符重新创建了一个可以和AMS通信的socket(/dev/socket/zygote)
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方法主要做了一下工作:
1、禁止启动其他线程;
2、设置pid;
3、解析C/C++层传进来的参数argv;
4、 设置相关日志追踪
5、preload 预加载
6、gcAndFinalize 垃圾回收
7、初始化ZygoteServer
8、fork systemServer 创建systemServer进程
9、zygoteServer.runSelectLoop 让zygote socket循环运行,等待请求创建子进程
其中重点工作是5、preload预加载,6、gcAndFinalize 垃圾回收,8、fork systemServer 创建systemServer进程 9、zygoteServer.runSelectLoop ,
我们先来看看preload预加载主要做了哪些事情,有哪些东西被提前加载了
preload
static void preload(TimingsTraceLog bootTimingsTraceLog) {
Log.d(TAG, "begin preload");
bootTimingsTraceLog.traceBegin("BeginPreload");
//调用ZygoteHooks.onBeginPreload()
beginPreload();
bootTimingsTraceLog.traceEnd(); // BeginPreload
bootTimingsTraceLog.traceBegin("PreloadClasses");
//预加载一些类
preloadClasses();
bootTimingsTraceLog.traceEnd(); // PreloadClasses
bootTimingsTraceLog.traceBegin("CacheNonBootClasspathClassLoaders");
//加载一些应用程序使用但不能放入引导类路径的jar包库,这些库过去是引导类路径的一部分,但必须删除。
//由于向后兼容性的原因,旧的系统应用仍然会使用它们,因此他们被缓存在这里以保持性能特征。
cacheNonBootClasspathClassLoaders();
bootTimingsTraceLog.traceEnd(); // CacheNonBootClasspathClassLoaders
bootTimingsTraceLog.traceBegin("PreloadResources");
//加载常用资源,以便它们可以跨进程共享,比如apk开发常用的color,drawble等资源
preloadResources();
bootTimingsTraceLog.traceEnd(); // PreloadResources
Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "PreloadAppProcessHALs");
//一些被大多数app进程加载的内容,需要通过hal来添加(native)
nativePreloadAppProcessHALs();
Trace.traceEnd(Trace.TRACE_TAG_DALVIK);
Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "PreloadGraphicsDriver");
//根据属性ro.zygote.disable_gl_preload来判断是否禁止预加载图像驱动相关内容(native)
maybePreloadGraphicsDriver();
Trace.traceEnd(Trace.TRACE_TAG_DALVIK);
//加载几个共享库:libandroid.so、libcompiler_rt.so、libjnigraphics.so
preloadSharedLibraries();
//启动字体缓存,设置Typeface
preloadTextResources();
// Ask the WebViewFactory to do any initialization that must run in the zygote process,
// for memory sharing purposes.
//为了内存共享,webViewFactory执行所有必须在zygote进程在运行的初始化
WebViewFactory.prepareWebViewInZygote();
endPreload();
//注册AndroidKeyStoreProvider并预热已经注册的provider
warmUpJcaProviders();
Log.d(TAG, "end preload");
sPreloadComplete = true;
}
可以看到预加载一些Java类、资源文件、图像资源等公共资源在zygote启动的时候就进行加载。这样一来,根据fork的copy-on-write机制,其他由zygote fork出来的进程在使用这些资源的时候就不需要再次加载了,而是直接使用。所以这是一种牺牲系统开机时间,来提高系统应用运行时的运行效率的手段。
其中 preloadClasses是读取/system/etc/preloaded-classes文件。/system/etc/preloaded-classes这个文件中每行一个全限定名格式的类(#开头的注释行和空白行则自动跳过)。该文件是由文件frameworks\base\tools\preload\WritePreloadedClassFile.java自动生成,其对于哪些类需要预加载有明确的说明:
/*
* pie\frameworks\base\tools\preload\WritePreloadedClassFile.java
* The set of classes to preload. We preload a class if:
* a) it's loaded in the bootclasspath (i.e., is a system class) 1、即系统类
* b) it takes > MIN_LOAD_TIME_MICROS = 1250 us to load, and 2、加载时长超过1250ms的类
* c) it's loaded by more than one process, or it's loaded by anapplication 3、不止一个进程会去加载的类
*/
###gcAndFinalize
gcAndFinalize()方法主要就是在预加载动作之后、后续从zygote fork其他进程的动作之前,进行的一次垃圾回收
/**
* Runs several special GCs to try to clean up a few generations of softly- and final-reachable
* objects, along with any other garbage. This is only useful just before a fork().
*/
private static void gcAndFinalize() {
ZygoteHooks.gcAndFinalize();
}
/libcore/dalvik/src/main/java/dalvik/system/ZygoteHooks.java
@SystemApi(client = MODULE_LIBRARIES)
@libcore.api.CorePlatformApi(status = libcore.api.CorePlatformApi.Status.STABLE)
public static void gcAndFinalize() {
final VMRuntime runtime = VMRuntime.getRuntime();
/* runFinalizationSync() lets finalizers be called in Zygote,
* which doesn't have a HeapWorker thread.
*/
System.gc();
runtime.runFinalizationSync();
System.gc();
}
forkSystemServer()
forksystemServer方法就是创建systemServer进程。zygote首先fork出了它的第一个进程,然后将该进程改名为system_server。我将在下一篇文章中记录
runSelectLoop()
zygote除了fork出system_server进程这个任务外,还有一个重要的任务,那就是接收AMS(ActivityManagerService)发来创建java层应用程序的请求,fork出一个个进程,并在新进程中执行该请求中相关应用程序的main方法。上层的一个个应用程序就是这样通过zygote创建而来,因为应用程序都是由zygote孕育而来,所以就不难理解zygote(受精卵)的名称的由来了
/**
* 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.
* @param abiList list of ABIs supported by this zygote.
*/
Runnable runSelectLoop(String abiList) {
ArrayList<FileDescriptor> socketFDs = new ArrayList<>();
ArrayList<ZygoteConnection> peers = new ArrayList<>();
//拿到socket的文件描述符 ,先将server soket加入到这个socketFDS列表
socketFDs.add(mZygoteSocket.getFileDescriptor());
peers.add(null);
mUsapPoolRefillTriggerTimestamp = INVALID_TIMESTAMP;
while (true) {//时间间隔持续轮询
fetchUsapPoolPolicyPropsWithMinInterval();
mUsapPoolRefillAction = UsapPoolRefillAction.NONE;
int[] usapPipeFDs = null;
StructPollfd[] pollFDs;
// Allocate enough space for the poll structs, taking into account
// the state of the USAP pool for this Zygote (could be a
// regular Zygote, a WebView Zygote, or an AppZygote).
if (mUsapPoolEnabled) {
usapPipeFDs = Zygote.getUsapPipeFDs();
pollFDs = new StructPollfd[socketFDs.size() + 1 + usapPipeFDs.length];
} else {
pollFDs = new StructPollfd[socketFDs.size()];
}
/*
* 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 deny list
* 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;
if (mUsapPoolEnabled) {
pollFDs[pollIndex] = new StructPollfd();
pollFDs[pollIndex].fd = mUsapPoolEventFD;
pollFDs[pollIndex].events = (short) POLLIN;
++pollIndex;
// The usapPipeFDs array will always be filled in if the USAP Pool is enabled.
assert usapPipeFDs != null;
for (int usapPipeFD : usapPipeFDs) {
FileDescriptor managedFd = new FileDescriptor();
managedFd.setInt$(usapPipeFD);
pollFDs[pollIndex] = new StructPollfd();
pollFDs[pollIndex].fd = managedFd;
pollFDs[pollIndex].events = (short) POLLIN;
++pollIndex;
}
}
int pollTimeoutMs;
if (mUsapPoolRefillTriggerTimestamp == INVALID_TIMESTAMP) {
pollTimeoutMs = -1;
} else {
long elapsedTimeMs = System.currentTimeMillis() - mUsapPoolRefillTriggerTimestamp;
if (elapsedTimeMs >= mUsapPoolRefillDelayMs) {
// The refill delay has elapsed during the period between poll invocations.
// We will now check for any currently ready file descriptors before refilling
// the USAP pool.
pollTimeoutMs = 0;
mUsapPoolRefillTriggerTimestamp = INVALID_TIMESTAMP;
mUsapPoolRefillAction = UsapPoolRefillAction.DELAYED;
} else if (elapsedTimeMs <= 0) {
// This can occur if the clock used by currentTimeMillis is reset, which is
// possible because it is not guaranteed to be monotonic. Because we can't tell
// how far back the clock was set the best way to recover is to simply re-start
// the respawn delay countdown.
pollTimeoutMs = mUsapPoolRefillDelayMs;
} else {
pollTimeoutMs = (int) (mUsapPoolRefillDelayMs - elapsedTimeMs);
}
}
int pollReturnValue;
try {
pollReturnValue = Os.poll(pollFDs, pollTimeoutMs);
} catch (ErrnoException ex) {
throw new RuntimeException("poll failed", ex);
}
if (pollReturnValue == 0) {
// The poll returned zero results either when the timeout value has been exceeded
// or when a non-blocking poll is issued and no FDs are ready. In either case it
// is time to refill the pool. This will result in a duplicate assignment when
// the non-blocking poll returns zero results, but it avoids an additional
// conditional in the else branch.
mUsapPoolRefillTriggerTimestamp = INVALID_TIMESTAMP;
mUsapPoolRefillAction = UsapPoolRefillAction.DELAYED;
} else {
boolean usapPoolFDRead = false;
while (--pollIndex >= 0) {
if ((pollFDs[pollIndex].revents & POLLIN) == 0) {
continue;
}
//server socket 最先加入fds,因此这里是server socket收到的数据
if (pollIndex == 0) {
// Zygote server socket
//acceptCommandPeer函数得到zygoteConnection类并添加到socket连接列表peers中
//接着将该zygoteConnection的文件描述符添加到fd列表fds中,以便可以接收到ActivityManagerService发送过来的请求
ZygoteConnection newPeer = acceptCommandPeer(abiList);
//加入到peer和fds,即下一次也开始监听
peers.add(newPeer);
socketFDs.add(newPeer.getFileDescriptor());
} else if (pollIndex < usapPoolEventFDIndex) {//说明接收到AMS通过socket发送过来创建应用程序的请求
// Session socket accepted from the Zygote server socket
try {
//有socket连接时创建zygoteConnection对象,并添加到pollFDS
ZygoteConnection connection = peers.get(pollIndex);
boolean multipleForksOK = !isUsapPoolEnabled()
&& ZygoteHooks.isIndefiniteThreadSuspensionSafe();
final Runnable command =
connection.processCommand(this, multipleForksOK);
// 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 processCommand hasn't called "exec".
if (command == null) {
throw new IllegalStateException("command == null");
}
return command;//依然是提供Runnable接口,通过反射机制执行目标应用程序的main方法
} 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 processCommand. This
// shows up as a regular POLLIN event in our regular processing
// loop.
//处理完后,关闭socket连接,并从peers和socketFDs列表中移除
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.
// If this is the event FD the payload will be the number of USAPs removed.
// If this is a reporting pipe FD the payload will be the PID of the USAP
// that was just specialized. The `continue` statements below ensure that
// the messagePayload will always be valid if we complete the try block
// without an exception.
long messagePayload;
try {
byte[] buffer = new byte[Zygote.USAP_MANAGEMENT_MESSAGE_BYTES];
int readBytes =
Os.read(pollFDs[pollIndex].fd, buffer, 0, buffer.length);
if (readBytes == Zygote.USAP_MANAGEMENT_MESSAGE_BYTES) {
DataInputStream inputStream =
new DataInputStream(new ByteArrayInputStream(buffer));
messagePayload = inputStream.readLong();
} else {
Log.e(TAG, "Incomplete read from USAP management FD of size "
+ readBytes);
continue;
}
} catch (Exception ex) {
if (pollIndex == usapPoolEventFDIndex) {
Log.e(TAG, "Failed to read from USAP pool event FD: "
+ ex.getMessage());
} else {
Log.e(TAG, "Failed to read from USAP reporting pipe: "
+ ex.getMessage());
}
continue;
}
if (pollIndex > usapPoolEventFDIndex) {
Zygote.removeUsapTableEntry((int) messagePayload);
}
usapPoolFDRead = true;
}
}
if (usapPoolFDRead) {
int usapPoolCount = Zygote.getUsapPoolCount();
if (usapPoolCount < mUsapPoolSizeMin) {
// Immediate refill
mUsapPoolRefillAction = UsapPoolRefillAction.IMMEDIATE;
} else if (mUsapPoolSizeMax - usapPoolCount >= mUsapPoolRefillThreshold) {
// Delayed refill
mUsapPoolRefillTriggerTimestamp = System.currentTimeMillis();
}
}
}
if (mUsapPoolRefillAction != UsapPoolRefillAction.NONE) {
int[] sessionSocketRawFDs =
socketFDs.subList(1, socketFDs.size())
.stream()
.mapToInt(FileDescriptor::getInt$)
.toArray();
final boolean isPriorityRefill =
mUsapPoolRefillAction == UsapPoolRefillAction.IMMEDIATE;
final Runnable command =
fillUsapPool(sessionSocketRawFDs, isPriorityRefill);
if (command != null) {
return command;
} else if (isPriorityRefill) {
// Schedule a delayed refill to finish refilling the pool.
mUsapPoolRefillTriggerTimestamp = System.currentTimeMillis();
}
}
}
}
循环间隔一段时间轮询连接socket消息,看是否有AMS客户端发过来创建应用程序的请求,有的话则通过pie\frameworks\base\core\java\com\android\internal\os\ZygoteConnection.processCommand()方法创建进程并启动目标应用程序。文章来源:https://www.toymoban.com/news/detail-595968.html
###总结:zygote进程主要做了启动虚拟机、注册JNI函数、进入java世界,然后fork出system_server进程,之后作为守护进程监听并处理创建普通应用程序的工作。参考图片如下:添加链接描述文章来源地址https://www.toymoban.com/news/detail-595968.html
到了这里,关于Zygote进程分析的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!