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

Android Framework学习笔记(4)----Zygote进程

Zygote的启动流程

Init进程启动后,会加载并执行init.rc文件。该.rc文件中,就包含启动Zygote进程的Action。详见“RC文件解析”章节

根据Zygote对应的RC文件,可知Zygote进程是由/system/bin/app_process程序来创建的。

app_process大致处理流程如下,详见“app_process解析”章节

  1. 创建AppRuntime
  2. 整理传参,并将相应参数传给Runtime或Zygote进程。
  3. 使用Runtime调用start方法,传入“com.android.internal.os.ZygoteInit”类和zygote传参,启动zygote。

class AppRuntime 继承自 public AndroidRuntime。调用start方法后,将执行以下步骤。详见"AndroidRuntime解析"章节

  1. 搜集JVM参数,启动VM
  2. 注册JNI方法。
  3. 利用java的反射,调用com.android.internal.os.ZygoteInit类中的main方法,创建zygote进程。

Zygote代码分析

RC文件解析

Init.rc中的Zygote内容

init.rc中涉及Zygote的部分有五处。从代码中可以看出,在初始化晚期阶段late-init,会触发Zygote-start行为,而该行为会创建zygote,以及zygote_secondary两个进程。

import /system/etc/init/hw/init.${ro.zygote}.rcimport /system/etc/init/hw/init.boringssl.${ro.zygote}.rc...on late-inittrigger zygote-start...on zygote-startwait_for_prop odsign.verification.done 1# A/B update verifier that marks a successful boot.exec_start update_verifierstart statsdstart netdstart zygotestart zygote_secondary...on userspace-reboot-resumetrigger userspace-reboot-fs-remounttrigger post-fs-datatrigger zygote-starttrigger early-boottrigger boot

关于如何启动这两个进程,可以参照init.${ro.zygote}.rc。${ro.zygote}的值,可以通过shell指令“getprop ro.zygote”获取。以下图为例,zygote64_32代表64模式为主,32位模式为辅。

init.zygote64_32.rc

引用了init.zygote64.rc

声明了一个名字为“zygote_secondary”的service。该service将有/system/bin/app_process进程来启动。其中以“-”开头的是JVM参数,-Xzygote /system/bin。以“--”开头的是进程参数,--zygote --socket-name=zygote_secondary --enable-lazy-preload。

创建了两个socket,名字为zygote_secondary和usap_pool_secondary。

import /system/etc/init/hw/init.zygote64.rcservice zygote_secondary /system/bin/app_process32 -Xzygote /system/bin --zygote --socket-name=zygote_secondary --enable-lazy-preloadclass mainpriority -20user rootgroup root readproc reserved_disksocket zygote_secondary stream 660 root systemsocket usap_pool_secondary stream 660 root systemonrestart restart zygotetask_profiles ProcessCapacityHigh MaxPerformance

init.zygote64.rc

声明了一个名字为“zygote”的service。该service将有/system/bin/app_process进程来启动。其中以“-”开头的是JVM参数,-Xzygote /system/bin。以“--”开头的是进程参数,--zygote --start-system-server --socket-name=zygote。

创建了两个socket,名字为zygote和usap_pool_primary。

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 on# NOTE: If the wakelock name here is changed, then also# update it in SystemSuspend.cpponrestart write /sys/power/wake_lock zygote_kwlonrestart restart audioserveronrestart restart cameraserveronrestart restart mediaonrestart restart --only-if-running media.tuneronrestart restart netdonrestart restart wificondtask_profiles ProcessCapacityHigh MaxPerformancecritical window=${zygote.critical_window.minute:-off} target=zygote-fatal

init.boringssl.zygote64_32.rc

包含的都是在某些条件下触发的自测进程。了解即可。

on init && property:ro.product.cpu.abilist32=*exec_start boringssl_self_test32
on init && property:ro.product.cpu.abilist64=*exec_start boringssl_self_test64
on property:apexd.status=ready && property:ro.product.cpu.abilist32=*exec_start boringssl_self_test_apex32
on property:apexd.status=ready && property:ro.product.cpu.abilist64=*exec_start boringssl_self_test_apex64

app_process解析 

frameworks/base/cmds/app_process/app_main.cpp

int main(int argc, char* const argv[])
{if (!LOG_NDEBUG) {String8 argv_String;for (int i = 0; i < argc; ++i) {argv_String.append("\"");argv_String.append(argv[i]);argv_String.append("\" ");}ALOGV("app_process main with argv: %s", argv_String.c_str());}//步骤1:创建Runtime.--------------------------------------------AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));// Process command line arguments// ignore argv[0]argc--;argv++;// Everything up to '--' or first non '-' arg goes to the vm.//// The first argument after the VM args is the "parent dir", which// is currently unused.//// After the parent dir, we expect one or more the following internal// arguments ://// --zygote : Start in zygote mode// --start-system-server : Start the system server.// --application : Start in application (stand alone, non zygote) mode.// --nice-name : The nice name for this process.//// For non zygote starts, these arguments will be followed by// the main class name. All remaining arguments are passed to// the main method of this class.//// For zygote starts, all remaining arguments are passed to the zygote.// main function.//// Note that we must copy argument string values since we will rewrite the// entire argument block when we apply the nice name to argv0.//// As an exception to the above rule, anything in "spaced commands"// goes to the vm even though it has a space in it.const char* spaced_commands[] = { "-cp", "-classpath" };// Allow "spaced commands" to be succeeded by exactly 1 argument (regardless of -s).bool known_command = false;//步骤2:解析传参,将'-'开头的参数传给Runtime.--------------------------------------------int i;for (i = 0; i < argc; i++) {if (known_command == true) {runtime.addOption(strdup(argv[i]));// The static analyzer gets upset that we don't ever free the above// string. Since the allocation is from main, leaking it doesn't seem// problematic. NOLINTNEXTLINEALOGV("app_process main add known option '%s'", argv[i]);known_command = false;continue;}for (int j = 0;j < static_cast<int>(sizeof(spaced_commands) / sizeof(spaced_commands[0]));++j) {if (strcmp(argv[i], spaced_commands[j]) == 0) {known_command = true;ALOGV("app_process main found known command '%s'", argv[i]);}}if (argv[i][0] != '-') {break;}if (argv[i][1] == '-' && argv[i][2] == 0) {++i; // Skip --.break;}runtime.addOption(strdup(argv[i]));// The static analyzer gets upset that we don't ever free the above// string. Since the allocation is from main, leaking it doesn't seem// problematic. NOLINTNEXTLINEALOGV("app_process main add option '%s'", argv[i]);}// Parse runtime arguments.  Stop at first unrecognized option.bool zygote = false;bool startSystemServer = false;bool application = false;String8 niceName;String8 className;//步骤3:整理zygote进程的传参.--------------------------------------------++i;  // Skip unused "parent dir" argument.while (i < argc) {const char* arg = argv[i++];if (strcmp(arg, "--zygote") == 0) {zygote = true;niceName = ZYGOTE_NICE_NAME;} else if (strcmp(arg, "--start-system-server") == 0) {startSystemServer = true;} else if (strcmp(arg, "--application") == 0) {application = true;} else if (strncmp(arg, "--nice-name=", 12) == 0) {niceName = (arg + 12);} else if (strncmp(arg, "--", 2) != 0) {className = arg;break;} else {--i;break;}}//步骤4:根据整理的zygote传参,判断是否是zygote进程,并根据判断结果,补充“--abi-list”和“start-system-server”传参.--------------------------------------------Vector<String8> args;if (!className.empty()) {// We're not in zygote mode, the only argument we need to pass// to RuntimeInit is the application argument.//// The Remainder of args get passed to startup class main(). Make// copies of them before we overwrite them with the process name.args.add(application ? String8("application") : String8("tool"));runtime.setClassNameAndArgs(className, argc - i, argv + i);if (!LOG_NDEBUG) {String8 restOfArgs;char* const* argv_new = argv + i;int argc_new = argc - i;for (int k = 0; k < argc_new; ++k) {restOfArgs.append("\"");restOfArgs.append(argv_new[k]);restOfArgs.append("\" ");}ALOGV("Class name = %s, args = %s", className.c_str(), restOfArgs.c_str());}} else {// We're in zygote mode.maybeCreateDalvikCache();if (startSystemServer) {args.add(String8("start-system-server"));}char prop[PROP_VALUE_MAX];if (property_get(ABI_LIST_PROPERTY, prop, NULL) == 0) {LOG_ALWAYS_FATAL("app_process: Unable to determine ABI list from property %s.",ABI_LIST_PROPERTY);return 11;}String8 abiFlag("--abi-list=");abiFlag.append(prop);args.add(abiFlag);// In zygote mode, pass all remaining arguments to the zygote// main() method.for (; i < argc; ++i) {args.add(String8(argv[i]));}}if (!niceName.empty()) {runtime.setArgv0(niceName.c_str(), true /* setProcName */);}
//步骤5:使用runtime,调用“com.android.internal.os.ZygoteInit”类,并传入传参,启动zygote.--------------------------------------------if (zygote) {runtime.start("com.android.internal.os.ZygoteInit", args, zygote);} else if (!className.empty()) {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.");}
}

