安卓Zygote进程详解

news2024/12/24 4:28:28

目录

  • 一、概述
  • 二、Zygote如何被启动的?
    • 2.1 init.zygote64_32.rc
    • 2.2 Zygote进程在什么时候会被重启
    • 2.3 Zygote 启动后做了什么
    • 2.4 Zygote启动相关主要函数
  • 三、Zygote进程启动源码分析
    • 3.1 Nativate-C世界的Zygote启动要代码调用流程
      • 3.1.1 [app_main.cpp] main()
      • 3.1.2 [AndroidRuntime.cpp] start()
      • 3.1.3 [JniInvocation.cpp] Init()
      • 3.1.4 [AndroidRuntime.cpp] startVm()
      • 3.1.5 [AndroidRuntime.cpp] startReg()
      • 3.1.6 [Thread.cpp] androidSetCreateThreadFunc()
      • 3.1.7 [AndroidRuntime.cpp] register_jni_procs()
      • 3.1.8 [AndroidRuntime.cpp] gRegJNI()
    • 3.2 Java世界的Zygote启动主要代码调用流程:
      • 3.2.1 [ZygoteInit.java]main.cpp
      • 3.2.2 [ZygoteInit.java] preload()
      • 3.2.3 [ZygoteServer.java] ZygoteServer()
      • 3.2.4 [ZygoteInit.java] forkSystemServer()
      • 3.2.5 [ZygoteServer.java] runSelectLoop()
      • 3.2.6 [ZygoteConnection.java] processOneCommand()
      • 3.2.7 [ZygoteConnection.java] handleChildProc()
  • 四、问题分析
    • 4.1 为什么SystemServer和Zygote之间通信要采用Socket
    • 4.2 为什么一个java应用一个虚拟机?
    • 4.3 什么是Zygote资源预加载
    • 4.4 Zygote为什么要预加载
    • 4.5 Zygote 预加载的原理是什么?
  • 五、总结
  • 六、相关日志


一、概述

Init进程启动后,最重要的一个进程就是Zygote进程,Zygote是所有应用的鼻祖。SystemServer和其他所有Dalivik虚拟机进程都是由Zygote fork而来。

Zygote进程由app_process启动,Zygote是一个C/S模型,Zygote进程作为服务端,其他进程作为客户端向它发出“孵化-fork”请求,而Zygote接收到这个请求后就“孵化-fork”出一个新的进程。

由于Zygote进程在启动时会创建Java虚拟机,因此通过fork而创建的应用程序进程和SystemServer进程可以在内部获取一个Java虚拟机的实例拷贝。

核心源码

/system/core/rootdir/init.rc
/system/core/init/main.cpp
/system/core/init/init.cpp
/system/core/rootdir/init.zygote64_32.rc
/frameworks/base/cmds/app_process/app_main.cpp
/frameworks/base/core/jni/AndroidRuntime.cpp
/libnativehelper/JniInvocation.cpp
/frameworks/base/core/java/com/android/internal/os/Zygote.java
/frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
/frameworks/base/core/java/com/android/internal/os/ZygoteServer.java
/frameworks/base/core/java/com/android/internal/os/ZygoteConnection.java
/frameworks/base/core/java/com/android/internal/os/RuntimeInit.java
/frameworks/base/core/java/android/net/LocalServerSocket.java
/system/core/libutils/Threads.cpp

二、Zygote如何被启动的?

rc解析和进程调用

Init进程启动后,会解析init.rc文件,然后创建和加载service字段指定的进程。zygote进程就是以这种方式,被init进程加载的。

在 /system/core/rootdir/init.rc中,通过如下引用来load Zygote的rc:

import /init.${ro.zygote}.rc

其中${ro.zygote} 由各个厂家使用,现在的主流厂家基本使用zygote64_32,因此,rc文件为 init.zygote64_32.rc

2.1 init.zygote64_32.rc

第一个Zygote进程:
进程名:zygote

进程通过 /system/bin/app_process64来启动

启动参数:-Xzygote /system/bin --zygote --start-system-server --socket-name=zygote

socket的名称:zygote

 service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server --socket-name=zygote
	 class main
	 priority -20
	 user root                                   //用户为root
	 group root readproc reserved_disk           //访问组支持 root readproc reserved_disk
	 socket zygote stream 660 root system        //创建一个socket,名字叫zygote,以tcp形式  ,可以在/dev/socket 中看到一个 zygote的socket
	 socket usap_pool_primary stream 660 root system
	 onrestart write /sys/android_power/request_state wake       // onrestart 指当进程重启时执行后面的命令
	 onrestart write /sys/power/state on
	 onrestart restart audioserver
	 onrestart restart cameraserver
	 onrestart restart media
	 onrestart restart netd
	 onrestart restart wificond
	 onrestart restart vendor.servicetracker-1-1
	 writepid /dev/cpuset/foreground/tasks       // 创建子进程时,向 /dev/cpuset/foreground/tasks 写入pid

第二个Zygote进程:zygote_secondary

进程通过 /system/bin/app_process32来启动

启动参数:-Xzygote /system/bin --zygote --socket-name=zygote_secondary --enable-lazy-preload

socket的名称:zygote_secondary

    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,名字叫zygote_secondary,以tcp形式  ,可以在/dev/socket 中看到一个 zygote_secondary的socket
	    socket usap_pool_secondary stream 660 root system
	    onrestart restart zygote
	    writepid /dev/cpuset/foreground/tasks

从上面可以看出,zygote是通过进程文件 /system/bin/app_process64 和/system/bin/app_process32 来启动的。对应的代码入口为:

frameworks/base/cmds/app_process/app_main.cpp

2.2 Zygote进程在什么时候会被重启

Zygote进程重启,主要查看rc文件中有没有 “restart zygote” 这句话。在整个Android系统工程中搜索“restart zygote”,会发现以下文件:

/frameworks/native/services/inputflinger/host/inputflinger.rc      对应进程: inputflinger
/frameworks/native/cmds/servicemanager/servicemanager.rc           对应进程: servicemanager
/frameworks/native/services/surfaceflinger/surfaceflinger.rc       对应进程: surfaceflinger
/system/netd/server/netd.rc                                        对应进程: netd

通过上面的文件可知,zygote进程能够重启的时机:

inputflinger 进程被杀 (onrestart)
servicemanager 进程被杀 (onrestart)
surfaceflinger 进程被杀 (onrestart)
netd 进程被杀 (onrestart)
zygote进程被杀 (oneshot=false)
system_server进程被杀(waitpid)

2.3 Zygote 启动后做了什么

init进程通过init.zygote64_32.rc来调用/system/bin/app_process64 来启动zygote进程,入口app_main.cpp
调用AndroidRuntime的startVM()方法创建虚拟机,再调用startReg()注册JNI函数;
通过JNI方式调用ZygoteInit.main(),第一次进入Java世界;
registerZygoteSocket()建立socket通道,zygote作为通信的服务端,用于响应客户端请求;
preload()预加载通用类、drawable和color资源、openGL以及共享库以及WebView,用于提高app启动效率;
zygote完毕大部分工作,接下来再通过startSystemServer(),fork得力帮手system_server进程,也是上层framework的运行载体。
zygote任务完成,调用runSelectLoop(),随时待命,当接收到请求创建新进程请求时立即唤醒并执行相应工作。

2.4 Zygote启动相关主要函数

C空间:

[app_main.cpp] main()
[AndroidRuntime.cpp] start()
[JniInvocation.cpp] Init()
[AndroidRuntime.cpp] startVm()
[AndroidRuntime.cpp] startReg()
[Threads.cpp] androidSetCreateThreadFunc
[AndroidRuntime.cpp] register_jni_procs() --> gRegJNI.mProc

Java空间:

[ZygoteInit.java] main()
[ZygoteInit.java] preload()
[ZygoteServer.java] ZygoteServer
[ZygoteInit.java] forkSystemServer
[Zygote.java] forkSystemServer
[Zygote.java] nativeForkSystemServer
[ZygoteServer.java] runSelectLoop

三、Zygote进程启动源码分析

3.1 Nativate-C世界的Zygote启动要代码调用流程

3.1.1 [app_main.cpp] main()

int main(int argc, char* const argv[])
{
	 //zygote传入的参数argv为“-Xzygote /system/bin --zygote --start-system-server --socket-name=zygote”
	 //zygote_secondary传入的参数argv为“-Xzygote /system/bin --zygote --socket-name=zygote_secondary”
	...
    while (i < argc) {
        const char* arg = argv[i++];
        if (strcmp(arg, "--zygote") == 0) {
            zygote = true;
			//对于64位系统nice_name为zygote64; 32位系统为zygote
            niceName = ZYGOTE_NICE_NAME;
        } else if (strcmp(arg, "--start-system-server") == 0) {
			 //是否需要启动system server
            startSystemServer = true;
        } else if (strcmp(arg, "--application") == 0) {
			//启动进入独立的程序模式
            application = true;
        } else if (strncmp(arg, "--nice-name=", 12) == 0) {
			//niceName 为当前进程别名,区别abi型号
            niceName.setTo(arg + 12);
        } else if (strncmp(arg, "--", 2) != 0) {
            className.setTo(arg);
            break;
        } else {
            --i;
            break;
        }
    }
	..
	if (!className.isEmpty()) { //className不为空,说明是application启动模式
		...
	} else {
	  //进入zygote模式,新建Dalvik的缓存目录:/data/dalvik-cache
        maybeCreateDalvikCache();
		if (startSystemServer) { //加入start-system-server参数
            args.add(String8("start-system-server"));
        }
		String8 abiFlag("--abi-list=");
		abiFlag.append(prop);
		args.add(abiFlag);	//加入--abi-list=参数
		// In zygote mode, pass all remaining arguments to the zygote
		// main() method.
		for (; i < argc; ++i) {	//将剩下的参数加入args
			args.add(String8(argv[i]));
		}
	}
	...
    if (!niceName.isEmpty()) {
//设置一个“好听的昵称” zygote\zygote64,之前的名称是app_process
        runtime.setArgv0(niceName.string(), true /* setProcName */);
    }
    if (zygote) {	 //如果是zygote启动模式,则加载ZygoteInit
        runtime.start("com.android.internal.os.ZygoteInit", args, zygote);
    } else if (className) {	//如果是application启动模式,则加载RuntimeInit
        runtime.start("com.android.internal.os.RuntimeInit", args, zygote);
    } else {
		//没有指定类名或zygote,参数错误
        fprintf(stderr, "Error: no class name or --zygote supplied.\n");
        app_usage();
        LOG_ALWAYS_FATAL("app_process: no class name or --zygote supplied.");
    }
}

Zygote本身是一个Native的应用程序,刚开始的进程名称为“app_process”,运行过程中,通过调用setArgv0将名字改为zygote 或者 zygote64(根据操作系统而来),最后通过runtime的start()方法来真正的加载虚拟机并进入JAVA世界。

3.1.2 [AndroidRuntime.cpp] start()

void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote)
{
    ALOGD(">>>>>> START %s uid %d <<<<<<\n",
            className != NULL ? className : "(unknown)", getuid());
	...
    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;
    }

    jclass stringClass;
    jobjectArray strArray;
    jstring classNameStr;

	//等价 strArray= new String[options.size() + 1];
    stringClass = env->FindClass("java/lang/String");
    assert(stringClass != NULL);
	
	//等价 strArray[0] = "com.android.internal.os.ZygoteInit"
    strArray = env->NewObjectArray(options.size() + 1, stringClass, NULL);
    assert(strArray != NULL);
    classNameStr = env->NewStringUTF(className);
    assert(classNameStr != NULL);
    env->SetObjectArrayElement(strArray, 0, classNameStr);

	//strArray[1] = "start-system-server";
    //strArray[2] = "--abi-list=xxx";
    //其中xxx为系统响应的cpu架构类型,比如arm64-v8a.
    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);
    }

	//将"com.android.internal.os.ZygoteInit"转换为"com/android/internal/os/ZygoteInit"
    char* slashClassName = toSlashClassName(className != NULL ? className : "");
    jclass startClass = env->FindClass(slashClassName);
	//找到Zygoteinit类
    if (startClass == NULL) {
        ALOGE("JavaVM unable to locate class '%s'\n", slashClassName);
    } else {
		//找到这个类后就继续找成员函数main方法的Mehtod ID
        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()方法
            env->CallStaticVoidMethod(startClass, startMeth, strArray);
        }
    }
	//释放相应对象的内存空间
    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");
}

start()函数主要做了三件事情,一调用startVm开启虚拟机,二调用startReg注册JNI方法,三就是使用JNI把Zygote进程启动起来。

相关log

