zoukankan      html  css  js  c++  java
  • DexClassLoader和PathClassLoader载入Dex流程

        0x00

        在上一篇文章apk安装和优化原理,在最后我们分析了DexClassLoader和PathClassLoader的构造函数的不同。

        PathClassLoader最后调用的是new DexFile(pathFile),而DexClassLoader调用的是DexFile.loadDex(dexPathList[i], outputName, 0)。

        

        0x01

        new DexFile(pathFile)相应的代码位于libcoredalviksrcmainjavadalviksystemDexFile.java。

        public DexFile(String fileName) throws IOException {
            String wantDex = System.getProperty("android.vm.dexfile", "false");
            if (!wantDex.equals("true"))
                throw new UnsupportedOperationException("No dex in this VM");
    
            mCookie = openDexFile(fileName, null, 0);
            mFileName = fileName;
            //System.out.println("DEX FILE cookie is " + mCookie);
        }
        DexFile.loadDex(dexPathList[i], outputName, 0)相应的代码也位于libcoredalviksrcmainjavadalviksystemDexFile.java。

        static public DexFile loadDex(String sourcePathName, String outputPathName,
            int flags) throws IOException {
    
            /*
             * TODO: we may want to cache previously-opened DexFile objects.
             * The cache would be synchronized with close().  This would help
             * us avoid mapping the same DEX more than once when an app
             * decided to open it multiple times.  In practice this may not
             * be a real issue.
             */
            return new DexFile(sourcePathName, outputPathName, flags);
        }
        private DexFile(String sourceName, String outputName, int flags)
            throws IOException {
    
            String wantDex = System.getProperty("android.vm.dexfile", "false");
            if (!wantDex.equals("true"))
                throw new UnsupportedOperationException("No dex in this VM");
    
            mCookie = openDexFile(sourceName, outputName, flags);
            mFileName = sourceName;
            //System.out.println("DEX FILE cookie is " + mCookie);
        }
        我们能够看到事实上两者终于调用的都是openDexFile,仅仅只是DexClassLoader指定了生成优化后的apk路径,而PathClassLoader则不须要,由于在安装阶段已经生成了/data/dalvik-cache/xxx@classes.dex。


        0x02

        我们继续分析openDexFile,这种方法一个JNI方法。

        native private static int openDexFile(String sourceName, String outputName,
            int flags) throws IOException;
       代码位于libcoredalviksrcmainjavadalviksystemDexFile.java。

        相应的native方法位于dalvikvm ativedalvik_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 },
    };
    
        我们看到openDexFile相应的是Dalvik_dalvik_system_DexFile_openDexFile方法。

    static void Dalvik_dalvik_system_DexFile_openDexFile(const u4* args,
        JValue* pResult)
    {
        ......
        if (dvmRawDexFileOpen(sourceName, outputName, &pRawDexFile, false) == 0) {
            LOGV("Opening DEX file '%s' (DEX)
    ", sourceName);
    
            pDexOrJar = (DexOrJar*) malloc(sizeof(DexOrJar));
            pDexOrJar->isDex = true;
            pDexOrJar->pRawDexFile = pRawDexFile;
        } else if (dvmJarFileOpen(sourceName, outputName, &pJarFile, false) == 0) {
            LOGV("Opening DEX file '%s' (Jar)
    ", sourceName);
    
            pDexOrJar = (DexOrJar*) malloc(sizeof(DexOrJar));
            pDexOrJar->isDex = false;
            pDexOrJar->pJarFile = pJarFile;
        } else {
            LOGV("Unable to open DEX file '%s'
    ", sourceName);
            dvmThrowException("Ljava/io/IOException;", "unable to open DEX file");
        }
    
        ......
    
        RETURN_PTR(pDexOrJar);
    }
    
        代码位于dalvikvm ativedalvik_system_DexFile.c。

        这里调用dvmJarFileOpen,代码也位于dalvikvmJarFile.c中。

    int dvmJarFileOpen(const char* fileName, const char* odexOutputName,
        JarFile** ppJarFile, bool isBootstrap)
    {
        ZipArchive archive;
        DvmDex* pDvmDex = NULL;
        char* cachedName = NULL;
        bool archiveOpen = false;
        bool locked = false;
        int fd = -1;
        int result = -1;
    
        /* Even if we're not going to look at the archive, we need to
         * open it so we can stuff it into ppJarFile.
         */
        if (dexZipOpenArchive(fileName, &archive) != 0)
            goto bail;
        archiveOpen = true;
    
        /* If we fork/exec into dexopt, don't let it inherit the archive's fd.
         */
        dvmSetCloseOnExec(dexZipGetArchiveFd(&archive));
    
        /* First, look for a ".odex" alongside the jar file.  It will
         * have the same name/path except for the extension.
         */
        fd = openAlternateSuffix(fileName, "odex", O_RDONLY, &cachedName);
        if (fd >= 0) {
           .......
        } else {
            ZipEntry entry;
    
    tryArchive:
            /*
             * Pre-created .odex absent or stale.  Look inside the jar for a
             * "classes.dex".
             */
            entry = dexZipFindEntry(&archive, kDexInJarName);
            if (entry != NULL) {
                bool newFile = false;
    
                /*
                 * We've found the one we want.  See if there's an up-to-date copy
                 * in the cache.
                 *
                 * On return, "fd" will be seeked just past the "opt" header.
                 *
                 * If a stale .odex file is present and classes.dex exists in
                 * the archive, this will *not* return an fd pointing to the
                 * .odex file; the fd will point into dalvik-cache like any
                 * other jar.
                 */
                if (odexOutputName == NULL) {
                    cachedName = dexOptGenerateCacheFileName(fileName,
                                    kDexInJarName);
                    if (cachedName == NULL)
                        goto bail;
                } else {
                    cachedName = strdup(odexOutputName);
                }
                LOGV("dvmDexCacheStatus: Checking cache for %s (%s)
    ",
                    fileName, cachedName);
                fd = dvmOpenCachedDexFile(fileName, cachedName,
                        dexGetZipEntryModTime(&archive, entry),
                        dexGetZipEntryCrc32(&archive, entry),
                        isBootstrap, &newFile, /*createIfMissing=*/true);
                if (fd < 0) {
                    LOGI("Unable to open or create cache for %s (%s)
    ",
                        fileName, cachedName);
                    goto bail;
                }
                locked = true;
    
                /*
                 * If fd points to a new file (because there was no cached version,
                 * or the cached version was stale), generate the optimized DEX.
                 * The file descriptor returned is still locked, and is positioned
                 * just past the optimization header.
                 */
                if (newFile) {
                    u8 startWhen, extractWhen, endWhen;
                    bool result;
                    off_t dexOffset;
    
                    dexOffset = lseek(fd, 0, SEEK_CUR);
                    result = (dexOffset > 0);
    
                    if (result) {
                        startWhen = dvmGetRelativeTimeUsec();
                        result = dexZipExtractEntryToFile(&archive, entry, fd) == 0;
                        extractWhen = dvmGetRelativeTimeUsec();
                    }
                    if (result) {
                        result = dvmOptimizeDexFile(fd, dexOffset,
                                    dexGetZipEntryUncompLen(&archive, entry),
                                    fileName,
                                    dexGetZipEntryModTime(&archive, entry),
                                    dexGetZipEntryCrc32(&archive, entry),
                                    isBootstrap);
                    }
    
                    if (!result) {
                        LOGE("Unable to extract+optimize DEX from '%s'
    ",
                            fileName);
                        goto bail;
                    }
    
                    endWhen = dvmGetRelativeTimeUsec();
                    LOGD("DEX prep '%s': unzip in %dms, rewrite %dms
    ",
                        fileName,
                        (int) (extractWhen - startWhen) / 1000,
                        (int) (endWhen - extractWhen) / 1000);
                }
            } else {
               ......
            }
        }
    
        /*
         * Map the cached version.  This immediately rewinds the fd, so it
         * doesn't have to be seeked anywhere in particular.
         */
        if (dvmDexFileOpenFromFd(fd, &pDvmDex) != 0) {
            LOGI("Unable to map %s in %s
    ", kDexInJarName, fileName);
            goto bail;
        }
        ......
        LOGV("Successfully opened '%s' in '%s'
    ", kDexInJarName, fileName);
    
        *ppJarFile = (JarFile*) calloc(1, sizeof(JarFile));
        (*ppJarFile)->archive = archive;
        (*ppJarFile)->cacheFileName = cachedName;
        (*ppJarFile)->pDvmDex = pDvmDex;
        cachedName = NULL;      // don't free it below
        result = 0;
    
    bail:
        ......
        return result;
    }
    
        我们主要关注dvmOpenCachedDexFile方法。首先调用这种方法,尝试依据cachedName所指的优化文件名称在cache中查找并读取优化文件,假设没有。则要就对Dex进行优化。我们前面说过对于PathClassLoader,在安装阶段已经生成了/data/dalvik-cache/xxx@classes.dex,所以dvmOpenCachedDexFile方法返回的newFile为false。而对于DexClassLoader已经指明了要生成优化后的dex的路径。这里dvmOpenCachedDexFile方法返回的newFile为true。

        对于PathClassLoader。newFile为false。所以不须要再一次优化dex。而对于DexClassLoader,newFile为true。所以调用dvmOptimizeDexFile来优化dex。dvmOptimizeDexFile代码位于           dalvikvmanalysisDexPrepare.c。也就是说对于DexClassLoader也仅仅优化一次。第二次就不会再优化了。优化还是比較耗时的。

    bool dvmOptimizeDexFile(int fd, off_t dexOffset, long dexLength,
        const char* fileName, u4 modWhen, u4 crc, bool isBootstrap)
    {
        ......
        pid = fork();
        if (pid == 0) {
            static const char* kDexOptBin = "/bin/dexopt";
            ......
            androidRoot = getenv("ANDROID_ROOT");
            if (androidRoot == NULL) {
                LOGW("ANDROID_ROOT not set, defaulting to /system
    ");
                androidRoot = "/system";
            }
            execFile = malloc(strlen(androidRoot) + strlen(kDexOptBin) + 1);
            strcpy(execFile, androidRoot);
            strcat(execFile, kDexOptBin);
    
    		.....
            if (kUseValgrind)
                execv(kValgrinder, argv);
            else
                execv(execFile, argv);
    
            LOGE("execv '%s'%s failed: %s
    ", execFile,
                kUseValgrind ? " [valgrind]" : "", strerror(errno));
            exit(1);
        } else {
            ......
        }
    }
    
        也是fork出一个子线程去运行/system/bin/dexopt。也就是OptMain.c中的main方法,往后的运行流程请參考apk安装和优化原理一文。

    简单的脱壳程序就在dvmDexFileOpenPartial下断点,參考使用IDA Pro进行简单的脱壳。DexClassLoader载入dex首先要进行优化。优化的过程中会调用dvmDexFileOpenPartial。而dvmDexFileOpenPartial的dexAddr是dex在内存的基地址。dexLength是dex在内存中长度,具体请參考apk安装和优化原理一文。这样就能够在内存中把dex dump出来。



        我们回到dvmJarFileOpen,继续运行dvmDexFileOpenFromFd,代码位于dalvikvmDvmDex.c。

    int dvmDexFileOpenFromFd(int fd, DvmDex** ppDvmDex)
    {
        DvmDex* pDvmDex;
        DexFile* pDexFile;
        MemMapping memMap;
        int parseFlags = kDexParseDefault;
        int result = -1;
    
        if (gDvm.verifyDexChecksum)
            parseFlags |= kDexParseVerifyChecksum;
    
        if (lseek(fd, 0, SEEK_SET) < 0) {
            LOGE("lseek rewind failed
    ");
            goto bail;
        }
    
        if (sysMapFileInShmemWritableReadOnly(fd, &memMap) != 0) {
            LOGE("Unable to map file
    ");
            goto bail;
        }
    
        pDexFile = dexFileParse(memMap.addr, memMap.length, parseFlags);
        if (pDexFile == NULL) {
            LOGE("DEX parse failed
    ");
            sysReleaseShmem(&memMap);
            goto bail;
        }
    
        pDvmDex = allocateAuxStructures(pDexFile);
        if (pDvmDex == NULL) {
            dexFileFree(pDexFile);
            sysReleaseShmem(&memMap);
            goto bail;
        }
    
        /* tuck this into the DexFile so it gets released later */
        sysCopyMap(&pDvmDex->memMap, &memMap);
        *ppDvmDex = pDvmDex;
        result = 0;
    
    bail:
        return result;
    }
        fd为优化后的dex。对于PathClassLoader,位于/data/dalvik-cache/xxx@classes.dex。

    对于DexClassLoader。就是在new DexClassLoader(String dexPath, String dexOutputDir, String libPath, ClassLoader parent)指定的dexOutputDir路径中。

        在dvmDexFileOpenFromFd方法中首先调用sysMapFileInShmemWritableReadOnly方法把优化后的dex载入进内存。

    int sysMapFileInShmemWritableReadOnly(int fd, MemMapping* pMap)
    {
    #ifdef HAVE_POSIX_FILEMAP
        off_t start;
        size_t length;
        void* memPtr;
    
        assert(pMap != NULL);
    
        if (getFileStartAndLength(fd, &start, &length) < 0)
            return -1;
    
        memPtr = mmap(NULL, length, PROT_READ | PROT_WRITE, MAP_FILE | MAP_PRIVATE,
                fd, start);
        if (memPtr == MAP_FAILED) {
            LOGW("mmap(%d, R/W, FILE|PRIVATE, %d, %d) failed: %s
    ", (int) length,
                fd, (int) start, strerror(errno));
            return -1;
        }
        if (mprotect(memPtr, length, PROT_READ) < 0) {
            /* this fails with EACCESS on FAT filesystems, e.g. /sdcard */
            int err = errno;
            LOGV("mprotect(%p, %d, PROT_READ) failed: %s
    ",
                memPtr, length, strerror(err));
            LOGD("mprotect(RO) failed (%d), file will remain read-write
    ", err);
        }
    
        pMap->baseAddr = pMap->addr = memPtr;
        pMap->baseLength = pMap->length = length;
    
        return 0;
    #else
        return sysFakeMapFile(fd, pMap);
    #endif
    }
    
        代码位于dalvik/libdex/SysUtil.c。
        MemMapping结构体pMap中baseAddr和addr都指向dex映射到内存的首地址。


        返回到dvmDexFileOpenFromFd,继续运行dexFileParse。代码位于dalviklibdexDexFile.c。

    DexFile* dexFileParse(const u1* data, size_t length, int flags)
    {
        DexFile* pDexFile = NULL;
        const DexHeader* pHeader;
        const u1* magic;
        int result = -1;
    
        if (length < sizeof(DexHeader)) {
            LOGE("too short to be a valid .dex
    ");
            goto bail;      /* bad file format */
        }
    
        pDexFile = (DexFile*) malloc(sizeof(DexFile));
        if (pDexFile == NULL)
            goto bail;      /* alloc failure */
        memset(pDexFile, 0, sizeof(DexFile));
    
        /*
         * Peel off the optimized header.
         */
        if (memcmp(data, DEX_OPT_MAGIC, 4) == 0) {
            magic = data;
            if (memcmp(magic+4, DEX_OPT_MAGIC_VERS, 4) != 0) {
                LOGE("bad opt version (0x%02x %02x %02x %02x)
    ",
                     magic[4], magic[5], magic[6], magic[7]);
                goto bail;
            }
    
            pDexFile->pOptHeader = (const DexOptHeader*) data;
            LOGV("Good opt header, DEX offset is %d, flags=0x%02x
    ",
                pDexFile->pOptHeader->dexOffset, pDexFile->pOptHeader->flags);
    
            /* parse the optimized dex file tables */
            if (!dexParseOptData(data, length, pDexFile))
                goto bail;
    		data += pDexFile->pOptHeader->dexOffset;
            length -= pDexFile->pOptHeader->dexOffset;
            ......
        }
    
        dexFileSetupBasicPointers(pDexFile, data);
        pHeader = pDexFile->pHeader;
    
        ......
        result = 0;
    
    bail:
        if (result != 0 && pDexFile != NULL) {
            dexFileFree(pDexFile);
            pDexFile = NULL;
        }
        return pDexFile;
    }

        这种方法主要是生成DexFile结构,我们首先来看DexFile结构是什么样子的?

    typedef struct DexFile {
        /* directly-mapped "opt" header */
        const DexOptHeader* pOptHeader;
    
        /* pointers to directly-mapped structs and arrays in base DEX */
        const DexHeader*    pHeader;
        const DexStringId*  pStringIds;
        const DexTypeId*    pTypeIds;
        const DexFieldId*   pFieldIds;
        const DexMethodId*  pMethodIds;
        const DexProtoId*   pProtoIds;
        const DexClassDef*  pClassDefs;
        const DexLink*      pLinkData;
    
        /*
         * These are mapped out of the "auxillary" section, and may not be
         * included in the file.
         */
        const DexClassLookup* pClassLookup;
        const void*         pRegisterMapPool;       // RegisterMapClassPool
    
        /* points to start of DEX file data */
        const u1*           baseAddr;
    
        /* track memory overhead for auxillary structures */
        int                 overhead;
    
        /* additional app-specific data structures associated with the DEX */
        //void*               auxData;
    } DexFile;
        代码位于dalviklibdexDexFile.h中。

        dexFileParse这种方法首先为pDexFile->pOptHeader赋值,将优化文件头部与DexFile数据结构下的pOptHeader变量进行关联。

        然后调用dexParseOptData函数对优化数据进行处理,其作用也是将各个优化数据与DexFile数据结构中的相应成员变量进行关联。这里关联的是pClassLookup和pRegisterMapPool。

        最后调用dexFileSetupBasicPointers将Dex文件里其它各部分数据与DexFile数据结构建立完整的映射关系。代码位于dalviklibdexDexFile.c。

    void dexFileSetupBasicPointers(DexFile* pDexFile, const u1* data) {
        DexHeader *pHeader = (DexHeader*) data;
    
        pDexFile->baseAddr = data;
        pDexFile->pHeader = pHeader;
        pDexFile->pStringIds = (const DexStringId*) (data + pHeader->stringIdsOff);
        pDexFile->pTypeIds = (const DexTypeId*) (data + pHeader->typeIdsOff);
        pDexFile->pFieldIds = (const DexFieldId*) (data + pHeader->fieldIdsOff);
        pDexFile->pMethodIds = (const DexMethodId*) (data + pHeader->methodIdsOff);
        pDexFile->pProtoIds = (const DexProtoId*) (data + pHeader->protoIdsOff);
        pDexFile->pClassDefs = (const DexClassDef*) (data + pHeader->classDefsOff);
        pDexFile->pLinkData = (const DexLink*) (data + pHeader->linkOff);
    }
        重点说一下baseAddr指向dex文件的头部。



        运行完dexFileParse生成了DexFile结构。返回到dvmDexFileOpenFromFd,继续运行allocateAuxStructures方法来生成DvmDex结构pDvmDex。代码位于dalvikvmDvmDex.c。

    static DvmDex* allocateAuxStructures(DexFile* pDexFile)
    {
        DvmDex* pDvmDex;
        const DexHeader* pHeader;
        u4 stringCount, classCount, methodCount, fieldCount;
    
        pDvmDex = (DvmDex*) calloc(1, sizeof(DvmDex));
        if (pDvmDex == NULL)
            return NULL;
    
        pDvmDex->pDexFile = pDexFile;
        pDvmDex->pHeader = pDexFile->pHeader;
    
        pHeader = pDvmDex->pHeader;
    
        stringCount = pHeader->stringIdsSize;
        classCount = pHeader->typeIdsSize;
        methodCount = pHeader->methodIdsSize;
        fieldCount = pHeader->fieldIdsSize;
    
        pDvmDex->pResStrings = (struct StringObject**)
            calloc(stringCount, sizeof(struct StringObject*));
    
        pDvmDex->pResClasses = (struct ClassObject**)
            calloc(classCount, sizeof(struct ClassObject*));
    
        pDvmDex->pResMethods = (struct Method**)
            calloc(methodCount, sizeof(struct Method*));
    
        pDvmDex->pResFields = (struct Field**)
            calloc(fieldCount, sizeof(struct Field*));
    
        LOGV("+++ DEX %p: allocateAux %d+%d+%d+%d * 4 = %d bytes
    ",
            pDvmDex, stringCount, classCount, methodCount, fieldCount,
            (stringCount + classCount + methodCount + fieldCount) * 4);
    
        pDvmDex->pInterfaceCache = dvmAllocAtomicCache(DEX_INTERFACE_CACHE_SIZE);
    
        if (pDvmDex->pResStrings == NULL ||
            pDvmDex->pResClasses == NULL ||
            pDvmDex->pResMethods == NULL ||
            pDvmDex->pResFields == NULL ||
            pDvmDex->pInterfaceCache == NULL)
        {
            LOGE("Alloc failure in allocateAuxStructures
    ");
            free(pDvmDex->pResStrings);
            free(pDvmDex->pResClasses);
            free(pDvmDex->pResMethods);
            free(pDvmDex->pResFields);
            free(pDvmDex);
            return NULL;
        }
    
        return pDvmDex;
    
    }
    
        然后返回到dvmDexFileOpenFromFd,运行sysCopyMap把DvmDex结构pDvmDex的memMap附上值。最后返回DvmDex结构pDvmDex。
        

        运行完dvmDexFileOpenFromFd,返回到dvmJarFileOpen。生成了一个JarFile结构体ppJarFile,并赋值例如以下:

        *ppJarFile = (JarFile*) calloc(1, sizeof(JarFile));
        (*ppJarFile)->archive = archive;
        (*ppJarFile)->cacheFileName = cachedName;
        (*ppJarFile)->pDvmDex = pDvmDex;
        在返回到Dalvik_dalvik_system_DexFile_openDexFile中。生成一个DexOrJar结构体pDexOrJar。并赋值例如以下:
            pDexOrJar = (DexOrJar*) malloc(sizeof(DexOrJar));
            pDexOrJar->isDex = false;
            pDexOrJar->pJarFile = pJarFile;
        然后RETURN_PTR(pDexOrJar)返回给Java层的openDexFile,并赋值给mCookie。例如以下:

    mCookie = openDexFile(fileName, null, 0);
        下次通过mCookie。我们就能一步一步找到DexFile结构体(DexOrJar->JarFile->DvmDex->DexFile)。

       

        0x03

        最后附上一张DexFile的结构图:



        图中有一处错误,baseAddr和pHeader事实上都指向DexHeader。也就是dex文件头在内存中的虚拟地址。


        0x03

        那么PatchClassLoader对象是什么时候生成的呢?

        在Android加壳原理分析一文中,在handleBindApplication方法里须要获取ClassLoader,这个ClassLoader对象就是PathClassLoader对象。以下来看看是怎么形成的?

    private final void handleBindApplication(AppBindData data) { 
    			......
                try {
                    java.lang.ClassLoader cl = instrContext.getClassLoader();
                    mInstrumentation = (Instrumentation)
                        cl.loadClass(data.instrumentationName.getClassName()).newInstance();
                } catch (Exception e) {
                    throw new RuntimeException(
                        "Unable to instantiate instrumentation "
                        + data.instrumentationName + ": " + e.toString(), e);
                }
    			......
    }
        代码位于frameworksasecorejavaandroidappActivityThread.java。

        instrContext.getClassLoader(),实现例如以下,代码位于frameworksasecorejavaandroidappContextImpl.java。

        @Override
        public ClassLoader getClassLoader() {
            return mPackageInfo != null ?

    mPackageInfo.getClassLoader() : ClassLoader.getSystemClassLoader(); }

        mPackageInfo.getClassLoader()。实现例如以下。代码位于frameworksasecorejavaandroidappLoadedApk.java。

        public ClassLoader getClassLoader() {
            synchronized (this) {
                if (mClassLoader != null) {
                    return mClassLoader;
                }
    
                if (mIncludeCode && !mPackageName.equals("android")) {
                    String zip = mAppDir;
    
                    ......
                    mClassLoader =
                        ApplicationLoaders.getDefault().getClassLoader(
                            zip, mLibDir, mBaseClassLoader);
                    initializeJavaContextClassLoader();
                } else {
                    if (mBaseClassLoader == null) {
                        mClassLoader = ClassLoader.getSystemClassLoader();
                    } else {
                        mClassLoader = mBaseClassLoader;
                    }
                }
                return mClassLoader;
            }
        }
    
        ApplicationLoaders.getDefault().getClassLoader( zip, mLibDir, mBaseClassLoader),实现例如以下,代码位于frameworksasecorejavaandroidappApplicationLoaders.java中。

        public ClassLoader getClassLoader(String zip, String libPath, ClassLoader parent)
        {
            /*
             * This is the parent we use if they pass "null" in.  In theory
             * this should be the "system" class loader; in practice we
             * don't use that and can happily (and more efficiently) use the
             * bootstrap class loader.
             */
            ClassLoader baseParent = ClassLoader.getSystemClassLoader().getParent();
    
            synchronized (mLoaders) {
                if (parent == null) {
                    parent = baseParent;
                }
    
                /*
                 * If we're one step up from the base class loader, find
                 * something in our cache.  Otherwise, we create a whole
                 * new ClassLoader for the zip archive.
                 */
                if (parent == baseParent) {
                    ClassLoader loader = mLoaders.get(zip);
                    if (loader != null) {
                        return loader;
                    }
        
                    PathClassLoader pathClassloader =
                        new PathClassLoader(zip, libPath, parent);
                    
                    mLoaders.put(zip, pathClassloader);
                    return pathClassloader;
                }
    
                return new PathClassLoader(zip, parent);
            }
        }
    
        最后的时候,我们看到了PathClassLoader对象的生成。

  • 相关阅读:
    SQL Server 连接字符串和身份验证
    常用jQuery选择器总结【转】
    javascript深入理解js闭包[转]
    JS鼠标事件大全
    JS 获取各个宽度和高度
    移动设备屏幕缩放
    面向对象学习【类-匿名类】
    Java学习笔记之log4j与commons-logging<转>
    Java数据库连接——JDBC基础知识(操作数据库:增删改查)【转】
    静态方法和非静态方法的区别
  • 原文地址:https://www.cnblogs.com/yfceshi/p/7230522.html
Copyright © 2011-2022 走看看