class文件与dex文件解析
关于Android的热修复与插件化技术在如今基本上已经成为了“时髦技术”的标配了,或者说用来进行“炫技”的一种方式,毕境如今Android已经发展得非常之成熟了,基本上APP用的到东东都差不多,除了业务不同之外,但是!对于热修复与插件化并不是每个公司或者每个程序员愿意去应用到商用项目上的,因为既使不加它貌似对传统APP的开发也木有啥影响,毕境加它还是有些繁锁的,而不管有没有在商用APP上去集成过它们,并不影响它被众多开发者所追捧,如今去面个试我想被问到热修复与插件化相关的技术问题应该只多不少,而且还得让你去对它底层的原理进行一些阐述,如果不需要面试也得有必要去掌握这一技术,因为毕境能集成到自己的APP上是能够实际解决APP的一些问题的,基于此有必要系统的去探究,彻底掌握它们,所以接下来会从基础开始一点点去揭开它神秘的面纱。
对于Dex文件是能够在Android被执行的一种格式,而它是由class文件进行演变过来的,在android的热修复中是需要涉及到Dex文件之间的一个diff操作的,而它的基础就是得对其文件结构有一定的了解,所以这里基础就先来熟悉一下文件结构。
class文件解析:
什么是class文件:
能够被JVM识别,加载并执行的文件格式。
如何生成一个class文件:
是不是只有java文件才能够生成class文件呢?其实不是的,看下面这张图就晓得了:
对于class文件的生成一般是由两种方式来完成的:IDE自动生成、javac命令,这里主要是演示一下javac命令的方式,对于它在我们学习j2se的时候已经经历过了,这里再来温故一下:
新建一个最简单的java文件,里面内容如下:
然后编译生成class字节码文件:
然后运行:
另外对于javac命令还可以指令编译的JDK版本,如下:
class文件的作用:
用一句话描述:“记录一个类文件的所有信息”,class文件的信息是远远多于java源代码的信息的,比如说我们在写java代码时并没有定义"this"、"super"关键字,但是确能够使用它们去调用当前类的方法或父类的方法,这是因为在生成class字节码文件的时候JVM帮我们记录了this和super关键字,所以从这点也能体会到class字节码文件的信息要远远多于Java源代码所看到的信息。
class文件格式详解:
- 一种8位字节的二进制文件。
这个比较好理解,跟音视频格式的文件类似。 - 各个数据按顺序紧密的排列,无间隙。
这个不像有些文件可能为了读取上的方便会做一些填充,比如每80个字节是一行,这样的好处就是能让class文件更加的小,能够更快的被JVM所加载。 - 每个类或接口都单独占据一个class文件。
以上是class文件从宏观角度去分析,下面具体来了解一下它的具体格式,各个字段代表的含义,如下为class文件的所有字段:
那你怎么知道上面就是class文件格式所有的字段呢?不要着急,等对其有一个基本了解之后会做实验来验证的,下面具体一个个自上而下来了解一下其字段的含义:
magic:它其实是一个加密断,就像文件的MD5加密一样,用来判断其字节文件是否有被篡改过,如果被篡改过那么JVM会有一些处理的措施。
minor_version:表示此class文件最小能够被哪个版本的JDK所加载,也就是JDK最小适配的一个版本。
major_version:表示当前class文件由哪个版本的JDK所生成 ,比如咱们上面是由JDK1.8所生成的。
constant_pool_count:表示class文件中常量池的数量,通常来说是只有一个常量池,里面会存放许许多多的常量。
constant_pool:也就是真正存放常量的一个地方,其类型是一个结构体,如下:
access_flags:作用域标志,如class声明的pulic,private等。
this_class:这也就是为啥咱们可以直接在java源文件中使用"this"关键字的原因所在,jvm会自动生成一个这个字段。
super_class:其原理跟this_class一样。
interfaces_count/interfaces:保存了当前类实现的接口列表,interfaces_count 指的是当前类实现的接口数目,interfaces[] 是包含interfaces_count个接口的全局限定名的索引的数组,注意:只包含直接实现的接口,对于间接实现的不包含其中。
fields_count:表示类变量和实例变量的字段的数量总和。
fields:包含字段详细信息的列表,它是一个结构体类型:
methods_count:表示该类或者接口显示定义的方法的数量。
methods:包含方法信息的一个详细列表。也是一个结构体类型:
attribute_count/attributes:class文件的最后一部分是属性,它描述了该类或者接口所定义的一些属性信息。attributes_count指的是attributes列表中包含的attribute_info的数量。属性可以出现在class文件的很多地方,而不只是出现在attributes列表里。如果是attributes表里的属性,那么它就是对整个 class文件所对应的类或者接口的描述;如果出现在fileds的某一项里,那么它就是对该字段额外信息的描述;如果出现在methods的某一项里, 那么它就是对该方法额外信息的描述。
以上的这些字段代表的class字节码文件的所有信息,其中对于access_flags包含的具体内容下面再做一个详解:
另外对于常量池constant_pool所包含的内容下面也来说明一下:
CONSTANT_Integer_info:存放着整型相关的常量。
CONSTANT_Long_info:存放着长整型相关的常量。
CONSTANT_String_info:存放着字符符相关的常量。
当然啦其它基本类型的也有对应的来表示,上面只列举常用的三个,另外下面还有几个稍复杂的字段类型:
CONSTANT_Class_info:包含着类常量相关的一些信息。
CONSTANT_Fieldref_info:包含类成员变量相关的一些信息。
CONSTANT_Methodref_info:包含方法引用相关的一些信息。
注意:以上三个其实都是存放的一些索引信息,最终内容还是指向到具体的CONSTANT_Integer_info、CONSTANT_Long_info、CONSTANT_String_info相关的具体类型当中。
说了这么多那class文件里面的结构确实如我们所描述的那样么?这里只要真实查看一个class文件的结构就就可以验证了么,所以下面来做一下这个实验:
咱们之前已经生成了一个class文件了,如下:
那接下来就以这个文件为例进行查看,那用什么软件可以查看到class文件的格式信息呢?这里需要介绍一款软件,如下:
- 软件名称:010 Editor
- 下载地址:http://www.sweetscape.com/010editor/
主要是用来分析二进制文件的,比如之后的dex文件的格式也需要通过它,安装好之后用它打开我们要分析的Hello.class文件,如下:
其中整个class文件是包裹在这个大的结构体中:
其中struct关键字很显然就是c语言中的结构体,然后展开它:
下面具体来看一下:
而其中可以看到u2_class_index和u2_name_and_type_index都是索引信息,其真正的数据就是在之前咱们说的那些CONSTANT_Integer_info、CONSTANT_Long_info、CONSTANT_String_info等相印的字段里,接着往下再看:
其它的常量池相关的信息基本都差不多,先忽略,接着就可以看到是如下信息:
class文件的弊端:
- 内存占用大,不适合移动端。
从我们分析的class的结构信息就可以知晓,一个class文件就对应这么多东东,而一个app有成百上千个类,如果采用class文件存储的话在移动端是不太现实的,毕境移动端的资源是有限的。 - 堆栈的加栈模式,加载速度慢。
- 文件IO操作多,类查找慢。
主要是由于由于每一个class文件只存储了一个java源文件的所有信息,所以每一次加载新的class的时候都要执行一遍加载寻找。
当然它还有其它的一些弊端,正因为存在这些问题,所以dex文件格式就应运而生了,它是针对移动端专门定制的一种二进制格式,所以下面来看一下这种格式有啥特点。
dex文件解析:
什么是dex文件?
能够被DVM识别,加载并执行的文件格式。其中dex文件跟class文件类似,不仅仅只能由java源文件才能生成,其c/c++文件也可以生成dex。
如何生成一个dex文件:
当然也是由两种方式来生成啦,一是IDE自动build生成,另一种由是用dx命令生成,这里只演示dx命令手动生成dex的过程,首先当然得配制好dex命令啦,具体也就是需要将它的文件目录加到系统的path当中,这个文件一般是位于SDK的这个目录下:
配置好之后,接下来用它还是对之前的那个Hello.java进行生成,首先得要有Hello.class文件,注意:这里不能用太高版本的jdk来生成,所以这里采用javac的参数来指定稍低一些的版本来生成class,如下:
这是因为太高版本生成的class文件在一些Android手机上是无法执行的,JDK1.6生成的class文件基本上所有Android手机都能够运行,接着基于这个class文件然后生成dex文件,具体如下:
此时就已经生成好了dex文件了,接下来想办法让它在Android上能够得到执行,首先将这个dex文件导到模拟器中:
接下来进入到adb shell中去执行它:
dex文件的作用:
记录整个工程中所有类文件的信息,记住是整个工程!从这个描述来看就可以看到跟class文件的一个最大的区别就是:dex记录的是整个工程的类文件信息,而class只记录了一个java源文件的信息,
dex文件格式详解:
- 一种8位字节的二进制流文件。【跟class文件一样】
- 各个数据按顺序紧密的排列,无间隙。【跟class文件一样】
- 整个应用中所有的java源文件都放在一个dex中。【跟class最大区别的地方】
下面先来看一张图:
上面是dex整体的结构,下面来具体的看一下各个部分
字段名称 | 偏移量 | 长度(byte) | 当前例子中字段值 | 字段描述 |
magic | 0x0 | 0x8 | dex 035 | dex魔术字, 固定信息: dex\n035 |
checksum | 0x8 | 0x4 | 0x0F828C9C | alder32算法, 去除了magic和checksum 字段之外的所有内容的校验码 |
signature | 0xc | 0x14 | 58339636BED8A6CC826E A09B77D5C3A620262CD |
sha-1签名, 去除了magic、checksum和 signature字段之外的所有内容的签名 |
fileSize | 0x20 | 0x4 | 0x0000043C | 整个dex的文件大小 |
headerSize | 0x24 | 0x4 | 0x00000070 | 整个dex文件头的大小 (固定大小为0x70) |
endianTag | 0x28 | 0x4 | 0x12345678 | 字节序 (大尾方式、小尾方式) 默认为小尾方式 <--> 0x12345678 |
linkSize | 0x2c | 0x4 | 0x00000000 | 链接段的大小, 默认为0表示静态链接 |
linkOff | 0x30 | 0x4 | 0x00000000 | 链接段开始偏移 |
mapOff | 0x34 | 0x4 | 0x0000039C | map_item偏移 |
stringIdsSize | 0x38 | 0x4 | 0x00000019 | 字符串列表中的字符串个数 |
stringIdsOff | 0x3c | 0x4 | 0x00000070 | 字符串列表偏移 |
typeIdsSize | 0x40 | 0x4 | 0x00000009 | 类型列表中的类型个数 |
typeIdsOff | 0x44 | 0x4 | 0x000000D4 | 类型列表偏移 |
protoIdsSize | 0x48 | 0x4 | 0x00000006 | 方法声明列表中的个数 |
protoIdsOff | 0x4c | 0x4 | 0x000000F8 | 方法声明列表偏移 |
fieldIdsSize | 0x50 | 0x4 | 0x00000001 | 字段列表中的个数 |
fieldIdsOff | 0x54 | 0x4 | 0x00000140 | 字段列表偏移 |
methodIdsSize | 0x58 | 0x4 | 0x00000009 | 方法列表中的个数 |
methodIdsOff | 0x5c | 0x4 | 0x00000148 | 方法列表偏移 |
classDefsSize | 0x60 | 0x4 | 0x00000001 | 类定义列表中的个数 |
classDefsOff | 0x64 | 0x4 | 0x00000190 | 类定义列表偏移 |
dataSize | 0x68 | 0x4 | 0x0000028C | 数据段的大小, 4字节对齐 |
dataOff | 0x6c | 0x4 | 0x000001B0 | 数据段偏移 |
接下来用010Editor打开dex文件来查看另外两个区域:索引区和数据区:
其中先来看一下header数据区是否如我们之前所列的:
那最后的数据区在哪呢?其在在这:
class与dex文件对比:
- 本质上他们都是一样的,dex是从class文件演变而来的。
- class文件存在许多冗余信息,dex会去除冗余,并整合。
下面用一张图直观的感受一下这两者的区别:
class文件与dex文件解析的更多相关文章
- class 文件与dex文件区别 (dvm与jvm区别)及Android DVM介绍
区别一:dvm执行的是.dex格式文件 jvm执行的是.class文件 android程序编译完之后生产.class文件,然后,dex工具会把.class文件处理成.dex文件,然后把资源文件和 ...
- 插件化框架解读之Class文件与Dex文件的结构(一)
阿里P7移动互联网架构师进阶视频(每日更新中)免费学习请点击:https://space.bilibili.com/474380680 Class文件 Class文件是Java虚拟机定义并被其所识别的 ...
- 【转】Android系统中的.apk文件和dex文件
1. *.apk文件 APK是Android Package的缩写,即Android安装包.通过将APK文件直接传到Android模拟器或Android手机中执行即可安装. 使用Android打包工具 ...
- [Android Security] jar文件转smali文件
cp : https://blog.csdn.net/fengmm521/article/details/78446486 jar转smali文件一共要走两步,先将jar文件转为.dex文件 (dx工 ...
- Python3解析dex文件
一.说明 1.1 背景说明 看<加密与解密>的时候反复听说“PE文件格式”,到Android安全兴起就不断听说“dex文件格式”.意思是看得懂的,但自己不能手解析一番总觉得不踏实,所以决定 ...
- DEX文件解析---1、dex文件头解析
DEX文件解析---1.dex文件头解析 一.dex文件 dex文件是Android平台上可执行文件的一种文件类型.它的文件格式可以下面这张图概括: dex文件头一般固定为0x70个字 ...
- Android解析编译之后的所有文件(so,dex,xml,arsc)格式
我们在之前一篇一篇介绍了如何解析Android中编译之后的所有文件格式,所有的工作都完成了,这里我们就来做个总结,我们为什么要做这些工作: 第一篇:解析so文件格式 点击进入 这里我们解析so文件,主 ...
- DEX文件解析--7、类及其类数据解析(完结篇)
一.前言 前置技能链接: DEX文件解析---1.dex文件头解析 DEX文件解析---2.Dex文件checksum(校验和)解析 DEX文件解析--3.d ...
- DEX文件解析--3、dex文件字符串解析
一.前言 前两篇文章链接: 1.DEX文件头解析 2.DEX文件校验和解析 PS:前几天检查文件夹的时候发现DEX文件解析还只写了开头,正好找点事情来做,就去接着解析DEX ...
随机推荐
- Docker二
Docker生成镜像的两种方式 有时候从Docker镜像仓库中下载的镜像不能满足要求,我们可以基于一个基础镜像构建一个自己的镜像 两种方式: 更新镜像:使用docker commit命令 构建镜像:使 ...
- 【编程开发】非对称加密过程详解(基于RSA非对称加密算法实现)
1.非对称加密过程: 假如现实世界中存在A和B进行通讯,为了实现在非安全的通讯通道上实现信息的保密性.完整性.可用性(即信息安全的三个性质),A和B约定使用非对称加密通道进行通讯,具体 ...
- eNSP——通过Telent登录系统
我们先介绍一下Telent是干啥的: Telnet通常用在远程登录应用中,以便对本地或远端运行的网络设备进行配置.监控和维护.如网络中有多台设备需要配置和管理,用户无需为每一台 设备都连接一一个用户终 ...
- 环境变量配置文件profile
环境变量配置文件 在Ubuntu中有如下几个文件可以设置环境变量1./etc/profile:在登录时,操作系统定制用户环境时使用的第一个文件,此文件为系统的每个用户设置环境信息,当用户第一次登录时, ...
- std::unique_lock与std::lock_guard分析
背景 C++多线程编程中通常会对共享的数据进行写保护,以防止多线程在对共享数据成员进行读写时造成资源争抢,导致程序出现未定义或异常行为.通常的做法是在修改共享数据成员时进行加锁(mutex).在使用锁 ...
- NameNode 和 SecondaryNameNode
1. NN 和 2NN 工作机制 NameNode 会产生在磁盘中备份元数据的FsImage; 每当元数据有更新或者添加数据时,修改内存中的元数据并追加到Edits中; SecondaryNameNo ...
- input输入框内容变化实时监听
js实现的文本框内容发生改变立马触发事件简单介绍:本章节介绍一下如何在文本框的内容发生变化的时候,立马触发一个事件执行响应的操作,而不是像是keydown或者keyup事件一样,只能够检测通过键盘输入 ...
- 什么是云解析DNS?
产品概述 云解析DNS(Alibaba Cloud DNS)是一种安全.快速.稳定.可扩展的权威DNS服务,云解析DNS为企业和开发者将易于管理识别的域名转换为计算机用于互连通信的数字IP地址,从而将 ...
- kubernetes 健康检查和初始化容器
Pod-hook:postStart:1.$ $ vim preStart-hook.yaml---apiVersion: v1kind: Podmetadata: name: hook-demo1 ...
- getContextPath、getServletPath、getRequestURI、getRealPath、getRequestURL、getPathInfo();的区别
<% out.println("getContextPath: "+request.getContextPath()+"<br/>"); ou ...