AndroidRuntime解析

frameworks/base/core/jni/AndroidRuntime.cpp

Runtime的start方法

void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote)
{ALOGD(">>>>>> START %s uid %d <<<<<<\n",className != NULL ? className : "(unknown)", getuid());static const String8 startSystemServer("start-system-server");// Whether this is the primary zygote, meaning the zygote which will fork system server.bool primary_zygote = false;//步骤1:必要的参数及环境变量检查。-----------------------------------/** 'startSystemServer == true' means runtime is obsolete and not run from* init.rc anymore, so we print out the boot start event here.*/for (size_t i = 0; i < options.size(); ++i) {if (options[i] == startSystemServer) {primary_zygote = true;/* track our progress through the boot sequence */const int LOG_BOOT_PROGRESS_START = 3000;LOG_EVENT_LONG(LOG_BOOT_PROGRESS_START,  ns2ms(systemTime(SYSTEM_TIME_MONOTONIC)));}}const char* rootDir = getenv("ANDROID_ROOT");if (rootDir == NULL) {rootDir = "/system";if (!hasDir("/system")) {LOG_FATAL("No root directory specified, and /system does not exist.");return;}setenv("ANDROID_ROOT", rootDir, 1);}const char* artRootDir = getenv("ANDROID_ART_ROOT");if (artRootDir == NULL) {LOG_FATAL("No ART directory specified with ANDROID_ART_ROOT environment variable.");return;}const char* i18nRootDir = getenv("ANDROID_I18N_ROOT");if (i18nRootDir == NULL) {LOG_FATAL("No runtime directory specified with ANDROID_I18N_ROOT environment variable.");return;}const char* tzdataRootDir = getenv("ANDROID_TZDATA_ROOT");if (tzdataRootDir == NULL) {LOG_FATAL("No tz data directory specified with ANDROID_TZDATA_ROOT environment variable.");return;}//const char* kernelHack = getenv("LD_ASSUME_KERNEL");//ALOGD("Found LD_ASSUME_KERNEL='%s'\n", kernelHack);//步骤2:启动VM。-----------------------------------/* start the virtual machine */JniInvocation jni_invocation;jni_invocation.Init(NULL);JNIEnv* env;if (startVm(&mJavaVM, &env, zygote, primary_zygote) != 0) {return;}onVmCreated(env);/** Register android functions.*/
//步骤3:注册JNI方法。-----------------------------------if (startReg(env) < 0) {ALOGE("Unable to register all android natives\n");return;}/** We want to call main() with a String array with arguments in it.* At present we have two arguments, the class name and an option string.* Create an array to hold them.*/jclass stringClass;jobjectArray strArray;jstring classNameStr;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).c_str());assert(optionsStr != NULL);env->SetObjectArrayElement(strArray, i + 1, optionsStr);}//步骤4:利用java的反射,调用com.android.internal.os.ZygoteInit类中的main方法,创建zygote进程。-----------------------------------/** Start VM.  This thread becomes the main thread of the VM, and will* not return until the VM exits.*/char* slashClassName = toSlashClassName(className != NULL ? className : "");jclass startClass = env->FindClass(slashClassName);if (startClass == NULL) {ALOGE("JavaVM unable to locate class '%s'\n", slashClassName);/* keep going */} else {jmethodID startMeth = env->GetStaticMethodID(startClass, "main","([Ljava/lang/String;)V");if (startMeth == NULL) {ALOGE("JavaVM unable to find main() in '%s'\n", className);/* keep going */} else {env->CallStaticVoidMethod(startClass, startMeth, strArray);#if 0if (env->ExceptionCheck())threadExitUncaughtException(env);
#endif}}free(slashClassName);ALOGD("Shutting down VM\n");if (mJavaVM->DetachCurrentThread() != JNI_OK)ALOGW("Warning: unable to detach main thread\n");if (mJavaVM->DestroyJavaVM() != 0)ALOGW("Warning: VM did not shut down cleanly\n");
}

启动VM

该方法有600+行,都是收集VM参数,并调用JNI_CreateJavaVM启动VM。参数是一个可以做性能优化的点。了解即可。

