一. Zygote启动过程中的创建虚拟机过程
Zygote的代码位于/framework/base/cmds/app_process/app_main.cpp
int main(int argc, char* const argv[])
{
...
//[1.1]
AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));
... // handle args
if (zygote) {
//[1.2]
runtime.start("com.android.internal.os.ZygoteInit", args, zygote);
} else if (className) {
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.");
return 10;
}
}
main
方法中省略的代码中主要在处理传入的参数, 从而确定当前是否要执行zygote的逻辑以及启动zygote时是否需要启动system_server
, 这里主要两个关键调用:
-
AppRuntime runtime(...)
这行代码创建了一个AppRuntime
对象,AppRuntime继承自AndroidRuntime
-
runtime.start(...)
调用AppRuntime的start
方法,由于AppRuntime并没有重写父类的start方法,所以这里实际调用的是AndroidRuntime::start(...)
1.1 AndroidRuntime
AppRuntime
的定义就在app_main.cpp
中,其构造函数为:
AppRuntime(char* argBlockStart, const size_t argBlockLength)
: AndroidRuntime(argBlockStart, argBlockLength)
, mClass(NULL){}
可以看到AppRuntime的构造函数没做任何事,主要就是调用父类AndroidRuntime
的构造函数, AndroidRuntime
定义在/framework/base/include/android_runtime/AndroidRuntime.h
,对应的源文件在/framework/base/core/jni/AndroidRuntime.cpp
//全局变量
static AndroidRuntime* gCurRuntime = NULL;
AndroidRuntime::AndroidRuntime(char* argBlockStart, const size_t argBlockLength) :
mExitWithoutCleanup(false),
mArgBlockStart(argBlockStart),
mArgBlockLength(argBlockLength)
{
SkGraphics::Init();
// mOptions的类型是:Vector
mOptions.setCapacity(20);
assert(gCurRuntime == NULL); // one per process
gCurRuntime = this;
}
1.2 AndroidRuntime::start
void AndroidRuntime::start(const char* className, const Vector& options, bool zygote)
{
... //设置ANDROID_ROOT
/* 启动虚拟机 */
//[1.3]
JniInvocation jni_invocation;
//[1.4]
jni_invocation.Init(NULL);
JNIEnv* env;
//[1.5], mJavaVM是AndroidRuntime的static变量,初始化为NULL
if (startVm(&mJavaVM, &env, zygote) != 0) {
return;
}
//[1.6]
onVmCreated(env);
/* 注册android相关的jni方法 */
if (startReg(env) < 0) {
ALOGE("Unable to register all android natives\n");
return;
}
... //调用com.android.internal.os.ZygoteInit或者RuntimeInit的main方法
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");
}
1.3 JniInvocation::JniInvocation
JniInvocation::JniInvocation() :
handle_(NULL),
JNI_GetDefaultJavaVMInitArgs_(NULL),
JNI_CreateJavaVM_(NULL),
JNI_GetCreatedJavaVMs_(NULL) {
LOG_ALWAYS_FATAL_IF(jni_invocation_ != NULL, "JniInvocation instance already initialized");
jni_invocation_ = this;
}
JniInvocation
类的头文件和源文件分别在/libnativehelper/include/nativehelper/JniInvocation.h
,/libnativehelper/JniInvocation.cpp
.
JniInvocation
中有三个重要的变量:
-
JNI_CreateJavaVM_
(创建虚拟机实例) -
JNI_GetCreatedJavaVMs_
(获取创建的虚拟机实例) -
JNI_GetDefaultJavaVMInitArgs_
(获取虚拟机的默认初始化参数)
这三个变量是标准的Java虚拟机的接口,也就是说实现了这个三个接口,就可以实现一个Java虚拟机,具体可参考罗升阳的博客.
JniInvocation
的构造函数中初始化这三个变量为NULL
1.4 JniInvocation::Init
bool JniInvocation::Init(const char* library) {
#ifdef __ANDROID__
char buffer[PROP_VALUE_MAX];
#else
char* buffer = NULL;
#endif
//由于传入的library是NULL,所以最后实际获取到的library是libart.so
library = GetLibrary(library, buffer);
const int kDlopenFlags = RTLD_NOW | RTLD_NODELETE;
handle_ = dlopen(library, kDlopenFlags);
if (handle_ == NULL) {
... //打开libart.so失败,直接返回;如果打开其他library失败,则尝试打开libart.so
}
//寻找并导出JNI_GetDefaultJavaVMInitArgs_
if (!FindSymbol(reinterpret_cast(&JNI_GetDefaultJavaVMInitArgs_),
"JNI_GetDefaultJavaVMInitArgs")) {
return false;
}
//寻找并导出JNI_CreateJavaVM_
if (!FindSymbol(reinterpret_cast(&JNI_CreateJavaVM_),
"JNI_CreateJavaVM")) {
return false;
}
//寻找并导出JNI_GetCreatedJavaVMs_
if (!FindSymbol(reinterpret_cast(&JNI_GetCreatedJavaVMs_),
"JNI_GetCreatedJavaVMs")) {
return false;
}
return true;
}
bool JniInvocation::FindSymbol(void** pointer, const char* symbol) {
*pointer = dlsym(handle_, symbol);
... // handle error
return true;
}
JniInvocation::Init
的主要工作就是通过dlopen
函数打开libart.so
,之后利用dlsym
函数寻找并导出Java虚拟机的三个接口,这样就可以通过这三个接口创建并访问虚拟机
1.5 AndroidRuntime::startVm
int AndroidRuntime::startVm(JavaVM** pJavaVM, JNIEnv** pEnv, bool zygote)
{
... //解析启动参数
initArgs.version = JNI_VERSION_1_4;
initArgs.options = mOptions.editArray();
initArgs.nOptions = mOptions.size();
initArgs.ignoreUnrecognized = JNI_FALSE;
/**
* 创建虚拟机, 每一个进程有一个JavaVM*, 每一个线程有一个JNIEnv*
*/
//[1.5.1]
if (JNI_CreateJavaVM(pJavaVM, pEnv, &initArgs) < 0) {
ALOGE("JNI_CreateJavaVM failed\n");
return -1;
}
return 0;
}
Android::startVm
主要做了两项工作:
- 解析虚拟机启动参数
- 调用
JNI_CreateJavaVM
创建虚拟机.源码的注释中清楚地说明了创建虚拟机后每一个进程都应该具有一个JavaVM指针,而每一个线程都具有一个JNIEnv指针.JNI_CreateJavaVM
实现在/libnativehelper/JniInvocation.cpp
中,其主要逻辑就是返回之前从libart.so
中导出的JNI_CreateJavaVM_
接口,即JNI_CreateJavaVM
的真正实现是由libart.so
完成的
1.5.1 JniInvocation::JNI_CreateJavaVM
extern "C" jint JNI_CreateJavaVM(JavaVM** p_vm, JNIEnv** p_env, void* vm_args) {
return JniInvocation::GetJniInvocation().JNI_CreateJavaVM(p_vm, p_env, vm_args);
}
jint JniInvocation::JNI_CreateJavaVM(JavaVM** p_vm, JNIEnv** p_env, void* vm_args) {
return JNI_CreateJavaVM_(p_vm, p_env, vm_args);
}
JNI_CreateJavaVM_
就是之前在JniInvocation::Init
中导出的函数指针
1.6 AppRuntime::onVmCreated
AndroidRuntime::onVmCreated
是一个虚方法,AndroidRuntime类并没有实现这个方法,具体实现是由子类AppRuntime
实现
virtual void onVmCreated(JNIEnv* env){
if (mClassName.isEmpty()) {
return; // Zygote. Nothing to do here.
}
char* slashClassName = toSlashClassName(mClassName.string());
mClass = env->FindClass(slashClassName);
if (mClass == NULL) {
ALOGE("ERROR: could not find class '%s'\n", mClassName.string());
}
free(slashClassName);
mClass = reinterpret_cast(env->NewGlobalRef(mClass));
}
从代码中可以看出,如果是Zygote的启动,则onVmCreated
实际什么也没有做
二. libart.so中的JNI_CreateJavaVM
libart.so的代码都位于/art
目录下,而JNI_CreateJavaVM
定义在/art/runtime/java_vm_ext.cc
中:
extern "C" jint JNI_CreateJavaVM(JavaVM** p_vm, JNIEnv** p_env, void* vm_args) {
ScopedTrace trace(__FUNCTION__);
const JavaVMInitArgs* args = static_cast(vm_args);
//检查Jni版本号
if (IsBadJniVersion(args->version)) {
LOG(ERROR) << "Bad JNI version passed to CreateJavaVM: " << args->version;
return JNI_EVERSION;
}
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;
//[2.1] 创建Runtime
if (!Runtime::Create(options, ignore_unrecognized)) {
return JNI_ERR;
}
//初始化native loader, 确保在使用JNI之前所需的环境都已经设置好
android::InitializeNativeLoader();
Runtime* runtime = Runtime::Current();
//[2.2] 启动Runtime
bool started = runtime->Start();
if (!started) {
delete Thread::Current()->GetJniEnv();
delete runtime->GetJavaVM();
LOG(WARNING) << "CreateJavaVM failed";
return JNI_ERR;
}
//获取JNIEnv和JavaVM,返回给上层
*p_env = Thread::Current()->GetJniEnv();
*p_vm = runtime->GetJavaVM();
return JNI_OK;
}
2.1 Runtime::Create
代码位于/art/runtime/runtime.cc
bool Runtime::Create(const RuntimeOptions& raw_options, bool ignore_unrecognized) {
RuntimeArgumentMap runtime_options;
//首先调用ParseOptions,之后再调用另一个重载版本的Create
return ParseOptions(raw_options, ignore_unrecognized, &runtime_options) &&
Create(std::move(runtime_options));
}
bool Runtime::Create(RuntimeArgumentMap&& runtime_options) {
if (Runtime::instance_ != nullptr) {
return false;
}
instance_ = new Runtime;
//调用Runtime::Init(), [2.1.1]
if (!instance_->Init(std::move(runtime_options))) {
// TODO: Currently deleting the instance will abort the runtime on destruction. Now This will
// leak memory, instead. Fix the destructor. b/19100793.
// delete instance_;
instance_ = nullptr;
return false;
}
return true;
}
ParseOptions()
最终会调用ParsedOptions::DoParse
方法(/art/runtime/parsed_options.cc
),主要就是用来解析传入的启动参数,这里暂时先不分析其主要逻辑.从代码中可以看到Create
函数主要操作视调用Runtime::Init
函数
2.1.1 Runtime::Init
bool Runtime::Init(RuntimeArgumentMap&& runtime_options_in) {
RuntimeArgumentMap runtime_options(std::move(runtime_options_in));
ScopedTrace trace(__FUNCTION__);
MemMap::Init();
using Opt = RuntimeArgumentMap;
QuasiAtomic::Startup();
//创建OatFileManager, OatFileManager主要用来加载oat文件
oat_file_manager_ = new OatFileManager;
Thread::SetSensitiveThreadHook(runtime_options.GetOrDefault(Opt::HookIsSensitiveThread));
Monitor::Init(runtime_options.GetOrDefault(Opt::LockProfThreshold));
//从传入的参数中初始化boot_class_path_string_, class_path_string_, patchoat_executable_等变量
//创建monitor_list_, monitor_pool_, thread_list_, intern_table_
//继续获取一些基本变量
...
//查看参数中是否指定了解释执行,如果指定,则告知虚拟机所有代码都是解释执行
if (runtime_options.GetOrDefault(Opt::Interpret)) {
GetInstrumentation()->ForceInterpretOnly();
}
//仍然是从传入的参数中初始化一些基础变量, 并获取CompilerFilter
...
//创建堆Heap
heap_ = new gc::Heap(...);
if (!heap_->HasBootImageSpace() && !allow_dex_file_fallback_) {
LOG(ERROR) << "Dex file fallback disabled, cannot continue without image.";
return false;
}
... //获取dump_gc_performance_on_shutdown_, 配置Jdwp
//创建JIT选项,JIT是7.0中新增的,用来提升代码执行效率
jit_options_.reset(jit::JitOptions::CreateFromRuntimeArguments(runtime_options));
//如果此时是dex2oat程序,dex2oat执行时也会创建一个Runtime用来编译dex文件,此时不需要开启JIT选项
if (IsAotCompiler()) {
jit_options_->SetUseJitCompilation(false);
jit_options_->SetSaveProfilingInfo(false);
}
//创建lamba_box_table, arena_pool_, jit_arena_pool_, 如果是64位架构且当前是dex2oat, 获取low_4gb_arena_pool_
...
//创建线性分配器linear_alloc_,LinearAlloc创建时会用到上面创建的low_4gb_arena_pool_(64位架构且是dex2oat时)或者arena_pool_
linear_alloc_.reset(CreateLinearAlloc());
BlockSignals();
//初始化SIGSEGV信号处理函数为HandleUnexpectedSignal
InitPlatformSignalHandlers();
//arm, arm64, x86, mips, mips64, thumb2, x86_64架构下,
//implicit_null_checks_ = true
//implicit_so_checks_ !(RUNNING_ON_MEMORY_TOOL && kMemoryToolIsValgrind)
....
... //处理no_sig_chain = false时的情况(no_sig_chain在之前根据传入的参数获取)
//创建JavaVMExt
java_vm_ = new JavaVMExt(this, runtime_options);
//创建线程TLS
Thread::Startup();
//attach线程, 创建Thread对象,初始化Thread对象
Thread* self = Thread::Attach("main", false, nullptr, false);
// Set us to runnable so tools using a runtime can allocate and GC by default
self->TransitionFromSuspendedToRunnable();
// 验证heap
GetHeap()->EnableObjectValidation();
//创建ClassLinker
class_linker_ = new ClassLinker(intern_table_);
if (GetHeap()->HasBootImageSpace()) {
...
bool result = class_linker_->InitFromBootImage(&error_msg);
...
if (boot_class_path_string_.empty()) {
// 如果bootclasspath没有显示指定,则从加载的dex文件列表中进行构造,这里的dex文件列表是系统构建时已经创建好的众多预加载的文件
...
}
// 在intern_table_中添加boot image space;将boo image space添加到当前ClassLinker的ClassTable中
...
} else {
....
if (!class_linker_->InitWithoutImage(std::move(boot_class_path), &error_msg)) {
return false;
}
...
}
... //MethodTrace, ProfilerOptions, Trace
//提前分配一个OutOfMemoryError
self->ThrowNewException("Ljava/lang/OutOfMemoryError;",
"OutOfMemoryError thrown while trying to throw OutOfMemoryError; "
"no stack trace available");
pre_allocated_OutOfMemoryError_ = GcRoot(self->GetException());
self->ClearException();
//提前分配一个NoClassDefFoundError
self->ThrowNewException("Ljava/lang/NoClassDefFoundError;",
"Class not found using the boot class loader; no stack trace available");
pre_allocated_NoClassDefFoundError_ = GcRoot(self->GetException());
self->ClearException();
... //从传入的参数中获取native_bridge_file_name
return true;
}
Runtime::Init
方法代码量较大,整个过程中创建或者初始化了很多工具组件如MemMap, QuasiAtomic
等,并且从传入的参数依次获取了一些基础变量如boot_class_path_string_, class_path_string_
等,之后还设置信号处理函数等,不过整体来看Init
方法的主要逻辑很清楚,分别做了以下几件事:
- 创建
OatFileManager
对象,OatFileManager
是在7.0中新增的工具类,Runtime在解析读取oat文件都是通过这个工具类完成 - 创建了
Heap
(整个创建过程比较冗长,复杂) - 根据传入参数配置JIT选项,如果当前是dex2oat则不配置JIT
- 创建
LinearAlloc
- 创建
JavaVMExt
- 创建一个线程,同时attach线程(attach的过程实际就是创建Thread对象并初始化Thread对象的过程)
- 创建
ClassLinker
,如果有BootImageSpace
则调用ClassLinker::InitFromBootImage
完成ClassLinker的初始化;如果没有BootImageSpace
,则调用ClassLinker::InitWithoutImage
来完成初始化 - 提前分配一个
OutOfMemoryError
和NoClassDefFoundError
Heap
的创建过程比较复杂,个人觉得需要单独整理一个篇幅来学习,OatFileManager
和LinearAlloc
的构造函数都很简单, 另外ClassLinker
的初始化过程也较为繁琐,加上ClassLinker
类比较重要,同样需要单独的篇幅来学习
2.1.2 JavaVMExt::JavaVMExt
JavaVMExt
的源文件是/art/runtime/java_vm_ext.cc
,JavaVMExt
继承自JavaVM
:
class JavaVMExt : public JavaVM {
...
};
JavaVM
定义在/libnativehelper/include/nativehelper/jni.h
中
JavaVMExt::JavaVMExt(Runtime* runtime, const RuntimeArgumentMap& runtime_options)
: runtime_(runtime),
check_jni_abort_hook_(nullptr),
check_jni_abort_hook_data_(nullptr),
check_jni_(false), // Initialized properly in the constructor body below.
force_copy_(runtime_options.Exists(RuntimeArgumentMap::JniOptsForceCopy)),
tracing_enabled_(runtime_options.Exists(RuntimeArgumentMap::JniTrace)
|| VLOG_IS_ON(third_party_jni)),
trace_(runtime_options.GetOrDefault(RuntimeArgumentMap::JniTrace)),
globals_lock_("JNI global reference table lock"),
globals_(gGlobalsInitial, gGlobalsMax, kGlobal),
libraries_(new Libraries),
unchecked_functions_(&gJniInvokeInterface),
weak_globals_lock_("JNI weak global reference table lock", kJniWeakGlobalsLock),
weak_globals_(kWeakGlobalsInitial, kWeakGlobalsMax, kWeakGlobal),
allow_accessing_weak_globals_(true),
weak_globals_add_condition_("weak globals add condition", weak_globals_lock_) {
functions = unchecked_functions_;
SetCheckJniEnabled(runtime_options.Exists(RuntimeArgumentMap::CheckJni));
}
可以看到,JavaVMExt
的构造函数存储了Runtme
指针,之后初始化了自身变量
2.1.3 Thread::Startup
void Thread::Startup() {
...
//调用pthread_key_create来创建线程私有数据TLS
CHECK_PTHREAD_CALL(pthread_key_create, (&Thread::pthread_key_self_, Thread::ThreadExitCallback),
"self key");
...
}
2.1.4 Thread::Attach
Thread* Thread::Attach(const char* thread_name, bool as_daemon, jobject thread_group,
bool create_peer) {
Runtime* runtime = Runtime::Current();
...
Thread* self;
{
MutexLock mu(nullptr, *Locks::runtime_shutdown_lock_);
if (runtime->IsShuttingDownLocked()) {
...
return nullptr;
} else {
Runtime::Current()->StartThreadBirth();
//创建Thread对象
self = new Thread(as_daemon);
//初始化Thread对象
bool init_success = self->Init(runtime->GetThreadList(), runtime->GetJavaVM());
Runtime::Current()->EndThreadBirth();
if (!init_success) {
delete self;
return nullptr;
}
}
}
//设置创建String对象的entry point为StringFactory
self->InitStringEntryPoints();
self->SetState(kNative);
... //传入的create_peer为false
{
ScopedObjectAccess soa(self);
Dbg::PostThreadStart(self);
}
return self;
}
2.2 Runtime::Start
bool Runtime::Start() {
..
Thread* self = Thread::Current();
self->TransitionFromRunnableToSuspended(kNative);
started_ = true;
// 创建JIT
if (jit_options_->UseJitCompilation() || jit_options_->GetSaveProfilingInfo()) {
std::string error_msg;
if (!IsZygote()) {
// If we are the zygote then we need to wait until after forking to create the code cache
// due to SELinux restrictions on r/w/x memory regions.
CreateJit();
} else if (jit_options_->UseJitCompilation()) {
if (!jit::Jit::LoadCompilerLibrary(&error_msg)) {
// Try to load compiler pre zygote to reduce PSS. b/27744947
LOG(WARNING) << "Failed to load JIT compiler with error " << error_msg;
}
}
}
...
{
ScopedTrace trace2("InitNativeMethods");
//初始化JniConstants的常量,JniConstants定义在/libnativehelper/include/native/JniConstants.h
//注册runtime中的native method,主要对应于Java层的java.lang,dalvik.system这些包下的类
InitNativeMethods();
}
//创建main_thread_group和system_thread_group
InitThreadGroups(self);
//创建一个java.lang.Thread对象,并将Thread.nativePeer变量设为ART中的Thread对象self
Thread::FinishStartup();
//调用ClassLoader.getSystemClassLoader创建系统ClassLoader
system_class_loader_ = CreateSystemClassLoader(this);
//如果当前处于Zygote模式, 利用unshare,以及mount的SLAVE模式创建外部存储文件系统
if (is_zygote_) {
if (!InitZygote()) {
return false;
}
} else {
if (is_native_bridge_loaded_) {
PreInitializeNativeBridge(".");
}
NativeBridgeAction action = force_native_bridge_
? NativeBridgeAction::kInitialize
: NativeBridgeAction::kUnload;
InitNonZygoteOrPostFork(self->GetJniEnv(),
/* is_system_server */ false,
action,
GetInstructionSetString(kRuntimeISA));
}
//启动java.lang.Daemon中定义的后台线程
StartDaemonThreads();
{
ScopedObjectAccess soa(self);
self->GetJniEnv()->locals.AssertEmpty();
}
finished_starting_ = true;
//如果ProfilerOptions开启且存在profile文件,打开profile文件
if (profiler_options_.IsEnabled() && !profile_output_filename_.empty()) {
int fd = open(profile_output_filename_.c_str(), O_RDWR|O_CREAT|O_EXCL, 0660);
if (fd >= 0) {
close(fd);
} else if (errno != EEXIST) {
LOG(WARNING) << "Failed to access the profile file. Profiler disabled.";
}
}
... //Trace相关
return true;
}
Runtime::Start
主要操作是:
- 如果当前不是Zygote,则创建JIT
- 初始化
libnativehelper.so
中定义的JniConstants
,注册java.lang
,dalvik.system
包下的本地方法 - 创建main_thread_group和system_thread_group
- 创建一个java.lang.Thread对象,并将Thread.nativePeer变量设为ART中的Thread对象self
- 调用ClassLoader.getSystemClassLoader创建系统ClassLoader
- 如果当前处于Zygote模式, 利用unshare,以及mount的SLAVE模式创建外部存储文件系统;如果不是,则初始化native bridge
- 启动java.lang.Daemon中定义的后台线程
- 判断
ProfilerOptions
是否开启,如果开启且profile文件不为空,则打开profile文件(Profile文件是在7.0中跟JIT一起加入的, 主要为了提升运行效率) - 查看
Trace
相关配置,如果不为空,则开启Trace
三.总结
Java虚拟机有三个标准接口,只要实现这三个接口,就可以实现一个自定义的虚拟机,这三个接口分别是:JNI_CreateJavaVM_, JNI_GetCreatedJavaVMs_, JNI_GetDefaultJavaVMInitArgs_
,这三个接口的具体实现都位于libart.so
动态库中,Zygote进程是通过dlopen
打开libart.so
,之后通过dlsym
分别导出这三个接口,并调用JNI_CreateJavaVM_
创建虚拟机Runtime实例,并将Runtime实例保存在JavaVM
结构,JavaVM
代表的就是虚拟机执行环境(在libart.so
中实际返回的是其子类JavaVMExt
).
需要留意的是,源码的注释中写的很清楚,每一个进程都必须有一个
JavaVM
,而每一个线程都有一个JNIEnv
JNI_CreateJavaVM_
创建虚拟机Runtime的过程可以总结为:
- 解析传入的参数,将参数以
key-value
的形式组合在一起 - 调用
Runtime::Create
创建Runtime实例,创建的过程中还会依次创建OatFileManager, Heap, LinearAlloc, JavaVMExt, Thread, ClassLinker
,同时初始化线程和ClassLinker - 调用
Runtime::Start
完成最后的初始化工作