简述
PathClassLoader加载的过程 :
- 通过
DexPathList.addDexPath
来加载Dex文件 - 通过
makeDexElements
来加载DexElement , 每一个Element就是一个Dex - 在Native层 , 加载Oat/dex文件
- 根据加载到内存的基址来找到各个
Section
- 进行DexFile文件的校验
- 校验成功后 , 通过
ClassLinker->class_table
添加class_table
- 最后返回dex_files数组所在的Cookie
PathClassLoader的查找过程 :
- 通过
DexFile.loadClassBinaryName
加载 - 调用到
dalvik_system_DexFile.cc
中的DexFile_defineClassNative
函数 - 将
Cookie
也就是dex_files
基址传给Native , 初始化oat_file
以及dex_files
- 根据类名生成描述符
descriptor
- 遍历
dex_files
, 从dex_file
中查找Class
PathClassLoader
PathClassLoader
继承自BaseDexClassLoader
, 主要是把dexPath
传递给BaseDexClassLoader
public class PathClassLoader extends BaseDexClassLoader {
public PathClassLoader(String dexPath, ClassLoader parent) {
super(dexPath, null, null, parent);
}
public PathClassLoader(String dexPath, String librarySearchPath, ClassLoader parent) {
super(dexPath, null, librarySearchPath, parent);
}
}
BaseDexClassLoader
主要是通过DexPathList
来查找类 , 以及添加Dex路径 , 初始化DexFile的
public class BaseDexClassLoader extends ClassLoader {
public BaseDexClassLoader(String dexPath, File optimizedDirectory,
String librarySearchPath, ClassLoader parent) {
super(parent);
this.pathList = new DexPathList(this, dexPath, librarySearchPath, null);
}
@Override
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;
}
public void addDexPath(String dexPath) {
pathList.addDexPath(dexPath, null /*optimizedDirectory*/);
}
}
DexPathList
-
DexPathList
构造函数
- 通过
makeDexElements
加载Dex文件 , 生成Element对象 - 通过
makePathElement
加载动态链接库 , 生成Element对象
public DexPathList(ClassLoader definingContext, String dexPath,
String librarySearchPath, File optimizedDirectory) {
...
// 通过makeDexElements来加载dexPath的路径
this.dexElements = makeDexElements(splitDexPath(dexPath), optimizedDirectory,
suppressedExceptions, definingContext);
// 初始化so的路径
this.nativeLibraryDirectories = splitPaths(librarySearchPath, false);
// 初始化系统So路径
this.systemNativeLibraryDirectories =
splitPaths(System.getProperty("java.library.path"), true);
List<File> allNativeLibraryDirectories = new ArrayList<>(nativeLibraryDirectories);
// 添加所有So路径集合
allNativeLibraryDirectories.addAll(systemNativeLibraryDirectories);
// 加载动态链接库的Element
this.nativeLibraryPathElements = makePathElements(allNativeLibraryDirectories);
...
}
makeDexElements
- 遍历Dex文件 , 加载Dex文件 , 放入Elements数组中
private static Element[] makeDexElements(List<File> files, File optimizedDirectory,
List<IOException> suppressedExceptions, ClassLoader loader) {
Element[] elements = new Element[files.size()];
int elementsPos = 0;
// 遍历所有的Dex文件路径
for (File file : files) {
if (file.isDirectory()) {
// 将目录文件放到对应的数组中
elements[elementsPos++] = new Element(file);
} else if (file.isFile()) {
String name = file.getName();
// 判断是否以.dex结尾
if (name.endsWith(DEX_SUFFIX)) {
try {
// 通过loadDexFile加载dexs文件
DexFile dex = loadDexFile(file, optimizedDirectory, loader, elements);
if (dex != null) {
// 将dex放到Elements数组中
elements[elementsPos++] = new Element(dex, null);
}
} catch (IOException suppressed) {
}
} else {
DexFile dex = null;
try {
// 如果不以dex结尾也会通过`loadDexFile`尝试加载
dex = loadDexFile(file, optimizedDirectory, loader, elements);
} catch (IOException suppressed) {
suppressedExceptions.add(suppressed);
}
if (dex == null) {
// 如果加载失败 , 将文件放到elements中
elements[elementsPos++] = new Element(file);
} else {
elements[elementsPos++] = new Element(dex, file);
}
}
} else {
System.logW("ClassLoader referenced unknown path: " + file);
}
}
return elements;
}
loadDexFile
- 通过两种方式加载DexFile
private static DexFile loadDexFile(File file, File optimizedDirectory, ClassLoader loader,
Element[] elements)
throws IOException {
if (optimizedDirectory == null) {
// 如果odex文件路径为空的话 , 则会直接创建DexFile
return new DexFile(file, loader, elements);
} else {
// 如果odex文件路径不为空的话 , 则会通过DexFile.loadDex从odex中直接读取
String optimizedPath = optimizedPathFor(file, optimizedDirectory);
return DexFile.loadDex(file.getPath(), optimizedPath, 0, loader, elements);
}
}
DexFile
- 校验uid
- 通过
openDexFileNative
加载Dex文件 - 返回Cookie代表JNI层dex_file的指针
private DexFile(String sourceName, String outputName, int flags, ClassLoader loader,
DexPathList.Element[] elements) throws IOException {
if (outputName != null) {
try {
String parent = new File(outputName).getParent();
// 检查文件uid是否相同 , 如果不同的话 , 则抛异常
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) {
// assume we'll fail with a more contextual error later
}
}
// 调用openDexFileNative函数 , 加载Dex文件
mCookie = openDexFile(sourceName, outputName, flags, loader, elements);
mInternalCookie = mCookie;
mFileName = sourceName;
//System.out.println("DEX FILE cookie is " + mCookie + " sourceName=" + sourceName + " outputName=" + outputName);
}
openDexFileNative
- 获取
ClassLinker
对象 - 通过
OatFilemanager.OpenDexFilesFromOat
从oat文件中生成dex的数组(Vector) - 将·dex_files·数组的地址返回给Java层
static jobject DexFile_openDexFileNative(JNIEnv* env,
jclass,
jstring javaSourceName,
jstring javaOutputName ATTRIBUTE_UNUSED,
jint flags ATTRIBUTE_UNUSED,
jobject class_loader,
jobjectArray dex_elements) {
// 获取Runtime
Runtime* const runtime = Runtime::Current();
// 获取ClassLinker
ClassLinker* linker = runtime->GetClassLinker();
std::vector<std::unique_ptr<const DexFile>> dex_files;
std::vector<std::string> error_msgs;
const OatFile* oat_file = nullptr;
// 通过OpenDexFilesFromOat函数加载文件
dex_files = runtime->GetOatFileManager().OpenDexFilesFromOat(sourceName.c_str(),
class_loader,
dex_elements,
/*out*/ &oat_file,
/*out*/ &error_msgs);
// 如果dex_files不为空的话
if (!dex_files.empty()) {
// 将DexFile转成地址数组
jlongArray array = ConvertDexFilesToJavaArray(env, oat_file, dex_files);
if (array == nullptr) {
ScopedObjectAccess soa(env);
// 如果array为空 , 则释放defFile
for (auto& dex_file : dex_files) {
if (linker->IsDexFileRegistered(soa.Self(), *dex_file)) {
dex_file.release();
}
}
}
// 返回array数组作为Cookie返回
return array;
} else {
ScopedObjectAccess soa(env);
CHECK(!error_msgs.empty());
// 抛异常
auto it = error_msgs.begin();
auto itEnd = error_msgs.end();
for ( ; it != itEnd; ++it) {
ThrowWrappedIOException("%s", it->c_str());
}
return nullptr;
}
}
- 在
art/runtime/oat_file_manager.cc
中
- 初始化
oat_file_assistant
对象 , 主要用于保存odex、oat路径 -
oat_file
类型为ElfOatFile
- 通过
oat_file_assistant.OpenImageSpace
初始化ImageSpace, 其中会读取oat文件的header、data , 然后校验oat文件的checksum - 接着校验
Section
、Map
, 最后得到ImageSpace - 将ImageSpace添加到Heap
- 主要通过
ClassLinker->AddImageSpace
将oat/dex文件添加到JNIEnv中 - 添加成功后 , 释放imageSpace
- 如果没有添加成功 , 则通过
LoadDexFiles
重新尝试加载一次
td::vector<std::unique_ptr<const DexFile>> OatFileManager::OpenDexFilesFromOat(
const char* dex_location,
jobject class_loader,
jobjectArray dex_elements,
const OatFile** out_oat_file,
std::vector<std::string>* error_msgs) {
// 此处不用Mutex进行并发 , 因为分配oat/dex文件会导致大量GC
Thread* const self = Thread::Current();
// 验证没有锁
Locks::mutator_lock_->AssertNotHeld(self);
// 获取Rumtine
Runtime* const runtime = Runtime::Current();
// 创建OatFileAssistant对象 , 内部会判断当前的指令集与SOC架构是否匹配
// 同时会找到odex以及oat文件的路径
OatFileAssistant oat_file_assistant(dex_location,
kRuntimeISA,
!runtime->IsAotCompiler());
...
const OatFile* source_oat_file = nullptr;
// 从路径中读取oat_file , 类型为ElfOatFile
std::unique_ptr<const OatFile> oat_file(oat_file_assistant.GetBestOatFile().release());
if (accept_oat_file) {
VLOG(class_linker) << "Registering " << oat_file->GetLocation();
// 将oat_file插入oat_files_队列中
source_oat_file = RegisterOatFile(std::move(oat_file));
*out_oat_file = source_oat_file;
}
}
// 声明oat文件中的dex_file
std::vector<std::unique_ptr<const DexFile>> dex_files;
// 开始从oat文件中加载dex
if (source_oat_file != nullptr) {
bool added_image_space = false;
// 判断是否为可执行文件 , 因为是ELF文件 , 所以为true
if (source_oat_file->IsExecutable()) {
// 调用oat_file_assistant.OpenImageSpace函数将oat文件加载到内存中
// 并且初始化class_,method_等数组对象
std::unique_ptr<gc::space::ImageSpace> image_space =
kEnableAppImage ? oat_file_assistant.OpenImageSpace(source_oat_file) : nullptr;
// 如果加载成功
if (image_space != nullptr) {
{
...
// 将oat等镜像空间添加到Heap中
runtime->GetHeap()->AddSpace(image_space.get());
}
{
// 将dex_files添加到ClassLinker中
added_image_space = runtime->GetClassLinker()->AddImageSpace(image_space.get(),h_loader,dex_elements, dex_location,
/*out*/&dex_files,
/*out*/&temp_error_msg);
}
// 如果添加成功 , 则释放image_space
if (added_image_space) {
image_space.release();
} else {
LOG(INFO) << "Failed to add image file " << temp_error_msg;
// 否则清理dex_files
dex_files.clear();
{
// 清理Space
runtime->GetHeap()->RemoveSpace(image_space.get());
}
}
}
}
}
if (!added_image_space) {
DCHECK(dex_files.empty());
// 如果classLinker添加失败 , 则重新加载一次
dex_files = oat_file_assistant.LoadDexFiles(*source_oat_file, dex_location);
}
...
return dex_files;
}
- 在
ClassLinker. AddImageSpace
中
- 从
ImageSpace
中获取OatFile
指针 - 遍历
dex_caches
, 通过OpenOatDexFile
生成dex_file
对象 - 将
dex_file
添加到out_dex_files
数组中 , 在函数结束后返回 - 校验ClassLoader与BootClassLoader
- 将
dex_file_name
加入loader_dex_file_names
中 - 将
classLoader
的ClassTable
添加到Class
bool ClassLinker::AddImageSpace(
gc::space::ImageSpace* space,
Handle<mirror::ClassLoader> class_loader,
jobjectArray dex_elements,
const char* dex_location,
std::vector<std::unique_ptr<const DexFile>>* out_dex_files,
std::string* error_msg) {
// 初始化参数
Runtime* const runtime = Runtime::Current();
gc::Heap* const heap = runtime->GetHeap();
Thread* const self = Thread::Current();
...
// 从header中获取dex_Cache_object引用
Handle<mirror::ObjectArray<mirror::DexCache>> dex_caches(
hs.NewHandle(dex_caches_object->AsObjectArray<mirror::DexCache>()));
// 从header中获取Class数组的日志
Handle<mirror::ObjectArray<mirror::Class>> class_roots(hs.NewHandle(
header.GetImageRoot(ImageHeader::kClassRoots)->AsObjectArray<mirror::Class>()));
// 初始化 ClassLoader
MutableHandle<mirror::ClassLoader> image_class_loader(hs.NewHandle(
app_image ? header.GetImageRoot(ImageHeader::kClassLoader)->AsClassLoader() : nullptr));
// 从ImageSpace获取OatFile
const OatFile* oat_file = space->GetOatFile();
...
// 开始遍历dex_caches
for (int32_t i = 0; i < dex_caches->GetLength(); i++) {
// 获取DexCache指针
ObjPtr<mirror::DexCache> dex_cache = dex_caches->Get(i);
// 获取dex_cache的路径
std::string dex_file_location(dex_cache->GetLocation()->ToModifiedUtf8());
// 通过OpenOatFile打开Oat文件 , 获取DexFile
std::unique_ptr<const DexFile> dex_file = OpenOatDexFile(oat_file,
dex_file_location.c_str(),
error_msg);
...
// 设置dex_cache对象
dex_cache->SetDexFile(dex_file.get());
// 将dex_file加到out_dex_files数组中 , 后面返回
out_dex_files->push_back(std::move(dex_file));
}
...
// 如果是oat文件话
if (app_image) {
ScopedObjectAccessUnchecked soa(Thread::Current());
// 接下来要开始校验
// 判断当前ClassLoader是否是BootClassLoader
if (IsBootClassLoader(soa, image_class_loader.Get())) {
*error_msg = "Unexpected BootClassLoader in app image";
return false;
}
std::list<ObjPtr<mirror::String>> image_dex_file_names;
std::string temp_error_msg;
if (!FlattenPathClassLoader(image_class_loader.Get(), &image_dex_file_names, &temp_error_msg)) {
*error_msg = StringPrintf("Failed to flatten image class loader hierarchy '%s'",
temp_error_msg.c_str());
return false;
}
std::list<ObjPtr<mirror::String>> loader_dex_file_names;
if (!FlattenPathClassLoader(class_loader.Get(), &loader_dex_file_names, &temp_error_msg)) {
*error_msg = StringPrintf("Failed to flatten class loader hierarchy '%s'",
temp_error_msg.c_str());
return false;
}
// 遍历elements , 将有效的dex添加到已加载到dexfile中
auto elements = soa.Decode<mirror::ObjectArray<mirror::Object>>(dex_elements);
for (size_t i = 0, num_elems = elements->GetLength(); i < num_elems; ++i) {
ObjPtr<mirror::Object> element = elements->GetWithoutChecks(i);
if (element != nullptr) {
// If we are somewhere in the middle of the array, there may be nulls at the end.
ObjPtr<mirror::String> name;
// 在element中检查其中的dexfile以及name是否为空
// 不为空则将dex的名称push到loader_dex_file_names中
if (GetDexPathListElementName(element, &name) && name != nullptr) {
loader_dex_file_names.push_back(name);
}
}
}
...
// 开始更新ClassLinker中的class_table
ClassTable* class_table = nullptr;
{
WriterMutexLock mu(self, *Locks::classlinker_classes_lock_);
// 创建ClassLoader中的ClassTable
class_table = InsertClassTableForClassLoader(class_loader.Get());
}
// 创建临时的ClassTable
ClassTable::ClassSet temp_set;
// 从oat文件中读取ClassTable的Section
const ImageSection& class_table_section = header.GetImageSection(ImageHeader::kSectionClassTable);
// 判断classTable的Section大小是否大于0
const bool added_class_table = class_table_section.Size() > 0;
if (added_class_table) {
const uint64_t start_time2 = NanoTime();
size_t read_count = 0;
// 如果存在ClassTableSection的话 , 则读取出来保存到temp_set中
temp_set = ClassTable::ClassSet(space->Begin() + class_table_section.Offset(),
/*make copy*/false,
&read_count);
VLOG(image) << "Adding class table classes took " << PrettyDuration(NanoTime() - start_time2);
}
if (app_image) {
bool forward_dex_cache_arrays = false;
// 校验ClassLoader以及DexCache
if (!UpdateAppImageClassLoadersAndDexCaches(space,
class_loader,
dex_caches,
&temp_set,
/*out*/&forward_dex_cache_arrays,
/*out*/error_msg)) {
return false;
}
...
// 把oat文件插入到class_table中
if (!oat_file->GetBssGcRoots().empty()) {
// Insert oat file to class table for visiting .bss GC roots.
class_table->InsertOatFile(oat_file);
}
if (added_class_table) {
// 如果需要添加到classtable , 则添加到class_table中
WriterMutexLock mu(self, *Locks::classlinker_classes_lock_);
class_table->AddClassSet(std::move(temp_set));
}
...
return true;
}
OpenOatDexFile
static std::unique_ptr<const DexFile> OpenOatDexFile(const OatFile* oat_file,
const char* location,
std::string* error_msg)
REQUIRES_SHARED(Locks::mutator_lock_) {
DCHECK(error_msg != nullptr);
std::unique_ptr<const DexFile> dex_file;
// 根据路径得到OatDexFile对象
const OatFile::OatDexFile* oat_dex_file = oat_file->GetOatDexFile(location, nullptr, error_msg);
if (oat_dex_file == nullptr) {
return std::unique_ptr<const DexFile>();
}
std::string inner_error_msg;
// 根据地址找到dex_file结构 , 并且填充信息
dex_file = oat_dex_file->OpenDexFile(&inner_error_msg);
// 如果打开失败
if (dex_file == nullptr) {
*error_msg = StringPrintf("Failed to open dex file %s from within oat file %s error '%s'",
location,
oat_file->GetLocation().c_str(),
inner_error_msg.c_str());
return std::unique_ptr<const DexFile>();
}
// 校验失败
if (dex_file->GetLocationChecksum() != oat_dex_file->GetDexFileLocationChecksum()) {
*error_msg = StringPrintf("Checksums do not match for %s: %x vs %x",
location,
dex_file->GetLocationChecksum(),
oat_dex_file->GetDexFileLocationChecksum());
return std::unique_ptr<const DexFile>();
}
return dex_file;
}
OpenDexFile
std::unique_ptr<const DexFile> OatFile::OatDexFile::OpenDexFile(std::string* error_msg) const {
ScopedTrace trace(__PRETTY_FUNCTION__);
static constexpr bool kVerify = false;
static constexpr bool kVerifyChecksum = false;
// oat文件中dex_file的指针
return DexFile::Open(dex_file_pointer_,
// 整个文件大小
FileSize(),
// dex文件路径
dex_file_location_,
// dex文件路径的校验码
dex_file_location_checksum_,
this,
kVerify,
kVerifyChecksum,
error_msg);
}
OpenCommon
std::unique_ptr<DexFile> DexFile::OpenCommon(const uint8_t* base,
size_t size,
const std::string& location,
uint32_t location_checksum,
const OatDexFile* oat_dex_file,
bool verify,
bool verify_checksum,
std::string* error_msg,
VerifyResult* verify_result) {
// 通过dex_file基址初始化Dex_File
std::unique_ptr<DexFile> dex_file(new DexFile(base,
size,
location,
location_checksum,
oat_dex_file));
...
// 开始校验Dex
if (verify && !DexFileVerifier::Verify(dex_file.get(),
dex_file->Begin(),
dex_file->Size(),
location.c_str(),
verify_checksum,
error_msg)) {
if (verify_result != nullptr) {
*verify_result = VerifyResult::kVerifyFailed;
}
return nullptr;
}
if (verify_result != nullptr) {
*verify_result = VerifyResult::kVerifySucceeded;
}
return dex_file;
}
-
DexFile
构造函数
DexFile::DexFile(const uint8_t* base,
size_t size,
const std::string& location,
uint32_t location_checksum,
const OatDexFile* oat_dex_file)
: begin_(base),
size_(size),
location_(location),
location_checksum_(location_checksum),
// 初始化Header
header_(reinterpret_cast<const Header*>(base)),
// 初始化Stringid
string_ids_(reinterpret_cast<const StringId*>(base + header_->string_ids_off_)),
// 初始化type id
type_ids_(reinterpret_cast<const TypeId*>(base + header_->type_ids_off_)),
// 初始化filed_id
field_ids_(reinterpret_cast<const FieldId*>(base + header_->field_ids_off_)),
// 初始化method_id
method_ids_(reinterpret_cast<const MethodId*>(base + header_->method_ids_off_)),
proto_ids_(reinterpret_cast<const ProtoId*>(base + header_->proto_ids_off_)),
// 初始化class_def
class_defs_(reinterpret_cast<const ClassDef*>(base + header_->class_defs_off_)),
method_handles_(nullptr),
num_method_handles_(0),
call_site_ids_(nullptr),
num_call_site_ids_(0),
oat_dex_file_(oat_dex_file) {
// 初始化各个Section
InitializeSectionsFromMapList();
}
void DexFile::InitializeSectionsFromMapList() {
const MapList* map_list = reinterpret_cast<const MapList*>(begin_ + header_->map_off_);
if (header_->map_off_ == 0 || header_->map_off_ > size_) {
// Bad offset. The dex file verifier runs after this method and will reject the file.
return;
}
const size_t count = map_list->size_;
// 得到Map大小
size_t map_limit = header_->map_off_ + count * sizeof(MapItem);
if (header_->map_off_ >= map_limit || map_limit > size_) {
// Overflow or out out of bounds. The dex file verifier runs after
// this method and will reject the file as it is malformed.
return;
}
for (size_t i = 0; i < count; ++i) {
// 遍历所有的Section
const MapItem& map_item = map_list->list_[i];
if (map_item.type_ == kDexTypeMethodHandleItem) {
// 如果maptype为Method句柄的话
// 其中begin_也就是base , 基址
method_handles_ = reinterpret_cast<const MethodHandleItem*>(begin_ + map_item.offset_);
num_method_handles_ = map_item.size_;
} else if (map_item.type_ == kDexTypeCallSiteIdItem) {
call_site_ids_ = reinterpret_cast<const CallSiteIdItem*>(begin_ + map_item.offset_);
num_call_site_ids_ = map_item.size_;
}
}
}
}
12.DexFileVerifier::Verify
校验Dex文件
bool DexFileVerifier::Verify() {
// Check the header.
if (!CheckHeader()) {
return false;
}
// Check the map section.
if (!CheckMap()) {
return false;
}
// Check structure within remaining sections.
if (!CheckIntraSection()) {
return false;
}
// Check references from one section to another.
if (!CheckInterSection()) {
return false;
}
return true;
}
-
ElfOatFile
, 由于在Linux平台上 , 所以对应的oat_file
类型为ElfOatFile
ElfOatFile* ElfOatFile::OpenElfFile(File* file,
const std::string& location,
uint8_t* requested_base,
uint8_t* oat_file_begin, // Override base if not null
bool writable,
bool executable,
bool low_4gb,
const char* abs_dex_location,
std::string* error_msg) {
ScopedTrace trace("Open elf file " + location);
std::unique_ptr<ElfOatFile> oat_file(new ElfOatFile(location, executable));
bool success = oat_file->ElfFileOpen(file,
oat_file_begin,
writable,
low_4gb,
executable,
error_msg);
if (!success) {
CHECK(!error_msg->empty());
return nullptr;
}
网友评论