ART 加載類

一.創(chuàng)建Activity對象

ART在加載完dex文件后获茬,會通過Instrumentation創(chuàng)建Activity對象

private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
    ...
    Activity activity = null;
    try {
        //加載dex文件
        java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
        //創(chuàng)建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()甸祭,所以這里實際調(diào)用的基類ClassLoader.loadClass

2. ClassLoader.loadClass()

protected Class<?> loadClass(String className, boolean resolve) throws ClassNotFoundException {
    //先查找之前是否已經(jīng)過要加載的類, [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加載校焦,依照此順序,依次向下進行.
如果查找的是應(yīng)用自己的類栅贴,如果沒有加載過斟湃,最后都會在應(yīng)用自己的ClassLoader中查找

如果父類加載器沒有加載到類,則調(diào)用當前類加載器的findClass方法檐薯,在創(chuàng)建Activity對象這個場景下,當前的類加載器是PathClassLoader,而PathClassLoader并沒有重寫findClass,查看其父類BaseDexClassLoader,發(fā)現(xiàn)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方法坛缕,其實現(xiàn)在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曲梗,用來記錄已經(jīng)加載的類
  mirror::Class* c = cl->LookupClass(soa.Self(), descriptor.c_str(), descriptor_hash, loader);
  //如果找到類顽频,且類已經(jīng)被正確解析,則直接返回
  if (c != nullptr && c->IsResolved()) {
    return soa.AddLocalReference<jclass>(c);
  }
  //如果類是錯誤的骇陈,則拋出相應(yīng)異常
  if (c != nullptr && c->IsErroneous()) {
    ...
    return nullptr;
  }
  //執(zhí)行到這里宠页,意味著沒有在緩存的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文件中查找,直到加載到相應(yīng)的類

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實際就是封裝調(diào)用了defineClass(從代碼中可以看出俭嘁,傳入的參數(shù)中有一個是mCookie躺枕,這個變量保存的正是之前加載的dex文件列表),而defineClass實際調(diào)用的是native方法defineClassNative,只是額外做了異常處理.defineClassNative的實現(xiàn)在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變量轉(zhuǎn)換為vector類型的dex文件列表
    std::unique_ptr<std::vector<const DexFile*>> dex_files = ConvertJavaArrayToNative(env, cookie);
    ...

    ScopedUtfChars class_name(env, javaName);
    ...
    //將com.xx.xx轉(zhuǎn)換為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第一個關(guān)鍵步驟是將Java層傳入的mCookie變量轉(zhuǎn)換為Native的vector類型的dex文件列表
  2. 在Native層,每個dex文件有一個對應(yīng)的DexCache結(jié)構(gòu)拐云,該結(jié)構(gòu)緩存了dex文件中一些基本的信息
  3. 遍歷dex文件列表時,首先從dex文件中獲取ClassDef結(jié)構(gòu)近她,之后再根據(jù)這個ClassDef來加載相應(yīng)的類

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_);
      //查找是由已經(jīng)有對應(yīng)的dex_cache叉瘩,有則直接返回
      mirror::DexCache* dex_cache = FindDexCacheLocked(self, dex_file, true);
      if (dex_cache != nullptr) {
          return dex_cache;
      }
  }
  //獲取ClassLoader對應(yīng)的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創(chuàng)建一個dex_cache結(jié)構(gòu),此時不要持有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結(jié)構(gòu)失敗薇缅,則一定是發(fā)生了OOM
      if (h_dex_cache.Get() == nullptr) {
        self->AssertPendingOOMException();
        return nullptr;
      }
      //根據(jù)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還未初始化完成,且要加載的正好是幾個指定的系統(tǒng)類晌端,將kclass指向系統(tǒng)類
    ...

    if (klass.Get() == nullptr) {
        //創(chuàng)建Class對象
        klass.Assign(AllocClass(self, SizeOfClassWithoutEmbeddedTables(dex_file, dex_class_def)));
    }

    ...
    //獲取dex_cache結(jié)構(gòu)捅暴,如果未獲取到則創(chuàng)建
    mirror::DexCache* dex_cache = RegisterDexFile(dex_file, class_loader.Get());
    if (dex_cache == nullptr) {
        self->AssertPendingOOMException();
        return nullptr;
    }
    klass->SetDexCache(dex_cache);
    //設(shè)置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) {
        //如果插入失敗,則表明類已經(jīng)被加載過
        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中的關(guān)鍵步驟可以總結(jié)為: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對象設(shè)置基本屬性如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()獲取相應(yīng)ClassDef結(jié)構(gòu)在dex文件內(nèi)的索引號,這個索引號是在之前的
        //SetupClass()函數(shù)中獲取并設(shè)置
        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文件內(nèi)部獲取ClassData結(jié)構(gòu)
  2. 根據(jù)ClassDef的索引位置獲取相應(yīng)OatClass結(jié)構(gòu)演痒,通過OatClass結(jié)構(gòu)可以獲取類方法的本地機器指令
  3. 如果找到OatClass則根據(jù)OatClass來加載類成員

