Android KK ART初始化简析
原文地址: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_OS 52static 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()); 896 897 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"; 196 197 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: /system/bin/dex2oat--image=/data/dalvik-cache/system@framework@boot.art --runtime-arg -Xms64m--runtime-arg -Xmx64m --dex-file=/system/framework/core-libart.jar ... --oat-file=/data/dalvik-cache/system@framework@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_)); 217 218 // 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_location 1049 << " from within oat file " << oat_file.GetLocation(); 1050 } 1051 1052 CHECK_EQ(dex_file->GetLocationChecksum(), oat_dex_file->GetDexFileLocationChecksum()); 1053 1054 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"; 710 711 CHECK(host_prefix_.empty()) << host_prefix_; 712 713 // Restore main thread state to kNative as expected by native code. 714 Thread* self = Thread::Current(); 715 self->TransitionFromRunnableToSuspended(kNative); 716 717 started_ = true; 718 719 // InitNativeMethods needs to be after started_ so that the classes 720 // it touches will have methods linked to the oat file if necessary. 721 InitNativeMethods(); 722 723 // Initialize well known thread group values that may be accessed threads while attaching. 724 InitThreadGroups(self); 725 726 Thread::FinishStartup(); 727 728 if (is_zygote_) { 729 if (!InitZygote()) { 730 return false; 731 } 732 } else { 733 DidForkFromZygote(); 734 } 735 736 StartDaemonThreads(); 737 738 system_class_loader_ = CreateSystemClassLoader(); 739 740 self->GetJniEnv()->locals.AssertEmpty(); 741 742 VLOG(startup) << "Runtime::Start exiting"; 743 744 finished_starting_ = true; 745 746 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 exceptions 1008 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(); 737 738 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 be 1230 * attached to the JavaVM. (This needs to go away in favor of JNI 1231 * 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 will 873 * 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); 888 889#if 0 890 if (env->ExceptionCheck()) 891 threadExitUncaughtException(env); 892#endif 893 } 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 declared 242 // 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_COMPILER 271 (*art_portable_invoke_stub)(this, args, args_size, self, result, result_type); 272#else 273 (*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_stub 31 PUSH ebp // save ebp 32 PUSH ebx // save ebx 33 mov %esp, %ebp // copy value of stack pointer into base pointer 34 .cfi_def_cfa_register ebp 35 mov 20(%ebp), %ebx // get arg array size 36 addl LITERAL(28), %ebx // reserve space for return addr, method*, ebx, and ebp in frame 37 andl LITERAL(0xFFFFFFF0), %ebx // align frame size to 16 bytes 38 subl LITERAL(12), %ebx // remove space for return address, ebx, and ebp 39 subl %ebx, %esp // reserve stack space for argument array 40 lea 4(%esp), %eax // use stack pointer + method ptr as dest for memcpy 41 pushl 20(%ebp) // push size of region to memcpy 42 pushl 16(%ebp) // push arg array as source of memcpy 43 pushl %eax // push stack pointer as destination of memcpy 44 call SYMBOL(memcpy) // (void*, const void*, size_t) 45 addl LITERAL(12), %esp // pop arguments to memcpy 46 mov 12(%ebp), %eax // move method pointer into eax 47 mov %eax, (%esp) // push method pointer onto stack 48 call *METHOD_CODE_OFFSET(%eax) // call the method 49 mov %ebp, %esp // restore stack pointer 50 POP ebx // pop ebx 51 POP ebp // pop ebp 52 mov 20(%esp), %ecx // get result pointer 53 cmpl LITERAL(68), 24(%esp) // test if result type char == ‘D‘ 54 je return_double_portable 55 cmpl LITERAL(70), 24(%esp) // test if result type char == ‘F‘ 56 je return_float_portable 57 mov %eax, (%ecx) // store the result 58 mov %edx, 4(%ecx) // store the other half of the result 59 ret 60return_double_portable: 61 fstpl (%ecx) // store the floating point result as double 62 ret 63return_float_portable: 64 fstps (%ecx) // store the floating point result as float 65 ret 66END_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");
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。