int AndroidRuntime::startVm(JavaVM** pJavaVM, JNIEnv** pEnv, bool zygote, bool primary_zygote)
{JavaVMInitArgs initArgs;char propBuf[PROPERTY_VALUE_MAX];char jniOptsBuf[sizeof("-Xjniopts:")-1 + PROPERTY_VALUE_MAX];char heapstartsizeOptsBuf[sizeof("-Xms")-1 + PROPERTY_VALUE_MAX];char heapsizeOptsBuf[sizeof("-Xmx")-1 + PROPERTY_VALUE_MAX];char heapgrowthlimitOptsBuf[sizeof("-XX:HeapGrowthLimit=")-1 + PROPERTY_VALUE_MAX];char heapminfreeOptsBuf[sizeof("-XX:HeapMinFree=")-1 + PROPERTY_VALUE_MAX];char heapmaxfreeOptsBuf[sizeof("-XX:HeapMaxFree=")-1 + PROPERTY_VALUE_MAX];char usejitOptsBuf[sizeof("-Xusejit:")-1 + PROPERTY_VALUE_MAX];char jitpthreadpriorityOptsBuf[sizeof("-Xjitpthreadpriority:")-1 + PROPERTY_VALUE_MAX];char jitmaxsizeOptsBuf[sizeof("-Xjitmaxsize:")-1 + PROPERTY_VALUE_MAX];char jitinitialsizeOptsBuf[sizeof("-Xjitinitialsize:")-1 + PROPERTY_VALUE_MAX];char jitthresholdOptsBuf[sizeof("-Xjitthreshold:")-1 + PROPERTY_VALUE_MAX];char jitprithreadweightOptBuf[sizeof("-Xjitprithreadweight:")-1 + PROPERTY_VALUE_MAX];char jittransitionweightOptBuf[sizeof("-Xjittransitionweight:")-1 + PROPERTY_VALUE_MAX];char hotstartupsamplesOptsBuf[sizeof("-Xps-hot-startup-method-samples:")-1 + PROPERTY_VALUE_MAX];char saveResolvedClassesDelayMsOptsBuf[sizeof("-Xps-save-resolved-classes-delay-ms:")-1 + PROPERTY_VALUE_MAX];char profileMinSavePeriodOptsBuf[sizeof("-Xps-min-save-period-ms:")-1 + PROPERTY_VALUE_MAX];char profileMinFirstSaveOptsBuf[sizeof("-Xps-min-first-save-ms:") - 1 + PROPERTY_VALUE_MAX];char profileInlineCacheThresholdOptsBuf[sizeof("-Xps-inline-cache-threshold:") - 1 + PROPERTY_VALUE_MAX];char madviseWillNeedFileSizeVdex[sizeof("-XMadviseWillNeedVdexFileSize:")-1 + PROPERTY_VALUE_MAX];char madviseWillNeedFileSizeOdex[sizeof("-XMadviseWillNeedOdexFileSize:")-1 + PROPERTY_VALUE_MAX];char madviseWillNeedFileSizeArt[sizeof("-XMadviseWillNeedArtFileSize:")-1 + PROPERTY_VALUE_MAX];char gctypeOptsBuf[sizeof("-Xgc:")-1 + PROPERTY_VALUE_MAX];char backgroundgcOptsBuf[sizeof("-XX:BackgroundGC=")-1 + PROPERTY_VALUE_MAX];char heaptargetutilizationOptsBuf[sizeof("-XX:HeapTargetUtilization=")-1 + PROPERTY_VALUE_MAX];char foregroundHeapGrowthMultiplierOptsBuf[sizeof("-XX:ForegroundHeapGrowthMultiplier=")-1 + PROPERTY_VALUE_MAX];char finalizerTimeoutMsOptsBuf[sizeof("-XX:FinalizerTimeoutMs=")-1 + PROPERTY_VALUE_MAX];char threadSuspendTimeoutOptsBuf[sizeof("-XX:ThreadSuspendTimeout=")-1 + PROPERTY_VALUE_MAX];char cachePruneBuf[sizeof("-Xzygote-max-boot-retry=")-1 + PROPERTY_VALUE_MAX];char dex2oatXmsImageFlagsBuf[sizeof("-Xms")-1 + PROPERTY_VALUE_MAX];char dex2oatXmxImageFlagsBuf[sizeof("-Xmx")-1 + PROPERTY_VALUE_MAX];char dex2oatCompilerFilterBuf[sizeof("--compiler-filter=")-1 + PROPERTY_VALUE_MAX];char dex2oatImageCompilerFilterBuf[sizeof("--compiler-filter=")-1 + PROPERTY_VALUE_MAX];char dex2oatThreadsBuf[sizeof("-j")-1 + PROPERTY_VALUE_MAX];char dex2oatThreadsImageBuf[sizeof("-j")-1 + PROPERTY_VALUE_MAX];char dex2oatCpuSetBuf[sizeof("--cpu-set=")-1 + PROPERTY_VALUE_MAX];char dex2oatCpuSetImageBuf[sizeof("--cpu-set=")-1 + PROPERTY_VALUE_MAX];char dex2oat_isa_variant_key[PROPERTY_KEY_MAX];char dex2oat_isa_variant[sizeof("--instruction-set-variant=") -1 + PROPERTY_VALUE_MAX];char dex2oat_isa_features_key[PROPERTY_KEY_MAX];char dex2oat_isa_features[sizeof("--instruction-set-features=") -1 + PROPERTY_VALUE_MAX];char dex2oatFlagsBuf[PROPERTY_VALUE_MAX];char dex2oatImageFlagsBuf[PROPERTY_VALUE_MAX];char extraOptsBuf[PROPERTY_VALUE_MAX];char perfettoHprofOptBuf[sizeof("-XX:PerfettoHprof=") + PROPERTY_VALUE_MAX];char perfettoJavaHeapStackOptBuf[sizeof("-XX:PerfettoJavaHeapStackProf=") + PROPERTY_VALUE_MAX];enum {kEMDefault,kEMIntPortable,kEMIntFast,kEMJitCompiler,} executionMode = kEMDefault;char localeOption[sizeof("-Duser.locale=") + PROPERTY_VALUE_MAX];char lockProfThresholdBuf[sizeof("-Xlockprofthreshold:")-1 + PROPERTY_VALUE_MAX];char nativeBridgeLibrary[sizeof("-XX:NativeBridge=") + PROPERTY_VALUE_MAX];char cpuAbiListBuf[sizeof("--cpu-abilist=") + PROPERTY_VALUE_MAX];char corePlatformApiPolicyBuf[sizeof("-Xcore-platform-api-policy:") + PROPERTY_VALUE_MAX];char methodTraceFileBuf[sizeof("-Xmethod-trace-file:") + PROPERTY_VALUE_MAX];char methodTraceFileSizeBuf[sizeof("-Xmethod-trace-file-size:") + PROPERTY_VALUE_MAX];std::string fingerprintBuf;char javaZygoteForkLoopBuf[sizeof("-XX:ForceJavaZygoteForkLoop=") + PROPERTY_VALUE_MAX];char jdwpProviderBuf[sizeof("-XjdwpProvider:") - 1 + PROPERTY_VALUE_MAX];char opaqueJniIds[sizeof("-Xopaque-jni-ids:") - 1 + PROPERTY_VALUE_MAX];char bootImageBuf[sizeof("-Ximage:") - 1 + PROPERTY_VALUE_MAX];// Read if we are using the profile configuration, do this at the start since the last ART args// take precedence.std::string profile_boot_class_path_flag =server_configurable_flags::GetServerConfigurableFlag(RUNTIME_NATIVE_BOOT_NAMESPACE,PROFILE_BOOT_CLASS_PATH,/*default_value=*/"");bool profile_boot_class_path;switch (ParseBool(profile_boot_class_path_flag)) {case ParseBoolResult::kError:// Default to the system property.profile_boot_class_path =GetBoolProperty("dalvik.vm.profilebootclasspath", /*default_value=*/false);break;case ParseBoolResult::kTrue:profile_boot_class_path = true;break;case ParseBoolResult::kFalse:profile_boot_class_path = false;break;}if (profile_boot_class_path) {addOption("-Xcompiler-option");addOption("--count-hotness-in-compiled-code");addOption("-Xps-profile-boot-class-path");addOption("-Xps-profile-aot-code");addOption("-Xjitsaveprofilinginfo");}std::string use_jitzygote_image_flag =server_configurable_flags::GetServerConfigurableFlag(RUNTIME_NATIVE_BOOT_NAMESPACE,ENABLE_JITZYGOTE_IMAGE,/*default_value=*/"");// Use the APEX boot image for boot class path profiling to get JIT samples on BCP methods.// Also use the APEX boot image if it's explicitly enabled via configuration flag.const bool use_apex_image = profile_boot_class_path || (use_jitzygote_image_flag == "true");if (use_apex_image) {ALOGI("Using JIT Zygote image: '%s'\n", kJitZygoteImageOption);addOption(kJitZygoteImageOption);} else if (parseRuntimeOption("dalvik.vm.boot-image", bootImageBuf, "-Ximage:")) {ALOGI("Using dalvik.vm.boot-image: '%s'\n", bootImageBuf);} else {ALOGI("Using default boot image");}std::string disable_lock_profiling =server_configurable_flags::GetServerConfigurableFlag(RUNTIME_NATIVE_BOOT_NAMESPACE,DISABLE_LOCK_PROFILING,/*default_value=*/ "");if (disable_lock_profiling == "true") {addOption(kLockProfThresholdRuntimeOption);ALOGI("Disabling lock profiling: '%s'\n", kLockProfThresholdRuntimeOption);} else {ALOGI("Leaving lock profiling enabled");}const bool checkJni = GetBoolProperty("dalvik.vm.checkjni", false);if (checkJni) {ALOGD("CheckJNI is ON");/* extended JNI checking */addOption("-Xcheck:jni");/* with -Xcheck:jni, this provides a JNI function call trace *///addOption("-verbose:jni");}const bool odsignVerificationSuccess = GetBoolProperty("odsign.verification.success", false);if (!odsignVerificationSuccess) {addOption("-Xdeny-art-apex-data-files");}property_get("dalvik.vm.execution-mode", propBuf, "");if (strcmp(propBuf, "int:portable") == 0) {executionMode = kEMIntPortable;} else if (strcmp(propBuf, "int:fast") == 0) {executionMode = kEMIntFast;} else if (strcmp(propBuf, "int:jit") == 0) {executionMode = kEMJitCompiler;}strcpy(jniOptsBuf, "-Xjniopts:");if (parseRuntimeOption("dalvik.vm.jniopts", jniOptsBuf, "-Xjniopts:")) {ALOGI("JNI options: '%s'\n", jniOptsBuf);}/* route exit() to our handler */addOption("exit", (void*) runtime_exit);/* route fprintf() to our handler */addOption("vfprintf", (void*) runtime_vfprintf);/* register the framework-specific "is sensitive thread" hook */addOption("sensitiveThread", (void*) runtime_isSensitiveThread);/* enable verbose; standard options are { jni, gc, class } *///addOption("-verbose:jni");addOption("-verbose:gc");//addOption("-verbose:class");// On Android, we always want to allow loading the PerfettoHprof plugin.// Even with this option set, we will still only actually load the plugin// if we are on a userdebug build or the app is debuggable or profileable.// This is enforced in art/runtime/runtime.cc.//// We want to be able to disable this, because this does not work on host,// and we do not want to enable it in tests.parseRuntimeOption("dalvik.vm.perfetto_hprof", perfettoHprofOptBuf, "-XX:PerfettoHprof=","true");// Enable PerfettoJavaHeapStackProf in the zygoteparseRuntimeOption("dalvik.vm.perfetto_javaheap", perfettoJavaHeapStackOptBuf,"-XX:PerfettoJavaHeapStackProf=", "true");if (primary_zygote) {addOption("-Xprimaryzygote");}/** The default starting and maximum size of the heap.  Larger* values should be specified in a product property override.*/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=");parseRuntimeOption("dalvik.vm.heaptargetutilization",heaptargetutilizationOptsBuf,"-XX:HeapTargetUtilization=");/* Foreground heap growth multiplier option */parseRuntimeOption("dalvik.vm.foreground-heap-growth-multiplier",foregroundHeapGrowthMultiplierOptsBuf,"-XX:ForegroundHeapGrowthMultiplier=");/** Finalizer and thread suspend timeouts.*/parseRuntimeOption("dalvik.vm.finalizer-timeout-ms",finalizerTimeoutMsOptsBuf,"-XX:FinalizerTimeoutMs=");parseRuntimeOption("dalvik.vm.thread-suspend-timeout-ms",threadSuspendTimeoutOptsBuf,"-XX:ThreadSuspendTimeout=");/** JIT related options.*/parseRuntimeOption("dalvik.vm.usejit", usejitOptsBuf, "-Xusejit:");parseRuntimeOption("dalvik.vm.jitmaxsize", jitmaxsizeOptsBuf, "-Xjitmaxsize:");parseRuntimeOption("dalvik.vm.jitinitialsize", jitinitialsizeOptsBuf, "-Xjitinitialsize:");parseRuntimeOption("dalvik.vm.jitthreshold", jitthresholdOptsBuf, "-Xjitthreshold:");parseRuntimeOption("dalvik.vm.jitpthreadpriority",jitpthreadpriorityOptsBuf,"-Xjitpthreadpriority:");addOption("-Xjitsaveprofilinginfo");parseRuntimeOption("dalvik.vm.jitprithreadweight",jitprithreadweightOptBuf,"-Xjitprithreadweight:");parseRuntimeOption("dalvik.vm.jittransitionweight", jittransitionweightOptBuf,"-Xjittransitionweight:");/** Use default platform configuration as limits for madvising,* when no properties are specified.*/parseRuntimeOption("dalvik.vm.madvise.vdexfile.size",madviseWillNeedFileSizeVdex,"-XMadviseWillNeedVdexFileSize:");parseRuntimeOption("dalvik.vm.madvise.odexfile.size",madviseWillNeedFileSizeOdex,"-XMadviseWillNeedOdexFileSize:");parseRuntimeOption("dalvik.vm.madvise.artfile.size",madviseWillNeedFileSizeArt,"-XMadviseWillNeedArtFileSize:");/** Profile related options.*/parseRuntimeOption("dalvik.vm.hot-startup-method-samples", hotstartupsamplesOptsBuf,"-Xps-hot-startup-method-samples:");parseRuntimeOption("dalvik.vm.ps-resolved-classes-delay-ms", saveResolvedClassesDelayMsOptsBuf,"-Xps-save-resolved-classes-delay-ms:");parseRuntimeOption("dalvik.vm.ps-min-save-period-ms", profileMinSavePeriodOptsBuf,"-Xps-min-save-period-ms:");parseRuntimeOption("dalvik.vm.ps-min-first-save-ms", profileMinFirstSaveOptsBuf,"-Xps-min-first-save-ms:");parseRuntimeOption("dalvik.vm.ps-inline-cache-threshold", profileInlineCacheThresholdOptsBuf,"-Xps-inline-cache-threshold:");property_get("ro.config.low_ram", propBuf, "");if (strcmp(propBuf, "true") == 0) {addOption("-XX:LowMemoryMode");}/** Garbage-collection related options.*/parseRuntimeOption("dalvik.vm.gctype", gctypeOptsBuf, "-Xgc:");// If it set, honor the "enable_generational_cc" device configuration;// otherwise, let the runtime use its default behavior.std::string enable_generational_cc =server_configurable_flags::GetServerConfigurableFlag(RUNTIME_NATIVE_BOOT_NAMESPACE,ENABLE_GENERATIONAL_CC,/*default_value=*/ "");if (enable_generational_cc == "true") {addOption(kGenerationalCCRuntimeOption);} else if (enable_generational_cc == "false") {addOption(kNoGenerationalCCRuntimeOption);}parseRuntimeOption("dalvik.vm.backgroundgctype", backgroundgcOptsBuf, "-XX:BackgroundGC=");/** Enable/disable zygote native fork loop.*/parseRuntimeOption("dalvik.vm.force-java-zygote-fork-loop",javaZygoteForkLoopBuf,"-XX:ForceJavaZygoteForkLoop=");/** Enable debugging only for apps forked from zygote.*/if (zygote) {// Set the JDWP provider and required arguments. By default let the runtime choose how JDWP is// implemented. When this is not set the runtime defaults to not allowing JDWP.addOption("-XjdwpOptions:suspend=n,server=y");parseRuntimeOption("dalvik.vm.jdwp-provider",jdwpProviderBuf,"-XjdwpProvider:","default");}// Only pass an explicit opaque-jni-ids to apps forked from zygoteif (zygote) {parseRuntimeOption("dalvik.vm.opaque-jni-ids",opaqueJniIds,"-Xopaque-jni-ids:","swapable");}parseRuntimeOption("dalvik.vm.lockprof.threshold",lockProfThresholdBuf,"-Xlockprofthreshold:");if (executionMode == kEMIntPortable) {addOption("-Xint:portable");} else if (executionMode == kEMIntFast) {addOption("-Xint:fast");} else if (executionMode == kEMJitCompiler) {addOption("-Xint:jit");}// Extra options for JIT.parseCompilerOption("dalvik.vm.dex2oat-filter", dex2oatCompilerFilterBuf,"--compiler-filter=", "-Xcompiler-option");parseCompilerOption("dalvik.vm.dex2oat-threads", dex2oatThreadsBuf, "-j", "-Xcompiler-option");parseCompilerOption("dalvik.vm.dex2oat-cpu-set", dex2oatCpuSetBuf, "--cpu-set=","-Xcompiler-option");// Copy the variant.sprintf(dex2oat_isa_variant_key, "dalvik.vm.isa.%s.variant", ABI_STRING);parseCompilerOption(dex2oat_isa_variant_key, dex2oat_isa_variant,"--instruction-set-variant=", "-Xcompiler-option");// Copy the features.sprintf(dex2oat_isa_features_key, "dalvik.vm.isa.%s.features", ABI_STRING);parseCompilerOption(dex2oat_isa_features_key, dex2oat_isa_features,"--instruction-set-features=", "-Xcompiler-option");/** When running with debug.generate-debug-info, add --generate-debug-info to the compiler* options so that both JITted code and the boot image, if it is compiled on device, will* include native debugging information.*/property_get("debug.generate-debug-info", propBuf, "");bool generate_debug_info = (strcmp(propBuf, "true") == 0);if (generate_debug_info) {addOption("-Xcompiler-option");addOption("--generate-debug-info");}// The mini-debug-info makes it possible to backtrace through compiled code.bool generate_mini_debug_info = property_get_bool("dalvik.vm.minidebuginfo", 0);if (generate_mini_debug_info) {addOption("-Xcompiler-option");addOption("--generate-mini-debug-info");}property_get("dalvik.vm.dex2oat-flags", dex2oatFlagsBuf, "");parseExtraOpts(dex2oatFlagsBuf, "-Xcompiler-option");/* extra options; parse this late so it overrides others */property_get("dalvik.vm.extra-opts", extraOptsBuf, "");parseExtraOpts(extraOptsBuf, NULL);// Extra options for boot image generation.parseCompilerRuntimeOption("dalvik.vm.image-dex2oat-Xms", dex2oatXmsImageFlagsBuf,"-Xms", "-Ximage-compiler-option");parseCompilerRuntimeOption("dalvik.vm.image-dex2oat-Xmx", dex2oatXmxImageFlagsBuf,"-Xmx", "-Ximage-compiler-option");parseCompilerOption("dalvik.vm.image-dex2oat-filter", dex2oatImageCompilerFilterBuf,"--compiler-filter=", "-Ximage-compiler-option");// If there is a dirty-image-objects file, push it.if (hasFile("/system/etc/dirty-image-objects")) {addOption("-Ximage-compiler-option");addOption("--dirty-image-objects=/system/etc/dirty-image-objects");}parseCompilerOption("dalvik.vm.image-dex2oat-threads", dex2oatThreadsImageBuf, "-j","-Ximage-compiler-option");parseCompilerOption("dalvik.vm.image-dex2oat-cpu-set", dex2oatCpuSetImageBuf, "--cpu-set=","-Ximage-compiler-option");// The runtime may compile a boot image, when necessary, not using installd. Thus, we need// to pass the instruction-set-features/variant as an image-compiler-option.// Note: it is OK to reuse the buffer, as the values are exactly the same between//       * compiler-option, used for runtime compilation (DexClassLoader)//       * image-compiler-option, used for boot-image compilation on deviceparseCompilerOption(dex2oat_isa_variant_key, dex2oat_isa_variant,"--instruction-set-variant=", "-Ximage-compiler-option");parseCompilerOption(dex2oat_isa_features_key, dex2oat_isa_features,"--instruction-set-features=", "-Ximage-compiler-option");if (generate_debug_info) {addOption("-Ximage-compiler-option");addOption("--generate-debug-info");}if (generate_mini_debug_info) {addOption("-Ximage-compiler-option");addOption("--generate-mini-debug-info");}property_get("dalvik.vm.image-dex2oat-flags", dex2oatImageFlagsBuf, "");parseExtraOpts(dex2oatImageFlagsBuf, "-Ximage-compiler-option");/* Set the properties for locale */{strcpy(localeOption, "-Duser.locale=");const std::string locale = readLocale();strncat(localeOption, locale.c_str(), PROPERTY_VALUE_MAX);addOption(localeOption);}// Trace files are stored in /data/misc/trace which is writable only in debug mode.property_get("ro.debuggable", propBuf, "0");if (strcmp(propBuf, "1") == 0) {property_get("dalvik.vm.method-trace", propBuf, "false");if (strcmp(propBuf, "true") == 0) {addOption("-Xmethod-trace");parseRuntimeOption("dalvik.vm.method-trace-file",methodTraceFileBuf,"-Xmethod-trace-file:");parseRuntimeOption("dalvik.vm.method-trace-file-siz",methodTraceFileSizeBuf,"-Xmethod-trace-file-size:");property_get("dalvik.vm.method-trace-stream", propBuf, "false");if (strcmp(propBuf, "true") == 0) {addOption("-Xmethod-trace-stream");}}}// Native bridge library. "0" means that native bridge is disabled.//// Note: bridging is only enabled for the zygote. Other runs of//       app_process may not have the permissions to mount etc.property_get("ro.dalvik.vm.native.bridge", propBuf, "");if (propBuf[0] == '\0') {ALOGW("ro.dalvik.vm.native.bridge is not expected to be empty");} else if (zygote && strcmp(propBuf, "0") != 0) {snprintf(nativeBridgeLibrary, sizeof("-XX:NativeBridge=") + PROPERTY_VALUE_MAX,"-XX:NativeBridge=%s", propBuf);addOption(nativeBridgeLibrary);}#if defined(__LP64__)const char* cpu_abilist_property_name = "ro.product.cpu.abilist64";
#elseconst char* cpu_abilist_property_name = "ro.product.cpu.abilist32";
#endif  // defined(__LP64__)property_get(cpu_abilist_property_name, propBuf, "");if (propBuf[0] == '\0') {ALOGE("%s is not expected to be empty", cpu_abilist_property_name);return -1;}snprintf(cpuAbiListBuf, sizeof(cpuAbiListBuf), "--cpu-abilist=%s", propBuf);addOption(cpuAbiListBuf);// Dalvik-cache pruning counter.parseRuntimeOption("dalvik.vm.zygote.max-boot-retry", cachePruneBuf,"-Xzygote-max-boot-retry=");// If set, the property below can be used to enable core platform API violation reporting.property_get("persist.debug.dalvik.vm.core_platform_api_policy", propBuf, "");if (propBuf[0] != '\0') {snprintf(corePlatformApiPolicyBuf,sizeof(corePlatformApiPolicyBuf),"-Xcore-platform-api-policy:%s",propBuf);addOption(corePlatformApiPolicyBuf);}/** Retrieve the build fingerprint and provide it to the runtime. That way, ANR dumps will* contain the fingerprint and can be parsed.* Fingerprints are potentially longer than PROPERTY_VALUE_MAX, so parseRuntimeOption() cannot* be used here.* Do not ever re-assign fingerprintBuf as its c_str() value is stored in mOptions.*/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();initArgs.nOptions = mOptions.size();initArgs.ignoreUnrecognized = JNI_FALSE;/** Initialize the VM.** The JavaVM* is essentially per-process, and the JNIEnv* is per-thread.* If this call succeeds, the VM is ready, and we can start issuing* JNI calls.*/if (JNI_CreateJavaVM(pJavaVM, pEnv, &initArgs) < 0) {ALOGE("JNI_CreateJavaVM failed\n");return -1;}return 0;
}

