目录
1.2.6 Thread::Init
前言
Dalvik虚拟机和ART虚拟机
- Dalvik虚拟机,基于apache的JVM 改进而来,为Android 第一代虚拟机。在Android 4.4之前使用。
- ART 虚拟机,也叫ART 模式,是第二代虚拟机,Android 4.4推出,并从5.0开始默认使用执行程序。
两者区别:
- Dalvik每次都要将apk代码编译成机器码再运行,Art只会首次启动编译,而不必每次运行都要先编译一次。
- Art占用空间比Dalvik大,首次安装Apk的时间比Dalvk模式长
- Art减少编译,减少了CPU使用频率,使用明显改善电池续航;
- 应用启动更快、运行更快、体验更流畅、触感反馈更及时
重点说下art虚拟机:
当然无论是 Dalvik 还是 Art,或者未来可能出现的新型虚拟机,它们提供的功能将全部封装在一个 so 库中,并且对外需要暴露 JNI_GetDefaultVMInitArgs、JNI_CreateVM 和 JNI_GetCreatedJavaVMs 三个标准接口,使用者(比如 Zygote)只需要按照统一的接口标准就可以控制和使用所有同类型的虚拟机了。
组成 Android 虚拟机的核心自系统包括但不限于 Runtime、ClassLoader System、Execution、Engine System、Heap Manager 和 GC 系统、JIT、JNI 环境等。
和标准的 JVM 一样,类加载器在 Android 虚拟机中也扮演者很重要的作用,可以分为 Boot ClassLoader、System ClassLoader、Dex ClassLoader 等,所有被加载的类和它们的组成元素都将由 ClassLinker 做统一的管理。
除了字节码解释执行的方式,Art 还支持通过 AOT 来直接执行字节码编译而成的机器码。
AOT 的编译时机有两个:
- 随 Android ROM 构建时一起编译。
- 程序安装时执行编译(针对第三方应用程序)。
Art 引入了新的存储格式,即 OAT 文件来存储编译后的机器代码。而 OAT 机器码的加载需要用到 ELF 的基础能力。
另外,由于一股脑地在程序安装阶段将 Dex 转化为 OAT 造成造成了一定的资源浪费,从 Android N 版本开始,Art 又改变了之前的 OAT 策略——程序在安装时不再统一执行 dex2oat,而改由根据程序的实际运行情况来决定有哪些部分需要被编译成本地代码,即恢复了 Interpreter、JIT、OAT 三足鼎立的局面。一方面,这种新变化大幅加快了程序的安装速度,解决了系统更新时用户需要经历漫长等待的问题;另一方面,由于程序的首次启动必须通过解释器来运行,Android N 版本必须采用多种手段(新的解释器,将 Verification 前移等)来保证程序的启动速度不受影响。
应用程序除了解释执行外,还会在运行过程中实时做 JIT 编译——不过它的结果并不会被持久化。另外,虚拟机会记录下应用程序在动态运行过程中被执行过的函数,并输出到 Profile 文件里。
AOT compile daemon 将在系统同时满足 idle 和充电状态两个条件时才会被唤醒,并按照一定的逻辑来遍历执行应用程序的 AOT 优化。由于参与 AOT 的函数数量通常只占应用程序代码的一小部分,所以整体而言 Android N 版本 AOT 结果所占用的空间大小比旧版本要小很多。
本文涉及源码
platform/frameworks/base/cmds/app_process/app_main.cpp
platform/frameworks/base/core/jni/AndroidRuntime.cpp
platform/libnativehelper/JniInvocation.cpp
一、创建虚拟机
platform/frameworks/base/core/jni/AndroidRuntime.cpp
// app_main.cpp
main(){
AppRuntime runtime;
runtime.start("com.android.internal.os.ZygoteInit", args, zygote);
}
// class AppRuntime : public AndroidRuntime // AppRuntime继承AndroidRuntime
// AndroidRuntime.cpp
void AndroidRuntime::start(const char* className, const Vector& options, bool zygote){
//第一步:开始虚拟机
if (startVm(&mJavaVM, &env, zygote) != 0) {
return;
}
//第二步:注册系统jni
if (startReg(env) < 0) {
ALOGE("Unable to register all android natives\n");
return;
}
//第三步:进入zygoteinit.java main方法 startClass = com.android.internal.os.ZygoteInit
jmethodID startMeth = env->GetStaticMethodID(startClass, "main",
"([L;
}
//先重点分析第一步
void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote)
{
... //打印一些日志,获取ANDROID_ROOT环境变量
/* start the virtual machine */
JniInvocation jni_invocation;
jni_invocation.Init(NULL);//初始化JNI,加载libart.so
JNIEnv* env;
if (startVm(&mJavaVM, &env, zygote) != 0) {//创建虚拟机
return;
}
onVmCreated(env);//表示虚拟创建完成,但是里面是空实现
/*
* Register android functions.
*/
if (startReg(env) < 0) {注册JNI函数
ALOGE("Unable to register all android natives\n");
return;
}
... //JNI方式调用ZygoteInit类的main函数
}
1.1 JniInvocation.Init
定义在platform/libnativehelper/JniInvocation.cpp
bool JniInvocation::Init(const char* library) {
#ifdef __ANDROID__ //走这个分支
char buffer[PROP_VALUE_MAX];
#else
char* buffer = NULL;
#endif
library = GetLibrary(library, buffer);//默认返回 libart.so
const int kDlopenFlags = RTLD_NOW | RTLD_NODELETE;
/*
* 1.dlopen功能是以指定模式打开指定的动态链接库文件(elf文件),并返回一个句柄,dlopen的内容比较多,后续会单独讲elf的加载过程
* 2.RTLD_NOW表示需要在dlopen返回前,解析出所有未定义符号,如果解析不出来,在dlopen会返回NULL
* 3.RTLD_NODELETE表示在dlclose()期间不卸载库,并且在以后使用dlopen()重新加载库时不初始化库中的静态变量
*/
handle_ = dlopen(library, kDlopenFlags); // 获取libart.so的句柄
if (handle_ == NULL) { //获取失败打印错误日志并尝试再次打开libart.so
....异常重试处理
}
/*
* 1.FindSymbol函数内部实际调用的是dlsym
* 2.dlsym作用是根据 动态链接库 操作句柄(handle)与符号(symbol),返回符号对应的地址
* 3.这里实际就是从libart.so中将JNI_GetDefaultJavaVMInitArgs等对应的地址存入&JNI_GetDefaultJavaVMInitArgs_中
*/
if (!FindSymbol(reinterpret_cast<void**>(&JNI_GetDefaultJavaVMInitArgs_),
"JNI_GetDefaultJavaVMInitArgs")) {
return false;
}
if (!FindSymbol(reinterpret_cast<void**>(&JNI_CreateJavaVM_),
"JNI_CreateJavaVM")) {
return false;
}
if (!FindSymbol(reinterpret_cast<void**>(&JNI_GetCreatedJavaVMs_),
"JNI_GetCreatedJavaVMs")) {
return false;
}
return true;
}
Init函数主要作用是初始化JNI,具体工作是首先通过dlopen加载libart.so获得其句柄,然后调用dlsym从libart.so中找到
JNI_GetDefaultJavaVMInitArgs、JNI_CreateJavaVM、JNI_GetCreatedJavaVMs三个函数地址,赋值给对应成员属性,
这三个函数会在后续虚拟机创建中调用.
1.2 startVm
定义在platform/frameworks/base/core/jni/AndroidRuntime.cpp
//pJavaVM & pEnv都是双重指针, 用于函数内部返回的;
int AndroidRuntime::startVm(JavaVM** pJavaVM, JNIEnv** pEnv, bool zygote)
{
JavaVMInitArgs initArgs;
/通过getprop的值设置JVM的堆栈信息
//主要介绍几个相关堆栈信息
//dalvik.vm.heapstartsize每次申请空间的大小,这个值越小,速度越慢,值越大越容易空间不够
//dalvik.vm.heapgrowthlimit 每个应用内存空间的大小
//dalvik.vm.heapsize large模式下每个应用空间内存大小 minifest配置android:largeHeap="true"
//dalvik.vm.heaptargetutilization 应用堆栈使用率一般都是0.75
...
//虚拟机结束的时候,会调用这个函数指针runtime_exit
addOption("exit", (void*) runtime_exit);各//将参数放入mOptions数组中
...
initArgs.version = JNI_VERSION_1_4;
initArgs.options = mOptions.editArray();//将mOptions赋值给initArgs
initArgs.nOptions = mOptions.size();
initArgs.ignoreUnrecognized = JNI_FALSE;
pJavaVM & pEnv都是双重指针, 用于函数内部返回的;
if (JNI_CreateJavaVM(pJavaVM, pEnv, &initArgs) < 0) {//调用libart.so的JNI_CreateJavaVM函数
ALOGE("JNI_CreateJavaVM failed\n");
return -1;
}
return 0;
}
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_
}
这个函数特别长,但是里面做的事情很单一,其实就是从各种系统属性中读取一些参数,然后通过addOption设置到AndroidRuntime的mOptions数组中存起来,
另外就是调用之前从libart.so中找到JNI_CreateJavaVM函数,并将这些参数传入
1.2.1 JNI_CreateJavaVM
//java_vm_ext.cc
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;
//创建Runtime对象
if (!Runtime::Create(options, ignore_unrecognized)) {
return JNI_ERR;
}
....
Runtime* runtime = Runtime::Current();
bool started = runtime->Start(); //Runtime启动
if (!started) { //如果启动失败,则释放当前的JniEnv & JavaVM 对象;
delete Thread::Current()->GetJniEnv();
delete runtime->GetJavaVM();
LOG(WARNING) << "CreateJavaVM failed";
return JNI_ERR;
}
...
//初始化两个jni相关最重要的结构JavaVM和JNIEnv
//函数不需要return, 直接是通过指针变量返回即可;
*p_env = Thread::Current()->GetJniEnv();
*p_vm = runtime->GetJavaVM();
}
1.2.2 Runtime::Create
组成 Android 虚拟机的核心自系统包括但不限于 Runtime、ClassLoader System、Execution、Engine System、Heap Manager 和 GC 系统、JIT、JNI 环境等;
调用了 Runtime::Init 方法,用于初始化虚拟机,包括:创建 Java 虚拟机、创建 Heap 堆管理对象、加载主线程等
art/runtime/runtime.cc
//两个参数,内部主要是解析虚拟机的参数
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)); //调用下面的一个参数的Create函数
}
bool Runtime::Create(RuntimeArgumentMap&& runtime_options) {
//一个进程只有一个Runtime实列,定义在头文件中 static Runtime* instance_; //static 保证全局唯一
if (Runtime::instance_ != nullptr) {
return false;
}
instance_ = new Runtime; //C++ 创建一个Runtime对象
if (!instance_->Init(std::move(runtime_options))) {//调用Runtime的Init方法
// 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;
}
Runtime::Create 成功启动了一个虚拟机后,接下去会通过 Init 函数来初始化;
1.2.3 Runtime::Init
bool Runtime::Init(RuntimeArgumentMap&& runtime_options_in) {
...
heap_ = new gc::Heap(...); // 创建堆管理对象
...
BlockSignals(); //信号相关,后面信号专题再继续展开分析
InitPlatformSignalHandlers();
java_vm_ = JavaVMExt::Create(this, runtime_options, &error_msg); // 创建 Java 虚拟机对象
Thread::Startup();
Thread* self = Thread::Attach("main", false, nullptr, false); // 主线程 attach
if (UNLIKELY(IsAotCompiler())) {
class_linker_ = new AotClassLinker(intern_table_);
} else {
class_linker_ = new ClassLinker(intern_table_); //创建ClassLinker实例负责管理java class。
}
if (GetHeap()->HasBootImageSpace()) { // 当前 Heap 是否包含 Boot Image(比如 boot.art)
bool result = class_linker_->InitFromBootImage(&error_msg);
...
} else {
if (runtime_options.Exists(Opt::BootClassPathDexList)) {
boot_class_path.swap(*runtime_options.GetOrDefault(Opt::BootClassPathDexList));
} else {
OpenDexFiles(dex_filenames,
dex_locations,
runtime_options.GetOrDefault(Opt::Image),
&boot_class_path);
}
instruction_set_ = runtime_options.GetOrDefault(Opt::ImageInstructionSet);
if (!class_linker_->InitWithoutImage(std::move(boot_class_path), &error_msg)) {
LOG(ERROR) << "Could not initialize without image: " << error_msg;
return false;
}
// TODO: Should we move the following to InitWithoutImage?
SetInstructionSet(instruction_set_);
...
}
......
//
self->ThrowNewException("Ljava/lang/OutOfMemoryError;",
"OutOfMemoryError thrown while trying to throw OutOfMemoryError; "
"no stack trace available");
pre_allocated_OutOfMemoryError_ = GcRoot<mirror::Throwable>(self->GetException());
self->ClearException();
// Pre-allocate a NoClassDefFoundError for the common case of failing to find a system class
// ahead of checking the application's class loader.
self->ThrowNewException("Ljava/lang/NoClassDefFoundError;",
"Class not found using the boot class loader; no stack trace available");
pre_allocated_NoClassDefFoundError_ = GcRoot<mirror::Throwable>(self->GetException());
self->ClearException();
return true;
}
1.2.4 JavaVMExt::Create
//创建C++ JavaVMExt对象
//内部持有当前进程全局唯一的Runtime对象;
std::unique_ptr<JavaVMExt> JavaVMExt::Create(Runtime* runtime,
const RuntimeArgumentMap& runtime_options,
std::string* error_msg) NO_THREAD_SAFETY_ANALYSIS {
std::unique_ptr<JavaVMExt> java_vm(new JavaVMExt(runtime, runtime_options, error_msg)); //构造函数
if (java_vm && java_vm->globals_.IsValid() && java_vm->weak_globals_.IsValid()) {
return java_vm;
}
return nullptr;
}
1.2.4 Thread::Startup
主要是创建
art/runtime/Thread.cc
void Thread::Startup() {
CHECK(!is_started_);
is_started_ = true;
......
// Allocate a TLS slot.
CHECK_PTHREAD_CALL(pthread_key_create, (&Thread::pthread_key_self_, Thread::ThreadExitCallback),"self key");
// Double-check the TLS slot allocation.
if (pthread_getspecific(pthread_key_self_) != nullptr) {
LOG(FATAL) << "Newly-created pthread TLS slot is not nullptr";
}
}
1.2.5 Thread::Attach
返回C++ 中的 Thread对象,并且根据第四个参数来确定是否需要找Java Thread来一一对应;
如果是zygote启动的时候,第四个参数为false;
//四个参数 "main", false, nullptr, false
Thread* Thread::Attach(const char* thread_name,bool as_daemon, jobject thread_group, bool create_peer) {
auto create_peer_action = [&](Thread* self) {
// If we're the main thread, ClassLinker won't be created until after we're attached,
// so that thread needs a two-stage attach. Regular threads don't need this hack.
// In the compiler, all threads need this hack, because no-one's going to be getting
// a native peer!
if (create_peer) { //什么情况下进入这个分支, 先跳过, 后续专题分析;
self->CreatePeer(thread_name, as_daemon, thread_group);
if (self->IsExceptionPending()) {
// We cannot keep the exception around, as we're deleting self. Try to be helpful and log it.
{
ScopedObjectAccess soa(self);
LOG(ERROR) << "Exception creating thread peer:";
LOG(ERROR) << self->GetException()->Dump();
self->ClearException();
}
return false;
}
} else {//因为第四个参数是false, 所以走这个分支;
// These aren't necessary, but they improve diagnostics for unit tests & command-line tools.
if (thread_name != nullptr) {
self->tlsPtr_.name->assign(thread_name);
::art::SetThreadName(thread_name); //设置线程名称
} else if (self->GetJniEnv()->check_jni) {
LOG(WARNING) << *Thread::Current() << " attached without supplying a name";
}
}
return true;
};
return Attach(thread_name, as_daemon, create_peer_action); //是一个模版函数
}
//是一个
template <typename PeerAction>
Thread* Thread::Attach(const char* thread_name, bool as_daemon, PeerAction peer_action) {
Runtime* runtime = Runtime::Current();
....
Thread* self;
{
MutexLock mu(nullptr, *Locks::runtime_shutdown_lock_);
if (runtime->IsShuttingDownLocked()) {
LOG(WARNING) << "Thread attaching while runtime is shutting down: " << thread_name;
return nullptr;
} else {
Runtime::Current()->StartThreadBirth();
self = new Thread(as_daemon); //创建C++ Thread对象
bool init_success = self->Init(runtime->GetThreadList(), runtime->GetJavaVM()); //调用Thread.Init函数
Runtime::Current()->EndThreadBirth();
if (!init_success) {
delete self;
return nullptr;
}
}
}
self->InitStringEntryPoints();
CHECK_NE(self->GetState(), kRunnable);
self->SetState(kNative);
// Run the action that is acting on the peer.
if (!peer_action(self)) { //函数指针处理,具体实现是上面的实现在create_peer_action
runtime->GetThreadList()->Unregister(self);
// Unregister deletes self, no need to do this here.
return nullptr;
}
{
ScopedObjectAccess soa(self);
runtime->GetRuntimeCallbacks()->ThreadStart(self);
}
return self;
}
1.2.6 Thread::Init
bool Thread::Init(ThreadList* thread_list, JavaVMExt* java_vm, JNIEnvExt* jni_env_ext) {
.....
SetUpAlternateSignalStack();
if (!InitStackHwm()) {
return false;
}
InitCpu();
InitTlsEntryPoints();
RemoveSuspendTrigger();
InitCardTable();
InitTid();
interpreter::InitInterpreterTls(this);
....
if (jni_env_ext != nullptr) {
DCHECK_EQ(jni_env_ext->vm, java_vm);
DCHECK_EQ(jni_env_ext->self, this);
tlsPtr_.jni_env = jni_env_ext;
} else {
std::string error_msg;
tlsPtr_.jni_env = JNIEnvExt::Create(this, java_vm, &error_msg); //创建当前线程的JNIEnvExt对象
if (tlsPtr_.jni_env == nullptr) {
LOG(ERROR) << "Failed to create JNIEnvExt: " << error_msg;
return false;
}
}
thread_list->Register(this); //将当前的C++ thread对象注册到Thread列表中
return true;
}
1.2.7 JNIEnvExt::Create
关于avaVMExt & JNIEnvExt的介绍,后续专题补充;
//jni_env_ext.cc
//返回JNIEnvExt对象
JNIEnvExt* JNIEnvExt::Create(Thread* self_in, JavaVMExt* vm_in, std::string* error_msg) {
std::unique_ptr<JNIEnvExt> ret(new JNIEnvExt(self_in, vm_in, error_msg));
if (CheckLocalsValid(ret.get())) {
return ret.release();
}
return nullptr;
}
1.2.8 ::art::SetThreadName
在zygote启动流程,给当前的主线程设置为main
//art/runtime/utils.cc
void SetThreadName(const char* thread_name) {
int hasAt = 0;
int hasDot = 0;
const char* s = thread_name;
while (*s) {
if (*s == '.') {
hasDot = 1;
} else if (*s == '@') {
hasAt = 1;
}
s++;
}
int len = s - thread_name;
if (len < 15 || hasAt || !hasDot) {
s = thread_name;
} else {
s = thread_name + len - 15;
}
#if defined(__linux__)
// pthread_setname_np fails rather than truncating long strings.
char buf[16]; // MAX_TASK_COMM_LEN=16 is hard-coded in the kernel.
strncpy(buf, s, sizeof(buf)-1);
buf[sizeof(buf)-1] = '\0';
errno = pthread_setname_np(pthread_self(), buf); //设置当前线程名为main
if (errno != 0) {
PLOG(WARNING) << "Unable to set the name of current thread to '" << buf << "'";
}
#else // __APPLE__
pthread_setname_np(thread_name);
#endif
}
看具体实列
ps | grep zygote
root 293 1 1301948 64212 ffffffff b56404b4 S zygote64
root 294 1 972560 52744 ffffffff f7399338 S zygote
root@xx:/ # cd proc/294/task
root@xxx:/proc/294/task # ls -l
dr-xr-xr-x root root 2023-02-06 10:26 1776
dr-xr-xr-x root root 2023-02-06 10:26 1777
dr-xr-xr-x root root 2023-02-06 10:26 1778
dr-xr-xr-x root root 2023-02-06 10:26 1779
dr-xr-xr-x root root 2023-02-06 10:26 1783
dr-xr-xr-x root root 2023-02-03 11:05 294
root@xx:/proc/294/task # cd 294
-r--r--r-- root root 0 2023-02-06 10:26 cmdline
-rw-r--r-- root root 0 2023-02-06 10:26 comm
root@xx:/proc/294/task/294 # cat comm //修改的是这里的节点值 线程名
main
root@xx:/proc/294/task # cat cmdline
zygote
1.2.9 Runtime::Start
bool Runtime::Start() {
VLOG(startup) << "Runtime::Start entering";
// Restore main thread state to kNative as expected by native code.
Thread* self = Thread::Current(); //返回当前线程中的C++ 对象
started_ = true;
....
// Initialize well known thread group values that may be accessed threads while attaching.
InitThreadGroups(self); //初始化线程组
Thread::FinishStartup(); //和java 中的Thread建立关系,这里面会有C调用Java
StartDaemonThreads(); //创建GC 相关的4个线程,反射Thread.java来启动线程
return true; //AndroidRuntime::startVm 函数终于执行结束,且一切运行正常
}
1.2.10 Thread::FinishStartup
void Thread::FinishStartup() {
Runtime* runtime = Runtime::Current();
CHECK(runtime->IsStarted());
// Finish attaching the main thread.
ScopedObjectAccess soa(Thread::Current());
Thread::Current()->CreatePeer("main", false, runtime->GetMainThreadGroup());
Thread::Current()->AssertNoPendingException();
Runtime::Current()->GetClassLinker()->RunRootClinits();
// The thread counts as started from now on. We need to add it to the ThreadGroup. For regular
// threads, this is done in Thread.start() on the Java side.
{
// This is only ever done once. There's no benefit in caching the method.
jmethodID thread_group_add = soa.Env()->GetMethodID(WellKnownClasses::java_lang_ThreadGroup,
"add",
"(Ljava/lang/Thread;)V");
CHECK(thread_group_add != nullptr);
ScopedLocalRef<jobject> thread_jobject(
soa.Env(), soa.Env()->AddLocalReference<jobject>(Thread::Current()->GetPeer()));
soa.Env()->CallNonvirtualVoidMethod(runtime->GetMainThreadGroup(),
WellKnownClasses::java_lang_ThreadGroup,
thread_group_add,
thread_jobject.get());
Thread::Current()->AssertNoPendingException();
}
}
1.2.11 Thread::CreatePeer
void Thread::CreatePeer(const char* name, bool as_daemon, jobject thread_group) {
Runtime* runtime = Runtime::Current();
JNIEnv* env = tlsPtr_.jni_env;
if (thread_group == nullptr) {
thread_group = runtime->GetMainThreadGroup();
}
jint thread_priority = GetNativePriority();
jboolean thread_is_daemon = as_daemon;
ScopedLocalRef<jobject> peer(env, env->AllocObject(WellKnownClasses::java_lang_Thread));
{
ScopedObjectAccess soa(this);
tlsPtr_.opeer = soa.Decode<mirror::Object>(peer.get()).Ptr();
}
//C 调用Java,并且java中的线程名获取也是main
env->CallNonvirtualVoidMethod(peer.get(),
WellKnownClasses::java_lang_Thread,
WellKnownClasses::java_lang_Thread_init,
thread_group, thread_name.get(), thread_priority, thread_is_daemon);
//Java中的nativePeer指向C++ 中的Thread地址
env->SetLongField(peer.get(), WellKnownClasses::java_lang_Thread_nativePeer,
reinterpret_cast<jlong>(self));
}
到这里 AndroidRuntime::startVm函数终于结束,并且返回true,继续往下执行;
二、小结
第一阶段主要工作是从libart.so提取出JNI初始函数JNI_CreateJavaVM等,然后读取一些系统属性作为参数调用JNI_CreateJavaVM创建虚拟机,包括C++ 中的Runtime, Thread对象, 返回了两个JNI 非常重要的结构 C++ JavaVMExt对象(进程唯一) & JNIEnvExt对象(线程唯一)
JNI 注册下一篇文章再继续分析;