ART|ART Runtime 创建(二)--启动参数

Android 7.0 aosp_shamu-userdebug
一. 启动时获取的参数 AndroidRuntime::startVm(/framework/bae/cpre/jni/AndroidRuntime.cpp)方法会首先获取大量系统属性,并将这些系统属性转化为实际的启动参数,下面是获取的系统属性以及对应的启动参数:
  • dalvik.vm.checkjni(ro.kernel.android.checkjni)
真实值:无
默认为false, 如果为true, 则添加参数-Xcheck:jni
  • dalvik.vm.execution-mode
真实值:无
默认为KEMDefault, 有四个取值:KEMDefault, kEMIntPortable, kEMIntFast, kEMJitCompiler. 如果不是kEMDefault,则相应的参数为:-Xint:portable, -Xint:fast, -Xint:jit
  • dalvik.vm.stack-trace-file
真实值:/data/anr/traces.txt
参数的形式为:-Xstacktracefile:/data/anr/traces.txt
  • dalvik.vm.jniopts
真实值:没有设置
如果有设置的话,参数形式为:Xjnipots:...
  • {exit, runtime_exit}
Hook Runtime的exit()runtime_exit(int code)函数
  • {vfprintf, runtime_vfprintf}
Hook Runtime的fprintf()runtime_vfprintf(FILE* fp, const char* format, va_list ap)函数
  • {sensitiveThread, runtime_isSensitiveThread()}
Hook Runtime的sensitiveThread()runtime_isSensitiveThread()函数
  • 直接添加参数-verbose:gc
  • dalvik.vm.heapstartsize
真实值:8m
参数的形式为:-Xms8m
  • dalvik.vm.heapsize
真实值:512m
参数的形式为:-Xmx512m
  • dalvik.vm.heapgrowthlimit
真实值:256m
参数形式为:-XX:HeapGrowthLimit=256m
  • dalvik.vm.heapminfree
真实值:512k,
参数形式为:-XX:HeapMinFree=512k
  • dalvik.vm.heapmaxfree
真实值:8m
参数形式为:-XX:HeapMaxFree=8m
  • dalvik.vm.heaputilization
真实值:0.75
参数形式为:-XX:HeapTargetUtilization=0.75
  • dalvik.vm.usejit
真实值:true
参数形式为:-Xusejit:true
  • dalvik.vm.jitmaxsize
真实值是:无
如果设置则参数形式为:-Xjitmaxsize:${dalvik.vm.jitmaxsize}
  • dalvik.vm.jitinitialize
真实值:无,
如果设置参数形式为:-Xjitinitialize:${dalvik.vm.jitinitialize}
  • dalvik.vm.jitthreshold
真实值:无
如果设置参数形式为:-Xjitthreshold:..
  • dalvik.vm.usejitprofiles
真实值:true,
参数形式为:-Xjitsaveprofilinginfo
  • dalvik.vm.jitprithreadweight
真实值:无
如果设置,参数的形式为:-Xjitprithreadweight
  • dalvik.vm.jittransitionweight
真实值:无
如果设置,参数的形式为:-Xjittransitionweight:${dalvik.vm.jittransitionweight}
  • ro.config.low_ram
真实值:无
如果设置,参数形式为:-XXLowMemoryMode
  • dalvik.vm.gctype
真实值:无
如果设置,参数形式为:-Xgc:${dalvik.vm.gctype}
  • dalvik.vm.backgroundgctype
真实值:无
如果设置,参数形式为:-XX:BackgroundGC=${dalvik.vm.backgroundgctype}
  • 直接添加参数-agentlib:jdwp=transport=dt_android_adb,suspend=n,server=y
  • dalvik.vm.lockprof.threshold
真实值:500
参数形式为:-Xlockprofthreshold:500
  • vold.decrypt
trigger_restart_framework
因为不等于trigfer_restart_min_framework1,所以还要获取属性dalvik.vm.image-dex2oat-filter, 系统中并未设置该值,如果设置了,参数的形式为:--compiler-filter=${dalvik.vm.image-dex2oat-filter}, -Ximage-compiler-option
  • 直接添加参数Ximage-compiler-option
  • 直接添加参数--compiled-classes=/system/etc/preloaded-classes
  • 【ART|ART Runtime 创建(二)--启动参数】如果文件/system/etc/compiled-classes存在(实际存在),则添加参数:-Ximage-compiler-option, --compiled-classes=/system/etc/compiled-classes
  • dalvik.vm.imgae-dex2oat-flags
真实值:无
如果设置,参数形式为:-Ximage-compile-option, ${image-dex2oat-flags}
  • dalvik.vm.dex2oat-Xms
