android中热修复与插件化(一)

简介

目前android技术最前沿莫属热修复与插件化的技术点,当下用得最多的就是阿里的Andfix,和微信的Tinker框架,针对源码的实现,再次做个记录。

热修复给我们解决的问题
  1. 刚上线的APP应用,由于测试的疏忽,发现了一个严重的bug。
  2. 针对一些小功能,不想再次经历发布,打包发送给用户。

插件化解决的问题
  1. 解决应用越来越大所带来的问题(方法超过65535)
  2. 解决应用越来越大带来的合作开发的问题

我们从三方面来对于热修复和插件化进行分析。

目录
  • 知识详解模块
  • 热修复应用模块
  • 插件化应用模块
知识详解模块
  1. dex/class深入讲解
  2. jvm/dvm/art深入讲解

class文件结构深入解析

什么是class文件

class文件全名称为Java class文件,能被java虚拟机所识别的二进制文件。能够被jvm加载 并执行的文件格式。

如何生成一个class文件
  1. 通过IDE(代码编辑器)自动帮我们生成class文件
  2. 通过javac去生成class文件
class文件的作用
记录一个类文件的所以信息
class文件格式详解
1.一种8位字节的二进制流文件
2.各个数据按顺序紧密的排列,无间隙(例如:cafebabe00000032....)
3.每个类和接口都对应一个class文件    

class文件格式组成
这里写图片描述

注:其中u1,u2,u4,u8分别代表1字节,2字节,4字节和8字节的无符号类型整数。

我们编写一个java文件:

public class Hello{
      private int test;
      public int test(){
            return test;
        }
}

接下来用010Edit打开文件格式

ca fe ba be 00 00 00 32 00 12 0a 00 04 00 0e 09
00 03 00 0f 07 00 10 07 00 11 01 00 04 74 65 73
74 01 00 01 49 01 00 06 3c 69 6e 69 74 3e 01 00
03 28 29 56 01 00 04 43 6f 64 65 01 00 0f 4c 69
6e 65 4e 75 6d 62 65 72 54 61 62 6c 65 01 00 03
28 29 49 01 00 0a 53 6f 75 72 63 65 46 69 6c 65
01 00 0a 48 65 6c 6c 6f 2e 6a 61 76 61 0c 00 07
00 08 0c 00 05 00 06 01 00 05 48 65 6c 6c 6f 01
00 10 6a 61 76 61 2f 6c 61 6e 67 2f 4f 62 6a 65
63 74 00 21 00 03 00 04 00 00 00 01 00 02 00 05
00 06 00 00 00 02 00 01 00 07 00 08 00 01 00 09
00 00 00 1d 00 01 00 01 00 00 00 05 2a b7 00 01
b1 00 00 00 01 00 0a 00 00 00 06 00 01 00 00 00
01 00 01 00 05 00 0b 00 01 00 09 00 00 00 1d 00
01 00 01 00 00 00 05 2a b4 00 02 ac 00 00 00 01
00 0a 00 00 00 06 00 01 00 00 00 03 00 01 00 0c
00 00 00 02 00 0d

(ca fe ba be)
magic魔数,魔数的唯一作用是确定这个文件是否是class文件。魔数值固定为 0xCAFEBABE,不会改变。

(00 00 00 32)
minor_version、major_version副版本号和主版本号,当前副版本号是0,主版本号是50。

(00 12)
constant_pool_count常量池计数器,该常量数为17

constant_pool常量池,它包含 Class 文件结构及其子结构中引用的所有字符串常量、类或接口名、字段名和其它常量。constant_pool 就下来就是分析这17个常量了。

常量池如下:
          00 12  常量池的数目 18-1=17
          0a 00 04 00 0e  方法:java.lang.Ojbect void <init>()
          09 00 03 00 0f   方法 :Hello int test() 
          07 00 10  字符串:Hello
          07 00 11 字符串:java.lang.Ojbect
          01 00 04 74 65 73 74 字符串:test
          01 00 01 49  字符串:I
          01 00 06 3c 69 6e 69 74 3e 字符串:<init>
          01 00 03 28 29 56 字符串:()V
          01 00 04 43 6f 64 65 字符串:Code 
          01 00 0f 4c 69 6e 65 4e 75 6d 62 65 72 54 61 62 6c 65 字符串:LineNumberTable 
          01 00 03 28 29 49 字符串:()I
          01 00 0a 53 6f 75 72 63 65 46 69 6c 65 字符串:SourceFile
          01 00 0a 48 65 6c 6c 6f 2e 6a 61 76 61 字符串:Hello.java
          0c 00 07 00 08 NameAndType:<init> ()V
          0c 00 05 00 06 NameAndType:test I
          01 00 05 48 65 6c 6c 6f 字符串:Hello
          01 00 10 6a 61 76 61 2f 6c 61 6e 67 2f 4f 62 6a 65 63 74 字符串: java/lang/Object