01-10 11:20:31.369 722 722 D AndroidRuntime: >>>>>> START com.android.internal.os.ZygoteInit uid 0 <<<<<<
01-10 11:20:31.429 722 722 I AndroidRuntime: Using default boot image
01-10 11:20:31.429 722 722 I AndroidRuntime: Leaving lock profiling enabled

3.1.3 [JniInvocation.cpp] Init()

Init函数主要作用是初始化JNI,具体工作是首先通过dlopen加载libart.so获得其句柄,然后调用dlsym从libart.so中找到
JNI_GetDefaultJavaVMInitArgs、JNI_CreateJavaVM、JNI_GetCreatedJavaVMs三个函数地址,赋值给对应成员属性,这三个函数会在后续虚拟机创建中调用.

bool JniInvocation::Init(const char* library) {
  char buffer[PROP_VALUE_MAX];
  const int kDlopenFlags = RTLD_NOW | RTLD_NODELETE;
  /*
   * 1.dlopen功能是以指定模式打开指定的动态链接库文件,并返回一个句柄
   * 2.RTLD_NOW表示需要在dlopen返回前,解析出所有未定义符号,如果解析不出来,在dlopen会返回NULL
   * 3.RTLD_NODELETE表示在dlclose()期间不卸载库,并且在以后使用dlopen()重新加载库时不初始化库中的静态变量
   */
  handle_ = dlopen(library, kDlopenFlags); // 获取libart.so的句柄
  if (handle_ == NULL) { //获取失败打印错误日志并尝试再次打开libart.so
    if (strcmp(library, kLibraryFallback) == 0) {
      // Nothing else to try.
      ALOGE("Failed to dlopen %s: %s", library, dlerror());
      return false;
    }
    library = kLibraryFallback;
    handle_ = dlopen(library, kDlopenFlags);
    if (handle_ == NULL) {
      ALOGE("Failed to dlopen %s: %s", library, dlerror());
      return false;
    }
  }
  /*
   * 1.FindSymbol函数内部实际调用的是dlsym
   * 2.dlsym作用是根据 动态链接库 操作句柄(handle)与符号(symbol),返回符号对应的地址
   * 3.这里实际就是从libart.so中将JNI_GetDefaultJavaVMInitArgs等对应的地址存入&JNI_GetDefaultJavaVMInitArgs_中
   */
  if (!FindSymbol(reinterpret_cast<void**>(&JNI_GetDefaultJavaVMInitArgs_),
                  "JNI_GetDefaultJavaVMInitArgs")) {
    return false;
  }
  if (!FindSymbol(reinterpret_cast<void**>(&JNI_CreateJavaVM_),
                  "JNI_CreateJavaVM")) {
    return false;
  }
  if (!FindSymbol(reinterpret_cast<void**>(&JNI_GetCreatedJavaVMs_),
                  "JNI_GetCreatedJavaVMs")) {
    return false;
  }
  return true;
}

3.1.4 [AndroidRuntime.cpp] startVm()

该函数主要作用就是配置虚拟机的相关参数,再调用之前 JniInvocation初始化得到的 JNI_CreateJavaVM_来启动虚拟机。

int AndroidRuntime::startVm(JavaVM** pJavaVM, JNIEnv** pEnv, bool zygote, bool primary_zygote)
{
    JavaVMInitArgs initArgs;
	...
	 // JNI检测功能,用于native层调用jni函数时进行常规检测,比较弱字符串格式是否符合要求,资源是否正确释放。
	 //该功能一般用于早期系统调试或手机Eng版,对于User版往往不会开启,引用该功能比较消耗系统CPU资源,降低系统性能。
    bool checkJni = false;
    property_get("dalvik.vm.checkjni", propBuf, "");
    if (strcmp(propBuf, "true") == 0) {
        checkJni = true;
    } else if (strcmp(propBuf, "false") != 0) {
        /* property is neither true nor false; fall back on kernel parameter */
        property_get("ro.kernel.android.checkjni", propBuf, "");
        if (propBuf[0] == '1') {
            checkJni = true;
        }
    }
    ALOGV("CheckJNI is %s\n", checkJni ? "ON" : "OFF");
    if (checkJni) {
        /* extended JNI checking */
        addOption("-Xcheck:jni");
    }

    addOption("exit", (void*) runtime_exit); //将参数放入mOptions数组中

	 //对于不同的软硬件环境,这些参数往往需要调整、优化,从而使系统达到最佳性能
    parseRuntimeOption("dalvik.vm.heapstartsize", heapstartsizeOptsBuf, "-Xms", "4m");
    parseRuntimeOption("dalvik.vm.heapsize", heapsizeOptsBuf, "-Xmx", "16m");
    parseRuntimeOption("dalvik.vm.heapgrowthlimit", heapgrowthlimitOptsBuf, "-XX:HeapGrowthLimit=");
    parseRuntimeOption("dalvik.vm.heapminfree", heapminfreeOptsBuf, "-XX:HeapMinFree=");
    parseRuntimeOption("dalvik.vm.heapmaxfree", heapmaxfreeOptsBuf, "-XX:HeapMaxFree=");
	
	...
	
	//检索生成指纹并将其提供给运行时这样,anr转储将包含指纹并可以解析。
    std::string fingerprint = GetProperty("ro.build.fingerprint", "");
    if (!fingerprint.empty()) {
        fingerprintBuf = "-Xfingerprint:" + fingerprint;
        addOption(fingerprintBuf.c_str());
    }

    initArgs.version = JNI_VERSION_1_4;
    initArgs.options = mOptions.editArray(); //将mOptions赋值给initArgs
    initArgs.nOptions = mOptions.size();
    initArgs.ignoreUnrecognized = JNI_FALSE;

     //调用之前JniInvocation初始化的JNI_CreateJavaVM_, 参考[4.1.3]
    if (JNI_CreateJavaVM(pJavaVM, pEnv, &initArgs) < 0) {
        ALOGE("JNI_CreateJavaVM failed\n");
        return -1;
    }

    return 0;
}

3.1.5 [AndroidRuntime.cpp] startReg()

startReg首先是设置了Android创建线程的处理函数,然后创建了一个200容量的局部引用作用域,用于确保不会出现OutOfMemoryException,最后就是调用register_jni_procs进行JNI方法的注册

int AndroidRuntime::startReg(JNIEnv* env)
{
    ATRACE_NAME("RegisterAndroidNatives");
	//设置Android创建线程的函数javaCreateThreadEtc,这个函数内部是通过Linux的clone来创建线程的
    androidSetCreateThreadFunc((android_create_thread_fn) javaCreateThreadEtc);

    ALOGV("--- registering native functions ---\n");

	//创建一个200容量的局部引用作用域,这个局部引用其实就是局部变量
    env->PushLocalFrame(200);

	//注册JNI方法
    if (register_jni_procs(gRegJNI, NELEM(gRegJNI), env) < 0) {
        env->PopLocalFrame(NULL);
        return -1;
    }
    env->PopLocalFrame(NULL); //释放局部引用作用域
    return 0;
}

3.1.6 [Thread.cpp] androidSetCreateThreadFunc()

虚拟机启动后startReg()过程,会设置线程创建函数指针gCreateThreadFn指向javaCreateThreadEtc.

void androidSetCreateThreadFunc(android_create_thread_fn func) {
    gCreateThreadFn = func;
}

3.1.7 [AndroidRuntime.cpp] register_jni_procs()

它的处理是交给RegJNIRec的mProc,RegJNIRec是个很简单的结构体,mProc是个函数指针

static int register_jni_procs(const RegJNIRec array[], size_t count, JNIEnv* env)
{
    for (size_t i = 0; i < count; i++) {
        if (array[i].mProc(env) < 0) {/ /调用gRegJNI的mProc,参考[3.1.8]
            return -1;
        }
    }
    return 0;
}

3.1.8 [AndroidRuntime.cpp] gRegJNI()

static const RegJNIRec gRegJNI[] = {
    REG_JNI(register_com_android_internal_os_RuntimeInit),
    REG_JNI(register_com_android_internal_os_ZygoteInit_nativeZygoteInit),
    REG_JNI(register_android_os_SystemClock),
    REG_JNI(register_android_util_EventLog),
    REG_JNI(register_android_util_Log),
	...
}

    #define REG_JNI(name)      { name, #name }
    struct RegJNIRec {
        int (*mProc)(JNIEnv*);
    };
gRegJNI 中是一堆函数指针,因此循环调用 gRegJNI 的mProc,即等价于调用其所对应的函数指针。
例如调用: register_com_android_internal_os_RuntimeInit
这是一个JNI函数动态注册的标准方法。

int register_com_android_internal_os_RuntimeInit(JNIEnv* env)
{
    const JNINativeMethod methods[] = {
        { "nativeFinishInit", "()V",
            (void*) com_android_internal_os_RuntimeInit_nativeFinishInit },
        { "nativeSetExitWithoutCleanup", "(Z)V",
            (void*) com_android_internal_os_RuntimeInit_nativeSetExitWithoutCleanup },
    };

    //跟Java侧的com/android/internal/os/RuntimeInit.java 的函数nativeFinishInit() 进行一一对应
    return jniRegisterNativeMethods(env, "com/android/internal/os/RuntimeInit",
        methods, NELEM(methods));
}

3.2 Java世界的Zygote启动主要代码调用流程:

通过JNI调用ZygoteInit的main函数后,Zygote便进入了Java框架层,此前没有任何代码进入过Java框架层,换句换说Zygote开创了Java框架层。

3.2.1 [ZygoteInit.java]main.cpp

代码路径:frameworks\base\core\java\com\android\internal\os\ZygoteInit.java

main的主要工作:

  • 调用preload()来预加载类和资源
  • 调用ZygoteServer()创建两个Server端的Socket–/dev/socket/zygote 和 /dev/socket/zygote_secondary,Socket用来等待>- ActivityManagerService来请求Zygote来创建新的应用程序进程。
  • 调用forkSystemServer 来启动SystemServer进程,这样系统的关键服务也会由SystemServer进程启动起来。
  • 最后调用runSelectLoop函数来等待客户端请求

下面主要来分析这四件事。

public static void main(String argv[]) {
        // 1.创建ZygoteServer
        ZygoteServer zygoteServer = null;

        // 调用native函数,确保当前没有其它线程在运行
        ZygoteHooks.startZygoteNoThreadCreation();
        
        //设置pid为0,Zygote进入自己的进程组
        Os.setpgid(0, 0);
        ......
        Runnable caller;
        try {
            ......
            //得到systrace的监控TAG
            String bootTimeTag = Process.is64Bit() ? "Zygote64Timing" : "Zygote32Timing";
            TimingsTraceLog bootTimingsTraceLog = new TimingsTraceLog(bootTimeTag,
                    Trace.TRACE_TAG_DALVIK);
            //通过systradce来追踪 函数ZygoteInit, 可以通过systrace工具来进行分析
            //traceBegin 和 traceEnd 要成对出现,而且需要使用同一个tag
            bootTimingsTraceLog.traceBegin("ZygoteInit");

            //开启DDMS(Dalvik Debug Monitor Service)功能
            //注册所有已知的Java VM的处理块的监听器。线程监听、内存监听、native 堆内存监听、debug模式监听等等
            RuntimeInit.enableDdms();

            boolean startSystemServer = false;
            String zygoteSocketName = "zygote";
            String abiList = null;
            boolean enableLazyPreload = false;
            
            //2. 解析app_main.cpp - start()传入的参数
            for (int i = 1; i < argv.length; i++) {
                if ("start-system-server".equals(argv[i])) {
                    startSystemServer = true; //启动zygote时,才会传入参数:start-system-server
                } else if ("--enable-lazy-preload".equals(argv[i])) {
                    enableLazyPreload = true; //启动zygote_secondary时,才会传入参数:enable-lazy-preload
                } else if (argv[i].startsWith(ABI_LIST_ARG)) { //通过属性ro.product.cpu.abilist64\ro.product.cpu.abilist32 从C空间传来的值
                    abiList = argv[i].substring(ABI_LIST_ARG.length());
                } else if (argv[i].startsWith(SOCKET_NAME_ARG)) {
                    zygoteSocketName = argv[i].substring(SOCKET_NAME_ARG.length()); //会有两种值:zygote和zygote_secondary
                } else {
                    throw new RuntimeException("Unknown command line argument: " + argv[i]);
                }
            }

            // 根据传入socket name来决定是创建socket还是zygote_secondary
            final boolean isPrimaryZygote = zygoteSocketName.equals(Zygote.PRIMARY_SOCKET_NAME);

            // 在第一次zygote启动时,enableLazyPreload为false,执行preload
            if (!enableLazyPreload) {
                //systrace 追踪 ZygotePreload
                bootTimingsTraceLog.traceBegin("ZygotePreload");
                EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,
                        SystemClock.uptimeMillis());
                // 3.加载进程的资源和类,参考[4.2.2]
                preload(bootTimingsTraceLog);
                EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,
                        SystemClock.uptimeMillis());
                //systrae结束 ZygotePreload的追踪
                bootTimingsTraceLog.traceEnd(); // ZygotePreload
            } else {
                // 延迟预加载, 变更Zygote进程优先级为NORMAL级别,第一次fork时才会preload
                Zygote.resetNicePriority();
            }

            //结束ZygoteInit的systrace追踪
            bootTimingsTraceLog.traceEnd(); // ZygoteInit
            //禁用systrace追踪,以便fork的进程不会从zygote继承过时的跟踪标记
            Trace.setTracingEnabled(false, 0);
            
            // 4.调用ZygoteServer 构造函数,创建socket,会根据传入的参数,
            // 创建两个socket:/dev/socket/zygote 和 /dev/socket/zygote_secondary
            //参考[4.2.3]
            zygoteServer = new ZygoteServer(isPrimaryZygote);

            if (startSystemServer) {
                //5. fork出system server,参考[4.2.4]
                Runnable r = forkSystemServer(abiList, zygoteSocketName, zygoteServer);

                // 启动SystemServer
                if (r != null) {
                    r.run();
                    return;
                }
            }

            // 6.  zygote进程进入无限循环,处理请求
            caller = zygoteServer.runSelectLoop(abiList);
        } catch (Throwable ex) {
            Log.e(TAG, "System zygote died with exception", ex);
            throw ex;
        } finally {
            if (zygoteServer != null) {
                zygoteServer.closeServerSocket();
            }
        }

        // 7.在子进程中退出了选择循环。继续执行命令
        if (caller != null) {
            caller.run();
        }
    }