注册JNI

将gRegJNI数组里的JNI方法进行注册。RegJNIRec 包含100+个JNI方法。

/*static*/ int AndroidRuntime::startReg(JNIEnv* env)
{ATRACE_NAME("RegisterAndroidNatives");/** This hook causes all future threads created in this process to be* attached to the JavaVM.  (This needs to go away in favor of JNI* Attach calls.)*/androidSetCreateThreadFunc((android_create_thread_fn) javaCreateThreadEtc);ALOGV("--- registering native functions ---\n");/** Every "register" function calls one or more things that return* a local reference (e.g. FindClass).  Because we haven't really* started the VM yet, they're all getting stored in the base frame* and never released.  Use Push/Pop to manage the storage.*/env->PushLocalFrame(200);//核心步骤:将gRegJNI数组里的JNI方法进行注册。if (register_jni_procs(gRegJNI, NELEM(gRegJNI), env) < 0) {env->PopLocalFrame(NULL);return -1;}env->PopLocalFrame(NULL);//createJavaThread("fubar", quickTest, (void*) "hello");return 0;
}
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_CharsetUtils),REG_JNI(register_android_util_EventLog),REG_JNI(register_android_util_Log),REG_JNI(register_android_util_MemoryIntArray),REG_JNI(register_android_app_admin_SecurityLog),REG_JNI(register_android_content_AssetManager),REG_JNI(register_android_content_StringBlock),REG_JNI(register_android_content_XmlBlock),REG_JNI(register_android_content_res_ApkAssets),REG_JNI(register_android_content_res_ResourceTimer),REG_JNI(register_android_text_AndroidCharacter),REG_JNI(register_android_text_Hyphenator),REG_JNI(register_android_view_InputDevice),REG_JNI(register_android_view_KeyCharacterMap),REG_JNI(register_android_os_Process),REG_JNI(register_android_os_SystemProperties),REG_JNI(register_android_os_Binder),REG_JNI(register_android_os_Parcel),REG_JNI(register_android_os_PerformanceHintManager),REG_JNI(register_android_os_HidlMemory),REG_JNI(register_android_os_HidlSupport),REG_JNI(register_android_os_HwBinder),REG_JNI(register_android_os_HwBlob),REG_JNI(register_android_os_HwParcel),REG_JNI(register_android_os_HwRemoteBinder),REG_JNI(register_android_os_NativeHandle),REG_JNI(register_android_os_ServiceManager),REG_JNI(register_android_os_ServiceManagerNative),REG_JNI(register_android_os_storage_StorageManager),REG_JNI(register_android_service_DataLoaderService),REG_JNI(register_android_view_DisplayEventReceiver),REG_JNI(register_android_view_Surface),REG_JNI(register_android_view_SurfaceControl),REG_JNI(register_android_view_SurfaceControlHdrLayerInfoListener),REG_JNI(register_android_view_SurfaceSession),REG_JNI(register_android_view_InputApplicationHandle),// This must be called after register_android_view_SurfaceControl since it has a dependency// on the Java SurfaceControl object that references a native resource via static request.REG_JNI(register_android_view_InputWindowHandle),REG_JNI(register_android_view_CompositionSamplingListener),REG_JNI(register_android_view_TextureView),REG_JNI(register_android_view_TunnelModeEnabledListener),REG_JNI(register_com_google_android_gles_jni_EGLImpl),REG_JNI(register_com_google_android_gles_jni_GLImpl),REG_JNI(register_android_opengl_jni_EGL14),REG_JNI(register_android_opengl_jni_EGL15),REG_JNI(register_android_opengl_jni_EGLExt),REG_JNI(register_android_opengl_jni_GLES10),REG_JNI(register_android_opengl_jni_GLES10Ext),REG_JNI(register_android_opengl_jni_GLES11),REG_JNI(register_android_opengl_jni_GLES11Ext),REG_JNI(register_android_opengl_jni_GLES20),REG_JNI(register_android_opengl_jni_GLES30),REG_JNI(register_android_opengl_jni_GLES31),REG_JNI(register_android_opengl_jni_GLES31Ext),REG_JNI(register_android_opengl_jni_GLES32),REG_JNI(register_android_graphics_classes),REG_JNI(register_android_graphics_BLASTBufferQueue),REG_JNI(register_android_graphics_GraphicBuffer),REG_JNI(register_android_graphics_GraphicsStatsService),REG_JNI(register_android_graphics_SurfaceTexture),REG_JNI(register_android_database_CursorWindow),REG_JNI(register_android_database_SQLiteConnection),REG_JNI(register_android_database_SQLiteGlobal),REG_JNI(register_android_database_SQLiteDebug),REG_JNI(register_android_database_SQLiteRawStatement),REG_JNI(register_android_os_Debug),REG_JNI(register_android_os_FileObserver),REG_JNI(register_android_os_GraphicsEnvironment),REG_JNI(register_android_os_MessageQueue),REG_JNI(register_android_os_SELinux),REG_JNI(register_android_os_Trace),REG_JNI(register_android_os_UEventObserver),REG_JNI(register_android_net_LocalSocketImpl),REG_JNI(register_android_os_MemoryFile),REG_JNI(register_android_os_SharedMemory),REG_JNI(register_android_os_incremental_IncrementalManager),REG_JNI(register_com_android_internal_content_om_OverlayConfig),REG_JNI(register_com_android_internal_content_om_OverlayManagerImpl),REG_JNI(register_com_android_internal_net_NetworkUtilsInternal),REG_JNI(register_com_android_internal_os_ClassLoaderFactory),REG_JNI(register_com_android_internal_os_LongArrayMultiStateCounter),REG_JNI(register_com_android_internal_os_LongMultiStateCounter),REG_JNI(register_com_android_internal_os_Zygote),REG_JNI(register_com_android_internal_os_ZygoteCommandBuffer),REG_JNI(register_com_android_internal_os_ZygoteInit),REG_JNI(register_com_android_internal_security_VerityUtils),REG_JNI(register_com_android_internal_util_VirtualRefBasePtr),REG_JNI(register_android_hardware_Camera),REG_JNI(register_android_hardware_camera2_CameraMetadata),REG_JNI(register_android_hardware_camera2_DngCreator),REG_JNI(register_android_hardware_camera2_impl_CameraExtensionJpegProcessor),REG_JNI(register_android_hardware_camera2_utils_SurfaceUtils),REG_JNI(register_android_hardware_display_DisplayManagerGlobal),REG_JNI(register_android_hardware_HardwareBuffer),REG_JNI(register_android_hardware_OverlayProperties),REG_JNI(register_android_hardware_SensorManager),REG_JNI(register_android_hardware_SerialPort),REG_JNI(register_android_hardware_SyncFence),REG_JNI(register_android_hardware_UsbDevice),REG_JNI(register_android_hardware_UsbDeviceConnection),REG_JNI(register_android_hardware_UsbRequest),REG_JNI(register_android_hardware_location_ActivityRecognitionHardware),REG_JNI(register_android_media_AudioDeviceAttributes),REG_JNI(register_android_media_AudioEffectDescriptor),REG_JNI(register_android_media_AudioSystem),REG_JNI(register_android_media_AudioRecord),REG_JNI(register_android_media_AudioTrack),REG_JNI(register_android_media_AudioAttributes),REG_JNI(register_android_media_AudioProductStrategies),REG_JNI(register_android_media_AudioVolumeGroups),REG_JNI(register_android_media_AudioVolumeGroupChangeHandler),REG_JNI(register_android_media_MediaMetrics),REG_JNI(register_android_media_MicrophoneInfo),REG_JNI(register_android_media_RemoteDisplay),REG_JNI(register_android_media_ToneGenerator),REG_JNI(register_android_media_audio_common_AidlConversion),REG_JNI(register_android_media_midi),REG_JNI(register_android_opengl_classes),REG_JNI(register_android_ddm_DdmHandleNativeHeap),REG_JNI(register_android_backup_BackupDataInput),REG_JNI(register_android_backup_BackupDataOutput),REG_JNI(register_android_backup_FileBackupHelperBase),REG_JNI(register_android_backup_BackupHelperDispatcher),REG_JNI(register_android_app_backup_FullBackup),REG_JNI(register_android_app_Activity),REG_JNI(register_android_app_ActivityThread),REG_JNI(register_android_app_NativeActivity),REG_JNI(register_android_util_jar_StrictJarFile),REG_JNI(register_android_view_InputChannel),REG_JNI(register_android_view_InputEventReceiver),REG_JNI(register_android_view_InputEventSender),REG_JNI(register_android_view_InputQueue),REG_JNI(register_android_view_KeyEvent),REG_JNI(register_android_view_MotionEvent),REG_JNI(register_android_view_MotionPredictor),REG_JNI(register_android_view_PointerIcon),REG_JNI(register_android_view_VelocityTracker),REG_JNI(register_android_view_VerifiedKeyEvent),REG_JNI(register_android_view_VerifiedMotionEvent),REG_JNI(register_android_content_res_ObbScanner),REG_JNI(register_android_content_res_Configuration),REG_JNI(register_android_animation_PropertyValuesHolder),REG_JNI(register_android_security_Scrypt),REG_JNI(register_com_android_internal_content_F2fsUtils),REG_JNI(register_com_android_internal_content_NativeLibraryHelper),REG_JNI(register_com_android_internal_os_FuseAppLoop),REG_JNI(register_com_android_internal_os_KernelAllocationStats),REG_JNI(register_com_android_internal_os_KernelCpuBpfTracking),REG_JNI(register_com_android_internal_os_KernelCpuTotalBpfMapReader),REG_JNI(register_com_android_internal_os_KernelCpuUidBpfMapReader),REG_JNI(register_com_android_internal_os_KernelSingleProcessCpuThreadReader),REG_JNI(register_com_android_internal_os_KernelSingleUidTimeReader),REG_JNI(register_android_window_WindowInfosListener),REG_JNI(register_android_window_ScreenCapture),REG_JNI(register_jni_common),REG_JNI(register_android_tracing_PerfettoDataSource),REG_JNI(register_android_tracing_PerfettoDataSourceInstance),REG_JNI(register_android_tracing_PerfettoProducer),
};

