init进程到Zygote进程
init进程到Zygote进程流程图如下:
Android启动流程中,当内核启动之后,就会启动init进程。init进程是一个用户级进程,而且它是由内核拉起的。init进程的入口在system/core/init/init.cpp 的main方法。在Android9.0源码中,init.cpp文件没有main方法,在system/core/init文件夹中的main.cpp中找到了main方法:
int main(int argc, char** argv) {
#if __has_feature(address_sanitizer)
__asan_set_error_report_callback(AsanReportCallback);
#endif
if (!strcmp(basename(argv[0]), "ueventd")) {
return ueventd_main(argc, argv);
}
if (argc > 1) {
if (!strcmp(argv[1], "subcontext")) {
android::base::InitLogging(argv, &android::base::KernelLogger);
const BuiltinFunctionMap& function_map = GetBuiltinFunctionMap();
return SubcontextMain(argc, argv, &function_map);
}
if (!strcmp(argv[1], "selinux_setup")) {
return SetupSelinux(argv);
}
if (!strcmp(argv[1], "second_stage")) {
return SecondStageMain(argc, argv);
}
}
return FirstStageMain(argc, argv);
}
在main.cpp文件的main方法中根据条件,调用了init.h声明的SecondStageMain方法,尚不清楚条件是什么,不过最终会走到init.cpp文件中的SecondStageMain方法。为什么会走到这里?因为不走到这里说不通啊,哈哈哈哈
在init.cpp文件的SecondStageMain方法中,调用LoadBootScripts方法,读取解析init.rc文件:
static void LoadBootScripts(ActionManager& action_manager, ServiceList& service_list) {
Parser parser = CreateParser(action_manager, service_list);
std::string bootscript = GetProperty("ro.boot.init_rc", "");
if (bootscript.empty()) {
parser.ParseConfig("/system/etc/init/hw/init.rc");
if (!parser.ParseConfig("/system/etc/init")) {
late_import_paths.emplace_back("/system/etc/init");
}
// late_import is available only in Q and earlier release. As we don't
// have system_ext in those versions, skip late_import for system_ext.
//从上面日志看,应该会走这里,bootscript默认应该是空的
parser.ParseConfig("/system_ext/etc/init");
if (!parser.ParseConfig("/product/etc/init")) {
late_import_paths.emplace_back("/product/etc/init");
}
if (!parser.ParseConfig("/odm/etc/init")) {
late_import_paths.emplace_back("/odm/etc/init");
}
if (!parser.ParseConfig("/vendor/etc/init")) {
late_import_paths.emplace_back("/vendor/etc/init");
}
} else {
parser.ParseConfig(bootscript);
}
}
从源码log看,bootscript默认是空的,上面的代码应该是初始化各个文件夹
回到init.rc的SecondStageMain方法,继续往ActionManager对象添加信息。
// Run all property triggers based on current state of the properties.
am.QueueBuiltinAction(queue_property_triggers_action, "queue_property_triggers");
上面这句,运行所有的触发器(trigger)。
init.rc
import /system/etc/init/hw/init.${ro.zygote}.rc
on late-init
trigger zygote-start
on zygote-start && property:persist.sys.fuse=true
# Mount default storage into root namespace
mount none /mnt/user/0 /storage bind rec
mount none none /storage slave rec
on zygote-start && property:persist.sys.fuse=false
# Mount default storage into root namespace
mount none /mnt/runtime/default /storage bind rec
mount none none /storage slave rec
on zygote-start && property:persist.sys.fuse=""
# Mount default storage into root namespace
mount none /mnt/runtime/default /storage bind rec
mount none none /storage slave rec
##############
on zygote-start && property:ro.crypto.state=unencrypted
# A/B update verifier that marks a successful boot.
exec_start update_verifier_nonencrypted
start netd
start zygote
start zygote_secondary
on zygote-start && property:ro.crypto.state=unsupported
# A/B update verifier that marks a successful boot.
exec_start update_verifier_nonencrypted
start netd
start zygote
start zygote_secondary
on zygote-start && property:ro.crypto.state=encrypted && property:ro.crypto.type=file
# A/B update verifier that marks a successful boot.
exec_start update_verifier_nonencrypted
start netd
start zygote
start zygote_secondary
##############
on property:vold.decrypt=trigger_post_fs_data
trigger post-fs-data
trigger zygote-start
##############
on userspace-reboot-resume
trigger userspace-reboot-fs-remount
trigger post-fs-data
trigger zygote-start
trigger early-boot
trigger boot
init.rc文件中关于zygote的进程都在上面了,import /system/etc/init/hw/init.${ro.zygote}.rc,根据当前系统的版本import对应的init.zygoteXX.rc文件。接着,好多个start zygote,没看懂到底是哪个在执行,不过最终执行import进来的init.zygoteXX.rc文件。下面是64位的:
init.zygote64.rc:
service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server
class main
priority -20
user root
group root readproc reserved_disk
socket zygote stream 660 root system
socket usap_pool_primary stream 660 root system
onrestart write /sys/power/state on
onrestart restart audioserver
onrestart restart cameraserver
onrestart restart media
onrestart restart netd
onrestart restart wificond
writepid /dev/cpuset/foreground/tasks
service关键字表示这是要启动一个服务,zygote是服务的名字(这里的服务是init进程内部的概念,跟Android的服务不是一个东西)。
/system/bin/app_process64:指明zygote服务对应的二进制文件的路径。init进程会fork一个子进程来运行指定的程序,这个程序就是:frameworks/base/cmds/app_process/app_main.cpp。
-Xzygote /system/bin --zygote --start-system-server:启动zygote的时候传递给frameworks/base/cmds/app_process/app_main.cpp的参数
frameworks/base/cmds/app_process/app_main.cpp
int main(int argc, char* const argv[])
{
//....
//1、AppRuntime是内部类
AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));
// Process command line arguments 2、进程命令行参数
// ignore argv[0] 3、忽略第一个参数,好像是-Xzygote
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 启动zygote模式
// --start-system-server : Start the system server. //启动system server
// --application : Start in application (stand alone, non zygote) mode.application模 // 式,跟zygote模式互斥
// --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.
// 对于非zygote模式启动,这些参数将后跟主类名称。 所有其余的参数都传递给此类的main方法。
//
// For zygote starts, all remaining arguments are passed to the zygote.
// main function.
// 对于zygote模式启动,所有剩余的参数都传递给zygote。即main方法
// Note that we must copy argument string values since we will rewrite the
// entire argument block when we apply the nice name to argv0.
// 注意,我们必须复制参数字符串值,因为当我们将nice name 应用于argv0时,我们将重写整个参数块。
// As an exception to the above rule, anything in "spaced commands"
// goes to the vm even though it has a space in it.
// 作为上述规则的例外,“spaced commands”中的任何内容都将送至vm,即使其中有空格也是如此。
//**************下面这段代码没看懂*************************
const char* spaced_commands[] = { "-cp", "-classpath" };
// Allow "spaced commands" to be succeeded by exactly 1 argument (regardless of -s).
// 允许“spaced commands”后接正好1个参数(无论-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) {//--(哪个字符对应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]);
}
//**************上面这段代码没太看懂*************************
//传进来的参数 : -Xzygote /system/bin --zygote --start-system-server ,后面的不知道传没传
// 根据上面的代码,好像在遇到 /system/bin 的时候,因为不是以“-”开头,所以直接退出循环了
// Parse runtime arguments. Stop at first unrecognized option.
// 解析运行时参数。 停在第一个无法识别的选项。
bool zygote = false;
bool startSystemServer = false;
bool application = false;
String8 niceName;
String8 className;
//根据前面的分析,到这里 i 指向的argv的内容是 /system/bin
++i; // Skip unused "parent dir" argument. 跳过未使用的“父目录”参数。
// 递增一个之后, i 指向的argv内容就是 --zygote
// 所以下面的循环是可以执行的
while (i < argc) {
const char* arg = argv[i++];
if (strcmp(arg, "--zygote") == 0) {
//第一次会走到这里
zygote = true;
//static const char ZYGOTE_NICE_NAME[] = "zygote64";
niceName = ZYGOTE_NICE_NAME;
} else if (strcmp(arg, "--start-system-server") == 0) {
//第二次循环走这里
startSystemServer = true;
} else if (strcmp(arg, "--application") == 0) {
application = true;
} else if (strncmp(arg, "--nice-name=", 12) == 0) {
niceName.setTo(arg + 12);
} else if (strncmp(arg, "--", 2) != 0) {
className.setTo(arg);
break;
} else {
--i;
break;
}
}
//上面的循环只走两次,其他参数不符合了 最终: zygote = true; niceName = ZYGOTE_NICE_NAME;
// startSystemServer = true;
Vector<String8> args;
//className 没赋值 走else
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模式
maybeCreateDalvikCache(); //创建虚拟机缓存?
if (startSystemServer) {//添加启动system server到参数
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. 在zygote模式下,将所有剩余的参数传递给main()方法。
for (; i < argc; ++i) {//把剩余的参数放到args里面
args.add(String8(argv[i]));
}
}
if (!niceName.isEmpty()) {
//确实不为空,设置进程名字 zygote64
//使用 adb shell ps 命令查看,确实有名为zygote64的进程
runtime.setArgv0(niceName.string(), true /* setProcName */);
}
if (zygote) {
//启动zygote 然后转到Java世界
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方法的分析,基本上每一步都有注释。这个方法的功能主要是对启动zygote进程传递进来的参数进行处理。
AppRuntime
AppRuntime是app_miain.cpp里面的内部类,继承自AndroidRuntime。
void AndroidRuntime::setArgv0(const char* argv0, bool setProcName) {
// Set the kernel's task name, for as much of the name as we can fit. 设置内核的任务名称,并使用尽可能多的名称。
// The kernel's TASK_COMM_LEN minus one for the terminating NUL == 15. 内核的TASK_COMM_LEN减1代表终止NUL == 15。
if (setProcName) { //前面知道这个setProcName == true
int len = strlen(argv0);
if (len < 15) {
pthread_setname_np(pthread_self(), argv0);
} else {
pthread_setname_np(pthread_self(), argv0 + len - 15);
}
}
// Directly change the memory pointed to by argv[0]. 直接更改argv [0]指向的内存。
memset(mArgBlockStart, 0, mArgBlockLength);
strlcpy(mArgBlockStart, argv0, mArgBlockLength);
// Let bionic know that we just did that, because __progname points
// into argv[0] (https://issuetracker.google.com/152893281).
setprogname(mArgBlockStart);
}
setArgv0方法好像是做一些初始化工作。
void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote)
{
//对于zygote模式,className = com.android.internal.os.ZygoteInit options是参数列表 zygote = true
static const String8 startSystemServer("start-system-server");//options中第一个参数也是start-system-server
// Whether this is the primary zygote, meaning the zygote which will fork system server.
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.
*'startSystemServer == true'表示runtime已过时,不再从init.rc中运行,因此我们在此处打印启动启动事件。
*/
for (size_t i = 0; i < options.size(); ++i) {
if (options[i] == startSystemServer) {//options中第一个参数 是start-system-server
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)));
}
}
//***** 上面的代码没看懂。
//下面的代码是检查文件夹及运行环境是否满足条件
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 启动虚拟机*/
JniInvocation jni_invocation;
jni_invocation.Init(NULL);
JNIEnv* env; //JNI 引擎?
if (startVm(&mJavaVM, &env, zygote, primary_zygote) != 0) {//如果启动失败,返回的不是0,所以结果不为0,就直接退出
return;
}
onVmCreated(env);//这是个空方法
/*
* Register android functions. 注册Android方法,注册的是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.
* 我们要使用包含参数的String数组调用main()。 目前,我们有两个参数,即类名和选项字符串。 创建一个数组来保存它们。
*
* 调用Java类的main方法都需要一个String类型的数组,这里开始创建。用传递过来的类名和参数列表创建
*/
jclass stringClass; //jclass是JNI的数据类型?
jobjectArray strArray;//jobjectArray是JNI的数据类型?
jstring classNameStr;//jstring是JNI的数据类型?
stringClass = env->FindClass("java/lang/String");
assert(stringClass != NULL);//断言
strArray = env->NewObjectArray(options.size() + 1, stringClass, NULL);
assert(strArray != NULL);
classNameStr = env->NewStringUTF(className);
assert(classNameStr != NULL);
env->SetObjectArrayElement(strArray, 0, classNameStr);
for (size_t i = 0; i < options.size(); ++i) {//把传过来的参数保存到JNI类型数组中
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.
* 启动虚拟机。 该线程成为虚拟机的主线程,直到虚拟机退出后才返回。
*/
char* slashClassName = toSlashClassName(className != NULL ? className : "");//className是:com.android.internal.os.ZygoteInit
jclass startClass = env->FindClass(slashClassName);
if (startClass == NULL) {
//找不到类走这里
ALOGE("JavaVM unable to locate class '%s'\n", slashClassName);
/* keep going */
} else {
//找到类走这里
//找main方法
jmethodID startMeth = env->GetStaticMethodID(startClass, "main",
"([Ljava/lang/String;)V");
if (startMeth == NULL) {
//找不到main方法走这里
ALOGE("JavaVM unable to find main() in '%s'\n", className);
/* keep going */
} else {
//找到main方法走这里
//调用main方法,到这就开始去到Java世界了,运行 com.android.internal.os.ZygoteInit 的main方法
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");
}
总结
init进程是怎么被拉起的,那是内核的事情,太底层了看不到。而init进程被拉起来之后,做了些什么事情呢?如下:
- 读取、解析、执行init.rc文件
- 解析init.rc到zygote start的时候, 程序运行到app_process.cpp的main方法(app_process.cpp的main方法的参数来源与init.zygote64.rc)
- app_process.cpp的main方法,解析参数,将参数一一准备好,放到一个String类型的列表中。
- 启动虚拟机、注册Android JNI方法
- 通过JNI,调用Java层的com.android.internal.os.ZygoteInit.java的main方法