当前位置: 代码迷 >> Android >> Android KK ART初步化简析
  详细解决方案

Android KK ART初步化简析

热度:63   发布时间:2016-04-28 06:42:49.0
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_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()函数来创建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());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.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_));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 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";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");

 

  相关解决方案