相关文章:

Android Framework学习笔记(4)----Zygote进程

Zygote的启动流程 Init进程启动后&#xff0c;会加载并执行init.rc文件。该.rc文件中&#xff0c;就包含启动Zygote进程的Action。详见“RC文件解析”章节。 根据Zygote对应的RC文件&#xff0c;可知Zygote进程是由/system/bin/app_process程序来创建的。 app_process大致处…...

澎湃算力 玩转AI 华为昇腾AI开发板——香橙派OriengePi AiPro边缘计算案例评测

澎湃算力 玩转AI 华为昇腾AI开发板 香橙派OriengePi AiPro 边缘计算案例评测 人工智能&#xff08;AI&#xff09;技术正以前所未有的速度改变着我们的生活、工作乃至整个社会的面貌。作为推动这一变革的关键力量&#xff0c;边缘计算与AI技术的深度融合正成为行业发展的新趋势…...

<数据集>铁轨缺陷检测数据集<目标检测>

数据集格式&#xff1a;VOCYOLO格式 图片数量&#xff1a;844张 标注数量(xml文件个数)&#xff1a;844 标注数量(txt文件个数)&#xff1a;844 标注类别数&#xff1a;3 标注类别名称&#xff1a;[Spalling, Squat, Wheel Burn] 序号类别名称图片数框数1Spalling3315522…...

