一.Java层调用链
1.1 ActivityThread.performLaunchActivity
一般应用程序的启动都是由点击Launcher上的图标来启动,而点击图标时所执行的操作是startActivity(Intent intent)
,经过一系列复杂的调用链后,最终会初始化Activity实例并回调onCreate
,而执行初始化实例并回调onCreate
的方法是ActivityThread.performLaunchActivity
, 核心代码为:
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
...
Activity activity = null;
try {
//获取ClassLoader同时加载相应的dex文件
//r.packageInfo是LoadApk的实例
java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
//初始化Activity实例
activity = mInstrumentation.newActivity(
cl, component.getClassName(), r.intent);
StrictMode.incrementExpectedActivityCount(activity.getClass());
r.intent.setExtrasClassLoader(cl);
r.intent.prepareToEnterProcess();
if (r.state != null) {
r.state.setClassLoader(cl);
}
} catch (Exception e) {
if (!mInstrumentation.onException(activity, e)) {
throw new RuntimeException(
"Unable to instantiate activity " + component
+ ": " + e.toString(), e);
}
}
...
}
1.2 LoadApk.getClassLoader
public ClassLoader getClassLoader() {
synchronized (this) {
//如果已经加载过dex文件则直接返回ClassLoader
if (mClassLoader != null) {
return mClassLoader;
}
...
//如果还没有加载dex,则初始化相应的ClassLoader并加载dex文件
//mBaseClassLoader = null,在performLaunchActivity中初始化LoadApk的时候设置
mClassLoader = ApplicationLoaders.getDefault().getClassLoader(zip, lib,
mBaseClassLoader);
}
return mClassLoader;
}
1.3 ApplicationLoaders.getClassLoader
public ClassLoader getClassLoader(String zip, String libPath, ClassLoader parent){
//Class.getSystemClassLoader返回的是一个PathClassLoader
//baseParent是BootClassLoader
ClassLoader baseParent = ClassLoader.getSystemClassLoader().getParent();
synchronized (mLoaders) {
if (parent == null) {
parent = baseParent;
}
if (parent == baseParent) {
ClassLoader loader = mLoaders.get(zip);
if (loader != null) {
return loader;
}
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, zip);
//创建一个PathClassLoader,并放入缓存,方便以后直接获取
PathClassLoader pathClassloader =
new PathClassLoader(zip, libPath, parent);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
mLoaders.put(zip, pathClassloader);
return pathClassloader;
}
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, zip);
PathClassLoader pathClassloader = new PathClassLoader(zip, parent);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
return pathClassloader;
}
}
1.4 PathClassLoader()
public PathClassLoader(String dexPath, String libraryPath,
ClassLoader parent) {
//PathClassLoader继承自BaseDexClassLoader,所以会调用
//BaseDexClassLoader的构造函数
super(dexPath, null, libraryPath, parent);
}
1.5 BaseDexClassLoader()
//由PathClassLoader传入的参数可以知道第二个参数optimizedDirectory=null
public BaseDexClassLoader(String dexPath, File optimizedDirectory,
String libraryPath, ClassLoader parent) {
super(parent);
this.pathList = new DexPathList(this, dexPath, libraryPath, optimizedDirectory);
}
1.6 DexPathList()
public DexPathList(ClassLoader definingContext, String dexPath,
String libraryPath, File optimizedDirectory) {
...
this.definingContext = definingContext;
ArrayList<IOException> suppressedExceptions = new ArrayList<IOException>();
//加载dex文件
this.dexElements = makePathElements(splitDexPath(dexPath), optimizedDirectory,
suppressedExceptions);
this.nativeLibraryDirectories = splitPaths(libraryPath, false);
this.systemNativeLibraryDirectories =
splitPaths(System.getProperty("java.library.path"), true);
List<File> allNativeLibraryDirectories = new ArrayList<>(nativeLibraryDirectories);
allNativeLibraryDirectories.addAll(systemNativeLibraryDirectories);
//加载library文件
this.nativeLibraryPathElements = makePathElements(allNativeLibraryDirectories, null,
suppressedExceptions);
...
1.7 DexPathList.makePathElements()
private static Element[] makePathElements(List<File> files, File optimizedDirectory,
List<IOException> suppressedExceptions) {
List<Element> elements = new ArrayList<>();
for (File file : files) {
File zip = null;
File dir = new File("");
DexFile dex = null;
String path = file.getPath();
String name = file.getName();
if (path.contains(zipSeparator)) {
String split[] = path.split(zipSeparator, 2);
zip = new File(split[0]);
dir = new File(split[1]);
} else if (file.isDirectory()) {
//如果file是library会执行这一分支
elements.add(new Element(file, true, null, null));
} else if (file.isFile()) {
if (name.endsWith(DEX_SUFFIX)) {
//如果文件以.dex结尾,直接加载
try {
dex = loadDexFile(file, optimizedDirectory);
} catch (IOException ex) {
System.logE("Unable to load dex file: " + file, ex);
}
} else {
zip = file;
//加载位于.zip或者.apk文件内的dex文件
try {
dex = loadDexFile(file, optimizedDirectory);
} catch (IOException suppressed) {
suppressedExceptions.add(suppressed);
}
}
} else {
System.logW("ClassLoader referenced unknown path: " + file);
}
if ((zip != null) || (dex != null)) {
elements.add(new Element(dir, false, zip, dex));
}
}
return elements.toArray(new Element[elements.size()]);
}
1.8 DexPathList.loadDexFile()
private static DexFile loadDexFile(File file, File optimizedDirectory)
throws IOException {
if (optimizedDirectory == null) {
//如果是PathClassLoader,则执行这一步
return new DexFile(file);
} else {
//首先确保输出后的文件是以.dex结尾
String optimizedPath = optimizedPathFor(file, optimizedDirectory);
return DexFile.loadDex(file.getPath(), optimizedPath, 0);
}
}
1.8.1 DexFile(String fileName)
public DexFile(String fileName) throws IOException {
//mCookie是一个Object类型的对象,用这个对象来保存dex文件也可能是dex文件列表
//之后在加载class的时候,会把这个对象传入,从而加载相应的class
mCookie = openDexFile(fileName, null, 0);
mFileName = fileName;
guard.open("close");
}
1.8.2 DexFile.loadDex()
static public DexFile loadDex(String sourcePathName, String outputPathName,
int flags) throws IOException {
return new DexFile(sourcePathName, outputPathName, flags);
}
1.8.3 DexFile()
private DexFile(String sourceName, String outputName, int flags) throws IOException {
if (outputName != null) {
try {
String parent = new File(outputName).getParent();
//确保输出目录属于当前应用,即输出目录是应用的私有目录/data/data/package_name/xxx
if (Libcore.os.getuid() != Libcore.os.stat(parent).st_uid) {
throw new IllegalArgumentException("Optimized data directory " + parent
+ " is not owned by the current user. Shared storage cannot protect"
+ " your application from code injection attacks.");
}
} catch (ErrnoException ignored) {
}
}
//mCookie是一个Object类型的对象,用这个对象来保存dex文件也可能是dex文件列表
//之后在加载class的时候,会把这个对象传入,从而加载相应的class
mCookie = openDexFile(sourceName, outputName, flags);
mFileName = sourceName;
guard.open("close");
}
从以上代码片段中可以看出,最后加载dex文件都是调用DexFile.openDexFile
这个方法
1.9. DexFile.openDexFile()
private static Object openDexFile(String sourceName, String outputName, int flags) throws IOException {
return openDexFileNative(new File(sourceName).getAbsolutePath(),
(outputName == null) ? null : new File(outputName).getAbsolutePath(),
flags);
}
openDexFileNative
是一个native方法,之后的调用进入native层
二.Native调用链
2.1 DexFile_openDexFileNative()
static jobject DexFile_openDexFileNative(
JNIEnv* env, jclass, jstring javaSourceName, jstring javaOutputName, jint) {
...
ClassLinker* linker = Runtime::Current()->GetClassLinker();
std::vector<std::unique_ptr<const DexFile>> dex_files;
std::vector<std::string> error_msgs;
dex_files = linker->OpenDexFilesFromOat(sourceName.c_str(), outputName.c_str(), &error_msgs);
if (!dex_files.empty()) {
jlongArray array = ConvertNativeToJavaArray(env, dex_files);
... //错误处理,释放相应资源
//返回给Java层,由DexFile的mCookie指向
return array;
} else {
... //抛出异常
return nullptr;
}
}
2.2 ClassLinker::OpenDexFilesFromOat()
std::vector<std::unique_ptr<const DexFile>> ClassLinker::OpenDexFilesFromOat(
const char* dex_location, const char* oat_location,
std::vector<std::string>* error_msgs) {
CHECK(error_msgs != nullptr);
// Verify we aren't holding the mutator lock, which could starve GC if we
// have to generate or relocate an oat file.
Locks::mutator_lock_->AssertNotHeld(Thread::Current());
//Runtime::Current()->IsAotCompiler用来判断Runtime是否用于dex2oat,dex2oat程序
//也会创建一个Runtime,专门用来Compile
OatFileAssistant oat_file_assistant(dex_location, oat_location, kRuntimeISA,
!Runtime::Current()->IsAotCompiler());
// Lock the target oat location to avoid races generating and loading the
// oat file.
std::string error_msg;
if (!oat_file_assistant.Lock(&error_msg)) {
...
}
// Check if we already have an up-to-date oat file open.
const OatFile* source_oat_file = nullptr;
{
ReaderMutexLock mu(Thread::Current(), dex_lock_);
//oat_file_变量属于ClassLinker,用来存放oat文件
for (const OatFile* oat_file : oat_files_) {
...
// 判断oat文件是否正确
if (oat_file_assistant.GivenOatFileIsUpToDate(*oat_file)) {
source_oat_file = oat_file;
break;
}
}
}
// If we didn't have an up-to-date oat file open, try to load one from disk.
if (source_oat_file == nullptr) {
// Update the oat file on disk if we can. This may fail, but that's okay.
// Best effort is all that matters here.
// 根据dex文件产生对应的oat文件
if (!oat_file_assistant.MakeUpToDate(&error_msg)) {
...
}
// Get the oat file on disk.
std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile();
if (oat_file.get() != nullptr) {
// Take the file only if it has no collisions, or we must take it because of preopting.
bool accept_oat_file = !HasCollisions(oat_file.get(), &error_msg);
if (!accept_oat_file) {
...
// However, if the app was part of /system and preopted, there is no original dex file
// available. In that case grudgingly accept the oat file.
if (!DexFile::MaybeDex(dex_location)) {
accept_oat_file = true;
...
}
}
if (accept_oat_file) {
source_oat_file = oat_file.release();
//将oat_file添加至oat_file_
RegisterOatFile(source_oat_file);
}
}
}
std::vector<std::unique_ptr<const DexFile>> dex_files;
// Load the dex files from the oat file.
if (source_oat_file != nullptr) {
//通过OatFileAssistant加载dex文件
dex_files = oat_file_assistant.LoadDexFiles(*source_oat_file, dex_location);
if (dex_files.empty()) {
...
}
}
// Fall back to running out of the original dex file if we couldn't load any
// dex_files from the oat file.
if (dex_files.empty()) {
...
}
return dex_files;
}
2.3 OatFileAssistant::LoadDexFiles()
std::vector<std::unique_ptr<const DexFile>> OatFileAssistant::LoadDexFiles(
const OatFile& oat_file, const char* dex_location) {
std::vector<std::unique_ptr<const DexFile>> dex_files;
//先加载主dex文件.
//先从OatFile中获取OatDexFile, 在oat文件中每一个OatDexFile记录了相应的
//dex文件的文件名,文件偏移地址等关键信息
std::string error_msg;
const OatFile::OatDexFile* oat_dex_file = oat_file.GetOatDexFile(
dex_location, nullptr, false);
if (oat_dex_file == nullptr) {
...
return std::vector<std::unique_ptr<const DexFile>>();
}
//通过OatDexFile加载主dex, [2.4]
std::unique_ptr<const DexFile> dex_file = oat_dex_file->OpenDexFile(&error_msg);
if (dex_file.get() == nullptr) {
LOG(WARNING) << "Failed to open dex file from oat dex file: " << error_msg;
return std::vector<std::unique_ptr<const DexFile>>();
}
dex_files.push_back(std::move(dex_file));
//加载其余的次级dex文件
for (size_t i = 1; ; i++) {
//先获取次级dex文件的索引位置
std::string secondary_dex_location = DexFile::GetMultiDexLocation(i, dex_location);
//根据索引位置获取对应的OatDexFile结构
oat_dex_file = oat_file.GetOatDexFile(secondary_dex_location.c_str(), nullptr, false);
if (oat_dex_file == nullptr) {
// There are no more secondary dex files to load.
break;
}
//加载次级dex文件
dex_file = oat_dex_file->OpenDexFile(&error_msg);
if (dex_file.get() == nullptr) {
LOG(WARNING) << "Failed to open dex file from oat dex file: " << error_msg;
return std::vector<std::unique_ptr<const DexFile>>();
}
dex_files.push_back(std::move(dex_file));
}
return dex_files;
}
每一个dex文件的信息都被封装在一个OatDexFile中
OatDexFile数据结构:
const OatFile* const oat_file_
:指向oat文件的指针
const std::string dex_file_location_
:dex文件名
const std::string_canonical_dex_file_location_
:dex文件绝对路径
const uint32_t dex_file_location_cheksum_
:dex文件名的校验和
const uint8_t* const dex_file_pointer_
:指向对应dex文件在oat文件中相对于oatdata的偏移地址
const uint32_t* const oat_class_offsets_pointer_
:指向属于该dex文件的OatClass相对于oatdata的偏移地址
2.4 OatDexFile::OpenDexFile()
std::unique_ptr<const DexFile> OatFile::OatDexFile::OpenDexFile(std::string* error_msg) const {
return DexFile::Open(dex_file_pointer_, FileSize(), dex_file_location_,
dex_file_location_checksum_, this, error_msg);
}
2.5 DexFile::Open()
static std::unique_ptr<const DexFile> Open(const uint8_t* base, size_t size,
const std::string& location,
uint32_t location_checksum,
const OatDexFile* oat_dex_file,
std::string* error_msg) {
return OpenMemory(base, size, location, location_checksum, nullptr, oat_dex_file, error_msg);
}
2.6 DexFile::OpenMemory()
std::unique_ptr<const DexFile> DexFile::OpenMemory(const uint8_t* base,
size_t size,
const std::string& location,
uint32_t location_checksum,
MemMap* mem_map,//nullptr
const OatDexFile* oat_dex_file,
std::string* error_msg) {
//确保以4字节对齐
CHECK_ALIGNED(base, 4); // various dex file structures must be word aligned
//初始化一个DexFile对象
std::unique_ptr<DexFile> dex_file(
new DexFile(base, size, location, location_checksum, mem_map, oat_dex_file));
//检查dex的magic和version是否正确
if (!dex_file->Init(error_msg)) {
dex_file.reset();
}
return std::unique_ptr<const DexFile>(dex_file.release());
}
2.7 DexFile()
DexFile::DexFile(const uint8_t* base, size_t size,
const std::string& location,
uint32_t location_checksum,
MemMap* mem_map,
const OatDexFile* oat_dex_file)
: begin_(base),
size_(size),
location_(location),
location_checksum_(location_checksum),
mem_map_(mem_map),//nullptr
header_(reinterpret_cast<const Header*>(base)),
string_ids_(reinterpret_cast<const StringId*>(base + header_->string_ids_off_)),
type_ids_(reinterpret_cast<const TypeId*>(base + header_->type_ids_off_)),
field_ids_(reinterpret_cast<const FieldId*>(base + header_->field_ids_off_)),
method_ids_(reinterpret_cast<const MethodId*>(base + header_->method_ids_off_)),
proto_ids_(reinterpret_cast<const ProtoId*>(base + header_->proto_ids_off_)),
class_defs_(reinterpret_cast<const ClassDef*>(base + header_->class_defs_off_)),
find_class_def_misses_(0),
class_def_index_(nullptr),
oat_dex_file_(oat_dex_file) {
CHECK(begin_ != nullptr) << GetLocation();
CHECK_GT(size_, 0U) << GetLocation();
}
DexFile数据结构
const uint8_t* const begin_
;dex文件的起始地址
const size_t size_
: dex文件的大小,以字节为单位
const std::string location_
:dex文件的文件名
const uint32_t location_checksum_
:dex文件名的校验和
std::unique_ptr<MemMap> mem_map_
:
const Header* const header_
:指向dex文件的头部
const StringId* const string_ids_
:指向dex文件StringId列表
const TypeId* const type_ids
:指向dex文件TypeId列表
const FieldId* const field_ids_
:指向dex文件FieldId列表
const MethodId* const method_ids_
:指向dex文件MethodId列表
const ProtoId* const proto_ids
_:指向dex文件ProtoID列表
const ClassDef* const class_defs_
:指向dex文件ClassDef列表
三.总结
应用程序启动时,系统会创建属于该应用进程的PathClassLoader,创建PathClassLoader的过程就是加载dex文件的过程.
ART内部支持加载多个dex文件,这是因为ART采用AOT方式,在应用安装的时候会将apk文件的所有dex文件统一编译到一个oat文件中.
其实加载过程就是根据oat文件在Java层和Native层生成相应的数据结构,从而方便之后加载类和方法
网友评论