art\runtime\native\dalvik_system_DexFile.cc::DexFile_defineClassNative检查dex是否加载 , 类名是否合理 , 并遍历DexFile对象 , 查找Dex文件中的类的定义 , 找到就去调用ClassLinker::DefineClass函数 。
static jclass DexFile_defineClassNative(JNIEnv* env,jclass,jstring javaName,jobject javaLoader,jobject cookie,jobject dexFile) {std::vector<const DexFile*> dex_files;const OatFile* oat_file;if (!ConvertJavaArrayToDexFiles(env, cookie, /*out*/ dex_files, /*out*/ oat_file)) {VLOG(class_linker) << "Failed to find dex_file";DCHECK(env->ExceptionCheck());return nullptr;}ScopedUtfChars class_name(env, javaName);if (class_name.c_str() == nullptr) {VLOG(class_linker) << "Failed to find class_name";return nullptr;}const std::string descriptor(DotToDescriptor(class_name.c_str()));const size_t hash(ComputeModifiedUtf8Hash(descriptor.c_str()));for (auto& dex_file : dex_files) {const DexFile::ClassDef* dex_class_def =OatDexFile::FindClassDef(*dex_file, 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)));ObjPtr<mirror::DexCache> dex_cache =class_linker->RegisterDexFile(*dex_file, class_loader.Get());if (dex_cache == nullptr) {// OOME or InternalError (dexFile already registered with a different class loader).soa.Self()->AssertPendingException();return nullptr;}ObjPtr<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) {VLOG(class_linker) << "DexFile_defineClassNative returning " << result<< " for " << class_name.c_str();return soa.AddLocalReference<jclass>(result);}}}VLOG(class_linker) << "Failed to find dex_class_def " << class_name.c_str();return nullptr;}
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();}
经验总结扩展阅读
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-