日志

01-10 11:20:32.219 722 722 D Zygote : begin preload
01-10 11:20:32.219 722 722 I Zygote : Calling ZygoteHooks.beginPreload()
01-10 11:20:32.249 722 722 I Zygote : Preloading classes…
01-10 11:20:33.179 722 722 I Zygote : …preloaded 7587 classes in 926ms.
01-10 11:20:33.449 722 722 I Zygote : Preloading resources…
01-10 11:20:33.459 722 722 I Zygote : …preloaded 64 resources in 17ms.
01-10 11:20:33.519 722 722 I Zygote : Preloading shared libraries…
01-10 11:20:33.539 722 722 I Zygote : Called ZygoteHooks.endPreload()
01-10 11:20:33.539 722 722 I Zygote : Installed AndroidKeyStoreProvider in 1ms.
01-10 11:20:33.549 722 722 I Zygote : Warmed up JCA providers in 11ms.
01-10 11:20:33.549 722 722 D Zygote : end preload
01-10 11:20:33.649 722 722 D Zygote : Forked child process 1607
01-10 11:20:33.649 722 722 I Zygote : System server process 1607 has been created
01-10 11:20:33.649 722 722 I Zygote : Accepting command socket connections
10-15 06:11:07.749 722 722 D Zygote : Forked child process 2982
10-15 06:11:07.789 722 722 D Zygote : Forked child process 3004

3.2.2 [ZygoteInit.java] preload()

static void preload(TimingsTraceLog bootTimingsTraceLog) {
        Log.d(TAG, "begin preload");

        beginPreload(); // Pin ICU Data, 获取字符集转换资源等

        //预加载类的列表---/system/etc/preloaded-classes, 在版本:/frameworks/base/config/preloaded-classes 中,Android10.0中预计有7603左右个类
        //从下面的log看,成功加载了7587个类
        preloadClasses();

        preloadResources(); //加载图片、颜色等资源文件,部分定义在 /frameworks/base/core/res/res/values/arrays.xml中
        ......
        preloadSharedLibraries();   // 加载 android、compiler_rt、jnigraphics等library
        preloadTextResources();    //用于初始化文字资源

        WebViewFactory.prepareWebViewInZygote();    //用于初始化webview;
        endPreload();   //预加载完成,可以查看下面的log
        warmUpJcaProviders();
        Log.d(TAG, "end preload");

        sPreloadComplete = true;
    }

什么是预加载
预加载是指在zygote进程启动的时候就加载,这样系统只在zygote执行一次加载操作,所有APP用到该资源不需要再重新加载,减少资源加载时间,加快了应用启动速度,一般情况下,系统中App共享的资源会被列为预加载资源。

zygote fork子进程时,根据fork的copy-on-write机制可知,有些类如果不做改变,甚至都不用复制,子进程可以和父进程共享这部分数据,从而省去不少内存的占用。

预加载的原理:
zygote进程启动后将资源读取出来,保存到Resources一个全局静态变量中,下次读取系统资源的时候优先从静态变量中查找。

frameworks/base/config/preloaded-classes:
在这里插入图片描述

相关日志

01-10 11:20:32.219 722 722 D Zygote : begin preload
01-10 11:20:32.219 722 722 I Zygote : Calling ZygoteHooks.beginPreload()
01-10 11:20:32.249 722 722 I Zygote : Preloading classes…
01-10 11:20:33.179 722 722 I Zygote : …preloaded 7587 classes in 926ms.
01-10 11:20:33.539 722 722 I Zygote : Called ZygoteHooks.endPreload()
01-10 11:20:33.549 722 722 D Zygote : end preload

3.2.3 [ZygoteServer.java] ZygoteServer()

path: frameworks\base\core\java\com\android\internal\os\ZygoteServer.java
作用:ZygoteServer 构造函数初始化时,根据传入的参数,利用LocalServerSocket 创建了4个本地服务端的socket,用来建立连接。
分别是:zygote、usap_pool_primary、zygote_secondary、usap_pool_secondary

    private LocalServerSocket mZygoteSocket;
    private LocalServerSocket mUsapPoolSocket;

    //创建zygote的socket
    ZygoteServer(boolean isPrimaryZygote) {
        mUsapPoolEventFD = Zygote.getUsapPoolEventFD();

        if (isPrimaryZygote) {
            //创建socket,并获取socket对象,socketname: zygote
            mZygoteSocket = Zygote.createManagedSocketFromInitSocket(Zygote.PRIMARY_SOCKET_NAME);
            //创建socket,并获取socket对象,socketname:usap_pool_primary
            mUsapPoolSocket =
                    Zygote.createManagedSocketFromInitSocket(
                            Zygote.USAP_POOL_PRIMARY_SOCKET_NAME);
        } else {
            //创建socket,并获取socket对象,socketname: zygote_secondary
            mZygoteSocket = Zygote.createManagedSocketFromInitSocket(Zygote.SECONDARY_SOCKET_NAME);
            //创建socket,并获取socket对象,socketname: usap_pool_secondary
            mUsapPoolSocket =
                    Zygote.createManagedSocketFromInitSocket(
                            Zygote.USAP_POOL_SECONDARY_SOCKET_NAME);
        }
        fetchUsapPoolPolicyProps();
        mUsapPoolSupported = true;
    }

    static LocalServerSocket createManagedSocketFromInitSocket(String socketName) {
        int fileDesc;
        // ANDROID_SOCKET_PREFIX为"ANDROID_SOCKET_" 
        //加入传入参数为zygote,则fullSocketName:ANDROID_SOCKET_zygote
        final String fullSocketName = ANDROID_SOCKET_PREFIX + socketName;

        try {
            //init.zygote64_32.rc启动时,指定了4个socket:
            //分别是zygote、usap_pool_primary、zygote_secondary、usap_pool_secondary
            // 在进程被创建时,就会创建对应的文件描述符,并加入到环境变量中
            // 这里取出对应的环境变量
            String env = System.getenv(fullSocketName);
            fileDesc = Integer.parseInt(env);
        } catch (RuntimeException ex) {
            throw new RuntimeException("Socket unset or invalid: " + fullSocketName, ex);
        }

        try {
            FileDescriptor fd = new FileDescriptor();
            fd.setInt$(fileDesc);   // 获取zygote socket的文件描述符
            return new LocalServerSocket(fd);   // 创建Socket的本地服务端
        } catch (IOException ex) {
            throw new RuntimeException(
                "Error building socket from file descriptor: " + fileDesc, ex);
        }
    }

    path: \frameworks\base\core\java\android\net\LocalServerSocket.java
    public LocalServerSocket(FileDescriptor fd) throws IOException
    {
        impl = new LocalSocketImpl(fd);
        impl.listen(LISTEN_BACKLOG);
        localAddress = impl.getSockAddress();
    }

3.2.4 [ZygoteInit.java] forkSystemServer()

 private static Runnable forkSystemServer(String abiList, String socketName,
          ZygoteServer zygoteServer) {
      
      long capabilities = posixCapabilitiesAsBits(
              OsConstants.CAP_IPC_LOCK,
              OsConstants.CAP_KILL,
              OsConstants.CAP_NET_ADMIN,
              OsConstants.CAP_NET_BIND_SERVICE,
              OsConstants.CAP_NET_BROADCAST,
              OsConstants.CAP_NET_RAW,
              OsConstants.CAP_SYS_MODULE,
              OsConstants.CAP_SYS_NICE,
              OsConstants.CAP_SYS_PTRACE,
              OsConstants.CAP_SYS_TIME,
              OsConstants.CAP_SYS_TTY_CONFIG,
              OsConstants.CAP_WAKE_ALARM,
              OsConstants.CAP_BLOCK_SUSPEND
      );
      ......
      //参数准备
      /* 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",
              "--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 {
          //将上面准备的参数,按照ZygoteArguments的风格进行封装
          parsedArgs = new ZygoteArguments(args);
          Zygote.applyDebuggerSystemProperty(parsedArgs);
          Zygote.applyInvokeWithSystemProperty(parsedArgs);

          boolean profileSystemServer = SystemProperties.getBoolean(
                  "dalvik.vm.profilesystemserver", false);
          if (profileSystemServer) {
              parsedArgs.mRuntimeFlags |= Zygote.PROFILE_SYSTEM_SERVER;
          }

          //通过fork"分裂"出子进程system_server
          /* 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);
      }

      //进入子进程system_server
      /* For child process */
      if (pid == 0) {
          // 处理32_64和64_32的情况
          if (hasSecondZygote(abiList)) {
              waitForSecondaryZygote(socketName);
          }

          // fork时会copy socket,system server需要主动关闭
          zygoteServer.closeServerSocket();
          // system server进程处理自己的工作
          return handleSystemServerProcess(parsedArgs);
      }

      return null;
  }

ZygoteInit。forkSystemServer()会在新fork出的子进程中调用 handleSystemServerProcess(),

主要是返回Runtime.java的MethodAndArgsCaller的方法,然后通过r.run() 启动com.android.server.SystemServer的main 方法

handleSystemServerProcess代码流程:
handleSystemServerProcess()
    |
    [ZygoteInit.java]
    zygoteInit()
        |
    [RuntimeInit.java]
    applicationInit()
        |
    findStaticMain()
        |
    MethodAndArgsCaller()

3.2.5 [ZygoteServer.java] runSelectLoop()

