美文网首页Android-JVM程序员Android开发经验谈
热修复与插件化基础——dex与class

热修复与插件化基础——dex与class

作者: GitLqr | 来源:发表于2018-05-13 20:15 被阅读75次

    一、dex/class浅析

    1、class与dex对比

    类型 class文件 dex文件
    定义 能够被jvm识别、加载并执行的文件格式 能够被dvm识别、加载并执行的文件格式
    如何生成 使用java命令(javac) 使用java命令、dx命令
    作用 记录一个类文件的所有信息 记录整个工程中所有类文件的信息

    2、生成class与dex文件的指令

    生成并运行class文件对于我们而言实在太熟悉了,这里只演示dex文件的生成与运行。

    以 Hello World 为例:

    public class Hello {
        public static void main(String[] args){
            System.out.println("Hello LQR!");
        }
    }
    

    1)生成dex文件

    生成dex文件需要用到dx指令,与java指令一样,也是对应一个对应的程序来执行的,最好配置到环境变量中,具体可看文章末尾。

    生成dex文件之前需要先生成class文件,所需指令如下:

    javac -target 1.6 -source 1.6 Hello.java
    dx --dex -- output Hello.dex Hello.class
    

    2)运行dex文件

    class文件的运行需要依赖jvm,同理,dex文件的运行需要依赖dvm,所以dex文件需要在Android上才能运行。所需指令如下:

    adb push Hello.dex /storage/emulated/0
    adb shell
    dalvikvm -cp /sdcard/Hello.dex Hello
    

    使用adb将dex文件放送到Android手机的SD卡目录之后,再使用adb进入shell,运行dvm指令即可。

    二、class文件结构深入

    1、class文件结构:

    • 一种8位字节的二进制流文件
    • 各个数据按顺序紧密的排列,无间隙
    • 每个类或接口都单独占据一个class文件

    2、class文件结构的详解:

    一个class文件,包含下面表格的所有字段,

    类型 名称 数量 说明
    u4 magic 1 魔数,0xCAFEBAB
    u2 minor_version 1 次版本号
    u2 major_version 1 主版本号
    u2 constant_pool_count 1 常量池中常量个数
    cp_info constant_pool constant_pool_count-1 表类型数据集合,即常量池中每一项常量都是一个表,共有11种结构各不相同的表结构数据
    u2 access_flags 1 访问标志,用于识别类或接口层次的访问信息
    u2 this_class 1 类索引,用于确定这个类的全限定名
    u2 super_class 1 父类索引,用于确定这个类父类的全限定名
    u2 interfaces_count 1 接口索引计数器
    u2 interfaces interfaces_count 接口索引集合,用来描述这个类实现了哪些接口
    u2 fields_count 1 字段表计数器,即字段表集合中的字段表数据个数
    field_info fields fields_count 字段表集合,用于描述接口或类中声明的变量,包括类级别(static)和实例级别变量,不包括在方法内部声明的变量
    u2 methods_count 1 方法表计数器,即方法表集合中的方法表数据个数
    method_info methods methods_count 方法表集合,方法表结构和字段表结构一样
    u2 attributes_count 1 属性订数器
    attribute_info attributes attributes_count 在Class文件、属性表、方法表中都可以包含自己的属性表集合,用于描述某些场景的专有信息

    1,无符号数,以u1、u2、u4、u8分别代表1个字节、2个字节、4个字节、8个字节的无符号数
    2,表,以“_info”结尾,由多个无符号数或其它表构成的复合数据类型

    源自:JVM笔记5:Class文件结构

    3、class文件弊端:

    由class文件结构(第3点)所导致

    • 内存占用大,不适合移动端
    • 堆栈的加载模式,加载速度慢
    • 文件IO操作多,类查找慢

    基于以上几个class文件的特点,又因为移动端运存较小(以当年的移动端手机为标准),class并不适合直接在移动端设备上运行。

    二、dex文件结构深入

    1、dex文件结构:

    • 一种8位字节的二进制流文件
    • 各个数据按顺序紧密的排列,无间隙
    • 整个应用中所有java源文件都放在一个dex中

    2、dex文件结构的详解:

    dex文件与class文件的结构有很大的不同,如下图所示:

    对应的字段说明如下表所示:

    数据名称 解释
    header dex文件头部,记录整个dex文件的相关属性
    string_ids 字符串数据索引,记录了每个字符串在数据区的偏移量
    type_ids 类似数据索引,记录了每个类型的字符串索引
    proto_ids 原型数据索引,记录了方法声明的字符串,返回类型字符串,参数列表
    field_ids 字段数据索引,记录了所属类,类型以及方法名
    method_ids 类方法索引,记录方法所属类名,方法声明以及方法名等信息
    class_defs 类定义数据索引,记录指定类各类信息,包括接口,超类,类数据偏移量
    data 数据区,保存了各个类的真实数据
    link_data 连接数据区

    3、dex头文件

    下面是dex头文件中字段详解,与class文件的结构有部分相同的地方,但因为一个dex文件中包含n个class文件,在头文件中需要对所有class进行标记及记录相关信息,故会多出一些不同的字段。

    字段名称 偏移值 长度 说明
    magic 0x0 8 魔数字段,值为"dex\n035\0"
    checksum 0x8 4 校验码
    signature 0xc 20 sha-1签名
    file_size 0x20 4 dex文件总长度
    header_size 0x24 4 文件头长度,009版本=0x5c,035版本=0x70
    endian_tag 0x28 4 标示字节顺序的常量
    link_size 0x2c 4 链接段的大小,如果为0就是静态链接
    link_off 0x30 4 链接段的开始位置
    map_off 0x34 4 map数据基址
    string_ids_size 0x38 4 字符串列表中字符串个数
    string_ids_off 0x3c 4 字符串列表基址
    type_ids_size 0x40 4 类列表里的类型个数
    type_ids_off 0x44 4 类列表基址
    proto_ids_size 0x48 4 原型列表里面的原型个数
    proto_ids_off 0x4c 4 原型列表基址
    field_ids_size 0x50 4 字段个数
    field_ids_off 0x54 4 字段列表基址
    method_ids_size 0x58 4 方法个数
    method_ids_off 0x5c 4 方法列表基址
    class_defs_size 0x60 4 类定义标中类的个数
    class_defs_off 0x64 4 类定义列表基址
    data_size 0x68 4 数据段的大小,必须4k对齐
    data_off 0x6c 4 数据段基址

    源自:Dex文件格式详解

    对于class文件及dex文件的结构 都可以使用 “010 editor” 这个神器进行查看验证,网上也有相关的文章说明,有兴趣的道友可自行百度 或 访问如下2篇文章进行查阅了解,这里便不再啰嗦:

    4、dex文件的优势

    dex文件的头文件与索引区部分,保存了所有类及类中数据的索引,因此,dvm可通过这两部分快速查找到对应类及数据,相对于直接运行class文件而言,效率上提升了不少。

    三、dex与class两者的异同

    经过上面对class文件与dex文件的结构进行大概的了解之后,我们可以得出如下几个结论:

    • 本质上都是一样的,dex是从class文件演变而来的。
    • class文件存在许多冗余信息,dex文件会去除冗余,并整合。

    四、其他

    1、配置Android及dx环境变量

    以mac为例,windows请百度。

    1. 到用户目录下:
    cd ~
    
    1. 打开.bash_profile文件
    open -e .bash_profile
    

    如果当前用户目录下没有.bash_profile,可以使用 touch .bash_profile 自行创建

    export ANDROID_HOME=/Users/lqr/Library/Android/sdk
    export PATH=${PATH}:${ANDROID_HOME}/tools
    export PATH=${PATH}:${ANDROID_HOME}/platform-tools
    export PATH=${PATH}:${ANDROID_HOME}/build-tools/27.0.3
    

    ANDROID_HOME与build-tools的值需要根据电脑的情况修改。

    1. 配置生效
    source .bash_profile
    
    1. 测试

    在终端输入adb或dx命令看是否有命令反应即可。

    相关文章

      网友评论

        本文标题:热修复与插件化基础——dex与class

        本文链接:https://www.haomeiwen.com/subject/dztrdftx.html