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_framework
和1
,所以還要獲取屬性dalvik.vm.image-dex2oat-filter
, 系統中并未設置該值,如果設置了,參數的形式為:--compiler-filter=${dalvik.vm.image-dex2oat-filter}, -Ximage-compiler-option
直接添加參數
Ximage-compiler-option
直接添加參數
--compiled-classes=/system/etc/preloaded-classes
如果文件
/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 {
jint version;
jint nOptions;
JavaVMOption* options;
jboolean ignoreUnrecognized
}
typedef struct JavaVMOption {
const char* optionString;
void* extractInfo;
}
typedef std::vector<std::pair<std::string, const void*>> 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<JavaVMInitArgs*>(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<std::string> 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<unsigned int>(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方法主要做了以下幾件事:
- 先將所有的字符串參數名稱集中生成對應的
RuntimeArgumentMap::[KEY]
結構 - 從實際傳入的參數中解析
extra_info
,extra_info
用來hook函數,實際傳入的參數中hook的是下面三個函數:exit
,vfprintf
,sensitiveThread
- 判斷傳入的參數中是否有
-help,-showversion
,如果存在,則打印對應的幫助信息并返回 - 確保
-Xusejit
和-Xint
不能共同使用 -
getenv(BOOTCLASSPATH)
并設置-Xbootclasspath
-
getenv(CLASSPATH)
并設置-Xclasspath
- 設置
-XX:ParallelGCThreads=0u
- 根據實際傳入的參數設置
LogVerbosity
- 獲取
Xprofile
,由于實際參數中沒有設置,所以使用默認值,并設置Trace::SetDefaultClockSource
- 再次檢索
extra_info
- 根據
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
- 如果bootclasspath中包含
/core.jar
,則用/core-libart.jar
替換 - 如果指定了
-Xbootclasspath-location
,檢查-Xbootclasspath-location
鎖指定的path數量是否和-Xbootclasspath
中的path數量一樣,不一樣輸出Usage并返回 - 由于實際參數中并沒有指定
-Ximage:
和名為compilercallbacks
的extra_info
,指定Runtime的Image文件是/system/framework/boot.art
- 確保
-XX:HeapGrowthLimit
大于0同時小于-Xmx
4.5.1 ParsedOptions::ProcessSpecialOptions
bool ParsedOptions::ProcessSpecialOptions(const RuntimeOptions& options,
RuntimeArgumentMap* runtime_options,
std::vector<std::string>* 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<bool (*)()>(const_cast<void*>(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<int (*)(FILE *, const char*, va_list)>(const_cast<void*>(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<void(*)(jint)>(const_cast<void*>(hook));
if (runtime_options != nullptr) {
runtime_options->Set(M::HookExit, hook_exit);
}
hook_exit_ = hook_exit;
} else if (option == "abort") {
... //實際并沒有設置
} else {
... //實際并沒有設置
}
}
return true;
}