原文地址:http://blog.csdn.net/jinzhuojun/article/details/20613075
Android KK里引入了ART虚拟机作为Dalvik虚拟机的替代,其主要目的是把Bytecode的翻译优化从运行时提前到安装时,以空间换时间,从而达到更流畅的用户体验。目前,KK中Dalvik仍是默认的虚拟机,但用户可以在Developer Option中切换到ART虚拟机。坊间传闻在下一版可能会转正。Dalvik和ART的实现分别位于libdvm.so和libart.so这两个库。两个可以同时build也可以只build一个,通过Makefile中的变量PRODUCT_RUNTIMES来控制(https://source.android.com/devices/tech/dalvik/art.html)。ART本质和Dalvik是一样的,是将Java的Bytecode翻译成Native code。它的主要的实现代码在AOSP的art目录下,另外在libcore/libart/下还有一部分Java层的实现。本文以Zygote中初始化的部分为例简要分析下ART的大体工作流程。
故事从init.rc开始,在init.rc中由这一行表示启动zygote:
service zygote /system/bin/app_process -Xzygote /system/bin --zygote--start-system-server
init进程根据它执行app_process(frameworks/base/cmds/app_process/app_main.cpp),也就是Zygote了。Zygote会初始化AndroidRuntime并调用AndroidRuntime::start()函数:
223 runtime.start("com.android.internal.os.ZygoteInit",224 startSystemServer ? "start-system-server" : "");
AndroidRuntime::start()函数中,首先会启动Java虚拟机:
834 /* start the virtual machine */835 JniInvocation jni_invocation;836 jni_invocation.Init(NULL);837 JNIEnv* env;838 if (startVm(&mJavaVM, &env) != 0) {839 return;840 }
这里JniInvocation会初始化三个重要的Java虚拟机接口函数(声明在/libnativehelper/include/nativehelper/jni.h):
1097/*1098 * VM initialization functions.1099 *1100 * Note these are the only symbols exported for JNI by the VM.1101 */1102jint JNI_GetDefaultJavaVMInitArgs(void*);1103jint JNI_CreateJavaVM(JavaVM**, JNIEnv**, void*);1104jint JNI_GetCreatedJavaVMs(JavaVM**, jsize, jsize*);
JniInvocation的Init()函数中,会根据系统属性persist.sys.dalvik.vm.lib用dlopen()加载libdvm.so或libart.so。这两个so中都export出了JNI_GetDefaultJavaVMInitArgs,JNI_CreateJavaVM和JNI_GetCreatedJavaVMs这三个接口函数。
51#ifdef HAVE_ANDROID_OS52static const char* kLibrarySystemProperty = "persist.sys.dalvik.vm.lib";53#endif
那这几个函数是如何export出来的呢?以JNI_CreateJavaVM为例,JniInvocation::Init()中先在库中找到这个symbol,结果放于JNI_CreateJavaVM_这个成员变量里:
92 if (!FindSymbol(reinterpret_cast<void**>(&JNI_CreateJavaVM_),93 "JNI_CreateJavaVM")) {94 return false;95 }
这个变量里的函数指针又是通过另一个成员函数来调用的:
107jint JniInvocation::JNI_CreateJavaVM(JavaVM** p_vm, JNIEnv** p_env, void* vm_args) {108 return JNI_CreateJavaVM_(p_vm, p_env, vm_args);109}
但这个成员函数是私有的,外界不可访问。但注意下面的同名函数被设为JniInvocation类的友元函数,这意味着该函数可以访问JniInvocation中的private成员。
136extern "C" jint JNI_CreateJavaVM(JavaVM** p_vm, JNIEnv** p_env, void* vm_args) {137 return JniInvocation::GetJniInvocation().JNI_CreateJavaVM(p_vm, p_env, vm_args);138}
这样,JNI_CreateJavaVM就被export出去了。其它两个接口函数也是类似的。
接下来,AndroidRuntime::startVm()启动Java虚拟机。该函数先是处理一堆参数,如执行模式,checkjni等等。大多数参数都是从system property里读入,最后存放到mOptions这个结构体里。这个函数先是初始化一坨虚拟机启动参数,最后调用JNI_CreateJavaVM()来创建Java虚拟机。JNI_CreateJavaVM()的实现位于/art/runtime/jni_internal.cc。其主要任务是Runtime的初始化和两个关键数据结构-JavaVM和JNIEnv的初始化。前者代表Java虚拟机,每个进程一个;后者代表JNI的调用环境,每个线程一个。官方解释:http://developer.android.com/training/articles/perf-jni.html
2897 if (!Runtime::Create(options, ignore_unrecognized)) {2898 return JNI_ERR;2899 }2900 Runtime* runtime = Runtime::Current();2901 bool started = runtime->Start();2902 if (!started) {2903 delete Thread::Current()->GetJniEnv();2904 delete runtime->GetJavaVM();2905 LOG(WARNING) << "CreateJavaVM failed";2906 return JNI_ERR;2907 }2908 *p_env = Thread::Current()->GetJniEnv();2909 *p_vm = runtime->GetJavaVM();
在JavaVM和JNIEnv这两个核心数据结构中,最重要的是两张函数表:
2979const JNIInvokeInterface gJniInvokeInterface = {
在JavaVMExt的构造函数中赋值:
3008 functions = unchecked_functions = &gJniInvokeInterface;
而
2599const JNINativeInterface gJniNativeInterface = {
在JNIEnvExt构造函数中赋值:
2843 functions = unchecked_functions = &gJniNativeInterface;
这几个类的大体结构如下:
在JNI_CreateJavaVM()中,先是调用Create()函数来创建Runtime。Runtime是个单例,创建出来后紧接着调用Init()函数(/art/runtime/runtime.cc)。Init()函数会做很多初始化工作:解析参数,初始化Heap和JavaVMExt结构,线程和信号处理,创建ClassLinker等。
829bool Runtime::Init(const Options& raw_options, bool ignore_unrecognized) {…832 UniquePtr<ParsedOptions> options(ParsedOptions::Create(raw_options, ignore_unrecognized));…841 Monitor::Init(options->lock_profiling_threshold_, options->hook_is_sensitive_thread_);…868 monitor_list_ = new MonitorList;869 thread_list_ = new ThreadList;870 intern_table_ = new InternTable;…877 heap_ = new gc::Heap(…)892 BlockSignals();…895 java_vm_ = new JavaVMExt(this, options.get());896897 Thread::Startup();902 Thread* self = Thread::Attach("main", false, NULL, false);…913 if (GetHeap()->GetContinuousSpaces()[0]->IsImageSpace()) {914 class_linker_ = ClassLinker::CreateFromImage(intern_table_);915 } else {916 CHECK(options->boot_class_path_ != NULL);917 CHECK_NE(options->boot_class_path_->size(), 0U);918 class_linker_ = ClassLinker::CreateFromCompiler(*options->boot_class_path_, intern_table_);919 }
首先,Runtime::ParsedOptions::Create()中会解析参数,把raw_options中的参数放入parsed,如对环境变量BOOTCLASSPATH和CLASSPATH的处理:
324 const char* boot_class_path_string = getenv("BOOTCLASSPATH");325 if (boot_class_path_string != NULL) {326 parsed->boot_class_path_string_ = boot_class_path_string;327 }328 const char* class_path_string = getenv("CLASSPATH");329 if (class_path_string != NULL) {330 parsed->class_path_string_ = class_path_string;331 }
然后初始化Monitor(相当于mutex+conditional variable,可用于多个线程同步)和线程链表等。接着是比较重要的Heap及GC的初始化,
gc::Heap的实现在/art/runtime/gc/heap.cc中:
69Heap::Heap(…)…144 live_bitmap_.reset(new accounting::HeapBitmap(this));145 mark_bitmap_.reset(new accounting::HeapBitmap(this));…151 space::ImageSpace* image_space = space::ImageSpace::Create(image_file_name);…165 alloc_space_ = space::DlMallocSpace::Create(…)…178 large_object_space_ = space::LargeObjectMapSpace::Create("large object space");…190 // Allocate the card table.191 card_table_.reset(accounting::CardTable::Create(heap_begin, heap_capacity));…194 image_mod_union_table_.reset(new accounting::ModUnionTableToZygoteAllocspace(this));195 CHECK(image_mod_union_table_.get() != NULL) << "Failed to create image mod-union table";196197 zygote_mod_union_table_.reset(new accounting::ModUnionTableCardCache(this));198 CHECK(zygote_mod_union_table_.get() != NULL) << "Failed to create Zygote mod-union table";…
其中的ImageSpace::Create()会检测image文件,如果没有就调用GenerateImage()来创建。因此log中相应会有:
I/art ( 161): GenerateImage: [email protected]@boot.art --runtime-arg -Xms64m--runtime-arg -Xmx64m --dex-file=/system/framework/core-libart.jar ... [email protected]@boot.oat --base=0x60000000--image-classes-zip=/system/framework/framework...
可以看到它其实是调用了dex2oat,该命令把BOOTCLASSPATH里的包打成image文件,它最后会生成两个文件boot.art和boot.oat,前者是image文件,后者是elf文件。这个image会被放到创建的Heap中。接下来Heap()为一些数据结构分配空间,创建各种互斥量及初始化GC:
203 // Default mark stack size in bytes.204 static const size_t default_mark_stack_size = 64 * KB;205 mark_stack_.reset(accounting::ObjectStack::Create("mark stack", default_mark_stack_size));206 allocation_stack_.reset(accounting::ObjectStack::Create("allocation stack",207 max_allocation_stack_size_));208 live_stack_.reset(accounting::ObjectStack::Create("live stack",209 max_allocation_stack_size_));…214 gc_complete_lock_ = new Mutex("GC complete lock");215 gc_complete_cond_.reset(new ConditionVariable("GC complete condition variable",216 *gc_complete_lock_));217218 // Create the reference queue locks, this is required so for parallel object scanning in the GC.219 soft_ref_queue_lock_ = new Mutex("Soft reference queue lock");220 weak_ref_queue_lock_ = new Mutex("Weak reference queue lock");221 finalizer_ref_queue_lock_ = new Mutex("Finalizer reference queue lock");222 phantom_ref_queue_lock_ = new Mutex("Phantom reference queue lock");…232 // Create our garbage collectors.233 for (size_t i = 0; i < 2; ++i) {234 const bool concurrent = i != 0;235 mark_sweep_collectors_.push_back(new collector::MarkSweep(this, concurrent));236 mark_sweep_collectors_.push_back(new collector::PartialMarkSweep(this, concurrent));237 mark_sweep_collectors_.push_back(new collector::StickyMarkSweep(this, concurrent));238 }
MarkSweep,PartialMarkSweep和StickyMarkSweep都是art::gc::collector::GarbageCollector的继承类。它和几个子类应用了Template Method模式。GarbageCollector::Run()中实现了主要算法,其中调用了InitializePhase(),MarkingPhase(),ReclaimPhase()和FinishPhase()等几个虚函数,这几个虚函数在MarkSweep等几个子类中有具体实现。
回到Runtime::Init(),下面是ClassLinker的初始化。它主要调用CreateFromImage()函数来实现:
181ClassLinker* ClassLinker::CreateFromImage(InternTable* intern_table) {182 UniquePtr<ClassLinker> class_linker(new ClassLinker(intern_table));183 class_linker->InitFromImage();184 return class_linker.release();185}
InitFromImage()函数中,会从Heap中得到image的空间,然后得到dex caches数组,接着把这些dex caches对应的dex file信息注册到BootClassPath中去。
1017 gc::space::ImageSpace* space = heap->GetImageSpace();…1026 mirror::Object* dex_caches_object = space->GetImageHeader().GetImageRoot(ImageHeader::kDexCaches);1027 mirror::ObjectArray<mirror::DexCache>* dex_caches =1028 dex_caches_object->AsObjectArray<mirror::DexCache>();…1041 for (int32_t i = 0; i < dex_caches->GetLength(); i++) {1042 SirtRef<mirror::DexCache> dex_cache(self, dex_caches->Get(i));1043 const std::string& dex_file_location(dex_cache->GetLocation()->ToModifiedUtf8());1044 const OatFile::OatDexFile* oat_dex_file = oat_file.GetOatDexFile(dex_file_location, NULL);1045 CHECK(oat_dex_file != NULL) << oat_file.GetLocation() << " " << dex_file_location;1046 const DexFile* dex_file = oat_dex_file->OpenDexFile();1047 if (dex_file == NULL) {1048 LOG(FATAL) << "Failed to open dex file " << dex_file_location1049 << " from within oat file " << oat_file.GetLocation();1050 }10511052 CHECK_EQ(dex_file->GetLocationChecksum(), oat_dex_file->GetDexFileLocationChecksum());10531054 AppendToBootClassPath(*dex_file, dex_cache);1055 }
AppendToBootClassPath()函数将dex cache和dex file关联起来,同时把dex file注册到boot_class_path_,dex cache注册到dex_caches_。
1917void ClassLinker::AppendToBootClassPath(const DexFile& dex_file, SirtRef<mirror::DexCache>& dex_cache) {1918 CHECK(dex_cache.get() != NULL) << dex_file.GetLocation();1919 boot_class_path_.push_back(&dex_file);1920 RegisterDexFile(dex_file, dex_cache);1921}1938void ClassLinker::RegisterDexFileLocked(const DexFile& dex_file, SirtRef<mirror::DexCache>& dex_cache) {1939 dex_lock_.AssertExclusiveHeld(Thread::Current());1940 CHECK(dex_cache.get() != NULL) << dex_file.GetLocation();1941 CHECK(dex_cache->GetLocation()->Equals(dex_file.GetLocation()))1942 << dex_cache->GetLocation()->ToModifiedUtf8() << " " << dex_file.GetLocation();1943 dex_caches_.push_back(dex_cache.get());1944 dex_cache->SetDexFile(&dex_file);1945 dex_caches_dirty_ = true;1946}
这些个注册信息以后在ClassLinker调用FindClass()时会用到。Runtime的Create()和Init()函数完成后,在JNI_CreateJavaVM函数中Runtime的Start()函数被调用:
708bool Runtime::Start() {709 VLOG(startup) << "Runtime::Start entering";710711 CHECK(host_prefix_.empty()) << host_prefix_;712713 // Restore main thread state to kNative as expected by native code.714 Thread* self = Thread::Current();715 self->TransitionFromRunnableToSuspended(kNative);716717 started_ = true;718719 // InitNativeMethods needs to be after started_ so that the classes720 // it touches will have methods linked to the oat file if necessary.721 InitNativeMethods();722723 // Initialize well known thread group values that may be accessed threads while attaching.724 InitThreadGroups(self);725726 Thread::FinishStartup();727728 if (is_zygote_) {729 if (!InitZygote()) {730 return false;731 }732 } else {733 DidForkFromZygote();734 }735736 StartDaemonThreads();737738 system_class_loader_ = CreateSystemClassLoader();739740 self->GetJniEnv()->locals.AssertEmpty();741742 VLOG(startup) << "Runtime::Start exiting";743744 finished_starting_ = true;745746 return true;747}
在InitNativeMethods()函数中,JniConstants::init()和WellKnownClasses::Init()通过FindClass(),GetStaticFieldID()和GetStaticMethodID()函数分别初始化了一大坨系统基本类,方法和域。这一拨都是最基本的类,没初始化的话后面没法玩了。然后RegisterRuntimeNativeMethods()函数注册了一拨系统类中的Native函数:
1005void Runtime::RegisterRuntimeNativeMethods(JNIEnv* env) {1006#define REGISTER(FN) extern void FN(JNIEnv*); FN(env)1007 // Register Throwable first so that registration of other native methods can throw exceptions1008 REGISTER(register_java_lang_Throwable);…
接着InitNativeMethods()会load libjavacore.so这个库,单独load它是因为它本身包含了System.loadLibrary()实现,不先load它会导致鸡与蛋的问题:
965 if (!instance_->java_vm_->LoadNativeLibrary(mapped_name, NULL, reason)) {
回到Runtime::Start(),进行线程初始化,再判断是否为Zygote进程,如果是的话要调用InitZygote()进行初始化(其中主要是mount一些文件系统),否则调用DidForkFromZygote()(其中会创建线程池,创建signalcatcher线程和启动JDWP
调试线程)。再就是启动后台线程,然后用JNI调用java.lang.ClassLoader.getSystemClassLoader()得到系统的ClassLoader(由createSystemClassLoader()创建),一会调用com.android.internal.os.ZygoteInit.main()时用的就是它。
736 StartDaemonThreads();737738 system_class_loader_ = CreateSystemClassLoader();
从StartVM()返回后,AndroidRuntime执行startReg()来做了一件比较tricky的事情。它会在创建线程时加一个hook函数,这样每个Thread起来时会先去执行AndroidRuntime::javaThreadShell(),而该函数会初始化Java虚拟机环境,这样新建的线程就可以调用Java层了。
AndroidRuntime::startReg()1228 /*1229 * This hook causes all future threads created in this process to be1230 * attached to the JavaVM. (This needs to go away in favor of JNI1231 * Attach calls.)1232 */1233 androidSetCreateThreadFunc((android_create_thread_fn) javaCreateThreadEtc);
AndroidRuntime中的start()函数流程图大体如下:
基本的初始化工作完成后,接下来就可以执行主函数了。基本步骤是:
1. 先通过FindClass()找到相应的类。
2.再通过GetStaticMethodID()找到相应的方法。
3.最后就可以调用CallStaticVoidMethod()进入Java世界执行托管代码了。
以Zygote初始化为例,其中类名为com.android.internal.os.ZygoteInit,方法为main。
871 /*872 * Start VM. This thread becomes the main thread of the VM, and will873 * not return until the VM exits.874 */875 char* slashClassName = toSlashClassName(className);876 jclass startClass = env->FindClass(slashClassName);877 if (startClass == NULL) {878 ALOGE("JavaVM unable to locate class '%s'\n", slashClassName);879 /* keep going */880 } else {881 jmethodID startMeth = env->GetStaticMethodID(startClass, "main",882 "([Ljava/lang/String;)V");883 if (startMeth == NULL) {884 ALOGE("JavaVM unable to find main() in '%s'\n", className);885 /* keep going */886 } else {887 env->CallStaticVoidMethod(startClass, startMeth, strArray);888889#if 0890 if (env->ExceptionCheck())891 threadExitUncaughtException(env);892#endif893 }894 }
抛开杂七杂八的预处理,主要的就是三个函数:FindClass(),GetStaticMethodID()和CallStaticVoidMethod()。FindClass()的实现在/art/runtime/jni_internal.cc:
640 static jclass FindClass(JNIEnv* env, const char* name) {641 CHECK_NON_NULL_ARGUMENT(FindClass, name);642 Runtime* runtime = Runtime::Current();643 ClassLinker* class_linker = runtime->GetClassLinker();644 std::string descriptor(NormalizeJniClassDescriptor(name));645 ScopedObjectAccess soa(env);646 Class* c = NULL;647 if (runtime->IsStarted()) {648 ClassLoader* cl = GetClassLoader(soa);649 c = class_linker->FindClass(descriptor.c_str(), cl);650 } else {651 c = class_linker->FindSystemClass(descriptor.c_str());652 }653 return soa.AddLocalReference<jclass>(c);654 }
在这里GetClassLoader()调用GetSystemClassLoader()得到前面初始化好的系统ClassLoader。
267 ClassLoader* class_loader = soa.Decode<ClassLoader*>(Runtime::Current()->GetSystemClassLoader());
接着调用ClassLinker的FindClass()查找目标类,其中涉及几个关键函数:LookupClass(),DefineClass(),InsertClass(),LoadClass()和LinkClass()。以下简要介绍下它们的主要功能:
LookupClass()先在ClassLinker的成员变量class_table_中找指定类,找到就返回,找不到的话看是否要在image中找(class_loader为NULL且dex_cache_image_class_lookup_required为true)。如果要的话就调用LookupClassFromImage()在Image中进行查找,找到了就调用InsertClass()将找到的类放入到class_table_中方便下次查找。
DefineClass()做了很多事情,包括了LoadClass(),InsertClass()和LinkClass()等动作。其中,LoadClass()调用LoadField()和LoadMethod()等函数把类中的域和方法数据从dex文件中读出来,填入Class结构。
InsertClass()主要功能是把该类写入class_table_中方便下次查找。
LinkClass()顾名思义,就是动态绑定虚函数和接口函数了。其调用结构:
LinkSuperClass() // 检查父类。
LinkMethods()
LinkVirtualMethods() // 结合父类进行虚函数绑定,填写Class中的虚函数表vtable_。
LinkInterfaceMethods() //处理接口类函数信息iftable_。注意接口类中的虚函数也会影响虚函数表,因此会更新vtable_。
LinkInstanceFields() & LinkStaticFields() // 更新域信息,如域中的Offset和类的对象大小等。
对于FindClass()来说,类大体有以下几种情况:内置类,启动类,系统类和其它。内置类是很基本的类,一般是初始化时预加载好的(如WellKnownClasses和JniConstants里那一坨),它们可以通过LookupClassFromImage()函数找到。启动类是在BOOTCLASSPATH里的类,由于它们是启动类,所以这里还没有ClassLoader。除掉前面的内置类,其余的通过DexFile::FindInClassPath()查找得到。再就是系统类和其它类,它们的加载过程是类似的,都是通过ClassLoader的loadClass方法,区别在于前者通过特殊的SystemClassLoader进行加载。举例来说,对于一个还没被加载过的启动类,一般流程是这样的:
主要涉及到的类有以下几个,最核心的是Class类:
回到FindClass()函数,由于在调用ZygoteInit.main()时,所需的类在初始化时都已经装载链接好了。因此,这里走的不是上面的流程,而是直接通过JNI调用ClassLoader.loadClass()进行装载。完成后将找到的类转为jclass返回给AndroidRuntime。类的查找结束后,就可以找相应的方法了。GetStaticMethodID会调用FindMethodID()函数,它首先对该类进行验证,保证这个类是初始化好的,再调用其它函数进行目标函数的查找。关键几行如下:
235 ArtMethod* method = NULL;236 if (is_static) {237 method = c->FindDirectMethod(name, sig);238 } else {239 method = c->FindVirtualMethod(name, sig);240 if (method == NULL) {241 // No virtual method matching the signature. Search declared242 // private methods and constructors.243 method = c->FindDeclaredDirectMethod(name, sig);244 }245 }
可以看到,如果要找的是静态函数(通过GetStaticMethodID()过来的),则调用FindDirectMethod()查找该类及其父类的非虚函数(通过Class的成员变量direct_methods_),否则调用FindVirtualMethod()查找该类及其父类的虚函数(通过Class的成员变量virtual_methods_),没找到的话再调用FindDeclaredDirectMethod()查找该类的非虚函数。找到的条件是函数名和函数签名相同,如这里是"main"和"([Ljava/lang/String;)V"。找到目标函数后,就可以执行了。以下是执行目标函数的主干部分:
246void ArtMethod::Invoke(Thread* self, uint32_t* args, uint32_t args_size, JValue* result,247 char result_type) {…253 // Push a transition back into managed code onto the linked list in thread.254 ManagedStack fragment;255 self->PushManagedStackFragment(&fragment);…270#ifdef ART_USE_PORTABLE_COMPILER271 (*art_portable_invoke_stub)(this, args, args_size, self, result, result_type);272#else273 (*art_quick_invoke_stub)(this, args, args_size, self, result, result_type);274#endif…297 // Pop transition.298 self->PopManagedStackFragment(fragment);
前后分别是对托管代码栈的保存和恢复。要执行托管代码前,要先为其创建栈。这些栈通过ManagedStack的成员link_形成一个先入后出的链表。当执行完托管代码后,只要将最近放入的托管代码栈恢复回来即可。中间是目标函数的执行,但在跳入目标函数体前还需要先执行一些ABI层的上下文处理代码,这段代码称为stub。首先按ART_USE_PORTABLE_COMPILER来决定是用art_quick_invok_stub还是art_portable_invok_stub。由于它们是由汇编写成,平台相关,所以每个体系结构(x86, arm, mps)都有其实现。以x86体系为例,art_portable_invoke_stub定义在portable_entrypoints_x86.S中:
30DEFINE_FUNCTION art_portable_invoke_stub31 PUSH ebp // save ebp32 PUSH ebx // save ebx33 mov %esp, %ebp // copy value of stack pointer into base pointer34 .cfi_def_cfa_register ebp35 mov 20(%ebp), %ebx // get arg array size36 addl LITERAL(28), %ebx // reserve space for return addr, method*, ebx, and ebp in frame37 andl LITERAL(0xFFFFFFF0), %ebx // align frame size to 16 bytes38 subl LITERAL(12), %ebx // remove space for return address, ebx, and ebp39 subl %ebx, %esp // reserve stack space for argument array40 lea 4(%esp), %eax // use stack pointer + method ptr as dest for memcpy41 pushl 20(%ebp) // push size of region to memcpy42 pushl 16(%ebp) // push arg array as source of memcpy43 pushl %eax // push stack pointer as destination of memcpy44 call SYMBOL(memcpy) // (void*, const void*, size_t)45 addl LITERAL(12), %esp // pop arguments to memcpy46 mov 12(%ebp), %eax // move method pointer into eax47 mov %eax, (%esp) // push method pointer onto stack48 call *METHOD_CODE_OFFSET(%eax) // call the method49 mov %ebp, %esp // restore stack pointer50 POP ebx // pop ebx51 POP ebp // pop ebp52 mov 20(%esp), %ecx // get result pointer53 cmpl LITERAL(68), 24(%esp) // test if result type char == 'D'54 je return_double_portable55 cmpl LITERAL(70), 24(%esp) // test if result type char == 'F'56 je return_float_portable57 mov %eax, (%ecx) // store the result58 mov %edx, 4(%ecx) // store the other half of the result59 ret60return_double_portable:61 fstpl (%ecx) // store the floating point result as double62 ret63return_float_portable:64 fstps (%ecx) // store the floating point result as float65 ret66END_FUNCTION art_portable_invoke_stub
可以看到,这是x86体系中的函数调用过程。首先保存栈帧等信息,然后把参数数组拷贝到栈中,再执行call指令跳转到要执行的目标函数。METHOD_CODE_OFFSET指向ArtMethod中的成员变量entry_point_from_compiled_code_,也就是编译好的目标函数的地址。接下来,就是等目标函数愉快地执行完,然后恢复上下文,保存返回值,最后执行ret指令返回。查找目标函数和执行的过程比较直观:
这样,执行完托管代码后,返回到AndroidRuntimie::start()函数,调用DetachCurrentThread()和DestroyJavaVM()来做清理工作,关闭虚拟机,收工。
897 ALOGD("Shutting down VM\n");898 if (mJavaVM->DetachCurrentThread() != JNI_OK)899 ALOGW("Warning: unable to detach main thread\n");900 if (mJavaVM->DestroyJavaVM() != 0)901 ALOGW("Warning: VM did not shut down cleanly\n");