第2章 矩阵

A 乘以此列向量&#xff0c;1的位置依次往下&#xff0c;所以A的列向量全为0 B C、D 取BE 要统一...

抖音seo短视频矩阵源码系统开发搭建----开源+二次开发

抖音seo短视频矩阵源码系统开发搭建 是一项技术密集型工作&#xff0c;需要对大数据处理、人工智能等领域有深入了解。该系统开发过程中需要用到多种编程语言&#xff0c;如Java、Python等。同时&#xff0c;需要使用一些框架和技术&#xff0c;如Hadoop、Spark、PyTorch等&am…...

【ELK】简述

ELK 堆栈的作用 大规模日志管理与分析 随着系统规模的扩大&#xff0c;应用程序、服务器和网络设备会产生大量的日志数据。ELK 堆栈可以集中收集、存储和索引这些分散在不同服务器和系统中的日志&#xff0c;方便快速检索和分析&#xff0c;帮助您快速定位系统故障、异常事件和…...

PyTorch张量数值计算

文章目录 1、张量基本运算2、阿达玛积3、点积运算4、指定运算设备⭐5、解决在GPU运行PyTorch的问题 &#x1f343;作者介绍&#xff1a;双非本科大三网络工程专业在读&#xff0c;阿里云专家博主&#xff0c;专注于Java领域学习&#xff0c;擅长web应用开发、数据结构和算法&am…...