(00 21)
access_flags 描述的是当前类(或者接口)的访问修饰符, 如public, private等。
这里写图片描述

(00 03)
this_class类索引,this_class存的是当前类的名称在常量池里的索引,这里指向第三个常量,即是“Hello”。

(00 04)
super_class存的是父类的名称在常量池里的索引,这里指向第四个常量,即是“java/lang/Object”。

(00 00)
nterfaces包含interfaces_count和interfaces[]两个字段。这里interfaces_count为0,所以后面的内容也对应为空

fields_count字段计数器,fields_count 的值表示当前 Class 文件 fields数组的成员个数。

fields数组中的每个成员都必须是一个 fields_info 的数据项,用于表示当前类或接口中某个字段的完整描述。

methods_count 的值表示当前 Class 文件 methods[]数组的成员个数。

methods[]数组中的每个成员都必须是一个 method_info 的数据项,用于表示当前类或接口中某个方法的完整描述。

attributes_count 的值表示当前 Class 文件 attributes 表的成员个数。

attributes 表的每个项的值必须是 attribute_info 。

class文件弊端
 1.内存占用大,不适合移动端
 2.堆栈的加载模式,加载速度慢。
 3.文件io操作多,类查找慢。
接下来我们分析dex文件
什么是dex文件

能够被dvm识别,加载并执行的文件格式

如何生成一个dex文件
通过ide自动帮我们build生成
手动通过dx命令去生成dex文件
手动运行dex文件运行在手机上
执行dex文件
1.找到android sdk->build-tools->选择版本->dx,配置到环境变量中
2.在cmd中  dx --dex --output Hello.dex Hello.class
3.将dex文件push到手机存储卡中,然后执行adb shell进入手机控制台
4.使用dalvikvm -cp /sdcard/Hello.dex 类名 执行dex文件
dex文件的作用

记录整个工程中所有类文件的信息,记住是整个工程。

dex文件格式详解
1.一种8位字节的二进制流文件
2.各个数据按顺序紧密排列,无间隙。
3.整个应用中所有java源文件都放在一个dex中
dex文件结构

这里写图片描述

header(基本信息)

header是DEX文件头,包含magic字段、alder32校验值、SHA-1哈希值、string_ids的个数以及偏移地址等。DEX文件的头结构很固定,占用0x70个字节,具体定义代码如下所示(摘自DexFile.h):

struct DexHeader {
    u1  magic[8];           /* includes version number */  
    u4  checksum;           /* adler32 checksum */  
    u1  signature[kSHA1DigestLen]; /* SHA-1 hash */
    u4  fileSize;           /* length of entire file */
    u4  headerSize;         /* offset to start of next section */
    u4  endianTag;
    u4  linkSize;
    u4  linkOff;
    u4  mapOff;
    u4  stringIdsSize;
    u4  stringIdsOff;
    u4  typeIdsSize;
    u4  typeIdsOff;
    u4  protoIdsSize;
    u4  protoIdsOff;
    u4  fieldIdsSize;
    u4  fieldIdsOff;
    u4  methodIdsSize;
    u4  methodIdsOff;
    u4  classDefsSize;
    u4  classDefsOff;
    u4  dataSize;
    u4  dataOff;
};

magic[8]:共8个字节。目前为固定值dex\n035。

checksum:文件校验码,使用alder32算法校验文件除去magic、checksum外余下的所有文件区域,用于检查文件错误。

signature:使用 SHA-1算法hash除去magic,checksum和signature外余下的所有文件区域 ,用于唯一识别本文件 。

fileSize:DEX文件的长度。

headerSize:header大小,一般固定为0x70字节。

endianTag:指定了DEX运行环境的cpu字节序,预设值ENDIAN_CONSTANT等于0x12345678,表示默认采用Little-Endian字节序。

linkSize和linkOff:指定链接段的大小与文件偏移,大多数情况下它们的值都为0。link_size:LinkSection大小,如果为0则表示该DEX文件不是静态链接。link_off用来表示LinkSection距离DEX头的偏移地址,如果LinkSize为0,此值也会为0。

mapOff:DexMapList结构的文件偏移。

stringIdsSize和stringIdsOff:DexStringId结构的数据段大小与文件偏移。

typeIdsSize和typeIdsOff:DexTypeId结构的数据段大小与文件偏移。

protoIdsSize和protoIdsSize:DexProtoId结构的数据段大小与文件偏移。

fieldIdsSize和fieldIdsSize:DexFieldId结构的数据段大小与文件偏移。

methodIdsSize和methodIdsSize:DexMethodId结构的数据段大小与文件偏移。

classDefsSize和classDefsOff:DexClassDef结构的数据段大小与文件偏移。

dataSize和dataOff:数据段的大小与文件偏移。

class文件与dex文件对比

1.本质上他们都是一样的,dex是从class文件演变而来的
2.class文件存在许多冗余信息,dex会去除冗余信息

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值