目录

前言

一、创建虚拟机

1.1 JniInvocation.Init

1.2 startVm

1.2.1 JNI_CreateJavaVM

1.2.2 Runtime::Create

1.2.3 Runtime::Init

1.2.4 JavaVMExt::Create

1.2.4 Thread::Startup

1.2.5 Thread::Attach

1.2.6 Thread::Init​​​​​​​

1.2.7 JNIEnvExt::Create

1.2.8 ::art::SetThreadName

1.2.9 Runtime::Start

1.2.10 Thread::FinishStartup

1.2.11 Thread::CreatePeer

二、小结


前言

Dalvik虚拟机和ART虚拟机

  • Dalvik虚拟机,基于apache的JVM 改进而来,为Android 第一代虚拟机。在Android 4.4之前使用。
  • ART 虚拟机,也叫ART 模式,是第二代虚拟机,Android 4.4推出,并从5.0开始默认使用执行程序。

两者区别:

  1. Dalvik每次都要将apk代码编译成机器码再运行,Art只会首次启动编译,而不必每次运行都要先编译一次。
  2. Art占用空间比Dalvik大,首次安装Apk的时间比Dalvk模式长
  3. Art减少编译,减少了CPU使用频率,使用明显改善电池续航;
  4. 应用启动更快、运行更快、体验更流畅、触感反馈更及时

重点说下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;}//第二步:注册系统jniif (startReg(env) < 0) {ALOGE("Unable to register all android natives\n");return;}//第三步:进入zygoteinit.java main方法 startClass = com.android.internal.os.ZygoteInitjmethodID 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.soJNIEnv* 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];
#elsechar* buffer = NULL;
#endiflibrary = GetLibrary(library, buffer);//默认返回 libart.soconst 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_exitaddOption("exit", (void*) runtime_exit);各//将参数放入mOptions数组中...initArgs.version = JNI_VERSION_1_4;initArgs.options = mOptions.editArray();//将mOptions赋值给initArgsinitArgs.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); // 主线程 attachif (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.ccvoid 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_actionruntime->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);  //设置当前线程名为mainif (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 294root@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 commroot@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调用JavaStartDaemonThreads(); //创建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中的线程名获取也是mainenv->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 注册下一篇文章再继续分析;

AOSP 8.0 系统启动之四ART虚拟机启动(一)相关推荐

  1. AOSP 8.0 系统启动之三--Zygote启动(二)

    目录 前言 一.Art虚拟机启动 二.首次进入Java世界 2.1 禁用子线程创建 2.2 创建zygote socket并监听 2.3 加载系统资源 2.4 GC初始化并启动 2. 5启动Syste ...

  2. Android10.0系统启动之Launcher(桌面)启动流程-[Android取经之路]

    摘要:上一节我们讲完了Android10.0的ActivityManagerService的启动流程,在AMS的最后启动了Launcher进程,今天我们就来看看Launcher的真正启动流程. 阅读本 ...

  3. android art虚拟机安装,Android中art虚拟机启动流程

    本文基于Android8.1系统进行研究 一.启动zygote 在Linux内核启动完成后,首先启动系统的第一个进程init进程 init进程会读取init.rc中的配置文件 其中有Zygote的配置 ...

  4. android 开发art,Android应用开发之Android 系统启动原理(art 虚拟机)

    本文将带你了解Android应用开发之Android 系统启动原理(art 虚拟机),希望本文对大家学Android有所帮助. Android   系统启动原理(art 虚拟机) 一.虚拟机的启动 A ...

  5. Android 10.0 系统启动之SystemServer进程-[Android取经之路]

    摘要:上一节讲解了Zygote进程的整个启动流程.Zygote是所有应用的鼻祖.SystemServer和其他所有Dalivik虚拟机进程都是由Zygote fork而来.Zygote fork的第一 ...

  6. Android 10.0系统启动之init进程-[Android取经之路]

    摘要:init进程是linux系统中用户空间的第一个进程,进程号为1.当bootloader启动后,启动kernel,kernel启动完后,在用户空间启动init进程,再通过init进程,来读取ini ...

  7. JAVA虚拟机、Dalvik虚拟机和ART虚拟机

    从Android5.0开始废弃了Dalvik,全面推行ART. Dalvik与ART的区别 (1)在Dalvik下,应用每次运行都需要通过即时编译器(JIT)将字节码转换为机器码,即每次都要编译加运行 ...

  8. 面试:Art虚拟机和Davlik虚拟机简要对比

    Android 4.4以后推出了ART虚拟机,它与Davlik虚拟机最大的不同在于,系统在安装应用时会对其进行预编译一次,将字节码转换成机器指令,以后每次启动不会重新编译,直接运行本地机器码. 直接上 ...

  9. Android10.0系统启动之Zygote进程-[Android取经之路]

    [Android取经之路] 的源码都基于Android-Q(10.0) 进行分析 [Android取经之路] 系列文章: <系统启动篇> Android系统架构 Android是怎么启动的 ...

最新文章

  1. 系统时间、时区、字符集
  2. mvc3 之三 符号列表
  3. Python读取保存在hdf5文件中的脑电数据
  4. linux下Oracle 10g安装(超级详细图解教程)
  5. 数据结构基础概念、逻辑结构、物理结构
  6. OpenCV之滑动条的创建和使用
  7. C语言求字符串并集,怎样用c语言写求集合的交集,并集,补集”这个程序?
  8. 迁移Gitolite仓库到GitLab(一)
  9. Kaggle Tabular Playground Series - Jan 2022 学习笔记2(使用时间序列的线性回归)
  10. matlab划分训练集验证和测试集代码_数据集划分为训练集和测试集并生成标签--matlab代码...
  11. 中国最爱喝奶茶的城市找到了
  12. PMBOK 项目管理 九大知识领域和五大流程
  13. java and运算_JAVA中逻辑运算符“|”和“”与“||”和“”的用法
  14. [统计]_怎样用数据炒菜:统计建模的两种文化
  15. 职场人如何提高情商?推荐你看这本书
  16. AVL树的操作及调整成AVL树
  17. C语言:动态内存分配
  18. 80x86 汇编语言编程:判定数据序列的奇偶个数
  19. 计算机网络封装和解封的概念,以太网数据封装与解封过程
  20. Boost 入门02(字符串操作)

热门文章

  1. android4以下的音乐播放器,动静(音乐播放器)
  2. OSChina 周日乱弹 —— 给我两个公主我也抱的起来
  3. 公司申请高新认定需要有多少个软件著作权证书?
  4. linux|使用Telnet进行与板子通讯
  5. 手机User-Agent
  6. 用户管理和文件权限部分练习题
  7. 请不要问LCD和LED屏哪个好了,因为这完全不是同一个概念!
  8. 详解卷积神经网络的卷积过程--简单明了
  9. 汇编学习之nasm编译器下载使用
  10. 【IoT】产品设计:硬件产品外观样品设计工艺及要求(手板)