前面我们说到,init 进程会解析 init.rc 文件,执行对应的命令,其中一个重要的任务就是启动 Zygote 进程。接下来我们就来分析 Zygote 进程的启动和执行过程。
本文基于 AOSP android-10.0.0_r41 版本讲解
Zygote 进程的启动
在 system/core/rootdir/init.rc
中有如下定义
bash
# system/core/rootdir/init.rc
on late-init
# ......
trigger zygote-start
# ......
这里是一个 Action,当 late-init trigger 触发时,主动调用 trigger 命令触发 zygote-start Action。
bash
# system/core/rootdir/init.rc
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
system/core/rootdir/init.rc
中有三个 zygote 相关的 zygote-start,差异主要在后续的属性值判断,无论哪种情况,都会执行 start zygote
和 start zygote_secondary
.
从 Android 5.0 开始,Android 开始支持 64 位编译,Zygote 本身也会有 32 位和 64 位的区别,因此,通过 ro.zygote 属性来控制启动不同版本的 Zygote 进程:
bash
# system/core/rootdir/init.rc
import /init.${ro.zygote}.rc
在 android-10.0.0_r41 的源码中,有 4 个文件定义有 zygote-start:
bash
system/core/rootdir/init.zygote32.rc
system/core/rootdir/init.zygote64.rc
system/core/rootdir/init.zygote32_64.rc
system/core/rootdir/init.zygote64_32.rc
我们看下 system/core/rootdir/init.zygote64_32.rc
:
bash
service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server --socket-name=zygote
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/android_power/request_state wake
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_secondary /system/bin/app_process32 -Xzygote /system/bin --zygote --socket-name=zygote_secondary --enable-lazy-preload
class main
priority -20
user root
group root readproc reserved_disk
socket zygote_secondary stream 660 root system
socket usap_pool_secondary stream 660 root system
onrestart restart zygote
writepid /dev/cpuset/foreground/tasks
- 从文件内容中可以看到定义了两个 Zygote 服务:zygote 和 zygote_secondary
- 两个服务最大的区别是可执行文件不同:一个是 app_process32、一个是 app_process64
- init.zygote32_64.rc把两个可执行文件交换一下
- 对于 init.zygote32.rc 和 init.zygote64.rc 分别只有一个 Zygote 服务
app_process 的用法
在上一节 init 进程调用 app_process 启动 zygote 进程,app_process 是一个 cpp 的命令行程序,接下来我们来看看该命令的使用方法:
bash
app_process [java-options] cmd-dir start-class-name [options]
接着 zygote 启动的命令:
bash
/system/bin/app_process32 -Xzygote /system/bin --zygote --start-system-server --socket-name=zygote
- -Xzygote 属于
[java-options]
,这些参数会传给虚拟机,并且参数必须以-
开头,一旦遇到非-
或者--
,表示[java-options]
结束 - /system/bin :属于
cmd-dir
,程序的运行目录,随便指定即可,文件操作时会以此为当前路径,大多运行在/system/bin
下 --zygote --start-system-server --socket-name=zygote
都属于[options]
,这些参数都以符号--开头。参数--zygote
表示要启动 Zygote 进程,--start-system-server
表示要启动 SystemServer,--socket-name=zygote
用于指定 Zygote 中 socket 服务的名字
我们再看一个启动 Java 程序的命令:
bash
app_process -Djava.class.path=/data/local/tmp/Test.dex /data/lee Test
- -Djava.class.p**:属于
[java-options]
,这些参数会传给虚拟机,并且参数必须以 - 开头,一旦遇到非 - 或者 --,表示[java-options]
结束 - /data/lee:属于 cmd-dir,程序的运行目录,随便指定即可,文件操作时会以此为当前路径,大多运行在 /system/bin 下
- Test:属于 start-class-name,声明入口类的名称,有包名的话需要加上包名
app_process 源码分析
app_process
可执行文件对应的源码在 frameworks/base/cmds/app_process/app_main.cpp
:
cpp
// frameworks/base/cmds/app_process/app_main.cpp
int main(int argc, char* const argv[])
{
// ......
// 创建 AppRuntime 对象
AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));
argc--;
argv++;
这里的主要任务是创建 AppRuntime
对象,AndroidRuntime类是底层很重要很重要的一个类,主要作用是创建和初始化虚拟机。
cpp
// 解析 Java-Option 参数
const char* spaced_commands[] = { "-cp", "-classpath" };
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]);
}
这里把 Java-Option 参数从命令行中解析出来,并把参数添加到 AppRuntime
cpp
// 需要解析出的参数
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;
}
}
这里把 Option 参数命令行中解析出来,保存在 zygote startSystemServer
等局部变量中。
cpp
Vector<String8> args; //ZygoteInit 或者 RuntimeInit 启动需要的参数存在 Vector 中
if (!className.isEmpty()) { //RuntimeInit
// 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 { // ZygoteInit
// 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]));
}
}
这里准备 ZygoteInit 或者 RuntimeInit 启动需要的参数
cpp
if (!niceName.isEmpty()) {
runtime.setArgv0(niceName.string(), true /* setProcName */);
}
设置进程名称
cpp
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.");
}
}
启动对应的 Java 类,接下来就会执行到 frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
中 com.android.internal.os.ZygoteInit
类的 main 函数了。