frameworks 之Zygote
Zygote 中文意思为受精卵。 和其意思一样,该功能负责android系统孵化service 和 app 进程。
本文讲解Zygote的大概流程。涉及的相同的类,如下所示
- system/core/rootdir/init.zygote32.rc
- frameworks/base/cmds/app_process/app_main.cpp
- frameworks/base/core/jni/AndroidRuntime.cpp
- system/core/init/main.cpp
- frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
- frameworks/base/core/java/com/android/internal/os/Zygote.java
- frameworks/base/core/jni/com_android_internal_os_Zygote.cpp
Zygote.rc 解析
启动init进程后,会解析 Zygote.rc文件。该文件位于 system/core/rootdir 文件夹下
其中第一行 zygote 表示进程名, /system/bin/app_process 表示要启动的模块名 ,–zygote --start-system-server 表示参数, class main 表示入口方法。
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
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
writepid /dev/cpuset/foreground/tasks
critical window=${zygote.critical_window.minute:-off} target=zygote-fatal
Zygote 启动
根据上面的rc文件 全局搜索 grep app_process ./ -rn
可以看到该模块名为app_process的位于 base/cmds/app_process 下。
跳转到该文件夹下 打开 app_main.cpp 文件,查看main 方法
main 方法前面是解析参数,并对变量 zygote, startSystemServer 设置为true, 通过 runtime.start 方法启动, start方法是在继承在 AndroidRuntime 类实现
int main(int argc, char* const argv[])
{
// Parse runtime arguments. Stop at first unrecognized option.
bool zygote = false;
bool startSystemServer = false;
bool application = false;
String8 niceName;
String8 className;
// 将变量为true
++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;
}
}
// zygote 为true 通过runtime启动,com.android.internal.os.ZygoteInit 为类名
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.");
}
}
通过 全局查找 grep “AndroidRuntime” ./ -rn 得到该类的位置 在 core/jni/AndroidRuntime.cpp 下
该方法前面大部分还是参数变量判断,关键通过 jmethodID startMeth = env->GetStaticMethodID(startClass, “main”,
“([Ljava/lang/String;)V”); 启动 对应的main方法。根据上一步传进来的参数。可以得到启动了 ZygoteInit.java 类
void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote)
{
/*
* 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;
// 省略
// 加载传进来的类名,jni 加载对应的main方法
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);
#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");
}
ZygoteInit.java
查看对应的main方法 ,main 里面主要的方法有如下
preload(bootTimingsTraceLog); 预加载了类,资源,opengl,so库等
初始化ZygoteServer
forkSystemServer 启动 SystemServer
runSelectLoop 循环等待消息
public static void main(String[] argv) {
...
// 初始化参数 startSystemServer 决定启动 systemServer 服务
boolean startSystemServer = false;
String zygoteSocketName = "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)) {
zygoteSocketName = argv[i].substring(SOCKET_NAME_ARG.length());
} else {
throw new RuntimeException("Unknown command line argument: " + argv[i]);
}
}
...
// In some configurations, we avoid preloading resources and classes eagerly.
// In such cases, we will preload things prior to our first fork.
if (!enableLazyPreload) {
bootTimingsTraceLog.traceBegin("ZygotePreload");
EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,
SystemClock.uptimeMillis());
// 加载类资源 和so
preload(bootTimingsTraceLog);
EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,
SystemClock.uptimeMillis());
bootTimingsTraceLog.traceEnd(); // ZygotePreload
}
...
// 创建systemServiver 服务
zygoteServer = new ZygoteServer(isPrimaryZygote);
if (startSystemServer) {
Runnable r = forkSystemServer(abiList, zygoteSocketName, zygoteServer);
// {@code r == null} in the parent (zygote) process, and {@code r != null} in the
// child (system_server) process.
if (r != null) {
r.run();
return;
}
}
...
Log.i(TAG, "Accepting command socket connections");
// 等待服务
// The select loop returns early in the child process after a fork and
// loops forever in the zygote.
caller = zygoteServer.runSelectLoop(abiList);
}
其中 preload 里面的 preloadClasses 加载android所需的类 ,加载 preloaded-classes 文件 通过Class.forName 加载类。可通过find -name preloaded-classes 查看该文件的位置该文件通过编译时候拷贝到 system/ect目录下 。
static void preload(TimingsTraceLog bootTimingsTraceLog) {
preloadClasses();
preloadResources();
nativePreloadAppProcessHALs();
preloadSharedLibraries();
preloadTextResources();
}
private static final String PRELOADED_CLASSES = "/system/etc/preloaded-classes";
private static void preloadClasses() {
// 加载文件
InputStream is;
try {
is = new FileInputStream(PRELOADED_CLASSES);
} catch (FileNotFoundException e) {
Log.e(TAG, "Couldn't find " + PRELOADED_CLASSES + ".");
return;
}
...
// 循环遍历 通过 Class.forName 加载类文件
while ((line = br.readLine()) != null) {
// Skip comments and blank lines.
line = line.trim();
if (line.startsWith("#") || line.equals("")) {
continue;
}
Trace.traceBegin(Trace.TRACE_TAG_DALVIK, line);
try {
// Load and explicitly initialize the given class. Use
// Class.forName(String, boolean, ClassLoader) to avoid repeated stack lookups
// (to derive the caller's class-loader). Use true to force initialization, and
// null for the boot classpath class-loader (could as well cache the
// class-loader of this class in a variable).
Class.forName(line, true, null);
count++;
} catch (ClassNotFoundException e) {
if (line.contains("$$Lambda$")) {
if (LOGGING_DEBUG) {
missingLambdaCount++;
}
} else {
Log.w(TAG, "Class not found for preloading: " + line);
}
} catch (UnsatisfiedLinkError e) {
Log.w(TAG, "Problem preloading " + line + ": " + e);
} catch (Throwable t) {
Log.e(TAG, "Error preloading " + line + ".", t);
if (t instanceof Error) {
throw (Error) t;
} else if (t instanceof RuntimeException) {
throw (RuntimeException) t;
} else {
throw new RuntimeException(t);
}
}
Trace.traceEnd(Trace.TRACE_TAG_DALVIK);
}
}
runSelectLoop 里面是一个死循环,poll等待消息 如果没消息来 就会卡在这 ,如果第一次进来,调用 acceptCommandPeer,接着 acceptCommandPeer 又会调用 createNewConnection方法 创建 ZygoteConnection。
..
// poll等待消息 如果没消息来 就会卡在这
try {
pollReturnValue = Os.poll(pollFDs, pollTimeoutMs);
} catch (ErrnoException ex) {
throw new RuntimeException("poll failed", ex);
}
...
//如果第一次进来,调用 acceptCommandPeer,创建 ZygoteConnection
if (pollIndex == 0) {
// Zygote server socket
ZygoteConnection newPeer = acceptCommandPeer(abiList);
peers.add(newPeer);
socketFDs.add(newPeer.getFileDescriptor());
} else if (pollIndex < usapPoolEventFDIndex) {
ZygoteConnection connection = peers.get(pollIndex);
boolean multipleForksOK = !isUsapPoolEnabled()
&& ZygoteHooks.isIndefiniteThreadSuspensionSafe();
// 执行创建
final Runnable command =
connection.processCommand(this, multipleForksOK);
}
processCommand 方法里面会调用 forkAndSpecialize 继续调用 nativeForkAndSpecialize 创建进程,而 nativeForkAndSpecialize又会调用 ForkCommon 创建。
if (parsedArgs.mInvokeWith != null || parsedArgs.mStartChildZygote
|| !multipleOK || peer.getUid() != Process.SYSTEM_UID) {
// Continue using old code for now. TODO: Handle these cases in the other path.
// 创建进程
pid = Zygote.forkAndSpecialize(parsedArgs.mUid, parsedArgs.mGid,
parsedArgs.mGids, parsedArgs.mRuntimeFlags, rlimits,
parsedArgs.mMountExternal, parsedArgs.mSeInfo, parsedArgs.mNiceName,
fdsToClose, fdsToIgnore, parsedArgs.mStartChildZygote,
parsedArgs.mInstructionSet, parsedArgs.mAppDataDir,
parsedArgs.mIsTopApp, parsedArgs.mPkgDataInfoList,
parsedArgs.mAllowlistedDataInfoList, parsedArgs.mBindMountAppDataDirs,
parsedArgs.mBindMountAppStorageDirs);
try {
if (pid == 0) {
// in child
zygoteServer.setForkChild();
zygoteServer.closeServerSocket();
IoUtils.closeQuietly(serverPipeFd);
serverPipeFd = null;
return handleChildProc(parsedArgs, childPipeFd,
parsedArgs.mStartChildZygote);
} else {
// In the parent. A pid < 0 indicates a failure and will be handled in
// handleParentProc.
IoUtils.closeQuietly(childPipeFd);
childPipeFd = null;
handleParentProc(pid, serverPipeFd);
return null;
}
} finally {
IoUtils.closeQuietly(childPipeFd);
IoUtils.closeQuietly(serverPipeFd);
}
}
Zygote.cpp
forkSystemServer 会调用 Zygote.forkSystemServer 方法,而forkSystemServer 又会调用
nativeForkSystemServer 方法, 最终调用到 Zygote.cpp 里面的方法。直接查找 Zygote.cpp 可以看到该文件位于 frameworks/base/core/jni 。
/* Request to fork the system server process */
pid = Zygote.forkSystemServer(
parsedArgs.mUid, parsedArgs.mGid,
parsedArgs.mGids,
parsedArgs.mRuntimeFlags,
null,
parsedArgs.mPermittedCapabilities,
parsedArgs.mEffectiveCapabilities);
static int forkSystemServer(int uid, int gid, int[] gids, int runtimeFlags,
int[][] rlimits, long permittedCapabilities, long effectiveCapabilities) {
ZygoteHooks.preFork();
int pid = nativeForkSystemServer(
uid, gid, gids, runtimeFlags, rlimits,
permittedCapabilities, effectiveCapabilities);
// Set the Java Language thread priority to the default value for new apps.
Thread.currentThread().setPriority(Thread.NORM_PRIORITY);
ZygoteHooks.postForkCommon();
return pid;
}
看到关键语句pid 可以看出该方法是fork 出进程id, 调用的是liunx 自带fork方法 孵化出进程,当返回的id为0时候 代表是新进程,可以看到会调用 ForkCommon 方法。
pid_t pid = zygote::ForkCommon(env, true,
fds_to_close,
fds_to_ignore,
true);
if (pid == 0) {
// System server prcoess does not need data isolation so no need to
// know pkg_data_info_list.
SpecializeCommon(env, uid, gid, gids, runtime_flags, rlimits, permitted_capabilities,
effective_capabilities, MOUNT_EXTERNAL_DEFAULT, nullptr, nullptr, true,
false, nullptr, nullptr, /* is_top_app= */ false,
/* pkg_data_info_list */ nullptr,
/* allowlisted_data_info_list */ nullptr, false, false);
}
查看 ForkCommon 方法。里面调用了 Fork方法 创建进程
// 创建进程
pid_t pid = fork();
if (pid == 0) {
if (is_priority_fork) {
setpriority(PRIO_PROCESS, 0, PROCESS_PRIORITY_MAX);
} else {
setpriority(PRIO_PROCESS, 0, PROCESS_PRIORITY_MIN);
}
// The child process.
PreApplicationInit();
// Clean up any descriptors which must be closed immediately
DetachDescriptors(env, fds_to_close, fail_fn);
// Invalidate the entries in the USAP table.
ClearUsapTable();
// Re-open all remaining open file descriptors so that they aren't shared
// with the zygote across a fork.
gOpenFdTable->ReopenOrDetach(fail_fn);
// Turn fdsan back on.
android_fdsan_set_error_level(fdsan_error_level);
// Reset the fd to the unsolicited zygote socket
gSystemServerSocketFd = -1;
} else {
ALOGD("Forked child process %d", pid);
}
Liunx fork
fork函数是 Liunx ,fork() 返回的pid pid等于0 表示三fork新进程执行 不等于0 原来的进程执行代码。新建forkTest.c文件,
touch forkTest.c 内容如下
#include <unistd.h>
#include <stdio.h>
int main(void){
printf("main current process pid == %d \n", getpid());
// 创建进程
int pid = fork();
// 这里会分开2个线程 pid等于0 表示三fork新进程执行 不等于0 原来的进程执行代码
if (pid == 0) {
printf("fork newProgress child process pid = %d parent pid = %d \n", getpid(), getppid());
} else {
printf("this process pid = %d forkPid = %d parent pid = %d \n", getpid(),pid, getppid());
}
return 0;
}
然后执行 gcc forkTest.c -o forkTest 编译为二进制文件 ,在执行 ./forkTest 命令执行 查看打印
main current process pid == 7766
this process pid = 7766 forkPid = 7767 parent pid = 7144
fork newProgress child process pid = 7767 parent pid = 7766