DexClassLoader和PathClassLoader类加载机制

本文深入探讨DexClassLoader和PathClassLoader的类加载机制,从loadClass开始,通过分析libcore和dalvik系统源码,揭示如何从Dex文件生成ClassObject对象的过程。
摘要由CSDN通过智能技术生成

    0x00

    在DexClassLoader和PathClassLoader加载Dex流程一文中,我们分析了dex文件如何形成了DexFile结构体。本文中讲解类加载机制,实际上就是生成ClassObject对象。

    我们以DexClassLoader为例,讲解类加载机制,PathClassLoader是一样的。

    我们在加载类时通常会调用loadClass,那么我们就从loadClass来开始分析。

    

    0x01

    DexClassLoader类没有loadClass方法,所以调用的是父类ClassLoader类的loadClass方法,ClassLoader类的loadClass方法位于libcore\luni\src\main\java\java\lang\ClassLoader.java中。

    protected Class<?> loadClass(String className, boolean resolve) throws ClassNotFoundException {
        Class<?> clazz = findLoadedClass(className);

        if (clazz == null) {
            try {
                clazz = parent.loadClass(className, false);
            } catch (ClassNotFoundException e) {
                // Don't want to see this.
            }

            if (clazz == null) {
                clazz = findClass(className);
            }
        }

        return clazz;
    }
    DexClassLoader复写了父类ClassLoader的findClass方法,所以调用子类DexClassLoader类的方法findClass,代码位于libcore\dalvik\src\main\java\dalvik\system\DexClassLoader.java。
    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        if (VERBOSE_DEBUG)
            System.out.println("DexClassLoader " + this
                + ": findClass '" + name + "'");

        int length = mFiles.length;

        for (int i = 0; i < length; i++) {
            if (VERBOSE_DEBUG)
                System.out.println("  Now searching: " + mFiles[i].getPath());

            if (mDexs[i] != null) {
                String slashName = name.replace('.', '/');
                Class clazz = mDexs[i].loadClass(slashName, this);
                if (clazz != null) {
                    if (VERBOSE_DEBUG)
                        System.out.println("    found");
                    return clazz;
                }
            }
        }

        throw new ClassNotFoundException(name + " in loader " + this);
    }
    这里调用的是DexFile类的loadClass方法,代码位于libcore\dalvik\src\main\java\dalvik\system\DexFile.java。

    public Class loadClass(String name, ClassLoader loader) {
        String slashName = name.replace('.', '/');
        return loadClassBinaryName(slashName, loader);
    }
    public Class loadClassBinaryName(String name, ClassLoader loader) {
        return defineClass(name, loader, mCookie,
            null);
            //new ProtectionDomain(name) /*DEBUG ONLY*/);
    }
    defineClass对应的是JNI方法,如下:

native private static Class defineClass(String name, ClassLoader loader,
        int cookie, ProtectionDomain pd);
    还记得 DexClassLoader和PathClassLoade r加载Dex流程一文中,openDexFile也是JNI方法, 对应的native方法位于dalvik\vm\native\dalvik_system_DexFile.c。

const DalvikNativeMethod dvm_dalvik_system_DexFile[] = {
    { "openDexFile",        "(Ljava/lang/String;Ljava/lang/String;I)I",
        Dalvik_dalvik_system_DexFile_openDexFile },
    { "closeDexFile",       "(I)V",
        Dalvik_dalvik_system_DexFile_closeDexFile },
    { "defineClass",        "(Ljava/lang/String;Ljava/lang/ClassLoader;ILjava/security/ProtectionDomain;)Ljava/lang/Class;",
        Dalvik_dalvik_system_DexFile_defineClass },
    { "getClassNameList",   "(I)[Ljava/lang/String;",
        Dalvik_dalvik_system_DexFile_getClassNameList },
    { "isDexOptNeeded",     "(Ljava/lang/String;)Z",
        Dalvik_dalvik_system_DexFile_isDexOptNeeded },
    { NULL, NULL, NULL },
};

    defineClass对应的是Dalvik_dalvik_system_DexFile_defineClass方法。注意defineClass函数传递进来的参数有一个是mCookie,就是在DexClassLoader和PathClassLoader加载Dex流程一文中,openDexFile生成的,利用这个mCookie可以在native层找到openDexFile生成的DexFile结构体。


    0x02

    Dalvik_dalvik_system_DexFile_defineClass代码位于dalvik\vm\native\dalvik_system_DexFile.c

static void Dalvik_dalvik_system_DexFile_defineClass(const u4* args,
    JValue* pResult)
{
    StringObject* nameObj = (StringObject*) args[0];
    Object* loader = (Object*) args[1];
    int cookie = args[2];
    Object* pd = (Object*) args[3];
    ClassObject* clazz = NULL;
    DexOrJar* pDexOrJar = (DexOrJar*) cookie;
    DvmDex* pDvmDex;
    char* name;
    char* descriptor;

    name = dvmCreateCstrFromString(nameObj);
    descriptor = dvmDotToDescriptor(name);
    LOGV("--- Explicit class load '%s' 0x%08x\n", descriptor, cookie);
    free(name);

    if (!validateCookie(cookie))
        RETURN_VOID();

    if (pDexOrJar->isDex)
        pDvmDex = dvmGetRawDexFileDex(pDexOrJar->pRawDexFile);
    else
        pDvmDex = dvmGetJarFileDex(pDexOrJar->pJarFile);

    /* once we load something, we can't unmap the storage */
    pDexOrJar->okayToFree = false;

    clazz = dvmDefineClass(pDvmDex, descriptor, loader);
    ......

    ......

    free(descriptor);
    RETURN_PTR(clazz);
}
    首先通过cookie找到DexOrJar结构体pDexOrJar,然后根据pDexOrJar找到DvmDex结构体pDvmDex。

    下面我们来分析核心函数dvmDefineClass,这个用来生成ClassObject。dvmDefineClass,findClassNoInit 方法都位于dalvik\vm\oo\Class.c。


                
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值