When an Android application is launched an instance of dalvik.system.PathClassLoader
is created for use as the application’s ClassLoader
.
The dalvik.system.PathClassLoader
constructor is passed a ‘path’ which includes the application’s APK.
1.0 PathClassLoader
Class: dalvik.system.PathClassLoader
Source: $(ANDROID_SRC)/libcore/dalvik/src/main/java/dalvik/system/PathClassLoader.java
1.1 The Constructor
public PathClassLoader(String dexPath, ClassLoader parent)
{
super(dexPath, null, null, parent);
}
The PathClassLoader
constructor simply invokes the constructor of the super class which is BaseDexClassLoader
.
2.0 BaseDexClassLoader
Class: dalvik.system.BaseDexClassLoader
Source: $(ANDROID_SRC)/libcore/libdvm/src/main/java/dalvik/system/BaseDexClassLoader.java
2.1 The Constructor
public BaseDexClassLoader(String dexPath, File optimizedDirectory, String libraryPath, ClassLoader parent)
{
super(parent);
this.pathList = new DexPathList(this, dexPath, libraryPath, optimizedDirectory);
}
The BaseDexClassLoader
constructor creates an instance of DexPathList
which it will use when attempting to load classes.
It passes the DexPathList
constructor itself plus its dexPath
, libraryPath
and optimizedDirectory
arguments.
3.0 DexPathList
Class: dalvik.system.DexPathList
Source: $(ANDROID_SRC)/libcore/libdvm/src/main/java/dalvik/system/DexPathList.java
3.1 The Constructor
public DexPathList(ClassLoader definingContext, String dexPath, String libraryPath, File optimizedDirectory)
The constructor calls the method makeDexElements
to create an array of Element
s.
An Element
represents either a directory, a Dex file, or a ZIP file which was specified in the dexPath
argument.
3.2 makeDexElements
private static Element[] makeDexElements(ArrayList<File> files, File optimizedDirectory)
The method iterates over the elements in the files
argument.
If the name of the File
ends with one of
-
.apk
-
.jar
-
.zip
it invokes the loadDexFile
method passing it the File
and the optimizedDirectory
argument.
3.3 loadDexFile
private static DexFile loadDexFile(File file, File optimizedDirectory)
If the optimizedDirectory
argument is null
then the method creates a DexFile
instance passing the File
argument to the constructor.
4.0 DexFile
Class: dalvik.system.DexFile
Source: $(ANDROID_SRC)/libcore/libdvm/src/main/java/dalvik/system/DexFile.java
Source: $(ANDROID_SRC)/dalvik/vm/native/dalvik_system_DexFile.cpp
4.1 DexFile(File)
public DexFile(File file) throws IOException {
this(file.getPath());
}
4.2 DexFile(String)
public DexFile(String fileName) throws IOException
This constructor calls the method openDexFile
passing it the fileName
argument, null
, and 0
.
4.3 openDexFile
native private static int openDexFile(
String sourceName,
String outputName,
int flags)
throws
IOException;
If the sourceName
argument does not end with the suffix “.dex”, openDexFile
calls the function dvmJarFileOpen
passing it the C++ equivalents of its sourceName
and outputName
arguments plus a pointer to a JarFile*
on the stack and false
.
5.0 JarFile
Source: $(ANDROID_SRC)/dalvik/vm/JarFile.cpp
5.1 dvmJarFileOpen
int dvmJarFileOpen(const char* fileName, const char* odexOutputName, JarFile** ppJarFile, bool isBootstrap)
The function starts by calling the function dexZipOpenArchive
to open the named file.
If this is successful it then calls the function dexZipFindEntry
to find the classes.dex
file within the ZIP file.
6.0 ZipArchive
Source: $(ANDROID_SRC)/dalvik/libdex/ZipArchive.cpp
6.1 dexZipOpenArchive
int dexZipOpenArchive(const char* fileName, ZipArchive* pArchive)
The function attempts to open the named file using the open
system call.
If this is successful it then calls dexZipPrepArchive
passing it the file descriptor returned by the call to open
and the fileName
and pArchive
arguments.
6.2 dexZipPrepArchive
int dexZipPrepArchive(int fd, const char* debugFileName, ZipArchive* pArchive)
The function dexZipPrepArchive starts by mapping the Central Directory of the ZIP file into memory using the function mapCentralDirectory
.
It this is successful it then calls parseZipArchive
6.2 parseZipArchive
static int parseZipArchive(ZipArchive* pArchive)
The parseZipArchive
function begins by creating a linear hash table.
It then iterates over the File Headers in the Central Directory.
For each File Header it calls the function addtoHash
to create an entry in the linear hash table using the file name from the file header as the key.
The entry allocated within the linear hash table contains the address of the file name field within the File Header and the length of the file name.
Given the address of the file name field it is possible to determine the address of the File Header itself within the Central Directory.
6.4 addToHash
static void addToHash(ZipArchive* pArchive, const char* str, int strLen, unsigned int hash)
{
const int hashTableSize = pArchive->mHashTableSize;
int ent = hash & (hashTableSize - 1);
/*
* We over-allocated the table, so we're guaranteed to find an empty slot.
*/
while (pArchive->mHashTable[ent].name != NULL)
ent = (ent + 1) & (hashTableSize-1);
pArchive->mHashTable[ent].name = str;
pArchive->mHashTable[ent].nameLen = strLen;
}
6.5 dexZipFindEntry
ZipEntry dexZipFindEntry(const ZipArchive* pArchive, const char* entryName)
{
int nameLen = strlen(entryName);
unsigned int hash = computeHash(entryName, nameLen);
const int hashTableSize = pArchive->mHashTableSize;
int ent = hash & (hashTableSize-1);
while (pArchive->mHashTable[ent].name != NULL) {
if (pArchive->mHashTable[ent].nameLen == nameLen &&
memcmp(pArchive->mHashTable[ent].name, entryName, nameLen) == 0)
{
/* match */
return (ZipEntry)(long)(ent + kZipEntryAdj);
}
ent = (ent + 1) & (hashTableSize-1);
}
return NULL;
}
Copyright (c) 2013 By Simon Lewis. All Rights Reserved.
Unauthorized use and/or duplication of this material without express and written permission from this blog’s author and owner Simon Lewis is strictly prohibited.
Excerpts and links may be used, provided that full and clear credit is given to Simon Lewis and justanapplication.wordpress.com with appropriate and specific direction to the original content.