真实值:64m
参数形式为:-Xcompiler-option, --runtime-arg, -Xcompiler-option, -Xms64m
  • dalvik.vm.dex2oat-Xmx
真实值:512m
参数形式为:-Xcompiler-option, --runtime-arg, -Xcompiler-option, -Xms512m
  • dalvik.vm.dex2oat-filter
真实值:无
如果设置了,参数的形式为:-Xcompiler-option, --runtime-arg, -Xcompiler-option, --compiler-filter=${dalvik.vm.dex2oat-filter}
  • dalvik.vm.dex2oat-threads
真实值:无
如果设置了,参数形式为:-Xcompiler-option, --runtime-arg, -Xcompiler-option, -j${dalvik.vm.dex2oat-threads}
  • dalvik.vm.image-dex2oat-threads
真实值:无
如果设置了,参数形式为:-Ximage-compiler-option, --runtime-arg, -Ximage-compiler-option, -j${dalvik.vm.image-dex2oat-threads}
  • dalvik.vm.isa.arm.variant
真实值:krait
参数最终形式为:-Ximage-compiler-option, --runtime-arg, -Ximage-compiler-option, --instruction-set-variant=krait , -Xcompiler-option, --runtime-arg, -Xcompiler-option, --instruction-set-variant=krait
  • dalvik.vm.isa.arm.features
真实值:default
参数形式为:-Ximage-compiler-option, --runtime-arg, -Ximage-compiler-option, --instruction-set-features=default, -Xcompiler-option, --runtime-arg, -Xcompiler-option, instruction-set-variant-features=default
  • dalvik.vm.dex2oat-flags
真实值:无
如果设置,参数形式为:-Xcompiler-option, [dex2oat-flags]
  • dalvik.vm.extra-opts
真实值:无
如果设置,参数形式为:[extra-opts]
  • 读取Locale,然后添加参数-Duser.locale=zh-Hans-CN
  • ro.debuggable
真实值:1,
如果ro.debuggable=1同时dalvik.vm.method-trace=true(实际为false),则添加参数-Xmethod-trace, -Xmethod-trace-file:[dalvik.vm.method-trace-file], -Xmethod-trace-file-size:[dalvik.vm.method-trace-file-siz], 如果dalvik.vm.method-trace-stream=true, 添加参数-Xmethod-trace-stream(实际都没有添加)
  • ro.dalvik.vm.native.bridge
真实值:0
如果值不为0, 则参数为:-XX:NativeBridge=[ro.dalvik.vm.native.bridge]
  • ro.product.cpu.abilist32
真实值:[armeabi-v7a,armeabi]
参数形式为:--cpu-abilist=[armeabi-v7a,armeabi]
  • dalvik.vm.zygote.max-boot-retry
真实值:无
如果设置, 最终形式为:-Xzygote-max-boot-retry=[dalvik.vm.zygote.max-boot-retry]
  • debug.generate-debug-info
真实值:无
如果值为true, 添加参数:-Xcompiler-option, --generate-debug-info, -Ximage-compiler-option, --generate-debug-info
  • ro.build.fingerprint