代码路径: frameworks\base\core\java\com\android\internal\os\ZygoteServer.java

 Runnable runSelectLoop(String abiList) {
        ArrayList<FileDescriptor> socketFDs = new ArrayList<FileDescriptor>();
        ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();

        // 首先将server socket加入到fds
        socketFDs.add(mZygoteSocket.getFileDescriptor());
        peers.add(null);

        while (true) {
            fetchUsapPoolPolicyPropsWithMinInterval();

            int[] usapPipeFDs &##61; null;
            StructPollfd[] pollFDs = null;

            // 每次循环,都重新创建需要监听的pollFds
            // Allocate enough space for the poll structs, taking into account
            // the state of the USAP pool for this Zygote (could be a
            // regular Zygote, a WebView Zygote, or an AppZygote).
            if (mUsapPoolEnabled) {
                usapPipeFDs = Zygote.getUsapPipeFDs();
                pollFDs = new StructPollfd[socketFDs.size() + 1 + usapPipeFDs.length];
            } else {
                pollFDs = new StructPollfd[socketFDs.size()];
            }

            /*
             * For reasons of correctness the USAP pool pipe and event FDs
             * must be processed before the session and server sockets.  This
             * is to ensure that the USAP pool accounting information is
             * accurate when handling other requests like API blacklist
             * exemptions.
             */

            int pollIndex = 0;
            for (FileDescriptor socketFD : socketFDs) {
                 // 关注事件到来
                pollFDs[pollIndex] = new StructPollfd();
                pollFDs[pollIndex].fd = socketFD;
                pollFDs[pollIndex].events = (short) POLLIN;
                ++pollIndex;
            }

            final int usapPoolEventFDIndex = pollIndex;

            if (mUsapPoolEnabled) {
                pollFDs[pollIndex] = new StructPollfd();
                pollFDs[pollIndex].fd = mUsapPoolEventFD;
                pollFDs[pollIndex].events = (short) POLLIN;
                ++pollIndex;

                for (int usapPipeFD : usapPipeFDs) {
                    FileDescriptor managedFd = new FileDescriptor();
                    managedFd.setInt$(usapPipeFD);

                    pollFDs[pollIndex] = new StructPollfd();
                    pollFDs[pollIndex].fd = managedFd;
                    pollFDs[pollIndex].events = (short) POLLIN;
                    ++pollIndex;
                }
            }

            try {
                // 等待事件到来
                Os.poll(pollFDs, -1);
            } catch (ErrnoException ex) {
                throw new RuntimeException("poll failed", ex);
            }

            boolean usapPoolFDRead = false;

            //倒序处理,即优先处理已建立链接的信息,后处理新建链接的请求
            while (--pollIndex >= 0) {
                if ((pollFDs[pollIndex].revents & POLLIN) == 0) {
                    continue;
                }

                // server socket最先加入fds, 因此这里是server socket收到数据
                if (pollIndex == 0) {
                    // 收到新的建立通信的请求,建立通信连接
                    ZygoteConnection newPeer = acceptCommandPeer(abiList);
                    // 加入到peers和fds, 即下一次也开始监听
                    peers.add(newPeer);
                    socketFDs.add(newPeer.getFileDescriptor());

                } else if (pollIndex < usapPoolEventFDIndex) {
                    //说明接收到AMS发送过来创建应用程序的请求,调用processOneCommand
                    //来创建新的应用程序进程
                    // Session socket accepted from the Zygote server socket
                    try {
                        //有socket连接,创建ZygoteConnection对象,并添加到fds。
                        ZygoteConnection connection = peers.get(pollIndex);
                        //处理连接,参考[4.2.6]
                        final Runnable command = connection.processOneCommand(this);

                        // TODO (chriswailes): Is this extra check necessary?
                        if (mIsForkChild) {
                            // We're in the child. We should always have a command to run at this
                            // stage if processOneCommand hasn't called "exec".
                            if (command == null) {
                                throw new IllegalStateException("command == null");
                            }

                            return command;
                        } else {
                            // We're in the server - we should never have any commands to run.
                            if (command != null) {
                                throw new IllegalStateException("command != null");
                            }

                            // We don't know whether the remote side of the socket was closed or
                            // not until we attempt to read from it from processOneCommand. This
                            // shows up as a regular POLLIN event in our regular processing loop.
                            if (connection.isClosedByPeer()) {
                                connection.closeSocket();
                                peers.remove(pollIndex);
                                socketFDs.remove(pollIndex);    //处理完则从fds中移除该文件描述符
                            }
                        }
                    } catch (Exception e) {
                        ......
                    } finally {
                        mIsForkChild = false;
                    }
                } else {
                    //处理USAP pool的事件
                    // Either the USAP pool event FD or a USAP reporting pipe.

                    // If this is the event FD the payload will be the number of USAPs removed.
                    // If this is a reporting pipe FD the payload will be the PID of the USAP
                    // that was just specialized.
                    long messagePayload = -1;

                    try {
                        byte[] buffer = new byte[Zygote.USAP_MANAGEMENT_MESSAGE_BYTES];
                        int readBytes = Os.read(pollFDs[pollIndex].fd, buffer, 0, buffer.length);

                        if (readBytes == Zygote.USAP_MANAGEMENT_MESSAGE_BYTES) {
                            DataInputStream inputStream =
                                    new DataInputStream(new ByteArrayInputStream(buffer));

                            messagePayload = inputStream.readLong();
                        } else {
                            Log.e(TAG, "Incomplete read from USAP management FD of size "
                                    + readBytes);
                            continue;
                        }
                    } catch (Exception ex) {
                        if (pollIndex == usapPoolEventFDIndex) {
                            Log.e(TAG, "Failed to read from USAP pool event FD: "
                                    + ex.getMessage());
                        } else {
                            Log.e(TAG, "Failed to read from USAP reporting pipe: "
                                    + ex.getMessage());
                        }

                        continue;
                    }

                    if (pollIndex > usapPoolEventFDIndex) {
                        Zygote.removeUsapTableEntry((int) messagePayload);
                    }

                    usapPoolFDRead = true;
                }
            }

            // Check to see if the USAP pool needs to be refilled.
            if (usapPoolFDRead) {
                int[] sessionSocketRawFDs =
                        socketFDs.subList(1, socketFDs.size())
                                .stream()
                                .mapToInt(fd -> fd.getInt$())
                                .toArray();

                final Runnable command = fillUsapPool(sessionSocketRawFDs);

                if (command != null) {
                    return command;
                }
            }
        }
}

3.2.6 [ZygoteConnection.java] processOneCommand()

Runnable processOneCommand(ZygoteServer zygoteServer) {
    ...
    //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.mTargetSdkVersion);
    if (pid == 0) {
        // 子进程执行
        zygoteServer.setForkChild();
        //进入子进程流程,参考[4.2.7]
        return handleChildProc(parsedArgs, descriptors, childPipeFd,
                parsedArgs.mStartChildZygote);
    } else {
        //父进程执行
        // In the parent. A pid < 0 indicates a failure and will be handled in 
        //handleParentProc.
        handleParentProc(pid, descriptors, serverPipeFd);
        return null;
    }
    ...
}

3.2.7 [ZygoteConnection.java] handleChildProc()

private Runnable handleChildProc(ZygoteArguments parsedArgs, FileDescriptor[] descriptors, FileDescriptor pipeFd, boolean isZygote) {
      ...
      if (parsedArgs.mInvokeWith != null) {
          ...
          throw new IllegalStateException("WrapperInit.execApplication unexpectedly returned");
      } else {
          if (!isZygote) {
              // App进程将会调用到这里,执行目标类的main()方法
              return ZygoteInit.zygoteInit(parsedArgs.mTargetSdkVersion,
                      parsedArgs.mRemainingArgs, null /* classLoader */);
          } else {
              return ZygoteInit.childZygoteInit(parsedArgs.mTargetSdkVersion,
                      parsedArgs.mRemainingArgs, null /* classLoader */);
          }
      }
  }

四、问题分析

4.1 为什么SystemServer和Zygote之间通信要采用Socket

进程间通信常用的是binder,为什么这里要采用socket呢。
主要是为了解决fork的问题:

UNIX上C++程序设计守则3:多线程程序里不准使用fork
Binder通讯是需要多线程操作的,代理对象对Binder的调用是在Binder线程,需要再通过Handler调用主线程来操作。
比如AMS与应用进程通讯,AMS的本地代理IApplicationThread通过调用ScheduleLaunchActivity,调用到的应用进程ApplicationThread的ScheduleLaunchActivity是在Binder线程,
需要再把参数封装为一个ActivityClientRecord,sendMessage发送给H类(主线程Handler,ActivityThread内部类)
主要原因:害怕父进程binder线程有锁,然后子进程的主线程一直在等其子线程(从父进程拷贝过来的子进程)的资源,但是其实父进程的子进程并没有被拷贝过来,造成死锁。

所以fork不允许存在多线程。而非常巧的是Binder通讯偏偏就是多线程,所以干脆父进程(Zgote)这个时候就不使用binder线程

4.2 为什么一个java应用一个虚拟机?

1.android的VM(vm==Virtual Machine )也是类似JRE的东西,当然,各方面都截然不同,不过有一个作用都是一样的,为app提供了运行环境
2.android为每个程序提供一个vm,可以使每个app都运行在独立的运行环境,使稳定性提高。
3.vm的设计可以有更好的兼容性。android apk都被编译成字节码(bytecode),在运行的时候,vm是先将字节码编译真正可执行的代码,否则不同硬件设备的兼容是很大的麻烦。
4.android(非ROOT)没有windows下键盘钩子之类的东西,每个程序一个虚拟机,各个程序之间也不可以随意访问内存,所以此类木马病毒几乎没有。

4.3 什么是Zygote资源预加载

预加载是指在zygote进程启动的时候就加载,这样系统只在zygote执行一次加载操作,所有APP用到该资源不需要再重新加载,减少资源加载时间,加快了应用启动速度,一般情况下,系统中App共享的资源会被列为预加载资源。
zygote fork子进程时,根据fork的copy-on-write机制可知,有些类如果不做改变,甚至都不用复制,子进程可以和父进程共享这部分数据,从而省去不少内存的占用。

4.4 Zygote为什么要预加载

应用程序都从Zygote孵化出来,应用程序都会继承Zygote的所有内容。
如果在Zygote启动的时候加载这些类和资源,这些孵化的应用程序就继承Zygote的类和资源,这样启动引用程序的时候就不需要加载类和资源了,启动的速度就会快很多。
开机的次数不多,但是启动应用程序的次数非常多。

4.5 Zygote 预加载的原理是什么?

zygote进程启动后将资源读取出来,保存到Resources一个全局静态变量中,下次读取系统资源的时候优先从静态变量中查找。

五、总结

Zygote启动流程结束,Zygote进程共做了如下几件事:

  • 解析init.zygote64_32.rc,创建AppRuntime并调用其start方法,启动Zygote进程。
  • 创建JavaVM并为JavaVM注册JNI.
  • 通过JNI调用ZygoteInit的main函数进入Zygote的Java框架层。
  • 通过ZygoteServer创建服务端Socket,预加载类和资源,并通过runSelectLoop函数等待如ActivityManagerService等的请求。
  • 启动SystemServer进程。

六、相关日志

一份详细的zygote启动日志