Dockerfile相关命令

Dockerfile Dockerfile 是一个用来构建Docker镜像的文本文件&#xff0c;包含了一系列构建镜像所需的指令和参数。 指令详解 Dockerfile 指令说明FROM指定基础镜像&#xff0c;用于后续的指令构建&#xff0c;必须为第一个命令MAINTAINER指定Dockerfile的作者/维护者。&…...

【AI教程-吴恩达讲解Prompts】第1篇 - 课程简介

文章目录 简介Prompt学习相关资源 两类大模型原则与技巧 简介 欢迎来到面向开发者的提示工程部分&#xff0c;本部分内容基于吴恩达老师的《Prompt Engineering for Developer》课程进行编写。《Prompt Engineering for Developer》课程是由吴恩达老师与 OpenAI 技术团队成员 I…...

Leetcode - 周赛406

目录 一&#xff0c;3216. 交换后字典序最小的字符串 二&#xff0c;3217. 从链表中移除在数组中存在的节点 三&#xff0c;3218. 切蛋糕的最小总开销 I 四&#xff0c;3219. 切蛋糕的最小总开销 II 一&#xff0c;3216. 交换后字典序最小的字符串 本题要求交换一次相邻字符…...

【JavaScript 算法】拓扑排序:有向无环图的应用

&#x1f525; 个人主页&#xff1a;空白诗 文章目录 一、算法原理二、算法实现方法一&#xff1a;Kahn算法方法二&#xff1a;深度优先搜索&#xff08;DFS&#xff09;注释说明&#xff1a; 三、应用场景四、总结 拓扑排序&#xff08;Topological Sorting&#xff09;是一种…...

Fastgpt本地或服务器私有化部署常见问题

一、错误排查方式 遇到问题先按下面方式排查。 docker ps -a 查看所有容器运行状态,检查是否全部 running,如有异常,尝试docker logs 容器名查看对应日志。容器都运行正常的,docker logs 容器名 查看报错日志带有requestId的,都是 OneAPI 提示错误,大部分都是因为模型接…...

