欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Android ART虚拟机执行引擎-本地代码的执行

程序员文章站 2022-04-12 20:30:55
以前面分析的虚拟机的启动流程 ART 虚拟机的启动 为例。 zygote在调用AndroidRuntime的start函数时传入一个class名称: runtime.s...

以前面分析的虚拟机的启动流程 ART 虚拟机的启动 为例。

zygote在调用AndroidRuntime的start函数时传入一个class名称:

runtime.start("com.android.internal.os.ZygoteInit", args, zygote); 

这个classname就是要被执行的类对象,一旦虚拟机启动完成,就会调用这个类的main方法。因为zygote程序本身有一部分本地代码,也有很多java代码的实现,所以它也是需要启动一个虚拟机的。

JniInvocation中的init和startVM函数分别来初始化和启动虚拟机,然后通过onVMCreated()通知拥有者虚拟机的最新状态。接下来就是AndroidRuntime::start()的处理过程。

void AndroidRuntime::start(const char* className, const Vector& options, bool zygote)  
{
......
?//执行目标对象的主函数,也即是zygoteInit的main函数  
   char* slashClassName = toSlashClassName(className);  
    jclass startClass = env->FindClass(slashClassName);  
    if (startClass == NULL) {  
        ALOGE("JavaVM unable to locate class '%s'\n", slashClassName);  
        /* keep going */  
    } else {  
        jmethodID startMeth = env->GetStaticMethodID(startClass, "main",  
            "([Ljava/lang/String;)V");  
        if (startMeth == NULL) {  
            ALOGE("JavaVM unable to find main() in '%s'\n", className);  
            /* keep going */  
        } else {  
            env->CallStaticVoidMethod(startClass, startMeth, strArray);  
        }  
    }  
...... 
}  

先调用toSlashClassName把类名中的“.”转换成“/”,方便虚拟机根据类名查找类的存储地址。

接着主要完成三件事情:

1)找到包含目标class的package包;

2)加载并实例化classname表示的类对象;

3)java代码如何跟OAT中的native code准确对应起来的。

AndroidRuntime是运行在JNI环境的,env变量属于JNIEnv类型,提供了JNI环境下的各种处理函数,查找classname的关键调用是jclass startClass = env->FindClass(slashClassName);经过层层封装,FindClass最终调用了jni_internal.cc中的FindClass。

art/runtime/jni_internal.cc

  static jclass FindClass(JNIEnv* env, const char* name) {
    Runtime* runtime = Runtime::Current();
    ClassLinker* class_linker = runtime->GetClassLinker();
    std::string descriptor(NormalizeJniClassDescriptor(name));
    ScopedObjectAccess soa(env);
    mirror::Class* c = nullptr;
    if (runtime->IsStarted()) {
      StackHandleScope<1> hs(soa.Self());
      Handle class_loader(hs.NewHandle(GetClassLoader(soa)));
      c = class_linker->FindClass(soa.Self(), descriptor.c_str(), class_loader);
    } else {
      c = class_linker->FindSystemClass(soa.Self(), descriptor.c_str());
    }
    return soa.AddLocalReference(c);
  }

runtime是进程中的单例,通过它获取到class linker,Class Linker起到类连接器的作用,任何与目标程序以及虚拟机本身相关联的类,类中的方法等都属于它的管理范围。所以findClass的搜索范围包括class_linder中的class类、Jar包、Dex、Image文件等。

传给class_linkder->FindClass的参数:

Thread* self JNIEnv对应的线程;

char* descriptor 类描述符;

Handle<:classloader> class_loader 类加载器;

art/runtime/Class_linker.cc

