BaseDexClassLoader加载类流程源码阅读

news/2024/10/31 1:34:39/

安卓10

类图

在这里插入图片描述
双亲委派机制

Java层

BaseDexClassLoader 没有loadClass实现,继承的是 ClassLoader 实现

路径 libcore\ojluni\src\main\java\java\lang\ClassLoader.java

    protected Class<?> loadClass(String name, boolean resolve)throws ClassNotFoundException{// First, check if the class has already been loadedClass<?> c = findLoadedClass(name);if (c == null) {try {if (parent != null) {c = parent.loadClass(name, false);} else {c = findBootstrapClassOrNull(name);}} catch (ClassNotFoundException e) {// ClassNotFoundException thrown if class not found// from the non-null parent class loader}if (c == null) {// If still not found, then invoke findClass in order// to find the class.c = findClass(name);}}return c;}

libcore\dalvik\src\main\java\dalvik\system\BaseDexClassLoader.java
调用自身findClass

protected Class<?> findClass(String name) throws ClassNotFoundException {// First, check whether the class is present in our shared libraries.if (sharedLibraryLoaders != null) {for (ClassLoader loader : sharedLibraryLoaders) {try {return loader.loadClass(name);} catch (ClassNotFoundException ignored) {}}}// Check whether the class in question is present in the dexPath that// this classloader operates on.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;
}

libcore\dalvik\src\main\java\dalvik\system\DexPathList.java

/*** Finds the named class in one of the dex files pointed at by* this instance. This will find the one in the earliest listed* path element. If the class is found but has not yet been* defined, then this method will define it in the defining* context that this instance was constructed with.** @param name of class to find* @param suppressed exceptions encountered whilst finding the class* @return the named class or {@code null} if the class is not* found in any of the dex files*/
public Class<?> findClass(String name, List<Throwable> suppressed) {for (Element element : dexElements) {Class<?> clazz = element.findClass(name, definingContext, suppressed);if (clazz != null) {return clazz;}}if (dexElementsSuppressedExceptions != null) {suppressed.addAll(Arrays.asList(dexElementsSuppressedExceptions));}return null;
}//静态内部类 element 的findClasspublic Class<?> findClass(String name, ClassLoader definingContext,List<Throwable> suppressed) {return dexFile != null ? dexFile.loadClassBinaryName(name, definingContext, suppressed): null;}

libcore\dalvik\src\main\java\dalvik\system\DexFile.java

    public Class loadClassBinaryName(String name, ClassLoader loader, List<Throwable> suppressed) {return defineClass(name, loader, mCookie, this, suppressed);}private static Class defineClass(String name, ClassLoader loader, Object cookie,DexFile dexFile, List<Throwable> suppressed) {Class result = null;try {result = defineClassNative(name, loader, cookie, dexFile);} 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,DexFile dexFile)throws ClassNotFoundException, NoClassDefFoundError;

native层

art\runtime\native\dalvik_system_DexFile.cc

ClassLinker::DefineClass
—>ClassLinker::LoadClass 脱壳点

static jclass DexFile_defineClassNative(JNIEnv* env,jclass,jstring javaName,jobject javaLoader,jobject cookie,jobject dexFile) {const std::string descriptor(DotToDescriptor(class_name.c_str()));const size_t hash(ComputeModifiedUtf8Hash(descriptor.c_str()));for (auto& dex_file : dex_files) {const dex::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());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
DefineClass 可以重点看
在这里插入图片描述

ObjPtr<mirror::Class> ClassLinker::DefineClass(Thread* self,const char* descriptor,size_t hash,Handle<mirror::ClassLoader> class_loader,const DexFile& dex_file,const dex::ClassDef& dex_class_def) {SetupClass(*new_dex_file, *new_class_def, klass, class_loader.Get());// Add the newly loaded class to the loaded classes table.ObjPtr<mirror::Class> existing = InsertClass(descriptor, klass.Get(), hash);// 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, ClassStatus::kErrorUnresolved, 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, ClassStatus::kErrorUnresolved, 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, ClassStatus::kErrorUnresolved, self);}return nullptr;}/** 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();
}void ClassLinker::LoadClass(Thread* self,const DexFile& dex_file,const dex::ClassDef& dex_class_def,Handle<mirror::Class> klass) {ClassAccessor accessor(dex_file,dex_class_def,/* parse_hiddenapi_class_data= */ klass->IsBootStrapClassLoaded());if (!accessor.HasClassData()) {return;}Runtime* const runtime = Runtime::Current();{// 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(__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());LengthPrefixedArray<ArtField>* sfields = AllocArtFieldArray(self,allocator,accessor.NumStaticFields());LengthPrefixedArray<ArtField>* ifields = AllocArtFieldArray(self,allocator,accessor.NumInstanceFields());size_t num_sfields = 0u;size_t num_ifields = 0u;uint32_t last_static_field_idx = 0u;uint32_t last_instance_field_idx = 0u;// Methodsbool has_oat_class = false;const OatFile::OatClass oat_class = (runtime->IsStarted() && !runtime->IsAotCompiler())? OatFile::FindOatClass(dex_file, klass->GetDexClassDefIndex(), &has_oat_class): OatFile::OatClass::Invalid();const OatFile::OatClass* oat_class_ptr = has_oat_class ? &oat_class : nullptr;klass->SetMethodsPtr(AllocArtMethodArray(self, allocator, accessor.NumMethods()),accessor.NumDirectMethods(),accessor.NumVirtualMethods());size_t class_def_method_index = 0;uint32_t last_dex_method_index = dex::kDexNoIndex;size_t last_class_def_method_index = 0;// Use the visitor since the ranged based loops are bit slower from seeking. Seeking to the// methods needs to decode all of the fields.accessor.VisitFieldsAndMethods([&](const ClassAccessor::Field& field) REQUIRES_SHARED(Locks::mutator_lock_) {uint32_t field_idx = field.GetIndex();DCHECK_GE(field_idx, last_static_field_idx);  // Ordering enforced by DexFileVerifier.if (num_sfields == 0 || LIKELY(field_idx > last_static_field_idx)) {LoadField(field, klass, &sfields->At(num_sfields));++num_sfields;last_static_field_idx = field_idx;}}, [&](const ClassAccessor::Field& field) REQUIRES_SHARED(Locks::mutator_lock_) {uint32_t field_idx = field.GetIndex();DCHECK_GE(field_idx, last_instance_field_idx);  // Ordering enforced by DexFileVerifier.if (num_ifields == 0 || LIKELY(field_idx > last_instance_field_idx)) {LoadField(field, klass, &ifields->At(num_ifields));++num_ifields;last_instance_field_idx = field_idx;}}, [&](const ClassAccessor::Method& method) REQUIRES_SHARED(Locks::mutator_lock_) {ArtMethod* art_method = klass->GetDirectMethodUnchecked(class_def_method_index,image_pointer_size_);LoadMethod(dex_file, method, klass, art_method);LinkCode(this, art_method, oat_class_ptr, class_def_method_index);uint32_t it_method_index = method.GetIndex();if (last_dex_method_index == it_method_index) {// duplicate caseart_method->SetMethodIndex(last_class_def_method_index);} else {art_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;}, [&](const ClassAccessor::Method& method) REQUIRES_SHARED(Locks::mutator_lock_) {ArtMethod* art_method = klass->GetVirtualMethodUnchecked(class_def_method_index - accessor.NumDirectMethods(),image_pointer_size_);LoadMethod(dex_file, method, klass, art_method);LinkCode(this, art_method, oat_class_ptr, class_def_method_index);++class_def_method_index;});if (UNLIKELY(num_ifields + num_sfields != accessor.NumFields())) {LOG(WARNING) << "Duplicate fields in class " << klass->PrettyDescriptor()<< " (unique static fields: " << num_sfields << "/" << accessor.NumStaticFields()<< ", unique instance fields: " << num_ifields << "/" << accessor.NumInstanceFields()<< ")";// NOTE: Not shrinking the over-allocated sfields/ifields, just setting size.if (sfields != nullptr) {sfields->SetSize(num_sfields);}if (ifields != nullptr) {ifields->SetSize(num_ifields);}}// Set the field arrays.klass->SetSFieldsPtr(sfields);DCHECK_EQ(klass->NumStaticFields(), num_sfields);klass->SetIFieldsPtr(ifields);DCHECK_EQ(klass->NumInstanceFields(), num_ifields);}// Ensure that the card is marked so that remembered sets pick up native roots.WriteBarrier::ForEveryFieldWrite(klass.Get());self->AllowThreadSuspension();
}

参考

Android类加载流程分析
脱壳(一代壳)原理&脱壳相关概念详解


http://www.ppmy.cn/news/907142.html

相关文章

unity GUI按钮点击开关面板文本

gui一般格式 1画布canvas 2面板panel 3 按钮button 4文本text 2面板panel 3按钮button 4文本text 2面板panel 3文本text playmaker ugui插件 playmaker-addons-Ecosystem uGuiProxyFull

html 开关按钮 js代码,JavaScript实现开关等效果

废话不多说了&#xff0c;直接给大家贴代码了&#xff0c;具体代码如下所示&#xff1a;开关灯 html, body { margin: 0px; padding: 0px; width: 100%; height: 100%; cursor: pointer; background-color: white; } var oBody document.getElementById("bodyEle");…

手把手带你制作WIFI智能开关.走进物联网-ESP8266学习日记(三)

上一次我们初步认识了SDK编程和透传&#xff0c;给模组更新FW。 这一次我们直接用一个开源平台实现我们最终的目的&#xff0c;用一个APP远程控制模组开关。 我们使用的平台是机智云提供的开发平台。 开始之前我们先把硬件搭建起来&#xff0c;大概规划一下成品的样子 电路规划…

新发现Homekit智能触摸面板开关

一款Homekit直连的智能触摸面板开关&#xff0c;支持Homekit直连和绑定智能音箱使用&#xff0c;有美规和欧规款式&#xff0c;欧规可搭配86盒使用&#xff0c;可根据需要选择1/2/3键&#xff0c;绑定设备后轻松控制家里的电器设备&#xff0c;智能开关&#xff0c;当前外观上主…

开关电源PCB布局与EMC关系

一. 开关电源PCB设计之准备事项 1、外观结构尺寸&#xff0c;包括定位孔&#xff0c;风道流向&#xff0c;输入输出插座&#xff0c;需要与客户系统匹配&#xff0c;还需要与客户沟通装配上的问题&#xff0c;限高等。 2、安规认证&#xff0c;产品做哪种认证&#xff0c;哪些…

Bootstrap组件——折叠面板

折叠面板 一、折叠面板1.基础2.多个目标3.手风琴4.方法与事件 一、折叠面板 Bootstrap折叠板插件允许你在网页中用一点点JavaScript以及CSS类切换内容&#xff0c;控制内容的可见性。它是一个灵活的插件&#xff0c;使用少量的类&#xff08;来自必需的过渡插件&#xff09;&a…

python+opencv判断开关或按钮的状态

pythonopencv判断开关或按钮的状态 前言&#xff1a; 前期我们说过移动端定位问题&#xff08;使用adb 坐标&#xff0c;使用uiautomator2&#xff0c;opencv获取坐标的方法&#xff09;今天我们讲一下关于判断一个开关或者按键的状态。做个移动端的都会多少遇到开关或者按键无…