art\runtime\class_linker.cc::DefineClassDefineClass这个函数做了许多工作 , 相当于底层类加载逻辑的分发器,整体逻辑如下图:

文章插图
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);......// Get the real dex file. This will return the input if there aren't any callbacks or they do// nothing.DexFile const* new_dex_file = nullptr;DexFile::ClassDef const* new_class_def = nullptr;// TODO We should ideally figure out some way to move this after we get a lock on the klass so it// will only be called once.Runtime::Current()->GetRuntimeCallbacks()->ClassPreDefine(descriptor,klass,class_loader,dex_file,dex_class_def,&new_dex_file,&new_class_def);// Check to see if an exception happened during runtime callbacks. Return if so.if (self->IsExceptionPending()) {return nullptr;}ObjPtr<mirror::DexCache> dex_cache = RegisterDexFile(*new_dex_file, class_loader.Get());if (dex_cache == nullptr) {self->AssertPendingException();return nullptr;}klass->SetDexCache(dex_cache);SetupClass(*new_dex_file, *new_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<mirror::Class> lock(self, klass);klass->SetClinitThreadId(self->GetTid());// Make sure we have a valid empty iftable even if there are errors.klass->SetIfTable(GetClassRoot(kJavaLangObject)->GetIfTable());// Add the newly loaded class to the loaded classes table.ObjPtr<mirror::Class> existing = InsertClass(descriptor, klass.Get(), hash);if (existing != nullptr) {// 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, *new_dex_file, *new_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::kStatusErrorUnresolved, self);}return nullptr;}// Finish loading (if necessary) by finding parentsCHECK(!klass->IsLoaded());if (!LoadSuperAndInterfaces(klass, *new_dex_file)) {// Loading failed.if (!klass->IsErroneous()) {mirror::Class::SetStatus(klass, mirror::Class::kStatusErrorUnresolved, self);}return nullptr;}CHECK(klass->IsLoaded());// At this point the class is loaded. Publish a ClassLoad event.// Note: this may be a temporary class. It is a listener's responsibility to handle this.Runtime::Current()->GetRuntimeCallbacks()->ClassLoad(klass);// Link the class (if necessary)CHECK(!klass->IsResolved());// TODO: Use fast jobjects?auto interfaces = hs.NewHandle<mirror::ObjectArray<mirror::Class>>(nullptr);MutableHandle<mirror::Class> h_new_class = hs.NewHandle<mirror::Class>(nullptr);if (!LinkClass(self, descriptor, klass, interfaces, &h_new_class)) {// Linking failed.if (!klass->IsErroneous()) {mirror::Class::SetStatus(klass, mirror::Class::kStatusErrorUnresolved, self);}return nullptr;}self->AssertNoPendingException();CHECK(h_new_class != nullptr) << descriptor;CHECK(h_new_class->IsResolved() && !h_new_class->IsErroneousResolved()) << descriptor;// Instrumentation may have updated entrypoints for all methods of all// classes. However it could not update methods of this class while we// were loading it. Now the class is resolved, we can update entrypoints// as required by instrumentation.if (Runtime::Current()->GetInstrumentation()->AreExitStubsInstalled()) {// We must be in the kRunnable state to prevent instrumentation from// suspending all threads to update entrypoints while we are doing it// for this class.DCHECK_EQ(self->GetState(), kRunnable);Runtime::Current()->GetInstrumentation()->InstallStubsForClass(h_new_class.Get());}/** We send CLASS_PREPARE events to the debugger from here.The* definition of "preparation" is creating the static fields for a* class and initializing them to the standard default values, but not* executing any code (that comes later, during "initialization").** We did the static preparation in LinkClass.** The class has been prepared and resolved but possibly not yet verified* at this point.*/Runtime::Current()->GetRuntimeCallbacks()->ClassPrepare(klass, h_new_class);// Notify native debugger of the new class and its layout.jit::Jit::NewTypeLoadedIfUsingJit(h_new_class.Get());return h_new_class.Get();}
推荐阅读
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 静态属性的陷阱 python中类与对象的命名空间、__dict__ 和 dir 在继承中使用说明
- 浅谈 Golang 插件机制
- androidmanifest.xml 反编译
- .net程序员的android studio 初体验 (环境设置2022年10月)
- while.for循环和基本数据类型内置方法
- [CG从零开始] 3. 安装 pyassimp 库加载模型文件
- 15 JavaObject类
- 面向制造企业普适性ERP、MES类产品为什么那么难找?
- C#/VB.NET 读取条码类型及条码在图片中的坐标位置
- 补充部分---ScheduledThreadPoolExecutor类分析 线程池底层原理详解与源码分析