mirror::Class* ClassLinker::FindClass(Thread* self,
                                      const char* descriptor,
                                      Handle class_loader) {
  ...
  // Find the class in the loaded classes table.
  mirror::Class* klass = LookupClass(self, descriptor, hash, class_loader.Get());
 ?if (klass != nullptr) { //成功找到class对象
    return EnsureResolved(self, descriptor, klass);
  }
  // Class is not yet loaded.
  if (descriptor[0] == '[') {//class还没加载,并且是数组类
    return CreateArrayClass(self, descriptor, hash, class_loader);
  } else if (class_loader.Get() == nullptr) {//class没加载,但是非数组类
    // The boot class loader, search the boot class path.
    ClassPathEntry pair = FindInClassPath(descriptor, hash, boot_class_path_);//从boot class中搜索
    if (pair.second != nullptr) {
      return DefineClass(self,
                         descriptor,
                         hash,
                         ScopedNullHandle(),
                         *pair.first,
                         *pair.second);
    } else {
      // The boot class loader is searched ahead of the application class loader, failures are
      // expected and will be wrapped in a ClassNotFoundException. Use the pre-allocated error to
      // trigger the chaining with a proper stack trace.
      mirror::Throwable* pre_allocated = Runtime::Current()->GetPreAllocatedNoClassDefFoundError();
      self->SetException(pre_allocated);
      return nullptr;
    }
  } else {//class loader不为null的情况
    ScopedObjectAccessUnchecked soa(self);
    mirror::Class* cp_klass;
    if (FindClassInPathClassLoader(soa, self, descriptor, hash, class_loader, &cp_klass)) {
      // The chain was understood. So the value in cp_klass is either the class we were looking
      // for, or not found.
      if (cp_klass != nullptr) {
        return cp_klass;
      }
      // TODO: We handle the boot classpath loader in FindClassInPathClassLoader. Try to unify this
      //       and the branch above. TODO: throw the right exception here.

      // We'll let the Java-side rediscover all this and throw the exception with the right stack
      // trace.
    }

    ScopedLocalRef class_loader_object(soa.Env(),
                                                soa.AddLocalReference(class_loader.Get()));
    std::string class_name_string(DescriptorToDot(descriptor));
    ScopedLocalRef result(soa.Env(), nullptr);
    {
      ScopedThreadStateChange tsc(self, kNative);
      ScopedLocalRef class_name_object(soa.Env(),
                                                soa.Env()->NewStringUTF(class_name_string.c_str()));
      if (class_name_object.get() == nullptr) {
        DCHECK(self->IsExceptionPending());  // OOME.
        return nullptr;
      }
      CHECK(class_loader_object.get() != nullptr);
      result.reset(soa.Env()->CallObjectMethod(class_loader_object.get(),
                                               WellKnownClasses::java_lang_ClassLoader_loadClass,
                                               class_name_object.get()));
    }
......
}

FindClass的目的是找到descriptor所对应的class实现,然后加载到内存,转化为class对象。

首先,通过LookupClass确认这个类是否已经成功加载过;

然后,class _loader为null的情况,根据双亲委派模型,通过调用FindInClassPath在boot class path中查找,

FindClassInPathClassLoader-->

// Search a collection of DexFiles for a descriptor
ClassPathEntry FindInClassPath(const char* descriptor,
                               size_t hash, const std::vector& class_path) {
  for (const DexFile* dex_file : class_path) {
    const DexFile::ClassDef* dex_class_def = dex_file->FindClassDef(descriptor, hash);
    if (dex_class_def != nullptr) {
      return ClassPathEntry(dex_file, dex_class_def);
    }
  }
  return ClassPathEntry(nullptr, nullptr);
}

FindInClassPath的实现是在一组DexFile中查找那个文件包含了descriptor描述的类,找到后返回的是一个ClassPathEntry对象,ClassPathEntry是对DexFile文件位置的一种描述方式,找到classpath后,还需要执行加载、实例化、初始化类对象等等操作,才能让这个class真正可用,这以系列的操作是通过ClassLinker::DefineClass来完成的。

在class_loader不为null的情况,尝试调用FindClassInPathClassLoader来查找,这里会查找boot_class_path_下的所有的dexfile,还会查找DexPathList中所有Dex元素;

最后,如果前面都没找到,会通过class_loader.Get()自定义的loadclass来加载目标对象,如果这一步依然失败,那就报 class not found 错误。

在查找到目标对象后,接下来调用DefineClass让class变成可用状态,class的状态有很多种:

art/runtime/mirror/Class.h

  enum Status {
    kStatusRetired = -2,  // Retired, should not be used. Use the newly cloned one instead.
    kStatusError = -1,
    kStatusNotReady = 0,
    kStatusIdx = 1,  // Loaded, DEX idx in super_class_type_idx_ and interfaces_type_idx_.
    kStatusLoaded = 2,  // DEX idx values resolved.
    kStatusResolving = 3,  // Just cloned from temporary class object.
    kStatusResolved = 4,  // Part of linking.
    kStatusVerifying = 5,  // In the process of being verified.
    kStatusRetryVerificationAtRuntime = 6,  // Compile time verification failed, retry at runtime.
    kStatusVerifyingAtRuntime = 7,  // Retrying verification at runtime.
    kStatusVerified = 8,  // Logically part of linking; done pre-init.
    kStatusInitializing = 9,  // Class init in progress.
    kStatusInitialized = 10,  // Ready to go.
    kStatusMax = 11,
  };

具体看下DefineClass的实现:

art/runtime/Class_linker.cc

mirror::Class* ClassLinker::DefineClass(Thread* self,
                                        const char* descriptor,
                                        size_t hash,
                                        Handle class_loader,
                                        const DexFile& dex_file,
                                        const DexFile::ClassDef& dex_class_def) {
  StackHandleScope<3> hs(self);
  auto klass = hs.NewHandle(nullptr);

  if (klass.Get() == nullptr) {
    // Allocate a class with the status of not ready.
    // Interface object should get the right size here. Regular class will
    // figure out the right size later and be replaced with one of the right
    // size when the class becomes resolved.
//分配一个class空间,将状态迁移到kStatusNotReady
   ?klass.Assign(AllocClass(self, SizeOfClassWithoutEmbeddedTables(dex_file, dex_class_def)));
  }

  mirror::DexCache* dex_cache = RegisterDexFile(dex_file, class_loader.Get());
  if (dex_cache == nullptr) {
    self->AssertPendingOOMException();
    return nullptr;
  }
  klass->SetDexCache(dex_cache);
  SetupClass(dex_file, dex_class_def, klass, class_loader.Get());

  // Mark the string class by setting its access flag.
  if (UNLIKELY(!init_done_)) {
    if (strcmp(descriptor, "Ljava/lang/String;") == 0) {
      klass->SetStringClass();
    }
  }

  ObjectLock lock(self, klass);
  klass->SetClinitThreadId(self->GetTid());

  // Add the newly loaded class to the loaded classes table.
  mirror::Class* existing = InsertClass(descriptor, klass.Get(), hash);
  if (existing != nullptr) {//class_table已经存在这个class
    // We failed to insert because we raced with another thread. Calling EnsureResolved may cause
    // this thread to block.
    return EnsureResolved(self, descriptor, existing);
  }

  // Load the fields and other things after we are inserted in the table. This is so that we don't
  // end up allocating unfree-able linear alloc resources and then lose the race condition. The
  // other reason is that the field roots are only visited from the class table. So we need to be
  // inserted before we allocate / fill in these fields.
  LoadClass(self, dex_file, dex_class_def, klass);
  if (self->IsExceptionPending()) {
    VLOG(class_linker) << self->GetException()->Dump();
    // An exception occured during load, set status to erroneous while holding klass' lock in case
    // notification is necessary.
    if (!klass->IsErroneous()) {
      mirror::Class::SetStatus(klass, mirror::Class::kStatusError, self);
    }
    return nullptr;
  }

  MutableHandle h_new_class = hs.NewHandle(nullptr);
  if (!LinkClass(self, descriptor, klass, interfaces, &h_new_class)) {
    // Linking failed.
    if (!klass->IsErroneous()) {
      mirror::Class::SetStatus(klass, mirror::Class::kStatusError, self);
    }
    return nullptr;
  }
  
  return h_new_class.Get();
}

主要操作有AllocClass,SetupClass,InsertClass,LoadClass,LinkClass等。

AllocClass,负责申请Class对象所需的内存空间,这块空间是从Runtime::Current()->GetHeap()中获取的。

SetupClass,是对Class对象进行初始化,InsertClass将本次加载的class保存到一个已经加载的列表中。

LoadClass,是用成员变量、成员函数等来填满AllocClass申请的空间,首先从DexFile中查找Class数据所在的位置,接着通过FindOatClass查找DexClass对应的OatClass对象,然后调用LoadClassMembers加载成员变量、成员函数:

art/runtime/class_linker.cc

void ClassLinker::LoadClassMembers(Thread* self,
                                   const DexFile& dex_file,
                                   const uint8_t* class_data,
                                   Handle klass,
                                   const OatFile::OatClass* oat_class) {
  {
    // Note: We cannot have thread suspension until the field and method arrays are setup or else
    // Class::VisitFieldRoots may miss some fields or methods.
    ScopedAssertNoThreadSuspension nts(self, __FUNCTION__);
    // Load static fields.
    // We allow duplicate definitions of the same field in a class_data_item
    // but ignore the repeated indexes here, b/21868015.
    LinearAlloc* const allocator = GetAllocatorForClassLoader(klass->GetClassLoader());
    ClassDataItemIterator it(dex_file, class_data);
//加载静态成员变量
   ?LengthPrefixedArray* sfields = AllocArtFieldArray(self,
                                                                allocator,
                                                                it.NumStaticFields());
    size_t num_sfields = 0;
    uint32_t last_field_idx = 0u;
    for (; it.HasNextStaticField(); it.Next()) {
      uint32_t field_idx = it.GetMemberIndex();
      DCHECK_GE(field_idx, last_field_idx);  // Ordering enforced by DexFileVerifier.
      if (num_sfields == 0 || LIKELY(field_idx > last_field_idx)) {
        DCHECK_LT(num_sfields, it.NumStaticFields());
        LoadField(it, klass, &sfields->At(num_sfields));
        ++num_sfields;
        last_field_idx = field_idx;
      }
    }
    // Load instance fields.加载普通成员变量
    LengthPrefixedArray* ifields = AllocArtFieldArray(self,
                                                                allocator,
                                                                it.NumInstanceFields());
    size_t num_ifields = 0u;
    last_field_idx = 0u;
    for (; it.HasNextInstanceField(); it.Next()) {
      uint32_t field_idx = it.GetMemberIndex();
      DCHECK_GE(field_idx, last_field_idx);  // Ordering enforced by DexFileVerifier.
      if (num_ifields == 0 || LIKELY(field_idx > last_field_idx)) {
        DCHECK_LT(num_ifields, it.NumInstanceFields());
        LoadField(it, klass, &ifields->At(num_ifields));
        ++num_ifields;
        last_field_idx = field_idx;
      }
    }
    
    // Set the field arrays.
    klass->SetSFieldsPtr(sfields);
    DCHECK_EQ(klass->NumStaticFields(), num_sfields);
    klass->SetIFieldsPtr(ifields);
    DCHECK_EQ(klass->NumInstanceFields(), num_ifields);
    // Load methods.加载成员函数,
    klass->SetMethodsPtr(
        AllocArtMethodArray(self, allocator, it.NumDirectMethods() + it.NumVirtualMethods()),
        it.NumDirectMethods(),
        it.NumVirtualMethods());
    size_t class_def_method_index = 0;
    uint32_t last_dex_method_index = DexFile::kDexNoIndex;
    size_t last_class_def_method_index = 0;
    // TODO These should really use the iterators.
    for (size_t i = 0; it.HasNextDirectMethod(); i++, it.Next()) {
      ArtMethod* method = klass->GetDirectMethodUnchecked(i, image_pointer_size_);
      LoadMethod(self, dex_file, it, klass, method);
      LinkCode(method, oat_class, class_def_method_index);
      uint32_t it_method_index = it.GetMemberIndex();
      if (last_dex_method_index == it_method_index) {
        // duplicate case
        method->SetMethodIndex(last_class_def_method_index);
      } else {
        method->SetMethodIndex(class_def_method_index);
        last_dex_method_index = it_method_index;
        last_class_def_method_index = class_def_method_index;
      }
      class_def_method_index++;
    }
  }
}

加载的类信息,通过klass变量保存。

DefineClass的最后一步是LinkClass,建立各个class之间的关联,如父类、子类间的重载,多态性的Vtable和Itable等。

其中VTable就是Virtual Method table,用在类的继承关系时,解决多态性的问题。当在class中定义一个虚函数,Compiler会为他添加一个隐藏的成员变量,这个隐藏的成员变量会指向Vtable这个函数指针数组,这个数组的各个指针的具体值需要在运行时得到最终确定。如LinkMethods的实现:

bool ClassLinker::LinkMethods(Thread* self,
                              Handle klass,
                              Handle> interfaces,
                              bool* out_new_conflict,
                              ArtMethod** out_imt) {
  self->AllowThreadSuspension();
  // A map from vtable indexes to the method they need to be updated to point to. Used because we
  // need to have default methods be in the virtuals array of each class but we don't set that up
  // until LinkInterfaceMethods.
  std::unordered_map default_translations;
  // Link virtual methods then interface methods.
  // We set up the interface lookup table first because we need it to determine if we need to update
  // any vtable entries with new default method implementations.
  return SetupInterfaceLookupTable(self, klass, interfaces)
          && LinkVirtualMethods(self, klass, /*out*/ &default_translations)
          && LinkInterfaceMethods(self, klass, default_translations, out_new_conflict, out_imt);
}

先链接虚函数,在链接接口中的函数。

iftable就是指Interface table,是指多个接口及其对应method列表的集合,他解决的是类的implements关系,而Vtable解决的是类的extends关系。

到这里FindClass的实现就完成了。

下面是如何执行class中的函数。

前面的分析都是从AndroidRuntime::start方法开始的,

frameworks/base/core/jni/AndroidRuntime.cpp

void AndroidRuntime::start(const char* className, const Vector& options, bool zygote)
{
    
    /*
     * Start VM.  This thread becomes the main thread of the VM, and will
     * not return until the VM exits.
     */
    char* slashClassName = toSlashClassName(className);
    jclass startClass = env->FindClass(slashClassName);
    if (startClass == NULL) {
        ALOGE("JavaVM unable to locate class '%s'\n", slashClassName);
        /* keep going */
    } else {
        jmethodID startMeth = env->GetStaticMethodID(startClass, "main",
            "([Ljava/lang/String;)V");
        if (startMeth == NULL) {
            ALOGE("JavaVM unable to find main() in '%s'\n", className);
            /* keep going */
        } else {
            env->CallStaticVoidMethod(startClass, startMeth, strArray);
        }
    }
    
}

前面的分析都是从jclass startClass = env->FindClass(slashClassName);这句调用开始的。

接下来,先是GetStaticMethodID来从前面加载的class中获取main函数的methodID,同样调用的是jni_internal.cc中的方法。

主要的执行函数是:

art/runtime/jni_internal.cc

static jmethodID FindMethodID(ScopedObjectAccess& soa, jclass jni_class,
                              const char* name, const char* sig, bool is_static)
    SHARED_REQUIRES(Locks::mutator_lock_) {
  mirror::Class* c = EnsureInitialized(soa.Self(), soa.Decode(jni_class));
  if (c == nullptr) {
    return nullptr;
  }
  ArtMethod* method = nullptr;
  auto pointer_size = Runtime::Current()->GetClassLinker()->GetImagePointerSize();
  if (is_static) {
    method = c->FindDirectMethod(name, sig, pointer_size);
  } else if (c->IsInterface()) {
    method = c->FindInterfaceMethod(name, sig, pointer_size);
  } else {
    method = c->FindVirtualMethod(name, sig, pointer_size);
    if (method == nullptr) {
      // No virtual method matching the signature.  Search declared
      // private methods and constructors.
      method = c->FindDeclaredDirectMethod(name, sig, pointer_size);
    }
  }
  if (method == nullptr || method->IsStatic() != is_static) {
    ThrowNoSuchMethodError(soa, c, name, sig, is_static ? "static" : "non-static");
    return nullptr;
  }
  return soa.EncodeMethod(method);
}

获取到Method ID后,接着是执行这个函数:

art/runtime/jni_internal.cc

  static void CallStaticVoidMethod(JNIEnv* env, jclass, jmethodID mid, ...) {
    va_list ap;
    va_start(ap, mid);
    CHECK_NON_NULL_ARGUMENT_RETURN_VOID(mid);
    ScopedObjectAccess soa(env);
    InvokeWithVarArgs(soa, nullptr, mid, ap);
    va_end(ap);
  }

然后调用Reflection.cc中的InvokeWithVarArgs:

art/runtime/Reflection.cc

JValue InvokeWithVarArgs(const ScopedObjectAccessAlreadyRunnable& soa, jobject obj, jmethodID mid,
                         va_list args)
    SHARED_REQUIRES(Locks::mutator_lock_) {

  ArtMethod* method = soa.DecodeMethod(mid);
  bool is_string_init = method->GetDeclaringClass()->IsStringClass() && method->IsConstructor();
  if (is_string_init) {
    // Replace calls to String. with equivalent StringFactory call.
    method = soa.DecodeMethod(WellKnownClasses::StringInitToStringFactoryMethodID(mid));
  }
  mirror::Object* receiver = method->IsStatic() ? nullptr : soa.Decode(obj);
  uint32_t shorty_len = 0;
  const char* shorty = method->GetInterfaceMethodIfProxy(sizeof(void*))->GetShorty(&shorty_len);
  JValue result;
  ArgArray arg_array(shorty, shorty_len);
  arg_array.BuildArgArrayFromVarArgs(soa, receiver, args);
  InvokeWithArgArray(soa, method, &arg_array, &result, shorty);
  if (is_string_init) {
    // For string init, remap original receiver to StringFactory result.
    UpdateReference(soa.Self(), obj, result.GetL());
  }
  return result;
}
先通过DecodeMethod把methodID转成ArtMethod,如果是静态方法可以直接调用,否则还要指定它对应的对象receiver。

然后通过InvokeWithArgArray,进一步调用ArtMethod::Invoke:

art/runtime/Art_method.cc

void ArtMethod::Invoke(Thread* self, uint32_t* args, uint32_t args_size, JValue* result,
                       const char* shorty) {
  ...
  // Push a transition back into managed code onto the linked list in thread.
  ManagedStack fragment;
  self->PushManagedStackFragment(&fragment);

  Runtime* runtime = Runtime::Current();
  // Call the invoke stub, passing everything as arguments.
  // If the runtime is not yet started or it is required by the debugger, then perform the
  // Invocation by the interpreter, explicitly forcing interpretation over JIT to prevent
  // cycling around the various JIT/Interpreter methods that handle method invocation.
//runtime未启动,或者处于debug状态,或者要求使用interpreter执行,
  ?if (UNLIKELY(!runtime->IsStarted() || Dbg::IsForcedInterpreterNeededForCalling(self, this))) {
    if (IsStatic()) {
      art::interpreter::EnterInterpreterFromInvoke(
          self, this, nullptr, args, result, /*stay_in_interpreter*/ true);
    } else {
      mirror::Object* receiver =
          reinterpret_cast*>(&args[0])->AsMirrorPtr();
      art::interpreter::EnterInterpreterFromInvoke(
          self, this, receiver, args + 1, result, /*stay_in_interpreter*/ true);
    }
  } else {//非解释器执行的情况,直接执行函数对应的native code
    DCHECK_EQ(runtime->GetClassLinker()->GetImagePointerSize(), sizeof(void*));

    constexpr bool kLogInvocationStartAndReturn = false;
    bool have_quick_code = GetEntryPointFromQuickCompiledCode() != nullptr;

    if (!IsStatic()) {
        (*art_quick_invoke_stub)(this, args, args_size, self, result, shorty);
      } else {
        (*art_quick_invoke_static_stub)(this, args, args_size, self, result, shorty);
      }
      }
    } else {
    }
  }

  // Pop transition.
  self->PopManagedStackFragment(fragment);
}

invoke通过art_quick_invoke_stub,art_quick_invoke_static_stub来执行目标函数。这两个函数最终都是调用quick_invoke_reg_setup来完成执行过程。

art/runtime/arch/arm/quick_entrypoints_cc_arm.cc

static void quick_invoke_reg_setup(ArtMethod* method, uint32_t* args, uint32_t args_size,
                                   Thread* self, JValue* result, const char* shorty) {

}