Android源码学习——ClasLoader(3)

xiaoxiao2021-02-28  103

本文学习的源码参考AndroidXRef,版本为Lollipop 5.1.0_r1。


前面我们讲了ClassLoader的构造函数是怎么实现的,现在来看下具体类加载的实现吧。

在Android中,我们使用loadClass方法来加载我们需要的类,但是在PathClassLoader和DexClassLoader,以及他们的父类BaseDexClassLoader中都没有定义loadClass方法,那么最终调用还是父类ClassLoader中的loadClass方法。

public Class<?> loadClass(String className) throws ClassNotFoundException { return loadClass(className, false); } protected Class<?> loadClass(String className, boolean resolve) throws ClassNotFoundException { Class<?> clazz = findLoadedClass(className); if (clazz == null) { ClassNotFoundException suppressed = null; try { clazz = parent.loadClass(className, false); } catch (ClassNotFoundException e) { suppressed = e; } if (clazz == null) { try { clazz = findClass(className); } catch (ClassNotFoundException e) { e.addSuppressed(suppressed); throw e; } } } return clazz; }

有两个方法,loadClass(String className)本质上还是调用了loadClass(String className, boolean resolve),那么看下loadClass(String className, boolean resolve)的具体实现。 首先调用findLoadedClass(className)检查该类是否被加载,如果被加载则直接返回对应的Class对象; 没有被加载,则首先去调用parent的loadClass(className, false)方法,让父类去尝试加载这个类; 如果父类加载都失败的话,再去调用findClass(className)加载这个类。

这也即是双亲委派机制。 类加载器在加载一个类之前,会首先去检查自己以及自己以上的类加载器是否已经加载了这个类,如果已经加载过,就会直接将类对象返回;如果自己以上的类加载器都没有加载这个类,该类加载器自身才会去加载相应的类。

这么做的好处是: 1.效率 不会出现类的重复加载问题; 2.安全 已经加载过的类不会再被覆盖。

继续看findClass的实现,BaseDexClassLoader重写了该方法:

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; }

还是调用了DexPathList的findClass方法。

public Class findClass(String name, List<Throwable> suppressed) { 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; }

遍历所有的DexFile实例,然后调用loadClassBinaryName方法一个个尝试能不能加载想要的类。

public Class loadClassBinaryName(String name, ClassLoader loader, List<Throwable> suppressed) { return defineClass(name, loader, mCookie, suppressed); }

这个方法里面调用了defineClass,看下defineClass的实现:

private static Class defineClass(String name, ClassLoader loader, long 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; }

好吧,又调到native函数去了。

static jclass DexFile_defineClassNative(JNIEnv* env, jclass, jstring javaName, jobject javaLoader, jlong cookie) { std::vector<const DexFile*>* dex_files = toDexFiles(cookie, env); if (dex_files == NULL) { VLOG(class_linker) << "Failed to find dex_file"; return NULL; } ScopedUtfChars class_name(env, javaName); if (class_name.c_str() == NULL) { VLOG(class_linker) << "Failed to find class_name"; return NULL; } const std::string descriptor(DotToDescriptor(class_name.c_str())); const size_t hash(ComputeModifiedUtf8Hash(descriptor.c_str())); for (const DexFile* dex_file : *dex_files) { 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(); class_linker->RegisterDexFile(*dex_file); StackHandleScope<1> hs(soa.Self()); Handle<mirror::ClassLoader> class_loader( hs.NewHandle(soa.Decode<mirror::ClassLoader*>(javaLoader))); mirror::Class* result = class_linker->DefineClass(soa.Self(), descriptor.c_str(), hash, class_loader, *dex_file, *dex_class_def); if (result != nullptr) { VLOG(class_linker) << "DexFile_defineClassNative returning " << result; return soa.AddLocalReference<jclass>(result); } } } VLOG(class_linker) << "Failed to find dex_class_def"; return nullptr; }

首先是创建DexFile对象,然后对传入的类名javaName做类型转化赋值给class_name; 然后根据类名获取类描述符DotToDescriptor(class_name.c_str()),函数实现是:

std::string DotToDescriptor(const char* class_name) { std::string descriptor(class_name); std::replace(descriptor.begin(), descriptor.end(), '.', '/'); if (descriptor.length() > 0 && descriptor[0] != '[') { descriptor = "L" + descriptor + ";"; } return descriptor; }

通过ComputeModifiedUtf8Hash(descriptor.c_str())计算该类的hash索引; 遍历所有的dex_file,调用FindClassDef(descriptor.c_str(), hash)去获得这个类的ClassDef; 最后去获取ClassLinker,调用它的RegisterDexFile注册dex_file,并且调用DefineClass完成类的加载。


转载请注明原文地址: https://www.6miu.com/read-66551.html

最新回复(0)