dex文件中每一個類在oat文件中都由一個對應(yīng)的OatClass結(jié)構(gòu)亲轨,根據(jù)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__);
      //加載靜態(tài)屬性
      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);
          //將方法同對應(yīng)的本地機器指令關(guān)聯(lián)惦蚊,這樣在方法執(zhí)行時就可以知道該如何執(zhí)行, [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. 首先便是設(shè)置當前線程在沒有完成加載類成員工作之前不能被掛起
  2. 之后依次加載Static Field器虾,Instance Field,所有Field都用ArtField表示
  3. 加載完Field后,再依次加載Direct Method和Virtual Method并關(guān)聯(lián)Method對應(yīng)的機器指令蹦锋,所有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結(jié)構(gòu)種獲取對應(yīng)Method的索引
    uint32_t dex_method_idx = it.GetMemberIndex();
    //獲取MethodId結(jié)構(gòu)
    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枚舉類不設(shè)置finalizable,因為枚舉類已經(jīng)聲明了一個final finalize()
                if (strcmp(klass_descriptor, "Ljava/lang/Object;") != 0 &&
                    strcmp(klass_descriptor, "Ljava/lang/Enum;") != 0) {
                  klass->SetFinalizable();
                }
            }
        }
    } else if (method_name[0] == '<') {
        //判斷是不是實例化構(gòu)造函數(shù)
        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中獲取對應(yīng)的OatMethod,OatMethod中記錄了方法的本地機器指令的偏移地址
        //通過OatMethod::LinkMethod將OatMethod中記錄的信息設(shè)置到ArtMethod當中
        const OatFile::OatMethod oat_method = oat_class->GetOatMethod(class_def_method_index);
        oat_method.LinkMethod(method);
    }

    //之后設(shè)置方法執(zhí)行的entry point
    //判斷是否需要解釋執(zhí)行:
    //1.當沒有本地機器指令
    //2.Runtime指定以Interpreter方式運行且方法不是native同時也不是proxy
    //JNI方法是沒有對應(yīng)的DEX字節(jié)碼的葛圃,因此即使ART虛擬機運行在解釋模式中,JNI方法也不能通過解釋器來執(zhí)行
    bool enter_interpreter = NeedsInterpreter(method, method->GetEntryPointFromQuickCompiledCode());
    if (enter_interpreter && !method->IsNative()) {
        method->SetEntryPointFromInterpreter(artInterpreterToInterpreterBridge);
    } else {
        //有兩種情況會進入這一分支
        //不需要解釋執(zhí)行的方法
        //沒有本地機器指令或者Runtime以Interpreter方式運行憎妙,但該方法是native
        method->SetEntryPointFromInterpreter(artInterpreterToCompiledCodeBridge);
    }

    if (method->IsAbstract()) {
        //抽象方法沒有機器指令库正,當有機器指令的方法調(diào)用抽象方法時,需要設(shè)置一個橋接函數(shù)厘唾,從而轉(zhuǎn)到
        //解釋器褥符,由解釋器解釋執(zhí)行抽象方法
        method->SetEntryPointFromQuickCompiledCode(GetQuickToInterpreterBridge());
        return;
    }

    if (method->IsStatic() && !method->IsConstructor()) {
        method->SetEntryPointFromQuickCompiledCode(GetQuickResolutionStub());
    } else if (enter_interpreter) {
        if (!method->IsNative()) {
            method->SetEntryPointFromQuickCompiledCode(GetQuickToInterpreterBridge());
        } else {
            //只有當native方法沒有本地機器指令時,會執(zhí)行這一分支
            method->SetEntryPointFromQuickCompiledCode(GetQuickGenericJniStub());
        }
    }

    if (method->IsNative()) {
        // Unregistering restores the dlsym lookup stub.
        method->UnregisterNative();

        if (enter_interpreter) {
          //native方法且沒有對應(yīng)的機器指令阅嘶,則該方法如果是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方法主要作用是根據(jù)方法屬性來設(shè)置entry point

  1. 對于需要解釋的方法属瓣,該方法需要由解釋器解釋執(zhí)行,當另一個解釋方法調(diào)用了這個需要解釋執(zhí)行的方法時讯柔,該方法的入口函數(shù)是artInterpreterToInterpreterBridge,從而繼續(xù)在解釋器中解釋執(zhí)行抡蛙;如果當前方法是執(zhí)行本地機器指令,當另一個解釋執(zhí)行的方法調(diào)用了這個執(zhí)行本地機器指令的方法魂迄,該方法的入口函數(shù)是artInterpreterToCompiledCodeBridge粗截,artInterpreterToCompiledCodeBridge會去調(diào)用相應(yīng)的機器指令
  2. 抽象方法需要由被子類實現(xiàn),所以抽象類是沒有本地機器指令的捣炬,需要由解釋器解釋執(zhí)行熊昌,當有機器指令的方法調(diào)用抽象方法時, 需要設(shè)置一個橋接函數(shù),從而轉(zhuǎn)到
    解釋器湿酸,由解釋器解釋執(zhí)行抽象方法, 這個橋接函數(shù)是GetQuickToInterpreterBridge()
  3. 對于靜態(tài)非構(gòu)造函數(shù)婿屹,當有執(zhí)行機器指令的方法調(diào)用這類函數(shù)時,入口函數(shù)是GetQuickResolutionStub().因為靜態(tài)方法不需要創(chuàng)建對象便可執(zhí)行推溃,著就有可能出現(xiàn)類還未初始化昂利,方法就要執(zhí)行,所以此時就需要現(xiàn)將類初始化铁坎,再執(zhí)行靜態(tài)方法蜂奸,GetQuickResolutionStub完成的正是這項工作
  4. 對于需要解釋執(zhí)行且不是native的方法,當執(zhí)行本地機器指令的方法調(diào)用該方法時硬萍,入口函數(shù)是GetQuickToInterpreterBridge(),該函數(shù)會轉(zhuǎn)到解釋器扩所,由解釋器執(zhí)行這個需要解釋執(zhí)行的方法;當一個執(zhí)行本地機器指令的方法調(diào)用沒有機器指令的native方法時朴乖,入口函數(shù)是GetQuickGenericJniStub()
  5. 如果一個方法是native方法祖屏,設(shè)置本地方法的入口是通過GetJniDlsymLookupStub獲得的一個Stub

以上內(nèi)容參考老羅的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) {
        //執(zhí)行write barrier從而讓GC知道ClassLoader的ClassTable發(fā)生了改變
        Runtime::Current()->GetHeap()->WriteBarrierEveryFieldOf(class_loader);
    }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末助赞,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子赐劣,更是在濱河造成了極大的恐慌嫉拐,老刑警劉巖哩都,帶你破解...
    沈念sama閱讀 218,036評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件魁兼,死亡現(xiàn)場離奇詭異,居然都是意外死亡漠嵌,警方通過查閱死者的電腦和手機咐汞,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,046評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來儒鹿,“玉大人化撕,你說我怎么就攤上這事≡佳祝” “怎么了植阴?”我有些...
    開封第一講書人閱讀 164,411評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長圾浅。 經(jīng)常有香客問我掠手,道長,這世上最難降的妖魔是什么狸捕? 我笑而不...
    開封第一講書人閱讀 58,622評論 1 293
  • 正文 為了忘掉前任喷鸽,我火速辦了婚禮,結(jié)果婚禮上灸拍,老公的妹妹穿的比我還像新娘做祝。我一直安慰自己,他們只是感情好鸡岗,可當我...
    茶點故事閱讀 67,661評論 6 392
  • 文/花漫 我一把揭開白布混槐。 她就那樣靜靜地躺著,像睡著了一般轩性。 火紅的嫁衣襯著肌膚如雪声登。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,521評論 1 304
  • 那天炮姨,我揣著相機與錄音捌刮,去河邊找鬼。 笑死舒岸,一個胖子當著我的面吹牛绅作,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播蛾派,決...
    沈念sama閱讀 40,288評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼俄认,長吁一口氣:“原來是場噩夢啊……” “哼个少!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起眯杏,我...
    開封第一講書人閱讀 39,200評論 0 276
  • 序言:老撾萬榮一對情侶失蹤夜焦,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后岂贩,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體茫经,經(jīng)...
    沈念sama閱讀 45,644評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,837評論 3 336
  • 正文 我和宋清朗相戀三年萎津,在試婚紗的時候發(fā)現(xiàn)自己被綠了卸伞。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,953評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡锉屈,死狀恐怖荤傲,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情颈渊,我是刑警寧澤遂黍,帶...
    沈念sama閱讀 35,673評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站俊嗽,受9級特大地震影響雾家,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜乌询,卻給世界環(huán)境...
    茶點故事閱讀 41,281評論 3 329
  • 文/蒙蒙 一榜贴、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧妹田,春花似錦唬党、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,889評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至晶衷,卻和暖如春蓝纲,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背晌纫。 一陣腳步聲響...
    開封第一講書人閱讀 33,011評論 1 269
  • 我被黑心中介騙來泰國打工税迷, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人锹漱。 一個月前我還...
    沈念sama閱讀 48,119評論 3 370
  • 正文 我出身青樓箭养,卻偏偏與公主長得像,于是被迫代替她去往敵國和親哥牍。 傳聞我的和親對象是個殘疾皇子毕泌,可洞房花燭夜當晚...
    茶點故事閱讀 44,901評論 2 355

推薦閱讀更多精彩內(nèi)容