搜索 "Zygote"1个文件中匹配到368次,总计查找1次)
  C:\Users\henry.xue\666.txt (匹配368次)
	行  1328: 01-01 08:00:18.096   591   591 D AndroidRuntime: >>>>>> START com.android.internal.os.ZygoteInit uid 0 <<<<<<1442: 01-01 08:00:18.283   591   591 I zygote64: option[0]=-Xzygote
	行  1443: 01-01 08:00:18.283   591   591 I zygote64: option[1]=exit
	行  1444: 01-01 08:00:18.283   591   591 I zygote64: option[2]=vfprintf
	行  1445: 01-01 08:00:18.283   591   591 I zygote64: option[3]=sensitiveThread
	行  1446: 01-01 08:00:18.283   591   591 I zygote64: option[4]=-verbose:gc
	行  1447: 01-01 08:00:18.283   591   591 I zygote64: option[5]=-Xms8m
	行  1448: 01-01 08:00:18.283   591   591 I zygote64: option[6]=-Xmx512m
	行  1449: 01-01 08:00:18.283   591   591 I zygote64: option[7]=-XX:HeapMinFree=512k
	行  1450: 01-01 08:00:18.283   591   591 I zygote64: option[8]=-XX:HeapMaxFree=8m
	行  1451: 01-01 08:00:18.283   591   591 I zygote64: option[9]=-XX:HeapTargetUtilization=0.751452: 01-01 08:00:18.283   591   591 I zygote64: option[10]=-Xusejit:true
	行  1453: 01-01 08:00:18.283   591   591 I zygote64: option[11]=-Xjitsaveprofilinginfo
	行  1454: 01-01 08:00:18.283   591   591 I zygote64: option[12]=-XjdwpOptions:suspend=n,server=y
	行  1455: 01-01 08:00:18.283   591   591 I zygote64: option[13]=-XjdwpProvider:default1456: 01-01 08:00:18.283   591   591 I zygote64: option[14]=-Xlockprofthreshold:5001457: 01-01 08:00:18.283   591   591 I zygote64: option[15]=-Ximage-compiler-option
	行  1458: 01-01 08:00:18.283   591   591 I zygote64: option[16]=--runtime-arg
	行  1459: 01-01 08:00:18.283   591   591 I zygote64: option[17]=-Ximage-compiler-option
	行  1460: 01-01 08:00:18.283   591   591 I zygote64: option[18]=-Xms64m
	行  1461: 01-01 08:00:18.283   591   591 I zygote64: option[19]=-Ximage-compiler-option
	行  1462: 01-01 08:00:18.283   591   591 I zygote64: option[20]=--runtime-arg
	行  1463: 01-01 08:00:18.283   591   591 I zygote64: option[21]=-Ximage-compiler-option
	行  1464: 01-01 08:00:18.283   591   591 I zygote64: option[22]=-Xmx64m
	行  1465: 01-01 08:00:18.283   591   591 I zygote64: option[23]=-Ximage-compiler-option
	行  1466: 01-01 08:00:18.283   591   591 I zygote64: option[24]=--profile-file=/system/etc/boot-image.prof
	行  1467: 01-01 08:00:18.283   591   591 I zygote64: option[25]=-Ximage-compiler-option
	行  1468: 01-01 08:00:18.283   591   591 I zygote64: option[26]=--compiler-filter=speed-profile
	行  1469: 01-01 08:00:18.283   591   591 I zygote64: option[27]=-Xcompiler-option
	行  1470: 01-01 08:00:18.283   591   591 I zygote64: option[28]=--runtime-arg
	行  1471: 01-01 08:00:18.283   591   591 I zygote64: option[29]=-Xcompiler-option
	行  1472: 01-01 08:00:18.283   591   591 I zygote64: option[30]=-Xms64m
	行  1473: 01-01 08:00:18.283   591   591 I zygote64: option[31]=-Xcompiler-option
	行  1474: 01-01 08:00:18.283   591   591 I zygote64: option[32]=--runtime-arg
	行  1475: 01-01 08:00:18.283   591   591 I zygote64: option[33]=-Xcompiler-option
	行  1476: 01-01 08:00:18.283   591   591 I zygote64: option[34]=-Xmx512m
	行  1477: 01-01 08:00:18.283   591   591 I zygote64: option[35]=-Ximage-compiler-option
	行  1478: 01-01 08:00:18.283   591   591 I zygote64: option[36]=--instruction-set-variant=kryo300
	行  1479: 01-01 08:00:18.283   591   591 I zygote64: option[37]=-Xcompiler-option
	行  1480: 01-01 08:00:18.283   591   591 I zygote64: option[38]=--instruction-set-variant=kryo300
	行  1481: 01-01 08:00:18.283   591   591 I zygote64: option[39]=-Ximage-compiler-option
	行  1482: 01-01 08:00:18.283   591   591 I zygote64: option[40]=--instruction-set-features=default1483: 01-01 08:00:18.283   591   591 I zygote64: option[41]=-Xcompiler-option
	行  1484: 01-01 08:00:18.283   591   591 I zygote64: option[42]=--instruction-set-features=default1485: 01-01 08:00:18.283   591   591 I zygote64: option[43]=-Duser.locale=zh-Hans-CN
	行  1486: 01-01 08:00:18.283   591   591 I zygote64: option[44]=--cpu-abilist=arm64-v8a
	行  1487: 01-01 08:00:18.283   591   591 I zygote64: option[45]=-Xcompiler-option
	行  1488: 01-01 08:00:18.283   591   591 I zygote64: option[46]=--generate-mini-debug-info
	行  1489: 01-01 08:00:18.283   591   591 I zygote64: option[47]=-Xcore-platform-api-policy:just-warn
	行  1490: 01-01 08:00:18.283   591   591 I zygote64: option[48]=-Xfingerprint:qti/trinket/trinket:10/QKQ1.200816.002/eng.henry.20240508.184559:userdebug/test-keys
	行  1491: 01-01 08:00:18.286   591   591 I zygote64: Core platform API reporting enabled, enforcing=false
	行  1506: 01-01 08:00:18.323   592   592 D AndroidRuntime: >>>>>> START com.android.internal.os.ZygoteInit uid 0 <<<<<<1531: 01-01 08:00:18.407   592   592 I zygote  : option[0]=-Xzygote
	行  1532: 01-01 08:00:18.407   592   592 I zygote  : option[1]=exit
	行  1533: 01-01 08:00:18.407   592   592 I zygote  : option[2]=vfprintf
	行  1534: 01-01 08:00:18.407   592   592 I zygote  : option[3]=sensitiveThread
	行  1535: 01-01 08:00:18.407   592   592 I zygote  : option[4]=-verbose:gc
	行  1536: 01-01 08:00:18.407   592   592 I zygote  : option[5]=-Xms8m
	行  1537: 01-01 08:00:18.407   592   592 I zygote  : option[6]=-Xmx512m
	行  1538: 01-01 08:00:18.407   592   592 I zygote  : option[7]=-XX:HeapMinFree=512k
	行  1539: 01-01 08:00:18.407   592   592 I zygote  : option[8]=-XX:HeapMaxFree=8m
	行  1540: 01-01 08:00:18.407   592   592 I zygote  : option[9]=-XX:HeapTargetUtilization=0.751541: 01-01 08:00:18.407   592   592 I zygote  : option[10]=-Xusejit:true
	行  1542: 01-01 08:00:18.407   592   592 I zygote  : option[11]=-Xjitsaveprofilinginfo
	行  1543: 01-01 08:00:18.407   592   592 I zygote  : option[12]=-XjdwpOptions:suspend=n,server=y
	行  1544: 01-01 08:00:18.407   592   592 I zygote  : option[13]=-XjdwpProvider:default1545: 01-01 08:00:18.407   592   592 I zygote  : option[14]=-Xlockprofthreshold:5001546: 01-01 08:00:18.407   592   592 I zygote  : option[15]=-Ximage-compiler-option
	行  1547: 01-01 08:00:18.407   592   592 I zygote  : option[16]=--runtime-arg
	行  1548: 01-01 08:00:18.407   592   592 I zygote  : option[17]=-Ximage-compiler-option
	行  1549: 01-01 08:00:18.407   592   592 I zygote  : option[18]=-Xms64m
	行  1550: 01-01 08:00:18.407   592   592 I zygote  : option[19]=-Ximage-compiler-option
	行  1551: 01-01 08:00:18.407   592   592 I zygote  : option[20]=--runtime-arg
	行  1552: 01-01 08:00:18.407   592   592 I zygote  : option[21]=-Ximage-compiler-option
	行  1553: 01-01 08:00:18.407   592   592 I zygote  : option[22]=-Xmx64m
	行  1554: 01-01 08:00:18.407   592   592 I zygote  : option[23]=-Ximage-compiler-option
	行  1555: 01-01 08:00:18.407   592   592 I zygote  : option[24]=--profile-file=/system/etc/boot-image.prof
	行  1556: 01-01 08:00:18.407   592   592 I zygote  : option[25]=-Ximage-compiler-option
	行  1557: 01-01 08:00:18.407   592   592 I zygote  : option[26]=--compiler-filter=speed-profile
	行  1558: 01-01 08:00:18.407   592   592 I zygote  : option[27]=-Xcompiler-option
	行  1559: 01-01 08:00:18.407   592   592 I zygote  : option[28]=--runtime-arg
	行  1560: 01-01 08:00:18.407   592   592 I zygote  : option[29]=-Xcompiler-option
	行  1561: 01-01 08:00:18.407   592   592 I zygote  : option[30]=-Xms64m
	行  1562: 01-01 08:00:18.407   592   592 I zygote  : option[31]=-Xcompiler-option
	行  1563: 01-01 08:00:18.407   592   592 I zygote  : option[32]=--runtime-arg
	行  1564: 01-01 08:00:18.407   592   592 I zygote  : option[33]=-Xcompiler-option
	行  1565: 01-01 08:00:18.407   592   592 I zygote  : option[34]=-Xmx512m
	行  1566: 01-01 08:00:18.407   592   592 I zygote  : option[35]=-Ximage-compiler-option
	行  1567: 01-01 08:00:18.407   592   592 I zygote  : option[36]=--instruction-set-variant=cortex-a73
	行  1568: 01-01 08:00:18.407   592   592 I zygote  : option[37]=-Xcompiler-option
	行  1569: 01-01 08:00:18.407   592   592 I zygote  : option[38]=--instruction-set-variant=cortex-a73
	行  1570: 01-01 08:00:18.407   592   592 I zygote  : option[39]=-Ximage-compiler-option
	行  1571: 01-01 08:00:18.407   592   592 I zygote  : option[40]=--instruction-set-features=default1572: 01-01 08:00:18.407   592   592 I zygote  : option[41]=-Xcompiler-option
	行  1573: 01-01 08:00:18.407   592   592 I zygote  : option[42]=--instruction-set-features=default1574: 01-01 08:00:18.407   592   592 I zygote  : option[43]=-Duser.locale=zh-Hans-CN
	行  1575: 01-01 08:00:18.407   592   592 I zygote  : option[44]=--cpu-abilist=armeabi-v7a,armeabi
	行  1576: 01-01 08:00:18.407   592   592 I zygote  : option[45]=-Xcompiler-option
	行  1577: 01-01 08:00:18.407   592   592 I zygote  : option[46]=--generate-mini-debug-info
	行  1578: 01-01 08:00:18.407   592   592 I zygote  : option[47]=-Xcore-platform-api-policy:just-warn
	行  1579: 01-01 08:00:18.407   592   592 I zygote  : option[48]=-Xfingerprint:qti/trinket/trinket:10/QKQ1.200816.002/eng.henry.20240508.184559:userdebug/test-keys
	行  1580: 01-01 08:00:18.411   592   592 I zygote  : Core platform API reporting enabled, enforcing=false
	行  1834: 01-01 08:00:19.273   592   592 W zygote  : JNI RegisterNativeMethods: attempt to register 0 native methods for android.media.AudioAttributes
	行  1835: 01-01 08:00:19.273   591   591 W zygote64: JNI RegisterNativeMethods: attempt to register 0 native methods for android.media.AudioAttributes
	行  1836: 01-01 08:00:19.284   592   592 I sysui_multi_action: [757,804,799,boot_zygote_init,801,13415,802,1]1837: 01-01 08:00:19.287   591   591 I sysui_multi_action: [757,804,799,boot_zygote_init,801,13414,802,1]1839: 01-01 08:00:19.292   591   591 D Zygote  : begin preload
	行  1840: 01-01 08:00:19.292   591   591 I Zygote  : Calling ZygoteHooks.beginPreload()1842: 01-01 08:00:19.295   592   592 I zygote  : Explicit concurrent copying GC freed 305(38KB) AllocSpace objects, 0(0B) LOS objects, 98% free, 26KB/1562KB, paused 80us total 3.738ms
	行  1843: 01-01 08:00:19.300   592   592 I zygote  : Explicit concurrent copying GC freed 5(32KB) AllocSpace objects, 0(0B) LOS objects, 98% free, 26KB/1562KB, paused 51us total 3.548ms
	行  1844: 01-01 08:00:19.300   592   592 D Zygote32Timing: PostZygoteInitGC took to complete: 8ms
	行  1845: 01-01 08:00:19.300   592   592 D Zygote32Timing: ZygoteInit took to complete: 8ms
	行  1848: 01-01 08:00:19.330   592   592 I Zygote  : Accepting command socket connections
	行  1866: 01-01 08:00:19.359   591   591 D Zygote64Timing: BeginPreload took to complete: 68ms
	行  1867: 01-01 08:00:19.360   591   591 I Zygote  : Preloading classes...1868: 01-01 08:00:19.366   591   591 W Zygote  : Class not found for preloading: android.app.-$$Lambda$ActivityThread$ZXDWm3IBeFmLnFVblhB-IOZCr9o
	行  1876: 01-01 08:00:19.434   591   591 W Zygote  : Class not found for preloading: android.bluetooth.BluetoothA2dp$23203: 01-01 08:00:20.888   591   591 I zygote64: Thread[1,tid=591,Native,Thread*=0x72bf4e1c00,peer=0x12c02460,"main"] recursive attempt to load library "libmedia_jni.so"3205: 01-01 08:00:20.888   591   591 I zygote64: Thread[1,tid=591,Native,Thread*=0x72bf4e1c00,peer=0x12c02460,"main"] recursive attempt to load library "libmedia_jni.so"3206: 01-01 08:00:20.888   591   591 I zygote64: Thread[1,tid=591,Native,Thread*=0x72bf4e1c00,peer=0x12c02460,"main"] recursive attempt to load library "libmedia_jni.so"3217: 01-01 08:00:20.903   591   591 W Zygote  : Class not found for preloading: android.media.audiopolicy.AudioProductStrategies
	行  3219: 01-01 08:00:20.904   591   591 W Zygote  : Class not found for preloading: android.media.audiopolicy.AudioVolumeGroups
	行  3311: 01-01 08:00:21.019   591   591 W Zygote  : Class not found for preloading: android.view.-$$Lambda$SurfaceView$Cs7TGTdA1lXf9qW8VOJAfEsMjdk
	行  3316: 01-01 08:00:21.024   591   591 W Zygote  : Class not found for preloading: android.view.SurfaceView$33326: 01-01 08:00:21.028   591   591 W Zygote  : Class not found for preloading: android.view.textclassifier.-$$Lambda$TextClassificationManager$JIaezIJbMig_-kVzN6oArzkTsJE
	行  3340: 01-01 08:00:21.038   591   591 W Zygote  : Class not found for preloading: com.android.internal.net.NetworkStatsFactory
	行  3361: 01-01 08:00:21.044   591   591 W Zygote  : Class not found for preloading: com.android.internal.telephony.-$$Lambda$PhoneSubInfoController$8HFbCDJDN1mrLJG980qYH5MGqMk
	行  3363: 01-01 08:00:21.045   591   591 W Zygote  : Class not found for preloading: com.android.internal.telephony.-$$Lambda$PhoneSubInfoController$U28a_EGx2cvmQhDfRRgonMt5Zrc
	行  3365: 01-01 08:00:21.045   591   591 W Zygote  : Class not found for preloading: com.android.internal.telephony.-$$Lambda$SubscriptionInfoUpdater$-zZXM9oMRZ3vZz7dJOG19J00Bmw
	行  3367: 01-01 08:00:21.045   591   591 W Zygote  : Class not found for preloading: com.android.internal.telephony.-$$Lambda$SubscriptionInfoUpdater$D5yF1HbS4cvCyoAj3FESkPtA_0g
	行  3369: 01-01 08:00:21.045   591   591 W Zygote  : Class not found for preloading: com.android.internal.telephony.-$$Lambda$SubscriptionInfoUpdater$MMx9iQX0JVqqMPLTUZhdBubFSzU
	行  3379: 01-01 08:00:21.047   591   591 W Zygote  : Class not found for preloading: com.android.internal.telephony.GsmCdmaPhone$33390: 01-01 08:00:21.049   591   591 W Zygote  : Class not found for preloading: com.android.internal.telephony.NewNitzStateMachine$13392: 01-01 08:00:21.049   591   591 W Zygote  : Class not found for preloading: com.android.internal.telephony.NewNitzStateMachine
	行  3393: 01-01 08:00:21.049   591   591 W Zygote  : Class not found for preloading: com.android.internal.telephony.NewTimeServiceHelper$13394: 01-01 08:00:21.049   591   591 W Zygote  : Class not found for preloading: com.android.internal.telephony.NewTimeServiceHelper$Listener
	行  3396: 01-01 08:00:21.049   591   591 W Zygote  : Class not found for preloading: com.android.internal.telephony.NewTimeServiceHelper
	行  3399: 01-01 08:00:21.049   591   591 W Zygote  : Class not found for preloading: com.android.internal.telephony.PhoneConfigurationModels
	行  3410: 01-01 08:00:21.051   591   591 W Zygote  : Class not found for preloading: com.android.internal.telephony.SubscriptionController$ScLocalLog
	行  3417: 01-01 08:00:21.051   591   591 W Zygote  : Class not found for preloading: com.android.internal.telephony.UiccSmsController
	行  3422: 01-01 08:00:21.052   591   591 W Zygote  : Class not found for preloading: com.android.internal.telephony.dataconnection.DcController$23448: 01-01 08:00:21.059   591   591 W Zygote  : Class not found for preloading: com.android.internal.telephony.imsphone.-$$Lambda$ImsPhoneCallTracker$QlPVd_3u4_verjHUDnkn6zaSe54
	行  3449: 01-01 08:00:21.059   591   591 W Zygote  : Class not found for preloading: com.android.internal.telephony.imsphone.ImsPhone$33521: 01-01 08:00:21.123   591   591 I Zygote  : ...preloaded 7579 classes in 1764ms.3522: 01-01 08:00:21.123   591   591 I zygote64: VMRuntime.preloadDexCaches starting
	行  3539: 01-01 08:00:21.164   591   591 I zygote64: VMRuntime.preloadDexCaches strings total=386840 before=10362 after=103623540: 01-01 08:00:21.164   591   591 I zygote64: VMRuntime.preloadDexCaches types total=36461 before=7445 after=77153541: 01-01 08:00:21.164   591   591 I zygote64: VMRuntime.preloadDexCaches fields total=163548 before=8035 after=82363542: 01-01 08:00:21.164   591   591 I zygote64: VMRuntime.preloadDexCaches methods total=285632 before=11276 after=117093543: 01-01 08:00:21.164   591   591 I zygote64: VMRuntime.preloadDexCaches finished
	行  3544: 01-01 08:00:21.164   591   591 D Zygote64Timing: PreloadClasses took to complete: 1805ms
	行  3547: 01-01 08:00:21.173   591   591 I zygote64: The ClassLoaderContext is a special shared library.3548: 01-01 08:00:21.175   591   591 D ApplicationLoaders: Created zygote-cached class loader: /system/framework/android.hidl.base-V1.0-java.jar
	行  3569: 01-01 08:00:21.204   591   591 I zygote64: The ClassLoaderContext is a special shared library.3575: 01-01 08:00:21.207   591   591 D ApplicationLoaders: Created zygote-cached class loader: /system/framework/android.hidl.manager-V1.0-java.jar
	行  3576: 01-01 08:00:21.207   591   591 D Zygote64Timing: CacheNonBootClasspathClassLoaders took to complete: 42ms
	行  3871: 01-01 08:00:21.724   591   591 I Zygote  : Preloading resources...3885: 01-01 08:00:21.776   591   591 I Zygote  : ...preloaded 64 resources in 52ms.3886: 01-01 08:00:21.781   591   591 I Zygote  : ...preloaded 41 resources in 5ms.3887: 01-01 08:00:21.781   591   591 D Zygote64Timing: PreloadResources took to complete: 574ms
	行  3921: 01-01 08:00:21.859   591   591 I Zygote  : Preloading shared libraries...3924: 01-01 08:00:21.892   591   591 I Zygote  : Called ZygoteHooks.endPreload()3925: 01-01 08:00:21.894   591   591 I Zygote  : Installed AndroidKeyStoreProvider in 2ms.3926: 01-01 08:00:21.902   591   591 I Zygote  : Warmed up JCA providers in 8ms.3927: 01-01 08:00:21.902   591   591 D Zygote  : end preload
	行  3929: 01-01 08:00:21.902   591   591 D Zygote64Timing: ZygotePreload took to complete: 2610ms
	行  3933: 01-01 08:00:21.927   591   591 I zygote64: Explicit concurrent copying GC freed 64416(3553KB) AllocSpace objects, 16(388KB) LOS objects, 49% free, 2597KB/5194KB, paused 71us total 25.087ms
	行  3935: 01-01 08:00:21.946   591   591 I zygote64: Explicit concurrent copying GC freed 6069(209KB) AllocSpace objects, 0(0B) LOS objects, 49% free, 2420KB/4840KB, paused 44us total 16.420ms
	行  3936: 01-01 08:00:21.947   591   591 D Zygote64Timing: PostZygoteInitGC took to complete: 45ms
	行  3937: 01-01 08:00:21.947   591   591 D Zygote64Timing: ZygoteInit took to complete: 2656ms
	行  3996: 01-01 08:00:22.001   591   591 D Zygote  : Forked child process 15043997: 01-01 08:00:22.001   591   591 I Zygote  : System server process 1504 has been created
	行  4011: 01-01 08:00:22.012   591   591 I Zygote  : Accepting command socket connections
	行  5469: 01-01 08:00:25.895  1504  1969 D SystemServerInitThreadPool: Started executing SecondaryZygotePreload
	行  5470: 01-01 08:00:25.895  1504  1969 I SystemServer: SecondaryZygotePreload
	行  5484: 01-01 08:00:25.898   592   592 I Zygote  : Lazily preloading resources.5485: 01-01 08:00:25.898   592   592 D Zygote  : begin preload
	行  5486: 01-01 08:00:25.898   592   592 I Zygote  : Calling ZygoteHooks.beginPreload()5501: 01-01 08:00:25.900  1504  1504 W EntropyMixer: 	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:913)5517: 01-01 08:00:25.910   592   592 D ZygoteInitTiming_lazy: BeginPreload took to complete: 11ms
	行  5518: 01-01 08:00:25.910   592   592 I Zygote  : Preloading classes...5521: 01-01 08:00:25.911   592   592 W Zygote  : Class not found for preloading: android.app.-$$Lambda$ActivityThread$ZXDWm3IBeFmLnFVblhB-IOZCr9o
	行  5547: 01-01 08:00:25.930  1504  1504 I SettingsState: 	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:913)5557: 01-01 08:00:25.952   592   592 W Zygote  : Class not found for preloading: android.bluetooth.BluetoothA2dp$25786: 05-08 18:46:58.250   592   592 I zygote  : Thread[1,tid=592,Native,Thread*=0xf105ce00,peer=0x12c40078,"main"] recursive attempt to load library "libmedia_jni.so"5788: 05-08 18:46:58.251   592   592 I zygote  : Thread[1,tid=592,Native,Thread*=0xf105ce00,peer=0x12c40078,"main"] recursive attempt to load library "libmedia_jni.so"5789: 05-08 18:46:58.251   592   592 I zygote  : Thread[1,tid=592,Native,Thread*=0xf105ce00,peer=0x12c40078,"main"] recursive attempt to load library "libmedia_jni.so"5790: 05-08 18:46:58.262   592   592 W Zygote  : Class not found for preloading: android.media.audiopolicy.AudioProductStrategies
	行  5791: 05-08 18:46:58.263   592   592 W Zygote  : Class not found for preloading: android.media.audiopolicy.AudioVolumeGroups
	行  5824: 05-08 18:46:58.351   592   592 W Zygote  : Class not found for preloading: android.view.-$$Lambda$SurfaceView$Cs7TGTdA1lXf9qW8VOJAfEsMjdk
	行  5827: 05-08 18:46:58.356   592   592 W Zygote  : Class not found for preloading: android.view.SurfaceView$35832: 05-08 18:46:58.359   592   592 W Zygote  : Class not found for preloading: android.view.textclassifier.-$$Lambda$TextClassificationManager$JIaezIJbMig_-kVzN6oArzkTsJE
	行  5840: 05-08 18:46:58.368   592   592 W Zygote  : Class not found for preloading: com.android.internal.net.NetworkStatsFactory
	行  5841: 05-08 18:46:58.373   592   592 W Zygote  : Class not found for preloading: com.android.internal.telephony.-$$Lambda$PhoneSubInfoController$8HFbCDJDN1mrLJG980qYH5MGqMk
	行  5842: 05-08 18:46:58.373   592   592 W Zygote  : Class not found for preloading: com.android.internal.telephony.-$$Lambda$PhoneSubInfoController$U28a_EGx2cvmQhDfRRgonMt5Zrc
	行  5846: 05-08 18:46:58.373   592   592 W Zygote  : Class not found for preloading: com.android.internal.telephony.-$$Lambda$SubscriptionInfoUpdater$-zZXM9oMRZ3vZz7dJOG19J00Bmw
	行  5847: 05-08 18:46:58.373   592   592 W Zygote  : Class not found for preloading: com.android.internal.telephony.-$$Lambda$SubscriptionInfoUpdater$D5yF1HbS4cvCyoAj3FESkPtA_0g
	行  5848: 05-08 18:46:58.373   592   592 W Zygote  : Class not found for preloading: com.android.internal.telephony.-$$Lambda$SubscriptionInfoUpdater$MMx9iQX0JVqqMPLTUZhdBubFSzU
	行  5849: 05-08 18:46:58.374   592   592 W Zygote  : Class not found for preloading: com.android.internal.telephony.GsmCdmaPhone$35850: 05-08 18:46:58.376   592   592 W Zygote  : Class not found for preloading: com.android.internal.telephony.NewNitzStateMachine$15851: 05-08 18:46:58.376   592   592 W Zygote  : Class not found for preloading: com.android.internal.telephony.NewNitzStateMachine
	行  5852: 05-08 18:46:58.376   592   592 W Zygote  : Class not found for preloading: com.android.internal.telephony.NewTimeServiceHelper$15853: 05-08 18:46:58.376   592   592 W Zygote  : Class not found for preloading: com.android.internal.telephony.NewTimeServiceHelper$Listener
	行  5854: 05-08 18:46:58.376   592   592 W Zygote  : Class not found for preloading: com.android.internal.telephony.NewTimeServiceHelper
	行  5855: 05-08 18:46:58.376   592   592 W Zygote  : Class not found for preloading: com.android.internal.telephony.PhoneConfigurationModels
	行  5859: 05-08 18:46:58.378   592   592 W Zygote  : Class not found for preloading: com.android.internal.telephony.SubscriptionController$ScLocalLog
	行  5860: 05-08 18:46:58.378   592   592 W Zygote  : Class not found for preloading: com.android.internal.telephony.UiccSmsController
	行  5861: 05-08 18:46:58.379   592   592 W Zygote  : Class not found for preloading: com.android.internal.telephony.dataconnection.DcController$25865: 05-08 18:46:58.380   592   592 W Zygote  : Class not found for preloading: com.android.internal.telephony.imsphone.-$$Lambda$ImsPhoneCallTracker$QlPVd_3u4_verjHUDnkn6zaSe54
	行  5866: 05-08 18:46:58.380   592   592 W Zygote  : Class not found for preloading: com.android.internal.telephony.imsphone.ImsPhone$35914: 05-08 18:46:58.427   592   592 I Zygote  : ...preloaded 7579 classes in 478ms.5915: 05-08 18:46:58.427   592   592 I zygote  : VMRuntime.preloadDexCaches starting
	行  5962: 05-08 18:46:58.457  1504  1504 I UsbDeviceManager: 	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:913)5975: 05-08 18:46:58.468   592   592 I zygote  : VMRuntime.preloadDexCaches strings total=386840 before=10362 after=103625976: 05-08 18:46:58.468   592   592 I zygote  : VMRuntime.preloadDexCaches types total=36461 before=7445 after=77155977: 05-08 18:46:58.468   592   592 I zygote  : VMRuntime.preloadDexCaches fields total=163548 before=8035 after=82365978: 05-08 18:46:58.468   592   592 I zygote  : VMRuntime.preloadDexCaches methods total=285632 before=11276 after=117095979: 05-08 18:46:58.468   592   592 I zygote  : VMRuntime.preloadDexCaches finished
	行  5980: 05-08 18:46:58.468   592   592 D ZygoteInitTiming_lazy: PreloadClasses took to complete: 519ms
	行  5994: 05-08 18:46:58.473   592   592 I zygote  : The ClassLoaderContext is a special shared library.5998: 05-08 18:46:58.475   592   592 D ApplicationLoaders: Created zygote-cached class loader: /system/framework/android.hidl.base-V1.0-java.jar
	行  6000: 05-08 18:46:58.478   592   592 I zygote  : The ClassLoaderContext is a special shared library.6004: 05-08 18:46:58.479   592   592 D ApplicationLoaders: Created zygote-cached class loader: /system/framework/android.hidl.manager-V1.0-java.jar
	行  6005: 05-08 18:46:58.480   592   592 D ZygoteInitTiming_lazy: CacheNonBootClasspathClassLoaders took to complete: 11ms
	行  6163: 05-08 18:46:58.565   592   592 I Zygote  : Preloading resources...6184: 05-08 18:46:58.587   592   592 I Zygote  : ...preloaded 64 resources in 23ms.6187: 05-08 18:46:58.591   592   592 I Zygote  : ...preloaded 41 resources in 3ms.6188: 05-08 18:46:58.591   592   592 D ZygoteInitTiming_lazy: PreloadResources took to complete: 111ms
	行  6356: 05-08 18:46:58.728   592   592 I Zygote  : Preloading shared libraries...6357: 05-08 18:46:58.738   592   592 I Zygote  : Called ZygoteHooks.endPreload()6358: 05-08 18:46:58.738   592   592 I Zygote  : Installed AndroidKeyStoreProvider in 1ms.6359: 05-08 18:46:58.747   592   592 I Zygote  : Warmed up JCA providers in 9ms.6360: 05-08 18:46:58.747   592   592 D Zygote  : end preload
	行  6361: 05-08 18:46:58.748  1504  1969 D SystemServerTimingAsync: SecondaryZygotePreload took to complete: 813ms
	行  6362: 05-08 18:46:58.748  1504  1969 D SystemServerInitThreadPool: Finished executing SecondaryZygotePreload
	行  6497: 05-08 18:46:58.940   591   591 D Zygote  : Forked child process 20336612: 05-08 18:46:59.048   592   592 D Zygote  : Forked child process 20736613: 05-08 18:46:59.051  1504  1649 W ActivityManager: Slow operation: 60ms so far, now at startProcess: returned from zygote!6620: 05-08 18:46:59.052  1504  1649 W ActivityManager: Slow operation: 60ms so far, now at startProcess: asking zygote to start proc
	行  6640: 05-08 18:46:59.088   591   591 D Zygote  : Forked child process 21036641: 05-08 18:46:59.089  1504  1649 W ActivityManager: Slow operation: 97ms so far, now at startProcess: returned from zygote!6949: 05-08 18:46:59.210   591   591 D Zygote  : Forked child process 21626985: 05-08 18:46:59.310   592   592 I Zygote  : Process 2073 exited cleanly (0)7005: 05-08 18:46:59.341   592   592 D Zygote  : Forked child process 22137007: 05-08 18:46:59.348   591   591 I Zygote  : Process 2103 exited cleanly (0)7008: 05-08 18:46:59.348  1504  2064 W ZygoteProcess: Got error connecting to zygote, retrying. msg= Connection refused
	行  7009: 05-08 18:46:59.354  2213  2213 I WebViewZygoteInit: Starting WebViewZygoteInit
	行  7028: 05-08 18:46:59.383  1504  1649 W ActivityManager: Slow operation: 194ms so far, now at startProcess: asking zygote to start proc
	行  7049: 05-08 18:46:59.405   591   591 D Zygote  : Forked child process 22337053: 05-08 18:46:59.407  1504  1649 W ActivityManager: Slow operation: 218ms so far, now at startProcess: returned from zygote!7081: 05-08 18:46:59.414  1504  1649 W ActivityManager: Slow operation: 223ms so far, now at startProcess: asking zygote to start proc
	行  7102: 05-08 18:46:59.435  2162  2162 D ApplicationLoaders: Returning zygote-cached class loader: /system/framework/android.hidl.base-V1.0-java.jar
	行  7103: 05-08 18:46:59.439   591   591 D Zygote  : Forked child process 22457112: 05-08 18:46:59.444  1504  1649 W ActivityManager: Slow operation: 254ms so far, now at startProcess: returned from zygote!7118: 05-08 18:46:59.445  2213  2213 I WebViewZygoteInit: Beginning application preload for com.android.webview
	行  7120: 05-08 18:46:59.446  1504  1649 W ActivityManager: Slow operation: 253ms so far, now at startProcess: asking zygote to start proc
	行  7140: 05-08 18:46:59.472   591   591 D Zygote  : Forked child process 22657142: 05-08 18:46:59.475  1504  1649 W ActivityManager: Slow operation: 282ms so far, now at startProcess: returned from zygote!7151: 05-08 18:46:59.477  1504  1649 W ActivityManager: Slow operation: 281ms so far, now at startProcess: asking zygote to start proc
	行  7161: 05-08 18:46:59.503  2213  2213 I WebViewZygoteInit: Application preload done
	行  7163: 05-08 18:46:59.510   591   591 D Zygote  : Forked child process 22957167: 05-08 18:46:59.513  1504  1649 W ActivityManager: Slow operation: 317ms so far, now at startProcess: returned from zygote!7176: 05-08 18:46:59.513  1504  1649 W ActivityManager: Slow operation: 106ms so far, now at startProcess: asking zygote to start proc
	行  7232: 05-08 18:46:59.550  2233  2233 D ApplicationLoaders: Returning zygote-cached class loader: /system/framework/android.hidl.base-V1.0-java.jar
	行  7251: 05-08 18:46:59.556   591   591 D Zygote  : Forked child process 23277256: 05-08 18:46:59.558  1504  1649 W ActivityManager: Slow operation: 150ms so far, now at startProcess: returned from zygote!7330: 05-08 18:46:59.623  2245  2245 D ApplicationLoaders: Returning zygote-cached class loader: /system/framework/android.hidl.base-V1.0-java.jar
	行  7673: 05-08 18:46:59.691  2265  2265 E ContextImpl: 	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:935)7862: 05-08 18:46:59.842   591   591 D Zygote  : Forked child process 24358190: 05-08 18:47:00.039  1504  1504 D ApplicationLoaders: Returning zygote-cached class loader: /system/framework/android.hidl.base-V1.0-java.jar
	行  8206: 05-08 18:47:00.052   591   591 D Zygote  : Forked child process 25118348: 05-08 18:47:00.127   591   591 D Zygote  : Forked child process 25398352: 05-08 18:47:00.129  1504  1649 W ActivityManager: Slow operation: 51ms so far, now at startProcess: returned from zygote!8525: 05-08 18:47:00.274   591   591 D Zygote  : Forked child process 26008526: 05-08 18:47:00.276  2539  2539 D ApplicationLoaders: Returning zygote-cached class loader: /system/framework/android.hidl.base-V1.0-java.jar
	行  8782: 05-08 18:47:00.441  2600  2600 D ApplicationLoaders: Returning zygote-cached class loader: /system/framework/android.hidl.base-V1.0-java.jar
	行 10251: 05-08 18:47:00.943   591   591 D Zygote  : Forked child process 272611836: 05-08 18:47:01.847   591   591 D Zygote  : Forked child process 282412388: 05-08 18:47:02.144   591   591 D Zygote  : Forked child process 286812638: 05-08 18:47:02.312  2868  2868 D ApplicationLoaders: Returning zygote-cached class loader: /system/framework/android.hidl.base-V1.0-java.jar
	行 13068: 05-08 18:47:02.684  1504  1504 D ApplicationLoaders: Returning zygote-cached class loader: /system/framework/android.hidl.base-V1.0-java.jar
	行 13160: 05-08 18:47:02.806   591   591 D Zygote  : Forked child process 300813346: 05-08 18:47:02.955  2233  2233 D ApplicationLoaders: Returning zygote-cached class loader: /system/framework/android.hidl.base-V1.0-java.jar
	行 13581: 05-08 18:47:03.048   591   591 D Zygote  : Forked child process 306813618: 05-08 18:47:03.079  1504  1649 W ActivityManager: Slow operation: 54ms so far, now at startProcess: asking zygote to start proc
	行 13658: 05-08 18:47:03.102   591   591 D Zygote  : Forked child process 309813671: 05-08 18:47:03.111  1504  1649 W ActivityManager: Slow operation: 86ms so far, now at startProcess: returned from zygote!13699: 05-08 18:47:03.128  1504  1649 W ActivityManager: Slow operation: 68ms so far, now at startProcess: asking zygote to start proc
	行 13718: 05-08 18:47:03.151   591   591 D Zygote  : Forked child process 312813720: 05-08 18:47:03.152  1504  1649 W ActivityManager: Slow operation: 93ms so far, now at startProcess: returned from zygote!13821: 05-08 18:47:03.251  1504  1649 W ActivityManager: Slow operation: 189ms so far, now at startProcess: asking zygote to start proc
	行 13928: 05-08 18:47:03.308   591   591 D Zygote  : Forked child process 319713940: 05-08 18:47:03.315  1504  1649 W ActivityManager: Slow operation: 252ms so far, now at startProcess: returned from zygote!13954: 05-08 18:47:03.320  1504  1649 W ActivityManager: Slow operation: 256ms so far, now at startProcess: asking zygote to start proc
	行 13973: 05-08 18:47:03.364   591   591 D Zygote  : Forked child process 322313974: 05-08 18:47:03.365  1504  1649 W ActivityManager: Slow operation: 302ms so far, now at startProcess: returned from zygote!13982: 05-08 18:47:03.376  1504  1649 W ActivityManager: Slow operation: 311ms so far, now at startProcess: asking zygote to start proc
	行 13996: 05-08 18:47:03.415   591   591 D Zygote  : Forked child process 324213997: 05-08 18:47:03.416  1504  1649 W ActivityManager: Slow operation: 351ms so far, now at startProcess: returned from zygote!14010: 05-08 18:47:03.444  1504  1649 W ActivityManager: Slow operation: 378ms so far, now at startProcess: asking zygote to start proc
	行 14035: 05-08 18:47:03.489   591   591 D Zygote  : Forked child process 328914040: 05-08 18:47:03.500  1504  1649 W ActivityManager: Slow operation: 434ms so far, now at startProcess: returned from zygote!14049: 05-08 18:47:03.500  1504  1649 W ActivityManager: Slow operation: 434ms so far, now at startProcess: asking zygote to start proc
	行 14109: 05-08 18:47:03.568   591   591 D Zygote  : Forked child process 332514114: 05-08 18:47:03.571  1504  1649 W ActivityManager: Slow operation: 504ms so far, now at startProcess: returned from zygote!14148: 05-08 18:47:03.608  1504  1649 W ActivityManager: Slow operation: 483ms so far, now at startProcess: asking zygote to start proc
	行 14254: 05-08 18:47:03.657   591   591 D Zygote  : Forked child process 336514255: 05-08 18:47:03.659  1504  1649 W ActivityManager: Slow operation: 534ms so far, now at startProcess: returned from zygote!14281: 05-08 18:47:03.668  1504  1649 W ActivityManager: Slow operation: 306ms so far, now at startProcess: asking zygote to start proc
	行 14290: 05-08 18:47:03.685  3289  3289 D ApplicationLoaders: Returning zygote-cached class loader: /system/framework/android.hidl.base-V1.0-java.jar
	行 14566: 05-08 18:47:03.741   591   591 D Zygote  : Forked child process 340714587: 05-08 18:47:03.748  1504  1649 W ActivityManager: Slow operation: 386ms so far, now at startProcess: returned from zygote!14669: 05-08 18:47:03.757  1504  1649 W ActivityManager: Slow operation: 326ms so far, now at startProcess: asking zygote to start proc
	行 14770: 05-08 18:47:03.775  3128  3128 W System.err: 	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:935)14780: 05-08 18:47:03.778  3325  3325 D ApplicationLoaders: Returning zygote-cached class loader: /system/framework/android.hidl.base-V1.0-java.jar
	行 14805: 05-08 18:47:03.792   591   591 D Zygote  : Forked child process 342814812: 05-08 18:47:03.794  1504  1649 W ActivityManager: Slow operation: 363ms so far, now at startProcess: returned from zygote!14837: 05-08 18:47:03.799  1504  1649 W ActivityManager: Slow operation: 137ms so far, now at startProcess: asking zygote to start proc
	行 14960: 05-08 18:47:03.862   591   591 D Zygote  : Forked child process 346514961: 05-08 18:47:03.863  1504  1649 W ActivityManager: Slow operation: 201ms so far, now at startProcess: returned from zygote!15171: 05-08 18:47:03.978  3465  3465 D ApplicationLoaders: Returning zygote-cached class loader: /system/framework/android.hidl.base-V1.0-java.jar
	行 15352: 05-08 18:47:04.171   591   591 D Zygote  : Forked child process 356115486: 05-08 18:47:04.370   591   591 D Zygote  : Forked child process 360315777: 05-08 18:47:04.722   591   591 D Zygote  : Forked child process 365015954: 05-08 18:47:05.332  2295  2295 D ApplicationLoaders: Returning zygote-cached class loader: /system/framework/android.hidl.base-V1.0-java.jar
	行 15994: 05-08 18:47:05.415   591   591 D Zygote  : Forked child process 368916082: 05-08 18:47:05.618   591   591 D Zygote  : Forked child process 372116086: 05-08 18:47:05.645   591   591 D Zygote  : Forked child process 372716087: 05-08 18:47:05.648  1504  1649 W ActivityManager: Slow operation: 51ms so far, now at startProcess: returned from zygote!16094: 05-08 18:47:05.649  1504  1649 W ActivityManager: Slow operation: 51ms so far, now at startProcess: asking zygote to start proc
	行 16101: 05-08 18:47:05.674   591   591 D Zygote  : Forked child process 374116102: 05-08 18:47:05.675  1504  1649 W ActivityManager: Slow operation: 78ms so far, now at startProcess: returned from zygote!16109: 05-08 18:47:05.676  1504  1649 W ActivityManager: Slow operation: 76ms so far, now at startProcess: asking zygote to start proc
	行 16142: 05-08 18:47:05.728   591   591 D Zygote  : Forked child process 376316143: 05-08 18:47:05.729  1504  1649 W ActivityManager: Slow operation: 130ms so far, now at startProcess: returned from zygote!16165: 05-08 18:47:05.756  1504  1649 W ActivityManager: Slow operation: 150ms so far, now at startProcess: asking zygote to start proc
	行 16242: 05-08 18:47:05.812   591   591 D Zygote  : Forked child process 380116243: 05-08 18:47:05.813  1504  1649 W ActivityManager: Slow operation: 207ms so far, now at startProcess: returned from zygote!16250: 05-08 18:47:05.814  1504  1649 W ActivityManager: Slow operation: 206ms so far, now at startProcess: asking zygote to start proc
	行 16253: 05-08 18:47:05.839   592   592 D Zygote  : Forked child process 381116254: 05-08 18:47:05.840  1504  1649 W ActivityManager: Slow operation: 232ms so far, now at startProcess: returned from zygote!16261: 05-08 18:47:05.845  1504  1649 W ActivityManager: Slow operation: 236ms so far, now at startProcess: asking zygote to start proc
	行 16263: 05-08 18:47:05.871   591   591 D Zygote  : Forked child process 382716264: 05-08 18:47:05.878  1504  1649 W ActivityManager: Slow operation: 269ms so far, now at startProcess: returned from zygote!16271: 05-08 18:47:05.878  1504  1649 W ActivityManager: Slow operation: 267ms so far, now at startProcess: asking zygote to start proc
	行 16285: 05-08 18:47:05.934   591   591 D Zygote  : Forked child process 386616286: 05-08 18:47:05.935  1504  1649 W ActivityManager: Slow operation: 323ms so far, now at startProcess: returned from zygote!16348: 05-08 18:47:06.145  3866  3866 D ApplicationLoaders: Returning zygote-cached class loader: /system/framework/android.hidl.base-V1.0-java.jar
	行 16366: 05-08 18:47:06.272   591   591 D Zygote  : Forked child process 397816388: 05-08 18:47:06.406   591   591 D Zygote  : Forked child process 4018

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1792727.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

