Android Zygote进程启动过程
Zygote, 意为“受精卵”,Android系统中几乎所有的应用进程都是由Zygote进程孵化出来的,Java环境也是由Zygote创建起来的,它建立了我们app运行所需要的环境,是app的祖先,因此,分析它的启动以及内部逻辑显得非常有必要。
Android系统是基于Linux内核的,而在Linux系统中,所有的进程都是init进程的子孙进程,也就是说,所有的进程都是直接或者间接地由init进程fork出来的。Zygote进程也不例外,它是在系统启动的过程,由init进程创建的。在系统启动脚本system/core/rootdir/init.rc文件中,我们可以看到启动Zygote进程的脚本命令:
service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server socket zygote stream 666 # zygote需要一个套接字 onrestart write /sys/android_power/request_state wake # zygote重启的话,需要执行这个操作 onrestart write /sys/power/state on onrestart restart media onrestart restart netd
上述脚本表示要启动一个进程,名称为zygote, 可执行文件为/system/bin/app_process,
--Xzygote /system/bin --zygote --start-system-server
这些是传给zygote的参数,其余部分的作用见注释。
app_process对应的源码在frameworks/base/cmds/app_process目录下,其入口函数main在文件app_main.cpp中,接下来我们就从这个main函数入手来分析zygote的内部逻辑。
注意: 本文的源码分析基于Android 4.4。
/*
* 启动zygote的方式为/system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
* 所以 argc == 5
* argv里头存的就是这5个参数argv[0]=="/system/bin/app_process" ,argv[1] == "-Xzygote"....
*/
int main(int argc, char* const argv[])
{
......
// These are global variables in ProcessState.cpp
mArgC = argc;
mArgV = argv;
mArgLen = 0;
for (int i=0; i<argc; i++) {
mArgLen += strlen(argv[i]) + 1;
}
mArgLen--;
// 以上代码主要是将参数相关信息保存到全局变量中
AppRuntime runtime;
const char* argv0 = argv[0];
// Process command line arguments
// ignore argv[0]
argc--;
argv++;
// Everything up to ‘--‘ or first non ‘-‘ arg goes to the vm
int i = runtime.addVmArguments(argc, argv); // 这个函数会返回1,表示只处理了-Xzytote这一个参数,所谓的处理实际上就是将这个参数添加到了runtime对象的mOptions 变量中。
// Parse runtime arguments. Stop at first unrecognized option.
bool zygote = false;
bool startSystemServer = false;
bool application = false;
const char* parentDir = NULL;
const char* niceName = NULL;
const char* className = NULL;
// 进入循环之前 i == 1, argc == 4 argv 指向“-Xzygote”
while (i < argc) {
const char* arg = argv[i++];
if (!parentDir) {
parentDir = arg; // parentDir被赋值为"/system/bin"
} else if (strcmp(arg, "--zygote") == 0) {
zygote = true;
niceName = "zygote"; // 进程名
} 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 = arg + 12;
} else { // 不走这个分支
className = arg;
break;
}
}
if (niceName && *niceName) { // 设置进程名
setArgv0(argv0, niceName);
set_process_name(niceName);
}
runtime.mParentDir = parentDir;
if (zygote) { // 走这个分支
runtime.start("com.android.internal.os.ZygoteInit",
startSystemServer ? "start-system-server" : "");
} else if (className) {
// Remainder of args get passed to startup class main()
runtime.mClassName = className;
runtime.mArgC = argc - i;
runtime.mArgV = argv + i;
runtime.start("com.android.internal.os.RuntimeInit",
application ? "application" : "tool");
} 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;
}
}
main函数主要就是创建了runtime实例,并且解析参数,然后调用runtime的start函数,接着我们分析AppRuntime的start函数:
/*
* 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.
*/
// 首先我们明确下传进来的参数 className == "com.android.internal.os.ZygoteInit" options == "start-system-server"
void AndroidRuntime::start(const char* className, const char* options)
{
ALOGD("\n>>>>>> AndroidRuntime START %s <<<<<<\n",
className != NULL ? className : "(unknown)");
/*
* ‘startSystemServer == true‘ means runtime is obsolete and not run from
* init.rc anymore, so we print out the boot start event here.
*/
if (strcmp(options, "start-system-server") == 0) {
/* 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); //配置ANDROID_ROOT环境变量
}
//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;
if (startVm(&mJavaVM, &env) != 0) { // 创建虚拟机
return;
}
onVmCreated(env);
/*
* Register android functions.
*/
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;
jstring optionsStr;
stringClass = env->FindClass("java/lang/String");
assert(stringClass != NULL);
strArray = env->NewObjectArray(2, stringClass, NULL);
assert(strArray != NULL);
classNameStr = env->NewStringUTF(className);
assert(classNameStr != NULL);
env->SetObjectArrayElement(strArray, 0, classNameStr);
optionsStr = env->NewStringUTF(options);
env->SetObjectArrayElement(strArray, 1, optionsStr);
/*
* Start VM. This thread becomes the main thread of the VM, and will
* not return until the VM exits.
*/
char* slashClassName = toSlashClassName(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 {
/* 调用com.android.internal.os.ZygoteInit的main函数,strArray是参数,数组里面有两个元素,
className == "com.android.internal.os.ZygoteInit" options == "start-system-server" */
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");
}
start函数主要做了以下几件事情:
- 调用startVm函数创建虚拟机;
- 调用startReg函数注册Android Natvie函数;
- 让虚拟机去执行com.android.internal.os.ZygoteInit的main函数。
接下来我们分析下com.android.internal.os.ZygoteInit的main函数, 创建虚拟机以及注册native函数的过程后续再分析。
public static void main(String argv[]) {
try {
// Start profiling the zygote initialization.
SamplingProfilerIntegration.start();
registerZygoteSocket(); // 1、创建一个套接字,用于监听ams发过来的fork请求
EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,
SystemClock.uptimeMillis());
preload(); // 2、加载classes 和resources, 后面会详细分析
EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,
SystemClock.uptimeMillis());
// Finish profiling the zygote initialization.
SamplingProfilerIntegration.writeZygoteSnapshot();
// Do an initial gc to clean up after startup
gc();
// If requested, start system server directly from Zygote
if (argv.length != 2) {
throw new RuntimeException(argv[0] + USAGE_STRING);
}
if (argv[1].equals("start-system-server")) {
startSystemServer(); //3、 创建system server进程,ams wms pms等常见service都在该进程里面
} else if (!argv[1].equals("")) {
throw new RuntimeException(argv[0] + USAGE_STRING);
}
Log.i(TAG, "Accepting command socket connections");
if (ZYGOTE_FORK_MODE) {
runForkMode();
} else {
runSelectLoopMode(); // 4、进入循环监听模式,监听外来请求
}
closeServerSocket();
} catch (MethodAndArgsCaller caller) {
caller.run();
} catch (RuntimeException ex) {
Log.e(TAG, "Zygote died with exception", ex);
closeServerSocket();
throw ex;
}
}
com.android.internal.os.ZygoteInit的main函数主要做了四件事情:
- 调用registerZygoteSocket()创建一个套接字,用于监听ams发过来的fork请求;
- 调用preload()预加载classes 和resources;
- 调用startSystemServer()创建system server进程,ams wms pms等常见service都在该进程里面;
- 调用runSelectLoopMode()进入循环监听模式,监听外来请求。
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。