当前位置: 首页 > news >正文

Android 12系统源码_系统启动(二)Zygote进程

前言

Zygote(意为“受精卵”)是 Android 系统中的一个核心进程,负责 孵化(fork)应用进程,以优化应用启动速度和内存占用。它是 Android 系统启动后第一个由 init 进程启动的 Java 进程,后续所有 Android 应用进程(如 system_server 和用户应用)都由它 fork 而来。Zygote主要有以下几种作用。

  • 预加载 Java 类和资源
    在启动时加载 Android 核心类(如 Activity、View、Context)和系统资源(如 framework-res.apk),避免每个应用重复加载,节省内存和时间。

  • 进程孵化(fork)
    当启动新应用时,Zygote 会 fork 自身,生成一个新的子进程(即应用进程),并继承已预加载的类,减少启动开销。

  • 安全管理
    继承 Zygote 的安全策略(如 SELinux 上下文、UID/GID),确保应用运行在正确的权限环境下。

搜寻Zygote源码位置

我们在Android 12系统源码_系统启动(一)init进程这篇文章中有提到过init.rc脚本。

system/core/rootdir/init.rc

import /init.environ.rc
import /system/etc/init/hw/init.usb.rc
import /init.${ro.hardware}.rc
import /vendor/etc/init/hw/init.${ro.hardware}.rc
import /system/etc/init/hw/init.usb.configfs.rc
import /system/etc/init/hw/init.${ro.zygote}.rc

实际运行中的系统中,/system/etc/init/hw目录的具体内容如下所示:

# 进入/system/etc/init/hw目录,输入ls指令
# 可以看到如下内容init.rc  init.usb.configfs.rc  init.usb.rc  init.zygote32.rc  init.zygote64_32.rc

由于我本地的系统getprop ro.zygote的值是zygote64_32,这样init.rc引用的自然就是init.zygote64_32.rc脚本文件,Android系统/system/etc/init/hw/目录中的.rc脚本,最初都是从源码system/core/rootdir目录拷贝而来的。
rootdir目录

service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server --socket-name=zygoteclass mainpriority -20user rootgroup root readproc reserved_disksocket zygote stream 660 root systemsocket usap_pool_primary stream 660 root systemonrestart exec_background - system system -- /system/bin/vdc volume abort_fuseonrestart write /sys/power/state ononrestart restart audioserveronrestart restart cameraserveronrestart restart mediaonrestart restart netdonrestart restart wificondtask_profiles ProcessCapacityHigh MaxPerformancecritical window=${zygote.critical_window.minute:-off} target=zygote-fatal

结合以上代码可以知道init启动了zygote服务,对应的就是/system/bin/app_process64这个程序。
在aosp源码中通过以下指令进行搜索

grep "app_process" -rn ./ --include="*.bp"

通过以上指令我们可以定位到如下内容
搜索结果
可以知道app_process程序对应的源码地址为frameworks/base/cmds/app_process

Zygote入口函数

frameworks/base/cmds/app_process/app_main.cpp

class AppRuntime : public AndroidRuntime
{
public:AppRuntime(char* argBlockStart, const size_t argBlockLength): AndroidRuntime(argBlockStart, argBlockLength), mClass(NULL){}
}
#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
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());}//注释1,进行AppRuntime的构造AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));// 忽略 argv[0](程序名)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; // Skip --.break;}runtime.addOption(strdup(argv[i]));ALOGV("app_process main add option '%s'", argv[i]);}bool zygote = false;bool startSystemServer = false;bool application = false;String8 niceName;String8 className;++i;//跳过 "parent dir" 参数  //解析启动模式while (i < argc) {const char* arg = argv[i++];if (strcmp(arg, "--zygote") == 0) {zygote = true;niceName = ZYGOTE_NICE_NAME;// "zygote" 或 "zygote64"} else if (strcmp(arg, "--start-system-server") == 0) {startSystemServer = true; // 启动 system_server} else if (strcmp(arg, "--application") == 0) {application = true;// 标记为普通应用} else if (strncmp(arg, "--nice-name=", 12) == 0) {niceName.setTo(arg + 12);// 设置进程名(如 "webview_zygote")} else if (strncmp(arg, "--", 2) != 0) {className.setTo(arg);break;} else {--i;break;}}//准备启动参数Vector<String8> args;if (!className.isEmpty()) {// 普通 Java 模式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 模式maybeCreateDalvikCache();// 确保 Dalvik 缓存目录存在if (startSystemServer) {args.add(String8("start-system-server"));// 告知 Zygote 启动 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]));}}if (!niceName.isEmpty()) {// 设置进程名(如 "zygote")runtime.setArgv0(niceName.string(), true /* setProcName */);}if (zygote) {//注释2,启动 JVM,调用ZygoteInit.main(),进入 Zygote 的主循环。runtime.start("com.android.internal.os.ZygoteInit", args, zygote);} else if (className) {//启动 JVM,调用 RuntimeInit.main(),直接运行指定的 Java 类。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.");}
}

在注释1处,进行AppRuntime的构造,该类继承自AndroidRuntime。
由于我们这里主要是分析zgote主线逻辑,继续关注注释2处,调用runtime的start方法。

AndroidRuntime的start方法

frameworks/base/core/jni/AndroidRuntime.cpp