0605-JavaSE-单例模式-饿懒汉模式

​​​​​​​ 不能放在方法里面&#xff08;因为每个线程调用都会在方法里面实例化一个locker对象&#xff0c;但不属于同一个对象&#xff09;&#xff0c;然后要用static修饰成静态变量才会起到效果 //单例设计模式 //饿汉模式&#xff1a;在加载类的时候就已经开始创建 /…

Python3数据类型(新)详细介绍

文章目录 数据类型类型查看同时多个变量赋值标准数据类型1.数字(Number)2.字符串3.bool(布尔类型)4.元组元组的运算 运算运算* 运算元组的删除 5.列表(List)查找列表修改列表列表的切片列表是可以修改的列表的追加列表的插入列表的连接列表的删除列表的清空列表的复制 6.字典查…

创建常规DLL的动态链接库

本文仅供学习交流&#xff0c;严禁用于商业用途&#xff0c;如本文涉及侵权请及时联系本人将于及时删除 【例9.3】创建一个MFC 常规DLL的动态链接库Areadll&#xff0c;在该动态链接库中添加一个导出类CArea&#xff0c;通过该类获取正方形和圆的面积。 (1) 使用“MFC动态链接…

水泵选型指南

在现代暖通空调&#xff08;HVAC&#xff09;系统中&#xff0c;冷冻水泵是关键组件之一&#xff0c;它在提供冷却和空调效果方面起着至关重要的作用。选择合适的冷冻水泵不仅可以提高系统效率&#xff0c;还能节省能源和维护成本。本文将介绍冷冻水泵选型的关键因素和步骤。 …