真实值:Android/aosp_shamu/shamu:7.0/NBD91U/xx12231922:userdebug/test-keys
参数形式为:-Xfingerprint:Android/aosp_shamu/shamu:7.0/NBD91U/xx12231922:userdebug/test-keys
二. 实际传入的参数
{ {`-Xstacktracefile:/data/anr/traces.txt`, NULL}, //{optionString, extraInfo} {`exit`, runtime_exit}, {`vfprintf`, `runtime_vfprintf`}, {`sensitiveThread`, `runtime_isSensitiveThread`}, {`-verbose:gc`, NULL}, {`-Xms8m`, NULL}, {`-Xmx512m`, NULL}, {`-XX:HeapGrowthLimit=256m`,NULL}, {`-XX:HeapMinFree=512k`, NULL}, {`-XX:HeapMaxFree=8m`,NULL}, {`-XX:HeapTargetUtilization=0.75`,NULL}, {`-Xusejit:true`, NULL}, {`-Xjitsaveprofilinginfo`,NULL}, {`-agentlib:jdwp=transport=dt_android_adb,suspend=n,server=y`, NULL}, {`-Xlockprofthreshold:500`,NULL}, {`-Ximage-compiler-option`,NULL}, {`--compiled-classes=/system/etc/preloaded-classes`,NULL}, {`-Ximage-compiler-option`,NULL}, {`--compiled-classes=/system/etc/compiled-classes`,NULL}, {`-Xcompiler-option`,NULL}, {`--runtime-arg`,NULL}, {`-Xcompiler-option`,NULL}, {`-Xms64m`,NULL}, {`-Xcompiler-option`,NULL}, {`--runtime-arg`,NULL}, {`-Xcompiler-option`,NULL}, {`-Xmx512m`,NULL}, {`-Ximage-compiler-option`,NULL}, {`--runtime-arg`,NULL}, {`-Ximage-compiler-option`,NULL}, {`--instruction-set-variant=krait`,NULL}, {`-Xcompiler-option`,NULL}, {`--runtime-arg`,NULL}, {`-Xcompiler-option`,NULL}, {`--instruction-set-variant=krait`,NULL}, {`-Ximage-compiler-option`,NULL}, {`--runtime-arg`,NULL}, {`-Ximage-compiler-option`,NULL}, {`--instruction-set-features=default`,NULL}, {`-Xcompiler-option`,NULL}, {`--runtime-arg`,NULL}, {`-Xcompiler-option`,NULL}, {`--instruction-set-features=default`,NULL}, {`-Duser.locale=zh-Hans-CN`,NULL}, {`--cpu-abilist=[armeabi-v7a,armeabi]`,NULL}, {`-Xfingerprint:Android/aosp_shamu/shamu:7.0/NBD91U/xx12231922:userdebug/test-keys`, NULL} }

三. 存储参数的数据结构和方法 3.1 存储参数的数据结构
typedef struct JavaVMInitArgs { jintversion; jintnOptions; JavaVMOption* options; jbooleanignoreUnrecognized }typedef struct JavaVMOption { const char* optionString; void*extractInfo; }typedef std::vector> RuntimeOptions

3.2 最终传入的数据结构
JavaVMInitArgs initArgs; initArgs.version = JNI_VERSION_1_4; initArgs.options = mOptions.editArray(); initArgs.nOptions = mOptions.size(); initArgs.ignoreUnrecognized = JNI_FALSE;

3.3 添加参数的方法
void AndroidRuntime::addOption(const char* optionString, void* extraInfo) { JavaVMOption opt; opt.optionString = optionString; opt.extraInfo = extraInfo; mOptions.add(opt); }

四. 解析参数流程 4.1 JNI_CreateJavaVM
extern "C" jint JNI_CreateJavaVM(JavaVM** p_vm, JNIEnv** p_env, void* vm_args) { const JavaVMInitArgs* args = static_cast(vm_args); ... RuntimeOptions options; for (int i = 0; i < args->nOptions; ++i) { JavaVMOption* option = &args->options[i]; options.push_back(std::make_pair(std::string(option->optionString), option->extraInfo)); } bool ignore_unrecognized = args->ignoreUnrecognized; if (!Runtime::Create(options, ignore_unrecognized)) { return JNI_ERR; } ... }

4.2 Runtime::Create()
bool Runtime::Create(const RuntimeOptions& raw_options, bool ignore_unrecognized) { RuntimeArgumentMap runtime_options; return ParseOptions(raw_options, ignore_unrecognized, &runtime_options) && Create(std::move(runtime_options)); }

4.3 Runtime::ParseOptions
bool Runtime::ParseOptions(const RuntimeOptions& raw_options, bool ignore_unrecognized, RuntimeArgumentMap* runtime_options) { InitLogging(/* argv */ nullptr); bool parsed = ParsedOptions::Parse(raw_options, ignore_unrecognized, runtime_options); if (!parsed) { LOG(ERROR) << "Failed to parse options"; return false; } return true; }

4.4 ParsedOptions::Parse
位于/art/runtime/parsed_options.cc
bool ParsedOptions::Parse(const RuntimeOptions& options, bool ignore_unrecognized, RuntimeArgumentMap* runtime_options) { CHECK(runtime_options != nullptr); ParsedOptions parser; return parser.DoParse(options, ignore_unrecognized, runtime_options); }

4.5 ParsedOptions::DoParse
bool ParsedOptions::DoParse(const RuntimeOptions& options, bool ignore_unrecognized, RuntimeArgumentMap* runtime_options) { ... //将字符串参数生成对应的M::key结构 auto parser = MakeParser(ignore_unrecognized); std::vector argv_list; //解析带有extraOption的参数, [5.2] if (!ProcessSpecialOptions(options, nullptr, &argv_list)) { return false; }CmdlineResult parse_result = parser->Parse(argv_list); // 处理parse errors if (parse_result.IsError()) { ... }using M = RuntimeArgumentMap; RuntimeArgumentMap args = parser->ReleaseArgumentsMap(); if (args.Exists(M::Help)) { //-help Usage(nullptr); return false; } else if (args.Exists(M::ShowVersion)) { //-showversion UsageMessage(stdout, "ART version %s\n", Runtime::GetVersion()); Exit(0); } else if (args.Exists(M::BootClassPath)) { //-Xbootclasspath LOG(INFO) << "setting boot class path to " << *args.Get(M::BootClassPath); }//-Xusejit和-Xint不能同时使用 if (args.GetOrDefault(M::UseJitCompilation) && args.GetOrDefault(M::Interpret)) { Usage("-Xusejit:true and -Xint cannot be specified together"); Exit(0); }//获取默认的bootclasspath if (getenv("BOOTCLASSPATH") != nullptr) { args.SetIfMissing(M::BootClassPath, std::string(getenv("BOOTCLASSPATH"))); } //获取默认的classpath if (getenv("CLASSPATH") != nullptr) { args.SetIfMissing(M::ClassPath, std::string(getenv("CLASSPATH"))); } //设置参数-XX:ParallelGCThreads=0u //kDefaultEnableParallelGC=false args.SetIfMissing(M::ParallelGCThreads, gc::Heap::kDefaultEnableParallelGC ? static_cast(sysconf(_SC_NPROCESSORS_CONF) - 1u) : 0u); // -verbose:gc { LogVerbosity *log_verbosity = args.Get(M::Verbose); if (log_verbosity != nullptr) { gLogVerbosity = *log_verbosity; } } MaybeOverrideVerbosity(); // 设置-Xprofile:,由于在启动时没有指定这个参数,所以使用默认值: Trace::SetDefaultClockSource(args.GetOrDefault(M::ProfileClock)); //再次检查extraInfo if (!ProcessSpecialOptions(options, &args, nullptr)) { return false; }{// 如果没有设置,background回收器是默认的homogeneous compaction // 如果foreground回收器是GSS, 则background也是GSS // 如果是low memory模式, 则使用semispace gc::CollectorType background_collector_type_; gc::CollectorType collector_type_ = (XGcOption{}).collector_type_; // NOLINT [whitespace/braces] [5] //查看是否存在-XX:LowMemoryMode,实际上是没有的 bool low_memory_mode_ = args.Exists(M::LowMemoryMode); //获取参数-XX:BackgroundGC,实际上并未指定,所以使用默认值 background_collector_type_ = args.GetOrDefault(M::BackgroundGc); { //获取参数-Xgc,实际上参数中并没有指定 ... }if (background_collector_type_ == gc::kCollectorTypeNone) { if (collector_type_ != gc::kCollectorTypeGSS) { //如果foreground回收器不是GSS,且当前是low_memory_mode,则使用SS, 否则指定为homogeneous compact background_collector_type_ = low_memory_mode_ ? gc::kCollectorTypeSS : gc::kCollectorTypeHomogeneousSpaceCompact; } else { background_collector_type_ = collector_type_; } }args.Set(M::BackgroundGc, BackgroundGcOption { background_collector_type_ }); }#if defined(ART_TARGET) std::string core_jar("/core.jar"); std::string core_libart_jar("/core-libart.jar"); #else // The host uses hostdex files. std::string core_jar("/core-hostdex.jar"); std::string core_libart_jar("/core-libart-hostdex.jar"); #endif //获取-Xbootclasspath,之前已经通过getenv("BOOTCLASSPATH")设置 auto boot_class_path_string = args.GetOrDefault(M::BootClassPath); //在bootclasspath中查找/core.jar, 如果找到的话,则用/core-libart.jar替换 size_t core_jar_pos = boot_class_path_string.find(core_jar); if (core_jar_pos != std::string::npos) { boot_class_path_string.replace(core_jar_pos, core_jar.size(), core_libart_jar); args.Set(M::BootClassPath, boot_class_path_string); }{ //获取-Xbootclasspath和-Xbootclasspath-location: auto&& boot_class_path = args.GetOrDefault(M::BootClassPath); auto&& boot_class_path_locations = args.GetOrDefault(M::BootClassPathLocations); //实际并未指定-Xbootclasspath-location if (args.Exists(M::BootClassPathLocations)) { //如果boot_class_path_locations的path数量不等于boot_class_path中的path路径,打印Usage并返回 ... } } //如果没有指定compilercallbacks回调函数(实际参数中并没有指定)以及没有指定-Ximage(实际参数也并未指定) //指定image文件路径是/system/framework/boot.art if (!args.Exists(M::CompilerCallbacksPtr) && !args.Exists(M::Image)) { std::string image = GetAndroidRoot(); image += "/framework/boot.art"; args.Set(M::Image, image); }//获取-XX:HeapGrowthLimit(实际参数中为256m),判断是否小于0或者大于-Xmx(实际为512m) //如果小于0或者大于-Xmx,则将-XX:HeapGrowthLimit设为-Xmx的值 if (args.GetOrDefault(M::HeapGrowthLimit) <= 0u || args.GetOrDefault(M::HeapGrowthLimit) > args.GetOrDefault(M::MemoryMaximumSize)) { args.Set(M::HeapGrowthLimit, args.GetOrDefault(M::MemoryMaximumSize)); }//实际参数中并没有指定-Xexperimental if (args.GetOrDefault(M::Experimental) & ExperimentalFlags::kLambdas) { ... }*runtime_options = std::move(args); return true; }

DoParse方法主要做了以下几件事:
  1. 先将所有的字符串参数名称集中生成对应的RuntimeArgumentMap::[KEY]结构
  2. 从实际传入的参数中解析extra_info,extra_info用来hook函数,实际传入的参数中hook的是下面三个函数:exit,vfprintf,sensitiveThread
  3. 判断传入的参数中是否有-help,-showversion,如果存在,则打印对应的帮助信息并返回
  4. 确保-Xusejit-Xint不能共同使用
  5. getenv(BOOTCLASSPATH)并设置-Xbootclasspath
  6. getenv(CLASSPATH)并设置-Xclasspath
  7. 设置-XX:ParallelGCThreads=0u
  8. 根据实际传入的参数设置LogVerbosity
  9. 获取Xprofile,由于实际参数中没有设置,所以使用默认值,并设置Trace::SetDefaultClockSource
  10. 再次检索extra_info
  11. 根据kuseReadBarrier的值确定foreground GC, 如果kuseReadBarrier=true,foregroundGC=CC,否则foregroundGC=default; 查看实际参数中是否指定-Xgc,如果指定了则将参数指定的GC设为background GC(实际参数中并未指定); 如果foreground GC是GSS,则background GC也是GSS; 如果foreground GC不是GSS,则如果实际参数中指定了-XX:LowMemoryMode(实际参数中并未指定), 即低内存模式下backgroundGC=GSS, 否则backgroundGC=homogeneous Space Compact
  12. 如果bootclasspath中包含/core.jar,则用/core-libart.jar替换
  13. 如果指定了-Xbootclasspath-location,检查-Xbootclasspath-location锁指定的path数量是否和-Xbootclasspath中的path数量一样,不一样输出Usage并返回
  14. 由于实际参数中并没有指定-Ximage:和名为compilercallbacksextra_info,指定Runtime的Image文件是/system/framework/boot.art
  15. 确保-XX:HeapGrowthLimit大于0同时小于-Xmx
4.5.1 ParsedOptions::ProcessSpecialOptions
bool ParsedOptions::ProcessSpecialOptions(const RuntimeOptions& options, RuntimeArgumentMap* runtime_options, std::vector* out_options) { using M = RuntimeArgumentMap; for (size_t i = 0; i < options.size(); ++i) { const std::string option(options[i].first); if (option == "bootclasspath") { ... //实际并没有设置 } else if (option == "compilercallbacks") { ... //实际并没有设置 } else if (option == "imageinstructionset") { ... //实际并没有设置 } else if (option == "sensitiveThread") { const void* hook = options[i].second; bool (*hook_is_sensitive_thread)() = reinterpret_cast(const_cast(hook)); if (runtime_options != nullptr) { runtime_options->Set(M::HookIsSensitiveThread, hook_is_sensitive_thread); } } else if (option == "vfprintf") { const void* hook = options[i].second; if (hook == nullptr) { Usage("vfprintf argument was nullptr"); return false; } int (*hook_vfprintf)(FILE *, const char*, va_list) = reinterpret_cast(const_cast(hook)); if (runtime_options != nullptr) { runtime_options->Set(M::HookVfprintf, hook_vfprintf); } hook_vfprintf_ = hook_vfprintf; } else if (option == "exit") { const void* hook = options[i].second; if (hook == nullptr) { Usage("exit argument was nullptr"); return false; } void(*hook_exit)(jint) = reinterpret_cast(const_cast(hook)); if (runtime_options != nullptr) { runtime_options->Set(M::HookExit, hook_exit); } hook_exit_ = hook_exit; } else if (option == "abort") { ... //实际并没有设置 } else { ... //实际并没有设置 } }return true; }

    推荐阅读