void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote)
{//日志打印 AndroidRuntime: >>>>>> START com.android.internal.os.ZygoteInitALOGD(">>>>>> START %s uid %d <<<<<<\n",className != NULL ? className : "(unknown)", getuid());static const String8 startSystemServer("start-system-server");// Whether this is the primary zygote, meaning the zygote which will fork system server.bool primary_zygote = false;...代码省略...JniInvocation jni_invocation;jni_invocation.Init(NULL);JNIEnv* env;//启动java需要的jvm环境,才可以运行java代码if (startVm(&mJavaVM, &env, zygote, primary_zygote) != 0) {return;}onVmCreated(env);/** Register android functions.*/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 {//调用ZygoteInit类的main方法//startClass = com.android.internal.os.ZygoteInit//startMeth = main//strArray 字符串集合,存放方法参数env->CallStaticVoidMethod(startClass, startMeth, strArray);}}...代码省略...
}

app_main主要做的工作就是准备虚拟机环境,让进程运行到了java世界的ZygoteInit的main方法

ZygoteInit的main方法

frameworks/base/core/java/com/android/internal/os/ZygoteInit.java

public class ZygoteInit {public static void main(String[] argv) {ZygoteServer zygoteServer = null;//禁止在 Zygote 中创建线程,确保调用fork()方法构建子进程时进程状态简单。ZygoteHooks.startZygoteNoThreadCreation();try {//将 Zygote 设为独立的进程组,避免被信号误杀。Os.setpgid(0, 0);} catch (ErrnoException ex) {throw new RuntimeException("Failed to setpgid(0,0)", ex);}Runnable caller;try {// 记录启动时间(用于性能统计)final long startTime = SystemClock.elapsedRealtime();final boolean isRuntimeRestarted = "1".equals(SystemProperties.get("sys.boot_completed"));// 初始化 Trace 和日志工具(区分 32/64 位 Zygote)String bootTimeTag = Process.is64Bit() ? "Zygote64Timing" : "Zygote32Timing";// 用于记录启动耗时TimingsTraceLog bootTimingsTraceLog = new TimingsTraceLog(bootTimeTag,Trace.TRACE_TAG_DALVIK);bootTimingsTraceLog.traceBegin("ZygoteInit");RuntimeInit.preForkInit();// 初始化运行时环境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])) {//是否启动 system_serverstartSystemServer = true;} else if ("--enable-lazy-preload".equals(argv[i])) {//是否延迟预加载(优化启动速度)enableLazyPreload = true;} else if (argv[i].startsWith(ABI_LIST_ARG)) {// 支持的 CPU ABI 列表abiList = argv[i].substring(ABI_LIST_ARG.length());} else if (argv[i].startsWith(SOCKET_NAME_ARG)) {// "--socket-name="zygoteSocketName = argv[i].substring(SOCKET_NAME_ARG.length());} else {throw new RuntimeException("Unknown command line argument: " + argv[i]);}}final boolean isPrimaryZygote = zygoteSocketName.equals(Zygote.PRIMARY_SOCKET_NAME);if (!isRuntimeRestarted) {if (isPrimaryZygote) {FrameworkStatsLog.write(FrameworkStatsLog.BOOT_TIME_EVENT_ELAPSED_TIME_REPORTED,BOOT_TIME_EVENT_ELAPSED_TIME__EVENT__ZYGOTE_INIT_START,startTime);} else if (zygoteSocketName.equals(Zygote.SECONDARY_SOCKET_NAME)) {FrameworkStatsLog.write(FrameworkStatsLog.BOOT_TIME_EVENT_ELAPSED_TIME_REPORTED,BOOT_TIME_EVENT_ELAPSED_TIME__EVENT__SECONDARY_ZYGOTE_INIT_START,startTime);}}if (abiList == null) {throw new RuntimeException("No ABI list supplied.");}if (!enableLazyPreload) {bootTimingsTraceLog.traceBegin("ZygotePreload");EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,SystemClock.uptimeMillis());preload(bootTimingsTraceLog);// 注释1,预加载类、资源、OpenGL等EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,SystemClock.uptimeMillis());bootTimingsTraceLog.traceEnd();// ZygotePreload}// Do an initial gc to clean up after startupbootTimingsTraceLog.traceBegin("PostZygoteInitGC");gcAndFinalize();// 触发 GC 清理预加载后的内存bootTimingsTraceLog.traceEnd();// PostZygoteInitGCbootTimingsTraceLog.traceEnd();// ZygoteInitZygote.initNativeState(isPrimaryZygote);// 初始化 Native 层状态ZygoteHooks.stopZygoteNoThreadCreation();//解除线程创建限制,允许后续操作创建线程。zygoteServer = new ZygoteServer(isPrimaryZygote);//构造方法中会创建Zygote端需要的socketif (startSystemServer) {// 注释1,fork出system_server子进程Runnable r = forkSystemServer(abiList, zygoteSocketName, zygoteServer);//如果是父进程则返回null,如果是system_server子进程则返回SystemServerRunnableif (r != null) {r.run();return;}}Log.i(TAG, "Accepting command socket connections");//注释3,阻塞监听Socket,这轮询会在zygote进程中无限循环,但是如果fork出子进程(system_server或者Android应用进程)就会退出来caller = zygoteServer.runSelectLoop(abiList);} catch (Throwable ex) {Log.e(TAG, "System zygote died with fatal exception", ex);throw ex;} finally {if (zygoteServer != null) {//system_server进程和android应用进程会关闭socket,zygote仍然在runSelectLoop中轮询监听socketzygoteServer.closeServerSocket();}}if (caller != null) {caller.run(); // 注释4,在子进程中执行(如启动 ActivityThread)}}
}

在注释1处调用preload方法进行预加载。
在注释2处调用 Zygote.forkSystemServer() 创建system_server子进程,如果是父进程则返回null,如果是子进程则返回SystemServer的Runnable对象,并进一步调用该Runnable对象的run方法,最终会进入SystemServer的main方法中,加载Android系统需要的各种服务。
在注释3处调用zygoteServer的runSelectLoop方法阻塞监听Socket,等待 AMS 发送 fork 请求,收到请求后创建对应的子进程。
以上就是ZygoteInit的main方法的主要代码,下面我们具体分析一下。
在注释4处,如果当前是子进程,其实就是应用进程,则调用其返回的Runnable的run方法,最终会进入ActivityThread的main方法。

预加载

注释1处调用preload方法,预加载以下内容。