深度学习之非极大值抑制NMS介绍

1. 基本介绍 非极大值抑制&#xff08;Non-Maximum Suppression&#xff0c;NMS&#xff09;是深度学习中一种常用的目标检测算法&#xff0c;用于在检测结果中去除冗余的边界框。 在目标检测任务中&#xff0c;通常会使用候选框&#xff08;bounding boxes&#xff09;来表示可…

wincc7.5在现有Report中增加页面

已有报告&#xff0c;页面是3页&#xff0c;需要新加1页数据。 在布局文件中&#xff0c;看到有3个项&#xff0c;这个版本的Wincc就是这种布置&#xff1a; 需要在报告内容中加入新内容&#xff0c;分页依据内容上下间的缝隙&#xff08;gap &#xff09;。 这里插入嵌入la…

SwiftUI中Menu和ControlGroup的使用

本篇文章主要介绍一下Menu组件和ControlGroup组件的使用。Menu组件是在iOS 14&#xff08;tvOS 17&#xff09;推出的一个组件&#xff0c;点击后提供一个可选择的操作列表。ControlGroup组件是一个容器视图&#xff0c;以视觉上适当的方式为给定的上下文显示语义相关的控件&am…

【设计模式深度剖析】【3】【行为型】【职责链模式】| 以购物中心客户服务流程为例加深理解

