源码基于:Android R
0. 前言
之前一篇博文(Android 的init过程详解)中记录了init启动过程,后来另一篇(Android init.rc详解 )中记录了init.rc的解析过程,android详细的启动过程,就需要将所有的init rc文件解剖之后,从action到service挨个分析。这里记录一下zygote的启动过程。
1. zygote起点
system/core/rootdir/init.zygote64_32.rc
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 exec_background - system system -- /system/bin/vdc volume abort_fuse
onrestart write /sys/power/state on
onrestart restart audioserver
onrestart restart cameraserver
onrestart restart media
onrestart restart netd
onrestart restart wificond
task_profiles ProcessCapacityHigh MaxPerformance
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
task_profiles ProcessCapacityHigh MaxPerformance
自 Android 5.0 系统开始,zygote 不再是一个进程,而是两个进程,一个是 32 位 zygote,负责孵化 32 位进程(为了兼容使用了 armeabi 和 armeabi-v7a 等 32 位架构的本地动态库的应用),另一个是 64 位 zygote 进程,负责孵化 64 位应用进程(可加载 arm64-v8a 等 64 位架构本地库)。
通过上述 init.*.rc 得知,通过 app_process64 和 app_process32 两个程序分别引导启动zygote64 和 zygote,后面的命令行参数会在代码中解析。
平台启动完成后,可以查看到两个 zygote 进程:
root 392 1 13338156 36416 poll_schedule_timeout 0 S zygote64
root 393 1 1291412 6516 poll_schedule_timeout 0 S zygote
针对app_process64 看到了什么:
- 注意命令行参数,以及参数的顺序,其中包括需要启动system server 的参数
- 创建了socket zygote,权限是660 root system;
- 创建了socket usap_pool_primart,权限660 root system;
- 当 zygote64 进程重启的时候,会进行一系列操作,包括重启 audioserver、cameraserver、media、netd、wificond等;
- task_profiles
针对app_process32 看到了什么:
- 注意命令行参数,以及参数的顺序
- 创建了socket zygote_secondary,权限660 root system;
- 创建了usap_pool_secondary,权限660 root system;
- 当zygote 进程重启时,会重启zygote64
通过 socket 关键字分别指定了四个 socket:
- zygote
- zygote_secondary
- usap_pool_primary
- usap_pool_secondary
平台启动完成,会在平台的 /dev/socket 目录下看到这四个 zygote 文件。AMS 就是通这些 socket来和 zygote 进程通信请求 fork 一个个应用程序进程。
关键字 onrestart 详细的可以参考 Android init.rc详解
2. zygote 代码入口
/frameworks/base/cmds/app_process/Androd.bp
cc_binary {
name: "app_process",
srcs: ["app_main.cpp"],
multilib: {
lib32: {
version_script: ":art_sigchain_version_script32.txt",
suffix: "32",
},
lib64: {
version_script: ":art_sigchain_version_script64.txt",
suffix: "64",
},
},
详细的bp 规则这里不过多叙述了,感兴趣的同学可以自行查看。这里就是编译出app_process32 和app_process64 的地方,详细的代码目录 frameworks/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对象
AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));
// Process command line arguments
// ignore argv[0]
argc--;
argv++;
//后面解析-cp或-classpath的参数
const char* spaced_commands[] = { "-cp", "-classpath" };
// Allow "spaced commands" to be succeeded by exactly 1 argument (regardless of -s).
bool known_command = false;
//for循环主要解析'-'和'--'参数,注意for循环中的两次break
//显然,对比init.*.rc这里解析的是/system/bin之前的参数
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.
bool zygote = false;
bool startSystemServer = false;
bool application = false;
String8 niceName;
String8 className;
//++i跳过/system/bin 这个参数
++i; // Skip unused "parent dir" argument.
//while循环解析zygote进程的名称,确定该进程是否会启动system_server进程
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;
}
}
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 { //进入zygote模式
//创建/data/dalvik-cache目录,后期的classes.art 都在这里
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]));
}
}
if (!niceName.isEmpty()) {
runtime.setArgv0(niceName.string(), true /* setProcName */);
}
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.");
}
}
代码比较长,下面逐步剖析。
2.1 runtime 实例创建
AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));
这里的第二个参数是通过 computerArgBlockSize() 函数计算出args 的 data length,这里是强制认为args 占用了连续的空间:
static size_t computeArgBlockSize(int argc, char* const argv[]) {
uintptr_t start = reinterpret_cast<uintptr_t>(argv[0]);
uintptr_t end = reinterpret_cast<uintptr_t>(argv[argc - 1]);
end += strlen(argv[argc - 1]) + 1;
return (end - start);
}
接下来,来看下AppRuntime 类以及其构造:
class AppRuntime : public AndroidRuntime
{
public:
AppRuntime(char* argBlockStart, const size_t argBlockLength)
: AndroidRuntime(argBlockStart, argBlockLength)
, mClass(NULL)
{
}
AppRuntime 继承自AndroidRuntime 类,这里就是ART 在framework 中的管理类,ART 的创建、初始化都是从这里开始。
下面先来看下AndroidRuntime 的构造函数:
frameworks/base/core/jni/AndroidRuntime.cpp
static AndroidRuntime* gCurRuntime = NULL;
...
AndroidRuntime::AndroidRuntime(char* argBlockStart, const size_t argBlockLength) :
mExitWithoutCleanup(false),
mArgBlockStart(argBlockStart),
mArgBlockLength(argBlockLength)
{
...
assert(gCurRuntime == NULL); // one per process
gCurRuntime = this;
}
将argBlockStart 和argBlockLength 存放在AndroidRuntime 中,最主要的是创建了一个进程一个的gCurRuntime 实例。后期如果想要获取这个实例可以通过函数AndroidRuntime::getRuntim() 获取:
AndroidRuntime* AndroidRuntime::getRuntime()
{
return gCurRuntime;
}
2.2 for 循环解析命令行参数
for (i = 0; i < argc; i++) {
if (known_command == true) {
runtime.addOption(strdup(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]));
...
}
注意for 循环中的两次 break,进而得知,这里主要是将 '-' 和 '--' 跟着参数添加到 gCurRuntime 的option 中。
对于这里的命令就是将/system/bin 之前的参数添加到option 中。
2.3 while 循环解析zygote进程名
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;
}
}
- 通过指定参数--zygote 指定是启动zygote 进程,并且根据编译参数,确认(根据niceName)启动的是zygote64 还是 zygote;
- 通过指定参数--start-system-server 确认是否启动system_server 进程;
- 通过指定参数--application 确认是否是应用进程;
- 通过指定参数--nice-name= 可以强制指定这个进程名,这里就需要注意与--zygote 是否冲突;
- 如果参数不是 '--' 开头,则退出while循环
这里注意的是参数 --zygote,如果设定该参数,在cast 中会指定niceName 为ZYGOTE_NICE_NAME:
#if defined(__LP64__)
static const char ABI_LIST_PROPERTY[] = "ro.product.cpu.abilist64";
static const char ZYGOTE_NICE_NAME[] = "zygote64";
#else
static const char ABI_LIST_PROPERTY[] = "ro.product.cpu.abilist32";
static const char ZYGOTE_NICE_NAME[] = "zygote";
#endif
从Android.bp 中获悉,最终会根据编译选项不同,app_main.cpp 会被编译出zygote64 和zygote(32位),这里也是根据编译选项不同,ZYGOTE_NICE_NAME 也是分别对应。
2.4 进入zygote 模式
if (!className.isEmpty()) {
...
} else {
// We're in zygote mode.
maybeCreateDalvikCache(); //创建/data/dalvik-cache
if (startSystemServer) {
args.add(String8("start-system-server"));
}
...
}
if (!niceName.isEmpty()) { //指定进程名
runtime.setArgv0(niceName.string(), true /* setProcName */);
}
if (zygote) { //启动zygote
runtime.start("com.android.internal.os.ZygoteInit", args, zygote);
}
...
详细看代码注释,主要是四点:
- 创建/data/dalvik-cache,后期的classes.art 都在这里;
- 解析命令行其他参数,指定到args,在后面启动 zygote java时传入;
- 指定进程名,niceName 在第 2.3 节解析出来,进程名为zygote64 还是zygote
- 启动 zygote java,className 为 com.android.internal.os.ZygoteInit,args是上面解析好的;
2.5 AndroidRuntime.start()
void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote)
{
...
//之前做了些准备工作,这里开始创建虚拟机
JniInvocation jni_invocation;
jni_invocation.Init(NULL);
JNIEnv* env;
if (startVm(&mJavaVM, &env, zygote, primary_zygote) != 0) {
return;
}
onVmCreated(env);
//注册一些JNI方法
if (startReg(env) < 0) {
ALOGE("Unable to register all android natives\n");
return;
}
//JNIenv和JNI方法初始化、注册完成,就可以使用java了
//因为运行java 的main函数需要传入string数组的参数,下面会进行转换
jclass stringClass;
jobjectArray strArray;
jstring classNameStr;
...
//java端需要的参数解析完成后,准备启动虚拟机
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 {
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 {
env->CallStaticVoidMethod(startClass, startMeth, strArray);
...
}
代码比较多,大致分为:
- 初始化 JNI 调用,详细看 JniInvocation;
- 调用 startVm(),创建 JAVA 虚拟机;
- 调用 startReg(),注册JNI 方法,java需要调用c/c++接口,都是通过JNI 的方法完成的,这里也就打通了 java到native 的屏障了;
- 调用 2.4 节传入的com.android.internal.os.ZygoteInit 的 main() 函数;
3. ZygoteInit.main()
frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
public static void main(String argv[]) {
//step1, 设置限定,期间不允许创建线程,不然会抛出error,一直到stop截止
ZygoteHooks.startZygoteNoThreadCreation();
try {
Os.setpgid(0, 0); //step2, 设置zygote 的进程组信息
} catch (ErrnoException ex) {
throw new RuntimeException("Failed to setpgid(0,0)", ex);
}
...
Runnable caller;
try {
...
RuntimeInit.preForkInit(); //step3, enable DDMS
...
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)) {
zygoteSocketName = argv[i].substring(SOCKET_NAME_ARG.length());
} else {
throw new RuntimeException("Unknown command line argument: " + argv[i]);
}
}
...
//step4, 对于primary zygote,即zygote64进程,进行preload
if (!enableLazyPreload) {
...
preload(bootTimingsTraceLog);
...
}
...
//step5, fork 前的gc 和finalization 工作
gcAndFinalize();
//step6, 初始化zygote 的状态
Zygote.initNativeState(isPrimaryZygote);
//step7, 解除最开始的 startZygoteNoThreadCreation 限定
ZygoteHooks.stopZygoteNoThreadCreation();
//step8, 创建ZygoteServer 实例
zygoteServer = new ZygoteServer(isPrimaryZygote);
//step9, fork system_server进程,注意创建成功时子进程(system_server)会将携带
// 过来的socket关闭,详细可以查看forkSystemServer()函数
if (startSystemServer) {
Runnable r = forkSystemServer(abiList, zygoteSocketName, zygoteServer);
//如果system server 成功fork,此时处于子进程,直接运行进入system_server进程
if (r != null) {
r.run();
return;
}
}
...
//step10, 如果fork system_server成功,主进程会
// 继续流程,进入Zygote 循环,普通进程的fork 从这里获取
caller = zygoteServer.runSelectLoop(abiList);
} catch (Throwable ex) {
Log.e(TAG, "System zygote died with exception", ex);
throw ex;
} finally {
if (zygoteServer != null) {//创建的子进程都会将携带的socket关闭
zygoteServer.closeServerSocket();
}
}
//step11,对于普通进程来说,通过runSelectLoop 成功获得进程后,从这里进入该进程
if (caller != null) {
caller.run();
}
}
看代码中的注释,代码太长,大致分11步,下面来分别解析。
3.1 startZygoteNoThreadCreation()
libcore/dalvik/src/main/java/dalvik/system/ZygoteHooks.java
@libcore.api.CorePlatformApi
public static native void startZygoteNoThreadCreation();
@libcore.api.CorePlatformApi
public static native void stopZygoteNoThreadCreation();
这个是native 的接口,来看下JNI 的代码:
art/runtime/native/dalvik_system_ZygoteHooks.cc
static void ZygoteHooks_startZygoteNoThreadCreation(JNIEnv* env ATTRIBUTE_UNUSED,
jclass klass ATTRIBUTE_UNUSED) {
Runtime::Current()->SetZygoteNoThreadSection(true);
}
static void ZygoteHooks_stopZygoteNoThreadCreation(JNIEnv* env ATTRIBUTE_UNUSED,
jclass klass ATTRIBUTE_UNUSED) {
Runtime::Current()->SetZygoteNoThreadSection(false);
}
其实说白了,就是设置Runtime 中的一个变量:
art/runtime/runtime.h
void SetZygoteNoThreadSection(bool val) {
zygote_no_threads_ = val;
}
bool IsZygoteNoThreadSection() const {
return zygote_no_threads_;
}
start 时候会标记为true,stop 的时候会标记为false,默认值为false。
如果这个时候在zygote 中创建线程会如何:
art/runtime/native/java_lang_Thread.cc
static void Thread_nativeCreate(JNIEnv* env, jclass, jobject java_thread, jlong stack_size,
jboolean daemon) {
// There are sections in the zygote that forbid thread creation.
Runtime* runtime = Runtime::Current();
if (runtime->IsZygote() && runtime->IsZygoteNoThreadSection()) {
jclass internal_error = env->FindClass("java/lang/InternalError");
CHECK(internal_error != nullptr);
env->ThrowNew(internal_error, "Cannot create threads in zygote");
return;
}
Thread::CreateNativeThread(env, java_thread, stack_size, daemon == JNI_TRUE);
}
代码很清晰,如果是zygote 进程,如果创建线程会抛 Cannot create threads in zygote 的错误。
3.2 Os.setpgid()
try {
Os.setpgid(0, 0); //step2, 设置zygote 的进程组信息
} catch (ErrnoException ex) {
throw new RuntimeException("Failed to setpgid(0,0)", ex);
}
指定当前进程的信息;
3.3 RuntimeInit.preForkInit()
frameworks/base/core/java/com/android/internal/os/RuntimeInit.java
public static void preForkInit() {
if (DEBUG) Slog.d(TAG, "Entered preForkInit.");
RuntimeHooks.setThreadPrioritySetter(new RuntimeThreadPrioritySetter());
RuntimeInit.enableDdms();
...
MimeMap.setDefaultSupplier(DefaultMimeMapFactory::create);
}
private static void enableDdms() {
// Register handlers for DDM messages.
android.ddm.DdmRegister.registerHandlers();
}
这里不做过多说明,主要是zygote 启动前的准备工作,包括DDMS,enableDdms 可以查看:frameworks/base/core/java/android/ddm/DdmRegister.java
3.4 preload()
通过代码得知如果zygote 启动时配置了参数 --enable-lazy-preload,则不会进行preload 操作,如第 1 节所示,一般会在 zygote_primary 进程中会preload,而在 zygote_secondary 是不会进行preload:
static void preload(TimingsTraceLog bootTimingsTraceLog) {
...
preloadClasses();
cacheNonBootClasspathClassLoaders();
preloadResources();
nativePreloadAppProcessHALs();
maybePreloadGraphicsDriver();
preloadSharedLibraries();
preloadTextResources();
WebViewFactory.prepareWebViewInZygote();
warmUpJcaProviders();
sPreloadComplete = true;
}
- 通过 preloadClasses() 加载 /system/etc/preloaded-classes 里的所有class,其中以 # 开头或空白行忽略。主要通过 Class.forName() 进行加载;
- 通过 preloadResources() 创建一个Resources 实例,加载系统资源;
- 通过 nativePreloadAppProcessHALs() 进行HAL 预加载;
- 通过 maybePreloadGraphicsDrive() 对driver 进行预加载,详细看 jni_runtime.cpp;
- 通过 preloadSharedLibraries() 进行动态库的预加载,包括 libandroid.so、libcompiler_rt.so、libjnigraphics.so、libsfplugin_ccodec.so、libperformance_jni.so 等;
- 通过 preloadTextResources() 加载字体资源;
3.5 gcAndFinalize()
private static void gcAndFinalize() {
ZygoteHooks.gcAndFinalize();
}
libcore/dalvik/src/main/java/dalvik/system/ZygoteHooks.java
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();
}
在zygote 之前进行一些GC 操作。
3.6 initNativeState()
frameworks/base/core/java/com/android/internal/os/Zygote.java
static void initNativeState(boolean isPrimary) {
nativeInitNativeState(isPrimary);
}
protected static native void nativeInitNativeState(boolean isPrimary);
接着来看下JNI 中的处理:
frameworks/base/core/jni/com_android_internal_os_Zygote.cpp
static void com_android_internal_os_Zygote_nativeInitNativeState(JNIEnv* env, jclass,
jboolean is_primary) {
gZygoteSocketFD =
android_get_control_socket(is_primary ? "zygote" : "zygote_secondary");
...
gUsapPoolSocketFD =
android_get_control_socket(is_primary ? "usap_pool_primary" : "usap_pool_secondary");
...
initUnsolSocketToSystemServer();
gIsSecurityEnforced = security_getenforce();
selinux_android_seapp_context_init();
...
- 创建zygote 和USAP 的socket,保存在各自的FD 中;
- 确认selinux 状态并check
3.7 stopZygoteNoThreadCreation()
详细代码见上文第 3.1 节,这里主要解除最开始的 startZygoteNoThreadCreation 限定。
3.8 ZygoteServer 的构造
ZygoteServer(boolean isPrimaryZygote) {
mUsapPoolEventFD = Zygote.getUsapPoolEventFD();
if (isPrimaryZygote) {
mZygoteSocket = Zygote.createManagedSocketFromInitSocket(Zygote.PRIMARY_SOCKET_NAME);
mUsapPoolSocket =
Zygote.createManagedSocketFromInitSocket(
Zygote.USAP_POOL_PRIMARY_SOCKET_NAME);
} else {
mZygoteSocket = Zygote.createManagedSocketFromInitSocket(Zygote.SECONDARY_SOCKET_NAME);
mUsapPoolSocket =
Zygote.createManagedSocketFromInitSocket(
Zygote.USAP_POOL_SECONDARY_SOCKET_NAME);
}
mUsapPoolSupported = true;
fetchUsapPoolPolicyProps();
}
- 为 USAP(unspecialized app process) 创建event fd;
- 创建socket 并 listen;
- 初始化USAP pool 的一些prop;
3.9 forkSystemServer()
private static Runnable forkSystemServer(String abiList, String socketName,
ZygoteServer zygoteServer) {
...
/* Hardcoded command line to start the system server */
String args[] = {
"--setuid=1000",
"--setgid=1000",
"--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1021,1023,"
+ "1024,1032,1065,3001,3002,3003,3006,3007,3009,3010,3011",
"--capabilities=" + capabilities + "," + capabilities,
"--nice-name=system_server",
"--runtime-args",
"--target-sdk-version=" + VMRuntime.SDK_VERSION_CUR_DEVELOPMENT,
"com.android.server.SystemServer",
};
ZygoteArguments parsedArgs = null;
int pid;
try {
parsedArgs = new ZygoteArguments(args);
Zygote.applyDebuggerSystemProperty(parsedArgs);
Zygote.applyInvokeWithSystemProperty(parsedArgs);
...
/* Request to fork the system server process */
pid = Zygote.forkSystemServer(
parsedArgs.mUid, parsedArgs.mGid,
parsedArgs.mGids,
parsedArgs.mRuntimeFlags,
null,
parsedArgs.mPermittedCapabilities,
parsedArgs.mEffectiveCapabilities);
} catch (IllegalArgumentException ex) {
throw new RuntimeException(ex);
}
/* For child process */
if (pid == 0) {
if (hasSecondZygote(abiList)) {
waitForSecondaryZygote(socketName);
}
zygoteServer.closeServerSocket();
return handleSystemServerProcess(parsedArgs);
}
return null;
}
如果fork 成功,会分别进入子进程和父进程的逻辑,对于父进程是直接返回上一级继续执行后续,对于子进程则进入 handleSystemServerProcess,如下:
if (pid == 0) {
if (hasSecondZygote(abiList)) {
waitForSecondaryZygote(socketName);
}
zygoteServer.closeServerSocket(); //将父进程中的socket 关闭,不再需要了
return handleSystemServerProcess(parsedArgs); //子进程进入内部处理函数
}
对于子进程来说,从zygote 中携带过来的socket不会使用,直接close掉。后面通过 AMS 申请创建的应用进程都会将携带过来的 socket 都关掉。
另外,函数中具体的handleSystemServerProcess() 这里不再列出,其中主要操作是调用 ZygoteInit.zygoteInit():
public static final Runnable zygoteInit(int targetSdkVersion, long[] disabledCompatChanges,
String[] argv, ClassLoader classLoader) {
...
RuntimeInit.redirectLogStreams();
RuntimeInit.commonInit();
ZygoteInit.nativeZygoteInit();
return RuntimeInit.applicationInit(targetSdkVersion, disabledCompatChanges, argv,
classLoader);
}
这里不再过多分析,详细看system server 的启动过程分析。
3.10 zygoteServer.runSelectLoop()
在 3.9 节中会调用 forkSystemServer(),并且子进程会返回一个Runnable,而父进程返回NULL,所以,对于Zygote 进程来说,是返回NULL,继续会执行zygoteServer.runSelectLoop。
这里的代码比较多,对于zygote 来说,会在poll 触发的时候,创建ZygoteConnection:
if (pollIndex == 0) {
// Zygote server socket
ZygoteConnection newPeer = acceptCommandPeer(abiList);
peers.add(newPeer);
socketFDs.add(newPeer.getFileDescriptor());
}
其他详细的可以查看应用启动过程分析。
4. 总结
这样,Zygote进程就启动完成了,学习到这里,我们终于都对Android系统中的进程有了一个深刻的认识了,这里总结一下:
- 系统启动时init 进程会创建 zygote 进程,这是Android 系统的核心进程,用以孵化Android 中所有的应用程序,包括 system_server;
- 在 zygote 进程运行过程中分 native 部分和 java 部分:
- native 部分用以准备 java 所需的一切环境,核心是虚拟机的创建、JNIenv 初始化,以及JNI method 的注册。当 java 所需环境准备完成,最终会启动 zygote 的java 端代码;
- java 部分主要会预加载一些进程所需的资源(classes 和 resource 等),并创建 ZygoteServer 实例,该实例用以管理 socket 通信,最后根据需要会 fork system_server 进程并运行,然后通过 zygoteserver.runSelectLoop() 函数等待Android 普通应用进程的创建;
5. Q&A
为什么zygote使用socket通信而不使用binder?
答案是没必要
zygote 创建socket 进行消息通信,以此来孵化一个应用进程,而且采用了 LocalSocket 相对于网络Socket,减少了数据验证等环节,所以其实效率相对于正常的网络Socket会大幅的提升。虽然还是要经过两次拷贝,但是由于数据量并不大,所以其实影响并不明显。
而使用 binder,则需要做到:
- 优先启动 servicemanager,至少要早于 zygote;
- zygote 创建 BBinder,并将其binder 添加到 servicemanager 中;
- zygote fork 出 system_server 之后,需要在AMS 中创建 client 端的 binder 对象,便于与 zygote 通信,则需要通过 servicemanager 进行getService();
- AMS 通过binder 驱动,与 zygote 通信;
zygote 创建的 BBinder 内存会被携带到孵化的每个进程,包括 system_server;
zygote 创建BBinder 就意味着多线程,fork 出来的进程天生就是多线程,需要考虑死锁问题;