dex文件结构(二):dex文件加载基本原理

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 suppressedExceptions = new ArrayList();

//加载dex文件

this.dexElements = makePathElements(splitDexPath(dexPath), optimizedDirectory,

suppressedExceptions);

this.nativeLibraryDirectories = splitPaths(libraryPath, false);

this.systemNativeLibraryDirectories =

splitPaths(System.getProperty(“java.library.path”), true);

List allNativeLibraryDirectories = new ArrayList<>(nativeLibraryDirectories);

allNativeLibraryDirectories.addAll(systemNativeLibraryDirectories);

//加载library文件

this.nativeLibraryPathElements = makePathElements(allNativeLibraryDirectories, null,

suppressedExceptions);

1.7 DexPathList.makePathElements()

private static Element[] makePathElements(List files, File optimizedDirectory,

List suppressedExceptions) {

List 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调用链


[](http

s://blog.csdn.net/weixin_47933729/article/details/113146251)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> dex_files;

std::vectorstd::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> ClassLinker::OpenDexFilesFromOat(

const char* dex_location, const char* oat_location,

std::vectorstd::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 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> 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> OatFileAssistant::LoadDexFiles(

const OatFile& oat_file, const char* dex_location) {

std::vector<std::unique_ptr> 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>();

}

//通过OatDexFile加载主dex, [2.4]

std::unique_ptr 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>();

}

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>();

}

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 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 Open(const uint8_t* base, size_t size,

const std::string& location,

最后

小编这些年深知大多数初中级Android工程师,想要提升自己,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助

因此我收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人

都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

资料⬅专栏获取
g.csdn.net/weixin_47933729/article/details/113146251)2.4 OatDexFile::OpenDexFile()

std::unique_ptr 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 Open(const uint8_t* base, size_t size,

const std::string& location,

最后

小编这些年深知大多数初中级Android工程师,想要提升自己,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助

因此我收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。

[外链图片转存中…(img-uyIqHBKL-1719051994206)]

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人

都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

资料⬅专栏获取

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/32223.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

刷代码随想录有感(113):动态规划——爬楼梯plus

题干&#xff1a; 代码&#xff1a; #include<bits/stdc.h> using namespace std;int main(){int n,m;cin>>n>>m;vector<int>dp(n 1, 0);dp[0] 1;for(int j 0; j < n; j){for(int i 1; i < m; i){if(j > i)dp[j] dp[j - i];}}cout<&…

cocos 如何使用九宫格图片,以及在微信小程序上失效。

1.在图片下方&#xff0c;点击edit。 2.拖动线条&#xff0c;使四角不被拉伸。 3.使用。 其他 在微信小程序上失效&#xff0c;需要将packable合图功能取消掉。

速度测试分析软件MySpeed

什么是 MySpeed &#xff1f; MySpeed 是一款速度测试分析软件&#xff0c;可记录您长达 30 天的互联网速度。使用 MySpeed&#xff0c;您可以轻松生成有关速度、ping 等的清晰统计数据。配置运行状况检查&#xff0c;以便在出现错误或停机时通过 Gotify、Discord、WhatsApp 或…

海报设计师的福音来了,微软联合清华北大提出Glyph-ByT5-v2,可支持多国语言图文海报生成,效果惊艳!

清华&北大&微软&利物浦大学联合提出Glyph-ByT5-v2这款工具支持多语言图文生成&#xff0c;包括英语、中文、日文、韩文、法文、德文、西班牙文、意大利文、葡萄牙文和俄文。 以下分别展示中、英、日、韩图文的视觉文本结果一起带大家感受一下。 相关链接 论文地址…

Linux源码阅读笔记03-调度器及CFS调度器

调度器 调度器&#xff1a;Linux内核中用来安排调度进程&#xff08;一段程序的执行过程&#xff09;执行的模块成为调度器&#xff0c;他可以切换进程状态。比如&#xff1a;执行、可中断睡眠、不可中断睡眠、退出、暂停等&#xff1b; 调度器的主要职责&#xff1a;选择某些…

gbase8s关于客户端和数据库连接的方式和应用建立连接的简单线索分工

应用和数据库的连接分为本地连接和远程连接&#xff0c;当应用程序和数据库在同一台服务器上为本地连接&#xff0c;不在一台服务器上为远程连接 1. 本地连接 本地连接三种方式&#xff1a; 通过共享内存消息系统&#xff1a;应用和数据库在同一台服务器上&#xff0c;应用程…

C语言 | Leetcode C语言题解之第165题比较版本号

题目&#xff1a; 题解&#xff1a; int compareVersion(char * version1, char * version2){int len1 strlen(version1);int len2 strlen(version2);int i 0;int j 0;while (i < len1 || j < len2) {int num1 0;int num2 0;while (i < len1 && versio…

C#实现音乐在线播放和下载——Windows程序设计作业3

1. 作业内容 编写一个C#程序&#xff0c;在作业二实现的本地播放功能的基础上&#xff0c;新增在线播放和在线下载功能&#xff0c;作业二博客地址&#xff1a;C#实现简单音乐文件解析播放——Windows程序设计作业2 2. 架构选择 考虑到需求中的界面友好和跨版本兼容性&#xf…

STM32读取芯片内部温度

基于stm32f103cbt6这款芯片&#xff0c;原理部分请参考其他文章&#xff0c;此文章为快速上手得到结果&#xff0c;以结果为导向。 1.基础配置 打开stm32cubemx只需要勾选中 ADC1 Temperature Sensor Channel 2.代码分析 /** 函数名&#xff1a;float GetAdcAnlogValue(voi…

120.网络游戏逆向分析与漏洞攻防-邮件系统数据分析-邮件发送功能的封装

免责声明&#xff1a;内容仅供学习参考&#xff0c;请合法利用知识&#xff0c;禁止进行违法犯罪活动&#xff01; 如果看不懂、不知道现在做的什么&#xff0c;那就跟着做完看效果&#xff0c;代码看不懂是正常的&#xff0c;只要会抄就行&#xff0c;抄着抄着就能懂了 内容…

STM32项目分享:家庭环境监测系统

目录 一、前言 二、项目简介 1.功能详解 2.主要器件 三、原理图设计 四、PCB硬件设计 1.PCB图 2.PCB板打样焊接图 五、程序设计 六、实验效果 七、资料内容 项目分享 一、前言 项目成品图片&#xff1a; 哔哩哔哩视频链接&#xff1a; https://www.bilibili.…

集群初始配置

假设已经有三台或多台 Linux&#xff0c;可以是虚拟机或真实设备。如果希望使用这些 Linux 组成一个集群&#xff0c;并在上面运行一些分布式系统&#xff0c;可能需要如下操作。 1 设置静态IP 输入命令route -n打印路由表&#xff0c;可以查看网关地址。图形界面操作&#x…

跌倒识别:守护公共安全的AI技术应用场景-免费API调用

随着科技的不断进步&#xff0c;人工智能在各个领域的应用日益广泛&#xff0c;其中在公共安全领域&#xff0c;智能跌倒识别系统正逐渐成为守护人们安全的重要工具。本文将分享智能跌倒识别系统在不同场景下的应用及其重要性。 产品在线体验地址-API调用或本地化部署 AI算法模…

【第一性原理】邓巴数字

这里写自定义目录标题 什么是邓巴数字邓巴数背后的科学历史上各个组织的人数与邓巴数字的关系在人类进化中的意义现代社会中邓巴数字的体现邓巴数字的意义其他与沟通相关的数据注意事项结论参考 罗宾邓巴教授生于1947年&#xff0c;进化心理学家&#xff0c;牛津大学教授&#…

[信号与系统]关于LTI系统的转换方程、拉普拉斯变换和z变换

前言 本文还是作为前置知识。 LTI系统的传递函数 LTI系统的传递函数 H ( z ) H(z) H(z) 是输出信号的z变换 Y ( z ) Y(z) Y(z) 与输入信号的z变换 X ( z ) X(z) X(z) 的比值&#xff1a; H ( z ) Y ( z ) X ( z ) H(z) \frac{Y(z)}{X(z)} H(z)X(z)Y(z)​ 多项式比值表…

C++之提高篇

1.标准输入输出流 cin与cout的使用&#xff0c;就不多说了&#xff0c;说一个有关保留小数位数的操作&#xff0c;使用ostream对象的precision&#xff08;&#xff09;方法&#xff0c;表达的意思是数字总共有几位&#xff0c;注意&#xff0c;此时是包括整数部分的&#xff…

OpenAI策略:指令层级系统让大模型免于恶意攻击

现代的大模型&#xff08;LLMs&#xff09;不再仅仅是简单的自动完成系统&#xff0c;它们有潜力赋能各种代理应用&#xff0c;如网页代理、电子邮件秘书、虚拟助手等。然而&#xff0c;这些应用广泛部署的一个主要风险是敌手可能诱使模型执行不安全或灾难性的行动&#xff0c;…

使用 Python 进行测试(7)...until you make it

总结 我很懒&#xff0c;我想用最少的行动实现目标&#xff0c;例如生成测试数据。我们可以&#xff1a; 使用随机种子保证数据的一致性。 >>> random.seed(769876987698698) >>> [random.randint(0, 10) for _ in range(10)] [10, 9, 1, 9, 10, 6, 5, 10…

计算机组成原理 | 硬件电路整理

计算机组成原理 | 硬件电路整理 桶形移位器原理图 全加器逻辑框图 多位可控加减法电路逻辑框图 可级联的4位先行进位电路 4位快速加法器 16位组内并行、组间并行加法器 实现原码一位乘法的逻辑框图 补码一位乘法的逻辑框图 无符号数阵列乘法器 原码不恢复余数法硬件逻辑框图 基…

规模弹性: 管理谷歌的TPUv4机器学习超级计算机(二)

本文为翻译文章&#xff0c;原文为&#xff1a; Resiliency at Scale: Managing Google’sTPUv4 Machine Learning Supercomputer。 由于字数过长&#xff0c;文章分为两期发布&#xff0c;本片涵盖原文后半部分4&#xff5e;9节&#xff0c;前三章节请参考文章&#xff1a;规…