&#x1f448;️上一篇:命令模式 设计模式-专栏&#x1f448;️ 文章目录 职责链模式定义英文原话直译如何理解呢&#xff1f; 职责链模式的角色1. Handler&#xff08;抽象处理者&#xff09;2. ConcreteHandler&#xff08;具体处理者&#xff09;3. Client&#xff08;客户…

Go微服务: 基于rocketmq:server和rocketmq:broker搭建RocketMQ环境,以及生产消息和延迟消费消息的实现

RocketMQ 的搭建 1 ) 配置 docker-compose.yaml 文件 version: 3.5 services:rmqnamesrv:image: foxiswho/rocketmq:servercontainer_name: rmqnamesrvports:- 9876:9876volumes:- ./logs:/opt/logs- ./store:/opt/storenetworks:rmq:aliases:- rmqnamesrvrmqbroker:image: fo…

使用System-Verilog实现FPGA基于DE2-115开发板驱动HC_SR04超声波测距模块|集成蜂鸣器,led和vga提示功能

文章目录 前言一、SystemVerilog——下一代硬件设计语言1.1 语言基础2.2 面向对象编程1.3 接口&#xff08;Interfaces&#xff09;1.4 程序包&#xff08;Packages&#xff09;1.5 数据结构1.6 随机化&#xff08;Randomization&#xff09;1.7 并发性和时序控制1.8 功能增强1…

小程序丨最大填表限制如何开启?

老师在新建填表时&#xff0c;希望设置最大数量限制&#xff0c;若填表达到限制&#xff0c;后续的学生将不能继续提交填表。 通过开启【表格最大限制】功能即可实现&#xff0c;下面就来教大家如何制作吧。 &#x1f50e;如何开启表格最大限制功能&#xff1f; 按照常规流程…

Mac OS 用户开启 8080 端口

开启端口 sudo vim /etc/pf.conf # 开放对应端口 pass out proto tcp from any to any port 8080 # 刷新配置文件 sudo pfctl -f /etc/pf.conf sudo pfctl -e获取本机ip地址 ifconfig en0 | grep inet | grep -v inet6 | awk {print $2}访问指定端口

【UML用户指南】-03-UML的14种图

目录 1、结构图 1、类图&#xff08;class diagram&#xff09; 2、对象图&#xff08;object diagram&#xff09; 3、构件图 &#xff08;component diagram&#xff09; 4、组合结构图 5、包图&#xff08;package diagram&#xff09; 6、部署图&#xff08;deploym…

【LeetCode算法】第100题:相同的树

目录 一、题目描述 二、初次解答 三、官方解法 四、总结 一、题目描述 二、初次解答 1. 思路&#xff1a;二叉树的先序遍历。采用递归的先序遍历方法&#xff0c;首先访问根节点若不同则返回false&#xff0c;其次访问左子树和右子树。在访问左右子树时&#xff0c;需要注意…

gkuubibiih

c语言中的小小白-CSDN博客c语言中的小小白关注算法,c,c语言,贪心算法,链表,mysql,动态规划,后端,线性回归,数据结构,排序算法领域.https://blog.csdn.net/bhbcdxb123?spm1001.2014.3001.5343 给大家分享一句我很喜欢我话&#xff1a; 知不足而奋进&#xff0c;望远山而前行&am…

Kubernetes集群安装部署(Anolis OS 8)

本次 Kubernetes 集群是基于 kubeadm 进行部署的&#xff0c;操作系统采用的 Anolis OS 8.9。 主机IP配置k8s192.168.211.112核&#xff0c;4G&#xff0c;20G硬盘k8s2192.168.211.122核&#xff0c;2G&#xff0c;20G硬盘k8s3192.168.211.132核&#xff0c;2G&#xff0c;20G…

【Vue】异步更新 $nextTick

文章目录 一、引出问题二、解决方案三、代码实现 一、引出问题 需求 编辑标题, 编辑框自动聚焦 点击编辑&#xff0c;显示编辑框让编辑框&#xff0c;立刻获取焦点 即下图上面结构隐藏&#xff0c;下面结构显示&#xff0c;并且显示的时候让它自动聚焦。 代码如下 问题 “…

带Tkinter界面的小验证加密程序——Python课程作业案例分析

Python课程作业案例分析 作业题目要求实现结果动图题目分析主要库介绍和说明实现源码及注释作业题目要求 某个公司采用公用电话传递数据,数据是四位的整数,在传递过程中是加密的。加密规则如下:每位数字都加上5,然后用和除以10的余数代替该数字,再将第一位和第四位交换,…

持续监控和优化的简单介绍

DevOps 监控提供了有关生产环境状况的全面且最新的信息&#xff0c;以及有关其服务、基础设施和应用程序的详细信息。通过从日志和指标中收集数据&#xff0c;您可以在软件开发生命周期的每个步骤中监控合规性和性能。 监控不仅仅针对生产问题&#xff0c;它涵盖了规划、开发、…

python --对象属性、类属性、类方法和静态方法

对象属性和类属性 --掌握--对象属性 目标掌握对象属性的使用 对象属性&#xff0c;有时也称实例属性、普通属性、公有属性 、或者直接叫属性 在类内部&#xff0c;访问对象属性语法&#xff1a; self.对象属性名 在类外部&#xff0c;访问对象属性语法&#xff1a; 对象名.对…