Android KK ART初始化简析

原文地址:http://blog.csdn.net/jinzhuojun/article/details/20613075

 

Android KK里引入了ART虚拟机作为Dalvik虚拟机的替代,其主要目的是把Bytecode的翻译优化从运行时提前到安装时,以空间换时间,从而达到更流畅的用户体验。目前,KKDalvik仍是默认的虚拟机,但用户可以在Developer Option中切换到ART虚拟机。坊间传闻在下一版可能会转正。DalvikART的实现分别位于libdvm.solibart.so这两个库。两个可以同时build也可以只build一个,通过Makefile中的变量PRODUCT_RUNTIMES来控制(https://source.android.com/devices/tech/dalvik/art.html)。ART本质和Dalvik是一样的,是将JavaBytecode翻译成Native code。它的主要的实现代码在AOSPart目录下,另外在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_processframeworks/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.libdlopen()加载libdvm.solibart.so。这两个so中都export出了JNI_GetDefaultJavaVMInitArgs,JNI_CreateJavaVMJNI_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()函数来创建RuntimeRuntime是个单例,创建出来后紧接着调用Init()函数(/art/runtime/runtime.cc)Init()函数会做很多初始化工作:解析参数,初始化HeapJavaVMExt结构,线程和信号处理,创建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.artboot.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 cachedex 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函数中RuntimeStart()函数被调用:

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");

 

Android KK ART初始化简析,,5-wow.com

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。