Zygote 概述
- Zygote 时android中非常重要的一个进程,它和 init 进程、SystemServer 进程同为支持Android最重要的进程。、
- Linux 的进程时通过系统调用 fork 产生的,fork 出的子进程除了内核中的一些核心数据结构和父进程不同外,其余的内存影像都是和父进程共享的。只有当子进程需要去修改这些共享内存时,操作系统才会为子进程分配一个新的页面,并将老的页面上的数据复制一份到新的页面,这就是所谓的写时拷贝(Copy On Write)
- 通常子进程被fork出来后,会继续执行系统调用 exec 。exec将用一个新的可执行文件的内容替换当前的代码块、数据段、堆和栈。fork + exec 是 Linux 启动应用标准做法,init 也是通过这样启动各种服务。
- Zygote 启动各种应用时却只调用了 fork 没有调用 exec。Android引用中执行的是 java 代码,Java代码不同才造成了应用的不同,而对于Java 运行环境是相同的。
- Zygote 初始化时会创建虚拟机,同时把需要的系统类库和资源文件加载到内存里。Zygote fork出进程后,这个子进程也继承了能正常工作的虚拟机和各种系统资源,接下来的子进程中需要加在 APK 中的字节码就可以运行了。这样运行时间会大大缩短。
- 下图时 init 和 Zygote 区别
Zygote 进程的初始化
- Zygote 进程在 init 进程中以 Service 的方式启动的,5.0 以前是直接放在 init.rc 的代码块中,现在是放在了单独的文件中,然后在 init.rc 通过 import 方式引入文件,如下:
import /init.${ro.zygote}.rc
从import中可以看出,init.rc 并不是直接引入了某个固定的文件而是根据ro.zygote的属性来引入不同的文件,这是因为从 5.0 开始android开始支持64位编译,Zygote 本身也会有 32位和64位的区别,因此通过 ro.zygote 来控制启动不同的版本的 Zygote 进程。属性 ro.zygote 可能有“zygote32”、“zygote32_64”、“zygote64”、“zygote64_32”。所以在 init.rc同级目录下可能有四个zygote.rc文件,我在下载 9.0源码就可以搜索出如下结果:
service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
class main
priority -20
user root
group root readproc reserved_disk
socket zygote 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 /system/bin/app_process32 -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
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_process64 -Xzygote /system/bin --zygote --socket-name=zygote_secondary
class main
priority -20
user root
group root readproc reserved_disk
socket zygote_secondary stream 660 root system
onrestart restart zygote
writepid /dev/cpuset/foreground/tasks
从上面两个文件中可以看出 zygote32_64.rc 有两个 Zygote 服务,zygote 和 zygote_secondary,这两个服务最大的区别是启动可执行文件不同,一个是app_process32,另外一个是 app_process64。zygote64 和 zygote64_32 也差不带多,只不过把可执行文件换过来了。从这里可以知道Android支持四种运行模式。
- 纯32位模式:属性为ro.zygote的值为zygote32
- 以32位为主,64位为辅:属性为ro.zygote的值为zygote32_64
- 纯64位模式:属性为ro.zygote的值为zygote64
- 以64位为主,32位为辅:属性为ro.zygote的值为zygote64_32
- 从上面 Zygote 文件可以看出 Zygote进程可执行文件是 app_process,app_process文件的源文件位于下图:
app_process 的 main 函数
启动格式为:app_process[虚拟机参数] 运行目录 参数 [java 类]
- 虚拟机参数:以 _ 开头启动虚拟机时传递给虚拟机
- 运行目录:程序运行目录,通常是 /system/bin
- 参数:以–开头。参数 --zygote 表示启动 zygote,参数 --application表示以普通进程方式执行Java代码。
- Java类:将要执行的Java类,必须有一个静态的 main 。使用 -Zygote 时不会执行这个类,而是固定的执行 ZygoteInit 类。
main函数启动流程
- 创建AppRuntime 对象并保存参数
AppRuntime是在app_process 中定义的类,继承了系统的 AndroidRuntime类。AndroidRuntime类主要作用是创建初始化虚拟机。
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));
argc--;
argv++;
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]));
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;
break;
}
runtime.addOption(strdup(argv[i]));
ALOGV("app_process main add option '%s'", argv[i]);
}
int i;
for (i = 0; i < argc; i++) {
if (known_command == true) {
runtime.addOption(strdup(argv[i]));
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;
break;
}
runtime.addOption(strdup(argv[i]));
ALOGV("app_process main add option '%s'", argv[i]);
}
通常是从 init.rc 中传入的参数,“-Xzygote/system/bin --zygote --start-system-server”,解析后得到的结果将是
- 变量 parentDir 等于 /system/bin
- 变量 niceName 等于 zygote
- 变量 startSystemServer 等于 true
- 变量 zygote 等于 true
- 准备执行 ZygoteInit 或者 RuntimeInit 类的参数
Vector<String8> args;
if (!className.isEmpty()) {
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 {
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);
for (; i < argc; ++i) {
args.add(String8(argv[i]));
}
}
- 将本进程的名称改为–nice-name 指定的字符串。缺省情况下niceName为zygote或者zygote64
if (!niceName.isEmpty()) {
runtime.setArgv0(niceName.string(), true );
}
- 启动 Java 类,如果参数带有 --zygote 执行 zygoteInit类,否则执行传进来的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.");
}
app_process 除了能启动 Zygote进程还可以执行系统的某个Java类。Android手机常用工具 am 就是一个很好的例子。am 是一个通过发送 Intent 来启动应用程序的工具,但是 am 只是一个包含几行代码的脚本文件,实际上启动还是通过 app_process 来完成的。 am基本用法
- am start -n 包(package)名/包名.活动(activity)名称
启动虚拟机 AndroidRuntime类
- Android Runtime类是 Android底层很重要的一个类,它负责启动虚拟机以及Java线程。AndroidRuntime在一个进程中只有一个实例对象,保存在全局变量 gCurRuntime中。
- AndroidRuntime 构造函数如下(android9.0)
AndroidRuntime::AndroidRuntime(char* argBlockStart, const size_t argBlockLength) :
mExitWithoutCleanup(false),
mArgBlockStart(argBlockStart),
mArgBlockLength(argBlockLength)
{
SkGraphics::Init();
mOptions.setCapacity(20);
assert(gCurRuntime == NULL);
gCurRuntime = this;
}
AndroidRuntime 的构造函数中,5.0以前会对 skia图形系统进行设置,把底层使用的图形格式设置成 RGB565,一种16位图形格式,16位的图像格式没有24位的色彩丰富,但是能节省内存空间。Android5.0以后去调了这个设置,只保留了 mOptions.setCapacity(20); 来设置虚拟机的参数。 最后 AndroidRuntime 指针被放入了 gCurRuntime 全局指针,但是前面的 main() 函数中AndroidRuntime 是作为一个局部变量 runtime 创建的。这是因为如果启动的 Zygote ,在 ZygoteInit 中会进入等待 Socket 事件循环中,这样布局变量并不会被销毁,如果只执行一个 Java 类,执行结束完就结束了,说 runtime是一个局部变量也没什么问题。
启动虚拟机
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.");
}
- 在main() 函数的结尾,调用了 AndroidRuntime的start函数来执行 Java类。Zygote在运行Java前,还需要初始化整个Java环境,下面看看 start() 函数执行流程。
void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote)
{
ALOGD(">>>>>> START %s uid %d <<<<<<\n",
className != NULL ? className : "(unknown)", getuid());
static const String8 startSystemServer("start-system-server");
for (size_t i = 0; i < options.size(); ++i) {
if (options[i] == startSystemServer) {
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);
}
JniInvocation jni_invocation;
jni_invocation.Init(NULL);
JNIEnv* env;
if (startVm(&mJavaVM, &env, zygote) != 0) {
return;
}
onVmCreated(env);
if (startReg(env) < 0) {
ALOGE("Unable to register all android natives\n");
return;
}
jclass stringClass;
jobjectArray strArray;
jstring classNameStr;
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) {
jstring optionsStr = env->NewStringUTF(options.itemAt(i).string());
assert(optionsStr != NULL);
env->SetObjectArrayElement(strArray, i + 1, optionsStr);
}
char* slashClassName = toSlashClassName(className != NULL ? className : "");
jclass startClass = env->FindClass(slashClassName);
if (startClass == NULL) {
ALOGE("JavaVM unable to locate class '%s'\n", slashClassName);
} else {
jmethodID startMeth = env->GetStaticMethodID(startClass, "main",
"([Ljava/lang/String;)V");
if (startMeth == NULL) {
ALOGE("JavaVM unable to find main() in '%s'\n", className);
} else {
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");
}
onVmCreated会在当前虚拟机环境中根据类名来查找类对象,这表明 app_process 将要调用的Java类对象必须是系统Java类,而不能是随意的应用java类,如果调用普通Java类对象则方式不同。
virtual void onVmCreated(JNIEnv* env)
{
if (mClassName.isEmpty()) {
return;
}
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));
}
初始化工作 ZygoteInit 类
- Zygote 的 main 方法做了大概一下几个事情
:解析调用参数 :注册 Zygote 的 socket 监听接口,用来接收启动应用程序监听 :调用 preload() 方法装载系统资源。这样fork出的应用可以包含这些资源了 加快了启动速度。 :启动 SystemServer 进程 :调用 runSelectLoo() 方法进入监听和接收消息的循环
public static void main(String argv[]) {
ZygoteServer zygoteServer = new ZygoteServer();
ZygoteHooks.startZygoteNoThreadCreation();
try {
Os.setpgid(0, 0);
} catch (ErrnoException ex) {
throw new RuntimeException("Failed to setpgid(0,0)", ex);
}
final Runnable caller;
try {
if (!"1".equals(SystemProperties.get("sys.boot_completed"))) {
MetricsLogger.histogram(null, "boot_zygote_init",
(int) SystemClock.elapsedRealtime());
}
String bootTimeTag = Process.is64Bit() ? "Zygote64Timing" : "Zygote32Timing";
TimingsTraceLog bootTimingsTraceLog = new TimingsTraceLog(bootTimeTag,
Trace.TRACE_TAG_DALVIK);
bootTimingsTraceLog.traceBegin("ZygoteInit");
RuntimeInit.enableDdms();
boolean startSystemServer = false;
String socketName = "zygote";
String abiList = null;
boolean enableLazyPreload = false;
for (int i = 1; i < argv.length; i++) {
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)) {
socketName = argv[i].substring(SOCKET_NAME_ARG.length());
} else {
throw new RuntimeException("Unknown command line argument: " + argv[i]);
}
}
if (abiList == null) {
throw new RuntimeException("No ABI list supplied.");
}
zygoteServer.registerServerSocketFromEnv(socketName);
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();
} else {
Zygote.resetNicePriority();
}
bootTimingsTraceLog.traceBegin("PostZygoteInitGC");
gcAndFinalize();
bootTimingsTraceLog.traceEnd();
bootTimingsTraceLog.traceEnd();
Trace.setTracingEnabled(false, 0);
Zygote.nativeSecurityInit();
Zygote.nativeUnmountStorageOnInit();
ZygoteHooks.stopZygoteNoThreadCreation();
if (startSystemServer) {
Runnable r = forkSystemServer(abiList, socketName, zygoteServer);
if (r != null) {
r.run();
return;
}
}
Log.i(TAG, "Accepting command socket connections");
caller = zygoteServer.runSelectLoop(abiList);
} catch (Throwable ex) {
Log.e(TAG, "System zygote died with exception", ex);
throw ex;
} finally {
zygoteServer.closeServerSocket();
}
if (caller != null) {
caller.run();
}
}
|