美文网首页
ART 加载类

ART 加载类

作者: 王小宝wy | 来源:发表于2016-12-15 15:53 被阅读0次

    一.创建Activity对象

    ART在加载完dex文件后,会通过Instrumentation创建Activity对象

    private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
        ...
        Activity activity = null;
        try {
            //加载dex文件
            java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
            //创建Activity对象
            activity = mInstrumentation.newActivity(
                        cl, component.getClassName(), r.intent);
            StrictMode.incrementExpectedActivityCount(activity.getClass());
            r.intent.setExtrasClassLoader(cl);
            r.intent.prepareToEnterProcess();
            if (r.state != null) {
                r.state.setClassLoader(cl);
            }
        } catch (Exception e) {
            if (!mInstrumentation.onException(activity, e)) {
                throw new RuntimeException(
                        "Unable to instantiate activity " + component
                        + ": " + e.toString(), e);
            }
        }
        ...
    }
    

    1. Instrumentation.newActivity()

    public Activity newActivity(ClassLoader cl, String className,
                Intent intent)
                throws InstantiationException, IllegalAccessException,
                ClassNotFoundException {
        return (Activity)cl.loadClass(className).newInstance();
    }
    

    从之前的加载dex文件的过程中可以知道这里传入的ClassLoaderPathClassLoader

    以我自己写的demo为例,PathClassLoader是:

    dalvik.system.PathClassLoader[DexPathList[[zip file "/data/app/com.singuloid.myapplication-1/base.apk"],
      nativeLibraryDirectories=[/data/app/com.singuloid.myapplication-1/lib/arm, /system/lib, /vendor/lib]]]
    

    PathClassLoader继承自BaseDexClassLoader,而BaseDexClassLoader又是继承自ClassLoader,PathClassLoaderBaseDexClassLoader两个类都没有重写loadClass(),所以这里实际调用的基类ClassLoader.loadClass

    2. ClassLoader.loadClass()

    protected Class<?> loadClass(String className, boolean resolve) throws ClassNotFoundException {
        //先查找之前是否已经过要加载的类, [2.1]
        Class c = findLoadedClass(name);
        if (c == null) {
            long t0 = System.nanoTime();
            try {
                if (parent != null) {
                     //在parent中查找类
                     c = parent.loadClass(name, false);
                } else {
                     //如果parent为null,则代表当前ClassLoader是BootClassLoader
                     c = findBootstrapClassOrNull(name);
                }
             } catch (ClassNotFoundException e) {
                    // ClassNotFoundException thrown if class not found
                    // from the non-null parent class loader
             }
    
              if (c == null) {         
                  long t1 = System.nanoTime();
                  c = findClass(name);
              }
          }
          return c;
    }
    

    从代码中可以看出,ART的类加载机制也同样采用双亲委派模式,即先由父ClassLoader进行加载,如果没有加载成功,再交由子ClassLoader加载,依照此顺序,依次向下进行.
    如果查找的是应用自己的类,如果没有加载过,最后都会在应用自己的ClassLoader中查找

    如果父类加载器没有加载到类,则调用当前类加载器的findClass方法,在创建Activity对象这个场景下,当前的类加载器是PathClassLoader,而PathClassLoader并没有重写findClass,查看其父类BaseDexClassLoader,发现BaseDexClassLoader重写了findClass这个方法

    2.1 ClassLoader.findLoadedClass

    protected final Class<?> findLoadedClass(String name) {
        ClassLoader loader;
        if (this == BootClassLoader.getInstance())
            loader = null;
        else
            loader = this;
        return VMClassLoader.findLoadedClass(loader, name);
    }
    

    VMClassLoader.findLoadedClass是一个native方法,其实现在art/runtime/native/lava_lang_VMClassLoader

    static jclass VMClassLoader_findLoadedClass(JNIEnv* env, jclass, jobject javaLoader,
                                                jstring javaName) {
      ScopedFastNativeObjectAccess soa(env);
      mirror::ClassLoader* loader = soa.Decode<mirror::ClassLoader*>(javaLoader);
      ScopedUtfChars name(env, javaName);
      if (name.c_str() == nullptr) {
        return nullptr;
      }
      ClassLinker* cl = Runtime::Current()->GetClassLinker();
      std::string descriptor(DotToDescriptor(name.c_str()));
      const size_t descriptor_hash = ComputeModifiedUtf8Hash(descriptor.c_str());
      //在传入的ClassLoader中查找类,每一个ClassLoader都有一个ClassTable,用来记录已经加载的类
      mirror::Class* c = cl->LookupClass(soa.Self(), descriptor.c_str(), descriptor_hash, loader);
      //如果找到类,且类已经被正确解析,则直接返回
      if (c != nullptr && c->IsResolved()) {
        return soa.AddLocalReference<jclass>(c);
      }
      //如果类是错误的,则抛出相应异常
      if (c != nullptr && c->IsErroneous()) {
        ...
        return nullptr;
      }
      //执行到这里,意味着没有在缓存的ClassTable中找到类,需要进一步到dex文件中进行查找
      if (loader != nullptr) {
        StackHandleScope<1> hs(soa.Self());
        cl->FindClassInPathClassLoader(soa, soa.Self(), descriptor.c_str(), descriptor_hash,
                                       hs.NewHandle(loader), &c);
        if (c != nullptr) {
          return soa.AddLocalReference<jclass>(c);
        }
      }
      // Class wasn't resolved so it may be erroneous or not yet ready, force the caller to go into
      // the regular loadClass code.
      return nullptr;
    }
    

    3. BaseDexClassLoader.findClass()

    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        List<Throwable> suppressedExceptions = new ArrayList<Throwable>();
        Class c = pathList.findClass(name, suppressedExceptions);
        if (c == null) {
            ClassNotFoundException cnfe = new ClassNotFoundException("Didn't find class \"" + name + "\" on path: " + pathList);
            for (Throwable t : suppressedExceptions) {
                    cnfe.addSuppressed(t);
            }
            throw cnfe;
        }
        return c;
    }
    

    由之前的ART 加载dex文件可知,BaseDexClassLoaderpathList变量指向的是一个DexPathList,而DexPathList是用来保存加载的dex文件列表,从这里我们知道BaseDexClassLoader又将加载类的过程委派给了DexPathList

    4. DexPathList.findClass()

    public Class findClass(String name, List<Throwable> suppressed) {
        //迭代dexElements
        for (Element element : dexElements) {
            DexFile dex = element.dexFile;
    
            if (dex != null) {
                Class clazz = dex.loadClassBinaryName(name, definingContext, suppressed);
                if (clazz != null) {
                    return clazz;
                }
            }
        }
        if (dexElementsSuppressedExceptions != null) {
            suppressed.addAll(Arrays.asList(dexElementsSuppressedExceptions));
        }
        return null;
    }
    

    从代码中可知,其主要逻辑是遍历之前加载过得dex文件列表,依次在每个dex文件中查找,直到加载到相应的类

    5. DexFile.loadClassBinaryName()

    public Class loadClassBinaryName(String name, ClassLoader loader, List<Throwable> suppressed) {
        //mCookie保存的是加载的dex文件列表
        return defineClass(name, loader, mCookie, suppressed);
    }
    
    private static Class defineClass(String name, ClassLoader loader, Object cookie,
                                         List<Throwable> suppressed) {
        Class result = null;
        try {
            result = defineClassNative(name, loader, cookie);
        } catch (NoClassDefFoundError e) {
            if (suppressed != null) {
                suppressed.add(e);
            }
        } catch (ClassNotFoundException e) {
            if (suppressed != null) {
                suppressed.add(e);
            }
        }
        return result;
    }
    
    private static native Class defineClassNative(String name, ClassLoader loader, Object cookie)
                throws ClassNotFoundException, NoClassDefFoundError;
    

    loadClassBinaryName实际就是封装调用了defineClass(从代码中可以看出,传入的参数中有一个是mCookie,这个变量保存的正是之前加载的dex文件列表),而defineClass实际调用的是native方法defineClassNative,只是额外做了异常处理.defineClassNative的实现在art/runtime/native/dalvik_system_DexFile.cc

    6. DexFile_defineClassNative()

    static jclass DexFile_defineClassNative(JNIEnv* env, jclass, jstring javaName, jobject javaLoader,
                                            jobject cookie) {
        //将Java层传入的mCookie变量转换为vector类型的dex文件列表
        std::unique_ptr<std::vector<const DexFile*>> dex_files = ConvertJavaArrayToNative(env, cookie);
        ...
    
        ScopedUtfChars class_name(env, javaName);
        ...
        //将com.xx.xx转换为com/xx/xx
        const std::string descriptor(DotToDescriptor(class_name.c_str()));
        const size_t hash(ComputeModifiedUtf8Hash(descriptor.c_str()));
    
        for (auto& dex_file : *dex_files) {
            //首先获取ClassDef
            const DexFile::ClassDef* dex_class_def = dex_file->FindClassDef(descriptor.c_str(), hash);
    
            if (dex_class_def != nullptr) {
                ScopedObjectAccess soa(env);
    
                ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
                StackHandleScope<1> hs(soa.Self());
                Handle<mirror::ClassLoader> class_loader(
                    hs.NewHandle(soa.Decode<mirror::ClassLoader*>(javaLoader)));
    
                //生成dex_cache,并放入缓存队列, [6.1]
                class_linker->RegisterDexFile(*dex_file, class_loader.Get());
                //加载类,[7]
                mirror::Class* result = class_linker->DefineClass(soa.Self(), descriptor.c_str(), hash,
                                                                  class_loader, *dex_file, *dex_class_def);
                // Add the used dex file. This only required for the DexFile.loadClass API since normal
                // class loaders already keep their dex files live.
                class_linker->InsertDexFileInToClassLoader(soa.Decode<mirror::Object*>(dexFile),
                                                      class_loader.Get());
                if (result != nullptr) {
                    ...
                    return soa.AddLocalReference<jclass>(result);
                }
            }
        }
        return nullptr;
    }
    
    1. defineClassNative第一个关键步骤是将Java层传入的mCookie变量转换为Native的vector类型的dex文件列表
    2. 在Native层,每个dex文件有一个对应的DexCache结构,该结构缓存了dex文件中一些基本的信息
    3. 遍历dex文件列表时,首先从dex文件中获取ClassDef结构,之后再根据这个ClassDef来加载相应的类

    6.1 ClassLinker::RegisterDexFile()

    mirror::DexCache* ClassLinker::RegisterDexFile(const DexFile& dex_file,
                                                   mirror::ClassLoader* class_loader) {
      Thread* self = Thread::Current();
      {
          ReaderMutexLock mu(self, dex_lock_);
          //查找是由已经有对应的dex_cache,有则直接返回
          mirror::DexCache* dex_cache = FindDexCacheLocked(self, dex_file, true);
          if (dex_cache != nullptr) {
              return dex_cache;
          }
      }
      //获取ClassLoader对应的LinearAlloc
      LinearAlloc* const linear_alloc = GetOrCreateAllocatorForClassLoader(class_loader);
      DCHECK(linear_alloc != nullptr);
      ClassTable* table;
      {
          WriterMutexLock mu(self, *Locks::classlinker_classes_lock_);
          //获取ClassLoader的ClassTable
          table = InsertClassTableForClassLoader(class_loader);
      }
    
      StackHandleScope<1> hs(self);
      //在LinearAlloc创建一个dex_cache结构,此时不要持有dex_lock_锁,因为分配时可能会挂起所有线程而且可能存在线程需要
      //dex_lock_
      Handle<mirror::DexCache> h_dex_cache(hs.NewHandle(AllocDexCache(self, dex_file, linear_alloc)));
      {
          WriterMutexLock mu(self, dex_lock_);
          mirror::DexCache* dex_cache = FindDexCacheLocked(self, dex_file, true);
          if (dex_cache != nullptr) {
            return dex_cache;
          }
          //如果分配dex_cache结构失败,则一定是发生了OOM
          if (h_dex_cache.Get() == nullptr) {
            self->AssertPendingOOMException();
            return nullptr;
          }
          //根据dex_file生成dex_cache,并注册dex_cache
          RegisterDexFileLocked(dex_file, h_dex_cache);
      }
      table->InsertStrongRoot(h_dex_cache.Get());
      return h_dex_cache.Get();
    }
    

    7. ClassLinker::DefineClass

    mirror::Class* ClassLinker::DefineClass(Thread* self, const char* descriptor, size_t hash,
                                            Handle<mirror::ClassLoader> class_loader,
                                            const DexFile& dex_file,
                                            const DexFile::ClassDef& dex_class_def) {
    
        StackHandleScope<3> hs(self);
        auto klass = hs.NewHandle<mirror::Class>(nullptr);
    
        //如果ClassLinker还未初始化完成,且要加载的正好是几个指定的系统类,将kclass指向系统类
        ...
    
        if (klass.Get() == nullptr) {
            //创建Class对象
            klass.Assign(AllocClass(self, SizeOfClassWithoutEmbeddedTables(dex_file, dex_class_def)));
        }
    
        ...
        //获取dex_cache结构,如果未获取到则创建
        mirror::DexCache* dex_cache = RegisterDexFile(dex_file, class_loader.Get());
        if (dex_cache == nullptr) {
            self->AssertPendingOOMException();
            return nullptr;
        }
        klass->SetDexCache(dex_cache);
        //设置klass基本属性, [7.1]
        SetupClass(dex_file, dex_class_def, klass, class_loader.Get());
    
        ...
    
        ObjectLock<mirror::Class> lock(self, klass);
        klass->SetClinitThreadId(self->GetTid());
    
        // 将要加载的类添加到ClassLinker的已加载类列表
        mirror::Class* existing = InsertClass(descriptor, klass.Get(), hash);
        if (existing != nullptr) {
            //如果插入失败,则表明类已经被加载过
            return EnsureResolved(self, descriptor, existing);
        }
        //加载类,[7.2]
        LoadClass(self, dex_file, dex_class_def, klass);
        ...
    
        CHECK(!klass->IsLoaded());
        if (!LoadSuperAndInterfaces(klass, dex_file)) {
            ...
        }
        //正常情况下,此时klass->IsLoaded = true
        CHECK(klass->IsLoaded());
        //正常情况下,此时klass->isResolved = false
        CHECK(!klass->IsResolved());
        auto interfaces = hs.NewHandle<mirror::ObjectArray<mirror::Class>>(nullptr);
    
        MutableHandle<mirror::Class> h_new_class = hs.NewHandle<mirror::Class>(nullptr);
        //对加载后的类进行链接解析,[7.3]
        if (!LinkClass(self, descriptor, klass, interfaces, &h_new_class)) {
            ...
        }
        ...
        return h_new_class.Get();
    }
    

    DefineClass中的关键步骤可以总结为:SetupClass-->InsertClass-->LoadClass-->LoadSuperAndInterfaces-->LinkClass

    7.1 ClassLinker::SetupClass

    void ClassLinker::SetupClass(const DexFile& dex_file,
                                 const DexFile::ClassDef& dex_class_def,
                                 Handle<mirror::Class> klass,
                                 mirror::ClassLoader* class_loader) {
      ... //Check(...)
      const char* descriptor = dex_file.GetClassDescriptor(dex_class_def);
      ... //Check(...)
    
      klass->SetClass(GetClassRoot(kJavaLangClass));
      uint32_t access_flags = dex_class_def.GetJavaAccessFlags();
      ... //Check(...)
    
      klass->SetAccessFlags(access_flags);
      klass->SetClassLoader(class_loader);
      ... //Check(...)
    
      mirror::Class::SetStatus(klass, mirror::Class::kStatusIdx, nullptr);
    
      klass->SetDexClassDefIndex(dex_file.GetIndexForClassDef(dex_class_def));
      klass->SetDexTypeIndex(dex_class_def.class_idx_);
      ... //Check(...)
    }
    

    可以看到,SetupClass方法主要是给Class对象设置基本属性如access_flags,ClassLoader

    7.2 ClassLinker::LoadClass()

    void ClassLinker::LoadClass(Thread* self, const DexFile& dex_file,
                                const DexFile::ClassDef& dex_class_def,
                                Handle<mirror::Class> klass) {
        //获取ClassData
        const uint8_t* class_data = dex_file.GetClassData(dex_class_def);
        if (class_data == nullptr) {
            return;  // no fields or methods - for example a marker interface
        }
        bool has_oat_class = false;
        if (Runtime::Current()->IsStarted() && !Runtime::Current()->IsAotCompiler()) {
            //获取OatClass,通过OatClass可以获取类方法的本地机器指令
            //klass->GetDexClassDefIndex()获取相应ClassDef结构在dex文件内的索引号,这个索引号是在之前的
            //SetupClass()函数中获取并设置
            OatFile::OatClass oat_class = FindOatClass(dex_file, klass->GetDexClassDefIndex(),
                                                       &has_oat_class);
            if (has_oat_class) {
                //加载类成员, [7.2.1]
                LoadClassMembers(self, dex_file, class_data, klass, &oat_class);
            }
        }
        if (!has_oat_class) {
            LoadClassMembers(self, dex_file, class_data, klass, nullptr);
        }
    }
    
    1. 从dex文件内部获取ClassData结构
    2. 根据ClassDef的索引位置获取相应OatClass结构,通过OatClass结构可以获取类方法的本地机器指令
    3. 如果找到OatClass则根据OatClass来加载类成员

    dex文件中每一个类在oat文件中都由一个对应的OatClass结构,根据OatClass可以找到每一个类方法的本地机器指令

    7.2.1 ClassLinker::LoadClassMembers()
    void ClassLinker::LoadClassMembers(Thread* self,
                                       const DexFile& dex_file,
                                       const uint8_t* class_data,
                                       Handle<mirror::Class> klass,
                                       const OatFile::OatClass* oat_class) {
        {
          //在没有加载完类成员之前,不允许当前线程挂起
          ScopedAssertNoThreadSuspension nts(self, __FUNCTION__);
          //加载静态属性
          LinearAlloc* const allocator = GetAllocatorForClassLoader(klass->GetClassLoader());
          ClassDataItemIterator it(dex_file, class_data);
          LengthPrefixedArray<ArtField>* 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();
              if (num_sfields == 0 || LIKELY(field_idx > last_field_idx)) {
                //加载属性,[7.2.1.1]
                LoadField(it, klass, &sfields->At(num_sfields));
                ++num_sfields;
                last_field_idx = field_idx;
              }
          }
    
    
          //加载实例属性
          LengthPrefixedArray<ArtField>* 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();
              if (num_ifields == 0 || LIKELY(field_idx > last_field_idx)) {
                LoadField(it, klass, &ifields->At(num_ifields));
                ++num_ifields;
                last_field_idx = field_idx;
              }
            }
          ....
          // Set the field arrays.
          klass->SetSFieldsPtr(sfields);
          klass->SetIFieldsPtr(ifields);
    
          // 加载方法
          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;
          //首先加载直接方法
          for (size_t i = 0; it.HasNextDirectMethod(); i++, it.Next()) {
              ArtMethod* method = klass->GetDirectMethodUnchecked(i, image_pointer_size_);
              //加载方法,[7.2.1.2]
              LoadMethod(self, dex_file, it, klass, method);
              //将方法同对应的本地机器指令关联,这样在方法执行时就可以知道该如何执行, [7.2.1.3]
              LinkCode(method, oat_class, class_def_method_index);
              uint32_t it_method_index = it.GetMemberIndex();
              if (last_dex_method_index == it_method_index) {
                  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++;
          }
          //加载虚拟方法
          for (size_t i = 0; it.HasNextVirtualMethod(); i++, it.Next()) {
              ArtMethod* method = klass->GetVirtualMethodUnchecked(i, image_pointer_size_);
              LoadMethod(self, dex_file, it, klass, method);
              LinkCode(method, oat_class, class_def_method_index);
              class_def_method_index++;
          }
        }
        // Ensure that the card is marked so that remembered sets pick up native roots.
        Runtime::Current()->GetHeap()->WriteBarrierEveryFieldOf(klass.Get());
        self->AllowThreadSuspension();
    }
    
    1. 首先便是设置当前线程在没有完成加载类成员工作之前不能被挂起
    2. 之后依次加载Static Field,Instance Field,所有Field都用ArtField表示
    3. 加载完Field后,再依次加载Direct Method和Virtual Method并关联Method对应的机器指令,所有Method都用ArtMethod表示
    4. 当所有加载工作完成之后,告知线程加载工作完成,允许被挂起
    7.2.1.1 ClassLinker::LoadField()
    void ClassLinker::LoadField(const ClassDataItemIterator& it, Handle<mirror::Class> klass,
                                ArtField* dst) {
        const uint32_t field_idx = it.GetMemberIndex();
        dst->SetDexFieldIndex(field_idx);
        dst->SetDeclaringClass(klass.Get());
        dst->SetAccessFlags(it.GetFieldAccessFlags());
    }
    
    7.2.1.2 ClassLinker::LoadMethod()
    void ClassLinker::LoadMethod(Thread* self, const DexFile& dex_file, const ClassDataItemIterator& it,
                                 Handle<mirror::Class> klass, ArtMethod* dst) {
        //从dex文件的ClassData结构种获取对应Method的索引
        uint32_t dex_method_idx = it.GetMemberIndex();
        //获取MethodId结构
        const DexFile::MethodId& method_id = dex_file.GetMethodId(dex_method_idx);
        const char* method_name = dex_file.StringDataByIdx(method_id.name_idx_);
    
        ScopedAssertNoThreadSuspension ants(self, "LoadMethod");
        dst->SetDexMethodIndex(dex_method_idx);
        dst->SetDeclaringClass(klass.Get());
        dst->SetCodeItemOffset(it.GetMethodCodeItemOffset());
    
        dst->SetDexCacheResolvedMethods(klass->GetDexCache()->GetResolvedMethods());
        dst->SetDexCacheResolvedTypes(klass->GetDexCache()->GetResolvedTypes());
    
        uint32_t access_flags = it.GetMethodAccessFlags();
    
        //一般情况下,方法名不会是finalize
        if (UNLIKELY(strcmp("finalize", method_name) == 0)) {
            // Set finalizable flag on declaring class.
            if (strcmp("V", dex_file.GetShorty(method_id.proto_idx_)) == 0) {
                // Void return type.
                if (klass->GetClassLoader() != nullptr) {  // All non-boot finalizer methods are flagged.
                    klass->SetFinalizable();
                } else {
                    std::string temp;
                    const char* klass_descriptor = klass->GetDescriptor(&temp);
                    //Enum枚举类不设置finalizable,因为枚举类已经声明了一个final finalize()
                    if (strcmp(klass_descriptor, "Ljava/lang/Object;") != 0 &&
                        strcmp(klass_descriptor, "Ljava/lang/Enum;") != 0) {
                      klass->SetFinalizable();
                    }
                }
            }
        } else if (method_name[0] == '<') {
            //判断是不是实例化构造函数
            bool is_init = (strcmp("<init>", method_name) == 0);
            //判断是不是类初始化方法
            bool is_clinit = !is_init && (strcmp("<clinit>", method_name) == 0);
            if (UNLIKELY(!is_init && !is_clinit)) {
                ... //LOG
            } else {
                if (UNLIKELY((access_flags & kAccConstructor) == 0)) {
                    access_flags |= kAccConstructor;
                }
            }
        }
        dst->SetAccessFlags(access_flags);
    }
    
    7.2.1.3 ClassLinker::LinkCode()
    void ClassLinker::LinkCode(ArtMethod* method, const OatFile::OatClass* oat_class,
                                 uint32_t class_def_method_index) {
        Runtime* const runtime = Runtime::Current();
        if (runtime->IsAotCompiler()) {
            return;
        }
        ...
    
        if (oat_class != nullptr) {
            //从OatClass中获取对应的OatMethod,OatMethod中记录了方法的本地机器指令的偏移地址
            //通过OatMethod::LinkMethod将OatMethod中记录的信息设置到ArtMethod当中
            const OatFile::OatMethod oat_method = oat_class->GetOatMethod(class_def_method_index);
            oat_method.LinkMethod(method);
        }
    
        //之后设置方法执行的entry point
        //判断是否需要解释执行:
        //1.当没有本地机器指令
        //2.Runtime指定以Interpreter方式运行且方法不是native同时也不是proxy
        //JNI方法是没有对应的DEX字节码的,因此即使ART虚拟机运行在解释模式中,JNI方法也不能通过解释器来执行
        bool enter_interpreter = NeedsInterpreter(method, method->GetEntryPointFromQuickCompiledCode());
        if (enter_interpreter && !method->IsNative()) {
            method->SetEntryPointFromInterpreter(artInterpreterToInterpreterBridge);
        } else {
            //有两种情况会进入这一分支
            //不需要解释执行的方法
            //没有本地机器指令或者Runtime以Interpreter方式运行,但该方法是native
            method->SetEntryPointFromInterpreter(artInterpreterToCompiledCodeBridge);
        }
    
        if (method->IsAbstract()) {
            //抽象方法没有机器指令,当有机器指令的方法调用抽象方法时,需要设置一个桥接函数,从而转到
            //解释器,由解释器解释执行抽象方法
            method->SetEntryPointFromQuickCompiledCode(GetQuickToInterpreterBridge());
            return;
        }
    
        if (method->IsStatic() && !method->IsConstructor()) {
            method->SetEntryPointFromQuickCompiledCode(GetQuickResolutionStub());
        } else if (enter_interpreter) {
            if (!method->IsNative()) {
                method->SetEntryPointFromQuickCompiledCode(GetQuickToInterpreterBridge());
            } else {
                //只有当native方法没有本地机器指令时,会执行这一分支
                method->SetEntryPointFromQuickCompiledCode(GetQuickGenericJniStub());
            }
        }
    
        if (method->IsNative()) {
            // Unregistering restores the dlsym lookup stub.
            method->UnregisterNative();
    
            if (enter_interpreter) {
              //native方法且没有对应的机器指令,则该方法如果是non-static,则entry point是generic JNI trampoline
              //如果是static, 则entry point是resolution trampoline
              const void* entry_point = method->GetEntryPointFromQuickCompiledCode();
              DCHECK(IsQuickGenericJniStub(entry_point) || IsQuickResolutionStub(entry_point));
            }
        }
    }
    

    LinkCode方法主要作用是根据方法属性来设置entry point

    1. 对于需要解释的方法,该方法需要由解释器解释执行,当另一个解释方法调用了这个需要解释执行的方法时,该方法的入口函数是artInterpreterToInterpreterBridge,从而继续在解释器中解释执行;如果当前方法是执行本地机器指令,当另一个解释执行的方法调用了这个执行本地机器指令的方法,该方法的入口函数是artInterpreterToCompiledCodeBridgeartInterpreterToCompiledCodeBridge会去调用相应的机器指令
    2. 抽象方法需要由被子类实现,所以抽象类是没有本地机器指令的,需要由解释器解释执行,当有机器指令的方法调用抽象方法时, 需要设置一个桥接函数,从而转到
      解释器,由解释器解释执行抽象方法, 这个桥接函数是GetQuickToInterpreterBridge()
    3. 对于静态非构造函数,当有执行机器指令的方法调用这类函数时,入口函数是GetQuickResolutionStub().因为静态方法不需要创建对象便可执行,着就有可能出现类还未初始化,方法就要执行,所以此时就需要现将类初始化,再执行静态方法,GetQuickResolutionStub完成的正是这项工作
    4. 对于需要解释执行且不是native的方法,当执行本地机器指令的方法调用该方法时,入口函数是GetQuickToInterpreterBridge(),该函数会转到解释器,由解释器执行这个需要解释执行的方法;当一个执行本地机器指令的方法调用没有机器指令的native方法时,入口函数是GetQuickGenericJniStub()
    5. 如果一个方法是native方法,设置本地方法的入口是通过GetJniDlsymLookupStub获得的一个Stub

    以上内容参考老罗的Android运行时ART加载类和方法的过程分析

    8. ClassLinker::InsertDexFileInToClassLoader

    void ClassLinker::InsertDexFileInToClassLoader(mirror::Object* dex_file,
                                                   mirror::ClassLoader* class_loader) {
        Thread* const self = Thread::Current();
        WriterMutexLock mu(self, *Locks::classlinker_classes_lock_);
        ClassTable* const table = ClassTableForClassLoader(class_loader);
        //InsertStrongRoot方法将dex_file对象放入ClassTable的strong_table_队列中
        if (table->InsertStrongRoot(dex_file) && class_loader != nullptr) {
            //执行write barrier从而让GC知道ClassLoader的ClassTable发生了改变
            Runtime::Current()->GetHeap()->WriteBarrierEveryFieldOf(class_loader);
        }
    }
    

    相关文章

      网友评论

          本文标题:ART 加载类

          本文链接:https://www.haomeiwen.com/subject/xuiwmttx.html