基于深度学习的股票预测

基于深度学习的股票预测是一项复杂且具有挑战性的任务&#xff0c;涉及金融数据的分析和预测。其目的是利用深度学习模型来预测股票价格的走势&#xff0c;从而帮助投资者做出更为准确的投资决策。以下是对这一领域的系统介绍&#xff1a; 1. 任务和目标 股票预测的主要任务和…...

UNiapp 微信小程序渐变不生效

开始用的一直是这个&#xff0c;调试一直没问题&#xff0c;但是重新启动就没生效&#xff0c;经查询这个不适合小程序使用&#xff1a;不适合没生效 background-image:linear-gradient(to right, #33f38d8a,#6dd5ed00); 正确使用下面这个&#xff1a; 生效&#xff0c;适合…...

FinClip 率先入驻 AWS Marketplace,加速全球市场布局

近日&#xff0c;凡泰极客旗下的小程序数字管理平台 FinClip 已成功上线亚马逊云科技&#xff08;AWS&#xff09;Marketplace。未来&#xff0c;FinClip 将主要服务于海外市场的开放银行、超级钱包、财富管理、社交电商、智慧城市解决方案等领域。 在全球市场的多样性需求推动…...

ChatGPT对话:Windows如何将Python训练模型转换为TensorFlow.js格式

【编者按】编者目前正在做手机上的人工智能软件&#xff0c;第一次做这种工作&#xff0c;从一些基本工作开始与ChatGPT交流。对初学者应该有帮助。 一天后修改文章补充内容&#xff1a; 解决TensorFlow 2.X与TensorFlow Decision Forests版本冲突问题&#xff1a; 在使用tens…...

封装网络请求 鸿蒙APP HarmonyOS ArkTS

一、效果展示 通过在页面直接调用 userLogin(params) 方法&#xff0c;获取登录令牌 二、申请网络权限 访问网络时候首先需要申请网络权限&#xff0c;需要修改 src/main 目录下的 module.json5 文件&#xff0c;加入 requestPermissions 属性&#xff0c;详见官方文档 【声明权…...

2024年度上半年中国汽车保值率报告

来源&#xff1a;中国汽车流通协会&精真估 近期历史回顾&#xff1a; 2024上半年房地产企业数智化转型报告.pdf 2024国产院线电影路演数据洞察报告.pdf 空间数据智能大模型研究-2024年中国空间数据智能战略发展白皮书.pdf 2024年全球资产管理报告 2024年中型律师事务所的法…...

Go语言之内存分配

文章收录在网站&#xff1a;http://hardyfish.top/ 文章收录在网站&#xff1a;http://hardyfish.top/ 文章收录在网站&#xff1a;http://hardyfish.top/ 文章收录在网站&#xff1a;http://hardyfish.top/ Go 语言程序所管理的虚拟内存空间会被分为两部分&#xff1a;堆内…...

北京交通大学《深度学习》专业课,实验3卷积、空洞卷积、残差神经网络实验

一、实验要求 1. 二维卷积实验&#xff08;平台课与专业课要求相同&#xff09; ⚫ 手写二维卷积的实现&#xff0c;并在至少一个数据集上进行实验&#xff0c;从训练时间、预测精 度、Loss变化等角度分析实验结果&#xff08;最好使用图表展示&#xff09; ⚫ 使用torch.nn…...

2025 后端自学UNIAPP【项目实战:旅游项目】6、我的收藏页面

代码框架视图 1、先添加一个获取收藏景点的列表请求 【在文件my_api.js文件中添加】 // 引入公共的请求封装 import http from ./my_http.js// 登录接口&#xff08;适配服务端返回 Token&#xff09; export const login async (code, avatar) > {const res await http…...

VTK如何让部分单位不可见

最近遇到一个需求&#xff0c;需要让一个vtkDataSet中的部分单元不可见&#xff0c;查阅了一些资料大概有以下几种方式 1.通过颜色映射表来进行&#xff0c;是最正规的做法 vtkNew<vtkLookupTable> lut; //值为0不显示&#xff0c;主要是最后一个参数&#xff0c;透明度…...

Java面试专项一-准备篇

一、企业简历筛选规则 一般企业的简历筛选流程&#xff1a;首先由HR先筛选一部分简历后&#xff0c;在将简历给到对应的项目负责人后再进行下一步的操作。 HR如何筛选简历 例如&#xff1a;Boss直聘&#xff08;招聘方平台&#xff09; 直接按照条件进行筛选 例如&#xff1a…...

pikachu靶场通关笔记22-1 SQL注入05-1-insert注入(报错法)

目录 一、SQL注入 二、insert注入 三、报错型注入 四、updatexml函数 五、源码审计 六、insert渗透实战 1、渗透准备 2、获取数据库名database 3、获取表名table 4、获取列名column 5、获取字段 本系列为通过《pikachu靶场通关笔记》的SQL注入关卡(共10关&#xff0…...

Maven 概述、安装、配置、仓库、私服详解

目录 1、Maven 概述 1.1 Maven 的定义 1.2 Maven 解决的问题 1.3 Maven 的核心特性与优势 2、Maven 安装 2.1 下载 Maven 2.2 安装配置 Maven 2.3 测试安装 2.4 修改 Maven 本地仓库的默认路径 3、Maven 配置 3.1 配置本地仓库 3.2 配置 JDK 3.3 IDEA 配置本地 Ma…...

纯 Java 项目(非 SpringBoot)集成 Mybatis-Plus 和 Mybatis-Plus-Join

纯 Java 项目&#xff08;非 SpringBoot&#xff09;集成 Mybatis-Plus 和 Mybatis-Plus-Join 1、依赖1.1、依赖版本1.2、pom.xml 2、代码2.1、SqlSession 构造器2.2、MybatisPlus代码生成器2.3、获取 config.yml 配置2.3.1、config.yml2.3.2、项目配置类 2.4、ftl 模板2.4.1、…...

RSS 2025|从说明书学习复杂机器人操作任务:NUS邵林团队提出全新机器人装配技能学习框架Manual2Skill

视觉语言模型&#xff08;Vision-Language Models, VLMs&#xff09;&#xff0c;为真实环境中的机器人操作任务提供了极具潜力的解决方案。 尽管 VLMs 取得了显著进展&#xff0c;机器人仍难以胜任复杂的长时程任务&#xff08;如家具装配&#xff09;&#xff0c;主要受限于人…...

Rust 开发环境搭建

环境搭建 1、开发工具RustRover 或者vs code 2、Cygwin64 安装 https://cygwin.com/install.html 在工具终端执行&#xff1a; rustup toolchain install stable-x86_64-pc-windows-gnu rustup default stable-x86_64-pc-windows-gnu ​ 2、Hello World fn main() { println…...

Kafka主题运维全指南:从基础配置到故障处理

#作者&#xff1a;张桐瑞 文章目录 主题日常管理1. 修改主题分区。2. 修改主题级别参数。3. 变更副本数。4. 修改主题限速。5.主题分区迁移。6. 常见主题错误处理常见错误1&#xff1a;主题删除失败。常见错误2&#xff1a;__consumer_offsets占用太多的磁盘。 主题日常管理 …...

CVPR2025重磅突破:AnomalyAny框架实现单样本生成逼真异常数据,破解视觉检测瓶颈!

本文介绍了一种名为AnomalyAny的创新框架&#xff0c;该方法利用Stable Diffusion的强大生成能力&#xff0c;仅需单个正常样本和文本描述&#xff0c;即可生成逼真且多样化的异常样本&#xff0c;有效解决了视觉异常检测中异常样本稀缺的难题&#xff0c;为工业质检、医疗影像…...