    static void preload(TimingsTraceLog bootTimingsTraceLog) {Log.d(TAG, "begin preload");...代码省略...beginPreload();...代码省略...preloadClasses();//加载/system/etc/preloaded-classes目录下的类。...代码省略...preloadResources();//加载系统资源/system/framework/framework-res.apk...代码省略...preloadSharedLibraries();preloadTextResources();...代码省略...Log.d(TAG, "end preload");sPreloadComplete = true;}

孵化子进程,返回Runnable对象

在注释2处调用 Zygote.forkSystemServer() 孵化system_server子进程,如果是父进程则返回null,如果是子进程则返回实现了Runnable接口的MethodAndArgsCaller对象,并进一步调用该Runnable对象的run方法,最终会进入SystemServer的main方法中,加载Android系统需要的各种服务。

孵化system_server子进程

public class ZygoteInit {private static Runnable forkSystemServer(String abiList, String socketName,ZygoteServer zygoteServer) {...代码省略.../* Hardcoded command line to start the system server */String[] args = {"--setuid=1000",//用户id"--setgid=1000",//组id"--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,3012","--capabilities=" + capabilities + "," + capabilities,"--nice-name=system_server","--runtime-args","--target-sdk-version=" + VMRuntime.SDK_VERSION_CUR_DEVELOPMENT,"com.android.server.SystemServer",//SystemServer类名,只有这个条目是非--开头的};ZygoteArguments parsedArgs;int pid;try {...代码省略...parsedArgs = ZygoteArguments.getInstance(commandBuffer);...代码省略.../*调用Zygote的forkSystenServer方法fork system_server进程*/pid = Zygote.forkSystemServer(parsedArgs.mUid, parsedArgs.mGid,parsedArgs.mGids,parsedArgs.mRuntimeFlags,null,parsedArgs.mPermittedCapabilities,parsedArgs.mEffectiveCapabilities);} catch (IllegalArgumentException ex) {throw new RuntimeException(ex);}if (pid == 0) {...代码省略...//由于zygoteServer只有Zygote会使用,子进程system_server不需要使用,于是会将其关闭。zygoteServer.closeServerSocket();//继续调用handleSystemServerProcess方法return handleSystemServerProcess(parsedArgs);}return null;}
}   
>frameworks/base/core/java/com/android/internal/os/Zygote.javapublic final class Zygote {static int forkSystemServer(int uid, int gid, int[] gids, int runtimeFlags,int[][] rlimits, long permittedCapabilities, long effectiveCapabilities) {...代码省略...int pid = nativeForkSystemServer(uid, gid, gids, runtimeFlags, rlimits,permittedCapabilities, effectiveCapabilities);...代码省略...return pid;}   private static native int nativeForkSystemServer(int uid, int gid, int[] gids, int runtimeFlags,int[][] rlimits, long permittedCapabilities, long effectiveCapabilities);     }

开启线程池,返回实现了Runnable接口的MethodAndArgsCaller对象

public class ZygoteInit {private static Runnable handleSystemServerProcess(ZygoteArguments parsedArgs) {...代码省略...//从环境变量SYSTEMSERVERCLASSPATH获取到SystemServer类文件相应jar包的路径final String systemServerClasspath = Os.getenv("SYSTEMSERVERCLASSPATH");if (systemServerClasspath != null) {//对相应的jar包做dex优化处理performSystemServerDexOpt(systemServerClasspath);...代码省略...}...代码省略...ClassLoader cl = getOrCreateSystemServerClassLoader();//创建类加载器if (cl != null) {Thread.currentThread().setContextClassLoader(cl);}//调用ZygoteInit的zygoteInit方法return ZygoteInit.zygoteInit(parsedArgs.mTargetSdkVersion,parsedArgs.mDisabledCompatChanges,parsedArgs.mRemainingArgs, cl);}public static Runnable zygoteInit(int targetSdkVersion, long[] disabledCompatChanges,String[] argv, ClassLoader classLoader) {...代码省略...RuntimeInit.redirectLogStreams();RuntimeInit.commonInit();//调用native方法,主要是开启ProcessState线程池,用来进行binder通信ZygoteInit.nativeZygoteInit();//调用RuntimeInit的applicationInit方法return RuntimeInit.applicationInit(targetSdkVersion, disabledCompatChanges, argv,classLoader);}private static native void nativeZygoteInit();  }>frameworks/base/core/jni/AndroidRuntime.cppint register_com_android_internal_os_ZygoteInit_nativeZygoteInit(JNIEnv* env)
{const JNINativeMethod methods[] = {{ "nativeZygoteInit", "()V",(void*) com_android_internal_os_ZygoteInit_nativeZygoteInit },};return jniRegisterNativeMethods(env, "com/android/internal/os/ZygoteInit",methods, NELEM(methods));
}
static void com_android_internal_os_ZygoteInit_nativeZygoteInit(JNIEnv* env, jobject clazz)
{gCurRuntime->onZygoteInit();
}>frameworks/base/cmds/app_process/app_main.cppvirtual void onZygoteInit(){sp<ProcessState> proc = ProcessState::self();ALOGV("App process: starting thread pool.\n");proc->startThreadPool();//开启线程池}>frameworks/base/core/java/com/android/internal/os/RuntimeInit.javapublic class RuntimeInit {protected static Runnable applicationInit(int targetSdkVersion, long[] disabledCompatChanges,String[] argv, ClassLoader classLoader) {...代码省略...final Arguments args = new Arguments(argv);//解析参数argvreturn findStaticMain(args.startClass, args.startArgs, classLoader);}static class Arguments {String startClass;//类路径String[] startArgs;//参数Arguments(String args[]) throws IllegalArgumentException {parseArgs(args);}private void parseArgs(String args[])throws IllegalArgumentException {int curArg = 0;for (; curArg < args.length; curArg++) {String arg = args[curArg];if (arg.equals("--")) {curArg++;break;} else if (!arg.startsWith("--")) {//com.android.server.SystemServer字符串break;}}if (curArg == args.length) {throw new IllegalArgumentException("Missing classname argument to RuntimeInit!");}startClass = args[curArg++];startArgs = new String[args.length - curArg];System.arraycopy(args, curArg, startArgs, 0, startArgs.length);}        }    protected static Runnable findStaticMain(String className, String[] argv, ClassLoader classLoader) {Class<?> cl;...代码省略..//获取到SystemServer的类字节cl = Class.forName(className, true, classLoader);...代码省略..Method m;//获取到main方法的方法idm = cl.getMethod("main", new Class[] { String[].class });...代码省略..//这个就是ZygoteInit类中forkSystemServer的返回值rreturn new MethodAndArgsCaller(m, argv);}static class MethodAndArgsCaller implements Runnable {private final Method mMethod;private final String[] mArgs;public MethodAndArgsCaller(Method method, String[] args) {mMethod = method;mArgs = args;}public void run() {...代码省略...//通过反射调用mMethod静态方法,这里触发的其实就是SystemServer的main方法mMethod.invoke(null, new Object[] { mArgs });...代码省略...}}}

监听socket,等待AMS发送fork请求

注释3处调用zygoteServer的runSelectLoop方法阻塞监听Socket,等待 AMS 发送 fork 请求,收到请求后创建对应的子进程。

frameworks/base/core/java/com/android/internal/os/ZygoteServer.java

class ZygoteServer {private LocalServerSocket mZygoteSocket;//服务端socketZygoteServer(boolean isPrimaryZygote) {...代码省略...//调用Zygote的createManagedSocketFromInitSocket方法创建Zygote端需要的socketmZygoteSocket = Zygote.createManagedSocketFromInitSocket(Zygote.PRIMARY_SOCKET_NAME);...代码省略...       }/*** 开启zygote进程轮询监听。接收新的socket连接(会创建新的ZygoteConnection)* 并且从这些链接中中读取命令,并且执行*/Runnable runSelectLoop(String abiList) {ArrayList<FileDescriptor> socketFDs = new ArrayList<>();ArrayList<ZygoteConnection> peers = new ArrayList<>();socketFDs.add(mZygoteSocket.getFileDescriptor());peers.add(null);...代码省略...int pollReturnValue;try {//开启轮询pollReturnValue = Os.poll(pollFDs, pollTimeoutMs);} catch (ErrnoException ex) {throw new RuntimeException("poll failed", ex);}if (pollReturnValue == 0) {mUsapPoolRefillTriggerTimestamp = INVALID_TIMESTAMP;mUsapPoolRefillAction = UsapPoolRefillAction.DELAYED;} else {boolean usapPoolFDRead = false;while (--pollIndex >= 0) {if ((pollFDs[pollIndex].revents & POLLIN) == 0) {continue;}if (pollIndex == 0) {//如果是新的socket链接请求(建立新连接)//新建ZygoteConnection链接ZygoteConnection newPeer = acceptCommandPeer(abiList);//添加到链接数组中peers.add(newPeer);//添加到文件描述符数组中socketFDs.add(newPeer.getFileDescriptor());} else if (pollIndex < usapPoolEventFDIndex) {//如果是之前已经建立的socket链接(在已有连接上)try {//获取对应的ZygoteConnectionZygoteConnection connection = peers.get(pollIndex);boolean multipleForksOK = !isUsapPoolEnabled()&& ZygoteHooks.isIndefiniteThreadSuspensionSafe();//会执行ZygoteConnection发送过来的命令final Runnable command = connection.processCommand(this, multipleForksOK);if (mIsForkChild) {//子进程...代码省略...//退出,command就是前面的ZygoteInit的caller对象return command;} else {//父进程,上面是while无限循环,zygote进程永远不会退出...代码省略...if (connection.isClosedByPeer()) {connection.closeSocket();peers.remove(pollIndex);socketFDs.remove(pollIndex);}}} catch (Exception e) {...代码省略...} finally {mIsForkChild = false;}}}}}
}
>frameworks/base/core/java/com/android/internal/os/Zygote.java
public final class Zygote {public static final String PRIMARY_SOCKET_NAME = "zygote";private static final String ANDROID_SOCKET_PREFIX = "ANDROID_SOCKET_";static LocalServerSocket createManagedSocketFromInitSocket(String socketName) {int fileDesc;//fullSocketName为“ANDROID_SOCKET_zygote”final String fullSocketName = ANDROID_SOCKET_PREFIX + socketName;try {//获取ANDROID_SOCKET_zygote的坏境变量(即为/dev/socket/zygote的文件描述符的值)//该变量是init进程在启动zygote进程时保存到环境变量中的String env = System.getenv(fullSocketName);fileDesc = Integer.parseInt(env);} catch (RuntimeException ex) {throw new RuntimeException("Socket unset or invalid: " + fullSocketName, ex);}try {//绑定socket,在后面用来接收Android应用启动请求FileDescriptor fd = new FileDescriptor();fd.setInt$(fileDesc);return new LocalServerSocket(fd);} catch (IOException ex) {throw new RuntimeException("Error building socket from file descriptor: " + fileDesc, ex);}}
}

fork应用进程,进入ActivityThread的Main方法

ZygoteConnection的processCommand方法如下所示。

class ZygoteConnection {Runnable processCommand(ZygoteServer zygoteServer, boolean multipleOK) {...代码省略...//fork子进程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) {//当前进程是子进程中(应用进程中)zygoteServer.setForkChild();zygoteServer.closeServerSocket();IoUtils.closeQuietly(serverPipeFd);serverPipeFd = null;//继续调用handleChildProc方法return handleChildProc(parsedArgs, childPipeFd,parsedArgs.mStartChildZygote);} else {//当前进程是父进程中(zygote)return null;}} ...代码省略...}private Runnable handleChildProc(ZygoteArguments parsedArgs,FileDescriptor pipeFd, boolean isZygote) {//关闭ZygoteConnection中的socket链接closeSocket();Zygote.setAppProcessName(parsedArgs, TAG);...代码省略...if (!isZygote) {//执行ZygoteInit的zygoteInit方法,这里返回的是ActivityThread的main方法的Runnablereturn ZygoteInit.zygoteInit(parsedArgs.mTargetSdkVersion,parsedArgs.mDisabledCompatChanges,parsedArgs.mRemainingArgs, null /* classLoader */);} else {return ZygoteInit.childZygoteInit(parsedArgs.mRemainingArgs  /* classLoader */);}}
}

如果当前进程是应用子进程,则会返回的是ActivityThread的main方法,最终会进入ActivityThread的main方法中。

时序图

从Zygote进程所在的Native层 -> ZygoteInit所在的JVM层 -> SystemServer进程的启动
时序图

相关文章:

Android 12系统源码_系统启动(二)Zygote进程

前言 Zygote&#xff08;意为“受精卵”&#xff09;是 Android 系统中的一个核心进程&#xff0c;负责 孵化&#xff08;fork&#xff09;应用进程&#xff0c;以优化应用启动速度和内存占用。它是 Android 系统启动后第一个由 init 进程启动的 Java 进程&#xff0c;后续所有…...

python之并发编程

并发编程介绍 串行、并行与并发的区别 进程、线程、协程的区别 1. 进程 (Process) 定义&#xff1a;进程是操作系统为运行中的程序分配的基本单位。每个进程都有独立的地址空间和资源&#xff08;如内存、文件句柄等&#xff09;。特点&#xff1a; 进程是资源分配的基本单位…...

极速全场景 MPP数据库starrocks介绍

目录 一、引子 二、起源 &#xff08;一&#xff09;前身 &#xff08;二&#xff09;定位 三、特点 &#xff08;一&#xff09;高性能架构 &#xff08;二&#xff09;实时分析 &#xff08;三&#xff09;高并发与扩展性 &#xff08;四&#xff09;兼容性与生态 …...

MySQL 表连接(内连接与外连接)

&#x1f3dd;️专栏&#xff1a;Mysql_猫咪-9527的博客-CSDN博客 &#x1f305;主页&#xff1a;猫咪-9527-CSDN博客 “欲穷千里目&#xff0c;更上一层楼。会当凌绝顶&#xff0c;一览众山小。” 目录 1、表连接的核心概念 1.1 为什么需要表连接&#xff1f; 2、内连接&a…...

重学Java基础篇—什么是快速失败(fail-fast)和安全失败(fail-safe)?

快速失败&#xff08;fail-fast&#xff09; 和 安全失败&#xff08;fail-safe&#xff09; 是两种不同的迭代器设计策略&#xff0c;主要用于处理集合&#xff08;如 List、Map&#xff09;在遍历过程中被修改的场景。 它们的核心区别在于对并发修改的容忍度和实现机制。 1…...

Redis 集群配置

在币圈交易所&#xff0c;Redis 集群的节点数量和内存大小通常根据交易所的规模、访问量、并发需求等因素来决定。一般来说&#xff0c;可以按照以下标准配置&#xff1a; Redis 集群节点数量 小型交易所&#xff08;日活 < 10万&#xff0c;QPS < 10k&#xff09;&…...

容器C++

string容器 string构造函数 #include<iostream> using namespace std; #include<string.h> void test01() {string s1;//默认构造const char* str "hello world";string s2(str);//传入char*cout << "s2" << s2 << endl;s…...

Git 基础入门:从概念到实践的版本控制指南

一、Git 核心概念解析 1. 仓库&#xff08;Repository&#xff09; Git 的核心存储单元&#xff0c;包含项目所有文件及其完整历史记录。分为本地仓库&#xff08;开发者本地副本&#xff09;和远程仓库&#xff08;如 GitHub、GitLab 等云端存储&#xff09;&#xff0c;支持…...

蓝桥杯真题_小蓝和小桥的讨论

小蓝和小桥的讨论 问题描述 小蓝和小桥是一所高中的好朋友&#xff0c;他们正在讨论下一次的课程。这节课需要讨论 nn 个主题&#xff0c;第 ii 个主题对老师来说有 aia**i 的趣味度&#xff0c;对学生来说有 bib**i 的趣味度。 小蓝认为&#xff0c;如果一个主题对老师来说…...

【C++游戏引擎开发】《线性代数》(2):矩阵加减法与SIMD集成

一、矩阵加减法数学原理 1.1 定义 ​逐元素操作:运算仅针对相同位置的元素,不涉及矩阵乘法或行列变换。​交换律与结合律: 加法满足交换律(A + B = B + A)和结合律( ( A + B ) + C = A + ( B + C ) )。 ​减法不满足交换律(A − B ≠ B − A)。1.2 公式 ​ C i j = …...

HTML应用指南:利用POST请求获取全国小鹏汽车的充电桩位置信息

在新能源汽车快速发展的背景下&#xff0c;充电桩的分布和可用性成为影响用户体验的关键因素之一。随着全球对环境保护意识的增强以及政府对新能源政策的支持&#xff0c;越来越多的消费者倾向于选择电动汽车作为日常出行工具。然而&#xff0c;充电设施是否完备、便捷直接影响…...

工具介绍《WireShark》

Wireshark 过滤命令中符号含义详解 一、比较运算符 Wireshark 支持两种比较运算符语法&#xff1a;英文缩写&#xff08;如 eq&#xff09;和 C语言风格符号&#xff08;如 &#xff09;&#xff0c;两者功能等价。 符号&#xff08;英文缩写&#xff09;C语言风格符号含义示…...

深入理解 Linux 中磁盘空间驱动的编写:从原理到实践

在编写 Linux 内核中的磁盘空间驱动时&#xff0c;理解不同类型的存储设备及其在内核中的工作模式至关重要。常见的存储设备主要分为两类&#xff1a;采用 MTD&#xff08;Memory Technology Device&#xff09;模式的原始闪存设备&#xff08;如 NAND、NOR Flash&#xff09;&…...

flutter android端抓包工具

flutter做的android app&#xff0c;使用fiddler抓不了包&#xff0c;现介绍一款能支持flutter的抓包工具Reqable&#xff0c;使用方法如下&#xff1a; 1、下载电脑端安装包 下载地址为【https://reqable.com/zh-CN/download/】 2、还是在上述地址下载 android 端apk&#xf…...

知识周汇 | 用 matplotlib 轻松绘制折线图、散点图、柱状图、直方图

目录 前言 折线图 散点图 柱状图 直方图 组合图&#xff1a;柱状图和折线图 1. 导入库 2. 定义组合图函数 3. 设置中文字体和样式 4. 创建画布和子图 5. 绘制柱状图 6. 绘制折线图 7. 美化图表 8. 保存和显示图表 9. 调用函数 总结 前言 matplotlib 是 Python…...

Ribbon负载均衡的深度解析与应用

在微服务架构中&#xff0c;服务之间的调用频繁且复杂&#xff0c;因此负载均衡显得尤为重要。Spring Cloud生态系统中&#xff0c;Ribbon作为一个客户端负载均衡器&#xff0c;扮演着关键的角色。它不仅能提高系统的响应速度&#xff0c;还能确保系统的稳定性和可用性。接下来…...

Neo4j GDS-06-neo4j GDS 库中社区检测算法介绍

neo4j apoc 系列 Neo4j APOC-01-图数据库 apoc 插件介绍 Neo4j APOC-01-图数据库 apoc 插件安装 neo4j on windows10 Neo4j APOC-03-图数据库 apoc 实战使用使用 Neo4j APOC-04-图数据库 apoc 实战使用使用 apoc.path.spanningTree 最小生成树 Neo4j APOC-05-图数据库 apo…...

Android 删除aar中的一个类 aar包冲突 aar类冲突 删除aar中的一个包

Duplicate class com.xxxa.naviauto.sdk.listener.OnChangeListener found in modules jetified-xxxa-sdk-v1.1.2-release-runtime (:xxx-sdk-v1.1.2-release:) and jetified-xxxb-sdk-1.1.3-runtime (:xxxb-sdk-1.1.3:) A.aar B.aar 有类冲突&#xff1b; 使用 exclude 排除本…...

【老电脑翻新】华硕A456U(换电池+换固态+光驱换机械+重装系统+重装系统后开始菜单失灵问题解决)

前言 电脑华硕A456U买来快10年了&#xff0c;倒是还能用&#xff0c;就是比较卡&#xff0c;cpu占比总是100%&#xff0c;之前已经加过内存条了。想要不换个固态看看。 省流&#xff1a;没太大效果。 记录一下拆机&换固态的过程 准备 西部数据固态硬盘480G WD Green S…...

Unity 简单使用Addressables加载SpriteAtlas图集资源

思路很简单&#xff0c;传入图集名和资源名&#xff0c;利用Addressables提供的异步加载方式从ab包中加载。加载完成后存储进缓存字典里&#xff0c;以供后续使用。 添加引用计数&#xff0c;防止多个地方使用同一图集时&#xff0c;不会提前释放 using UnityEngine; using U…...

stable diffusion本地安装

1. 基本环境准备 安装conda 环境 pytorch基础学习-CSDN博客 创建虚拟环境&#xff1a; conda create -n sd python3.10 一定要指定用3.10&#xff0c;过高的版本会提示错误&#xff1a; 激活启用环境&#xff1a; conda activate sd 设置pip国内镜像源&#xff1a; pip conf…...

MQ 如何保证数据一致性?

大家好&#xff0c;我是苏三&#xff0c;又跟大家见面了。 前言 上个月&#xff0c;我们有个电商系统出了个灵异事件&#xff1a;用户支付成功了&#xff0c;但订单状态死活不改成“已发货”。 折腾了半天才定位到问题&#xff1a;订单服务的MQ消息&#xff0c;像人间蒸发一…...

spring @Autowired对属性、set方法,构造器的分别使用,以及配合 @Autowired 和 @Qualifier避免歧义性的综合使用案例

代码结构 依赖注入 在Spring IoC容器的概念中&#xff0c;主要是使用依赖注入来实现Bean之间的依赖关系的 举例 例如&#xff0c;人类&#xff08;Person&#xff09;有时候会利用动物&#xff08;Animal&#xff09;来完成一些事情&#xff0c;狗&#xff08;Dog&#xff0…...

Ubuntu 系统上完全卸载 Docker

以下是在 Ubuntu 系统上完全卸载 Docker 的分步指南 一.卸载验证 二.卸载步骤 1.停止 Docker 服务 sudo systemctl stop docker.socket sudo systemctl stop docker.service2.卸载 Docker 软件包 # 移除 Docker 核心组件 sudo apt-get purge -y \docker-ce \docker-ce-cli …...

国际机构Gartner发布2025年网络安全趋势

转自&#xff1a;中国新闻网 中新网北京3月14日电 国际机构高德纳(Gartner)14日发布的消息称&#xff0c;网络安全和风险管理在2025年“面临挑战与机遇并存的局面”&#xff0c;“实现转型和提高弹性”对确保企业在快速变化的数字世界中&#xff0c;实现安全且可持续的创新至关…...

设计秒杀系统(高并发的分布式系统)

学海无涯&#xff0c;志当存远。燃心砺志&#xff0c;奋进不辍。 愿诸君得此鸡汤&#xff0c;如沐春风&#xff0c;事业有成。 若觉此言甚善&#xff0c;烦请赐赞一枚&#xff0c;共励学途&#xff0c;同铸辉煌&#xff01; 思路 处理高并发 流量削峰&#xff1a;限流&#xf…...

C# 打印模板设计-ACTIVEX打印控件-多模板加载

一、启动软件 using System; using System.Collections.Generic; using System.Windows.Forms; using System.Data;namespace Print {static class Program{/// <summary>/// 应用程序的主入口点。/// </summary>[STAThread]static void Main(){//使用模板前必须…...

华为HCIE方向那么多应该如何选择?

在华为认证体系里&#xff0c;HCIE作为最高等级的认证&#xff0c;是ICT领域专业实力的有力象征。HCIE设置了多个细分方向&#xff0c;这些方向宛如不同的专业赛道&#xff0c;为期望在ICT行业深入发展的人提供了丰富的选择。今天&#xff0c;咱们就来好好聊聊华为HCIE方向的相…...

五子棋游戏

五子棋 - deveco <!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>五子棋 - deveco</title>…...

Vue3.5 企业级管理系统实战(十):面包屑导航组件

1 breadcrumb 组件 1.1 安装插件 path-to-regexp 首先&#xff0c;我们需要安装插件 path-to-regexp&#xff0c;以便在下面的面包屑组件中对路由地址进行解析。 path-to-regexp是一个 JavaScript 库&#xff0c;可将路径字符串转化为正则表达式&#xff0c;广泛用于 Web 开发…...

【python】OpenCV—Hand Detection

文章目录 1、功能描述2、代码实现3、效果展示4、完整代码5、参考6、其它手部检测和手势识别的方案 更多有趣的代码示例&#xff0c;可参考【Programming】 1、功能描述 基于 opencv-python 和 mediapipe 进行手部检测 2、代码实现 导入必要的库函数 import cv2 import media…...

[ComfyUI] SDXL Prompt Styler 自定义节点的作用解析

1. SDXL Prompt Styler 的位置与基本功能 在 ComfyUI 的 “新建节点” → “实用工具” 下,可以找到 Style 节点(SDXL Prompt Styler)。该节点的主要作用是对输入的描述进行结构化处理,并在转换为 Stable Diffusion XL (SDXL) 提示词时,自动补充风格相关的内容,使提示词…...

Oracle-rman restore遭遇RMAN-03002与ORA-19563

文章目录 在原DB上检查是否有重复的文件名&#xff1a;查看rman恢复的日志修正重名部分重新执行rman恢复结论&#xff1a; 在 RMAN 恢复过程中&#xff0c;遇到RMAN-03002连同ORA-19563:错误。 操作是将 Oracle 10.0.5的数据库备份从 RMAN備份恢复到另一台测试主机的同一个目录…...

FPGA中串行执行方式之使用时钟分频或延迟的方式

FPGA中串行执行方式之使用时钟分频或延迟的方式 在FPGA设计中,​时钟分频和延迟是两种常用的技术,用于控制信号的时序或调整信号的频率。它们可以用来实现简单的串行逻辑、状态转移或其他需要时间控制的场景。 时钟分频(Clock Division) 基本原理:时钟分频是通过将输入…...

Dubbo 全面解析:从 RPC 核心到服务治理实践

一、分布式系统与 RPC 框架概述 在当今互联网时代&#xff0c;随着业务规模的不断扩大&#xff0c;单体架构已经无法满足高并发、高可用的需求&#xff0c;分布式系统架构成为主流选择。而在分布式系统中&#xff0c;远程服务调用&#xff08;Remote Procedure Call&#xff0…...

JavaScript 调试入门指南

JavaScript 调试入门指南 一、调试准备阶段 1. 必备工具配置 浏览器套件:安装最新Chrome102+,开启实验性功能(地址栏输入chrome://flags/#enable-devtools-experiments)编辑器集成:VS Code安装以下扩展: JavaScript Debugger:支持浏览器与Node.js双端调试Error Lens:实…...

不能将下载行为传输到IDM

目录预览 一、问题描述二、原因分析三、解决方案四、参考链接 一、问题描述 安装IDM后&#xff0c;调用IDM下载软件显示&#xff1a;不能将下载行为传输到IDM&#xff0c;Error 0x80029C4A 二、原因分析 可能是识别浏览器插件不到&#xff0c;或者本地的插件版本不对导致的 三…...

spring security 认证流程分析

Spring Security 认证流程分析 Spring Security 的认证流程是一个模块化且可扩展的过程&#xff0c;核心围绕 过滤器链 和 认证组件 协作实现。以下是详细流程分析&#xff1a; 1. 请求拦截与过滤器链 • 入口&#xff1a;所有 HTTP 请求经过 Spring Security 的过滤器链。 •…...

Docker Compose 部署 Loki

官方文档&#xff1a;https://grafana.com/docs/loki/latest/setup/install/docker/ 环境准备 安装 Docker和Docker Compose 参考&#xff1a;https://qiangsh.blog.csdn.net/article/details/125375187 创建loki目录 mkdir -p /opt/loki/config mkdir -p /data/monitoring…...

nuxt3 seo优化

在 Nuxt3 中&#xff0c;通过 nuxtjs/seo、nuxtjs/sitemap 和 nuxtjs/robots 模块可以生成包含动态链接的站点地图&#xff08;sitemap.xml&#xff09;&#xff0c;但具体是“实时生成”还是“部署时生成”&#xff0c;取决于你的配置方式和数据更新频率。以下是具体分析&…...

CentOS 8 Stream 配置在线yum源参考 —— 筑梦之路

CentOS 8 Stream ISO 文件下载地址&#xff1a;http://mirrors.aliyun.com/centos-vault/8-stream/isos/x86_64/CentOS-Stream-8-20240603.0-x86_64-dvd1.isoCentOS 8 Stream 网络引导ISO 文件下载地址&#xff1a;http://mirrors.aliyun.com/centos-vault/8-stream/isos/x86_6…...

uniapp 在app上 字体如何不跟着系统字体大小变

在UniApp开发中&#xff0c;默认情况下App的字体可能会跟随系统字体设置而变化。如果你希望保持固定的字体样式&#xff0c;不随系统字体设置改变&#xff0c;可以采用以下几种方法&#xff1a; 方法一&#xff1a;全局CSS设置 在App.vue的样式中添加以下CSS&#xff1a; /*…...

leetcode141.环形链表

直接快慢指针&#xff0c;如果有环&#xff0c;那么快指针一定会在成环的起始点与慢指针相遇 /*** Definition for singly-linked list.* class ListNode {* int val;* ListNode next;* ListNode(int x) {* val x;* next null;* }* }*/ pu…...

【HTML5游戏开发教程】零基础入门合成大西瓜游戏实战 | JS物理引擎+Canvas动画+完整源码详解

《从咖啡杯到财务自由&#xff1a;一个程序员的合成之旅——当代码遇上物理引擎的匠心之作》 &#x1f31f; 这是小游戏开发系列的第四篇送福利文章&#xff0c;感谢一路以来支持和关注这个项目的每一位朋友&#xff01; &#x1f4a1; 文章力求严谨&#xff0c;但难免有疏漏之…...

【C#语言】深入理解C#多线程编程:从基础到高性能实践

文章目录 ⭐前言⭐一、多线程的本质价值&#x1f31f;1、现代计算需求&#x1f31f;2、C#线程演进史 ⭐二、线程实现方案对比&#x1f31f;1、传统线程模型&#x1f31f;2、现代任务模型&#xff08;推荐&#xff09;&#x1f31f;3、异步编程范式 ⭐三、线程安全深度解析&…...

短信验证码安全需求设计

背景&#xff1a; 近期发现部分系统再短信充值频繁&#xff0c;发现存在恶意消耗短信额度现象&#xff0c;数据库表排查&#xff0c;发现大量非合法用户非法调用短信接口API导致额度耗尽。由于系统当初设计存在安全缺陷&#xff0c;故被不法分子进行利用&#xff0c;造成损失。…...

selenium实现自动登录项目(5)

1、163邮箱自动登录功能 遇到的问题&#xff1a; 1、登录页面&#xff0c;在定位表单时候&#xff0c;采用id&#xff0c;xpath&#xff0c;css selector都无法定位成功&#xff0c;因为id后面有个随机生成的数字&#xff08;//*[id"x-URS-iframe1741925838640.6785&quo…...

多 线 程

一.基本知识 线程&#xff1a;线程是操作系统能够运行调度的最小单位 进程&#xff1a;进程是程序执行实体 多线程应用场景&#xff1a;拷贝、迁移大文件&#xff0c;加载大量的资源文件 并发&#xff1a;有多个指令在单个cpu上交替执行 并行&#xff1a;在同一时刻人&…...

C#:类型定义中使用‌问号(?)

在 C# 中&#xff0c;类型定义中的‌问号&#xff08;?&#xff09;‌主要用于控制类型的可空性&#xff0c;但具体行为因类型&#xff08;值类型或引用类型&#xff09;和 C# 版本而异。以下是清晰分类的说明&#xff1a; 一、可空值类型&#xff08;T?&#xff0c;适用于所…...

基于飞腾FT2000+服务器主板与DeepSeek大模型的国产化AI算力探索

随着国产化处理器和AI技术的快速发展&#xff0c;自主可控的算力解决方案日益受到关注。国内大模型技术飞速发展&#xff0c;Deepseek等大模型在自然语言处理、计算机视觉等领域展现出强大的能力。面对大模型的计算需求&#xff0c;服务器硬件的国产化成为重要趋势。 飞腾FT20…...