当前位置: 移动技术网 > IT编程>移动开发>Android > Android ART虚拟机执行引擎-本地代码的执行

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

2018年02月27日  | 移动技术网IT编程  | 我要评论

疥舒宁多少钱一盒,短篇美文,王瑞儿官网

以前面分析的虚拟机的启动流程 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 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) {

}

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网