Dalvik 可执行文件格式

本文档介绍了 .dex 文件的版式和内容,这类文件用于保存一系列类定义及其关联的辅助数据。

类型指南

名称 说明
byte 8 位有符号整数
ubyte 8 位无符号整数
short 16 位有符号整数,采用小端字节序
ushort 16 位无符号整数,采用小端字节序
int 32 位有符号整数,采用小端字节序
uint 32 位无符号整数,采用小端字节序
long 64 位有符号整数,采用小端字节序
ulong 64 位无符号整数,采用小端字节序
sleb128 有符号 LEB128,可变长度(见下文)
uleb128 无符号 LEB128,可变长度(见下文)
uleb128p1 无符号 LEB128 加 1,可变长度(见下文)

LEB128

LEB128(“Little-Endian Base 128”)表示任意有符号或无符号整数的可变长度编码。该格式借鉴了 DWARF3 规范。在 .dex 文件中,LEB128 仅用于对 32 位数字进行编码。

每个 LEB128 编码值均由 1-5 个字节组成,共同表示一个 32 位的值。每个字节均已设置其最高有效位(序列中的最后一个字节除外,其最高有效位已清除)。每个字节的剩余 7 位均为有效负荷,即第一个字节中有 7 个最低有效位,第二个字节中也是 7 个,依此类推。对于有符号 LEB128 (sleb128),序列中最后一个字节的最高有效负荷位会进行符号扩展,以生成最终值。在无符号情况 (uleb128) 下,任何未明确表示的位都会被解译为 0

双字节 LEB128 值的按位图
第一个字节第二个字节
1 bit6 bit5 bit4 bit3 bit2 bit1 bit0 0 bit13 bit12 bit11 bit10 bit9 bit8 bit7

变量 uleb128p1 用于表示一个有符号值,其表示法是编码为 uleb128 的值加 1。这使得编码 -1(或被视为无符号值 0xffffffff)成为一个单字节(但没有任何其他负数),并且该编码在下面这些明确说明的情况下非常实用:所表示的数值必须为非负数或 -1(或 0xffffffff);不允许任何其他负值(或不太可能需要使用较大的无符号值)。

以下是这类格式的一些示例:

编码序列 As sleb128 As uleb128 As uleb128p1
0000-1
01110
7f-1127126
80 7f-1281625616255

文件版式

名称 格式 说明
header header_item 标头
string_ids string_id_item[] 字符串标识符列表。这些是此文件使用的所有字符串的标识符,用于内部命名(例如类型描述符)或用作代码引用的常量对象。此列表必须使用 UTF-16 代码点值按字符串内容进行排序(不采用语言区域敏感方式),且不得包含任何重复条目。
type_ids type_id_item[] 类型标识符列表。这些是此文件引用的所有类型(类、数组或原始类型)的标识符(无论文件中是否已定义)。此列表必须按 string_id 索引进行排序,且不得包含任何重复条目。
proto_ids proto_id_item[] 方法原型标识符列表。这些是此文件引用的所有原型的标识符。此列表必须按返回类型(按 type_id 索引排序)主要顺序进行排序,然后按参数列表(按 type_id 索引排序的各个参数,采用字典排序方法)进行排序。该列表不得包含任何重复条目。
field_ids field_id_item[] 字段标识符列表。这些是此文件引用的所有字段的标识符(无论文件中是否已定义)。此列表必须进行排序,其中定义类型(按 type_id 索引排序)是主要顺序,字段名称(按 string_id 索引排序)是中间顺序,而类型(按 type_id 索引排序)是次要顺序。该列表不得包含任何重复条目。
method_ids method_id_item[] 方法标识符列表。这些是此文件引用的所有方法的标识符(无论文件中是否已定义)。此列表必须进行排序,其中定义类型(按 type_id 索引排序)是主要顺序,方法名称(按 string_id 索引排序)是中间顺序,而方法原型(按 proto_id 索引排序)是次要顺序。该列表不得包含任何重复条目。
class_defs class_def_item[] 类定义列表。这些类必须进行排序,以便所指定类的超类和已实现的接口比引用类更早出现在该列表中。此外,对于在该列表中多次出现的同名类,其定义是无效的。
call_site_ids call_site_id_item[] 调用站点标识符列表。这些是此文件引用的所有调用站点的标识符(无论文件中是否已定义)。此列表必须按 call_site_off 的升序进行排序。
method_handles method_handle_item[] 方法句柄列表。此文件引用的所有方法句柄的列表(无论文件中是否已定义)。此列表未进行排序,而且可能包含将在逻辑上对应于不同方法句柄实例的重复项。
data ubyte[] 数据区,包含上面所列表格的所有支持数据。不同的项有不同的对齐要求;如有必要,则在每个项之前插入填充字节,以实现所需的对齐效果。
link_data ubyte[] 静态链接文件中使用的数据。本文档尚未指定本区段中数据的格式。此区段在未链接文件中为空,而运行时实现可能会在适当的情况下使用这些数据。

位字段、字符串和常量的定义

DEX_FILE_MAGIC

在 header_item 中嵌入

常量数组/字符串 DEX_FILE_MAGIC 是字节列表,这类字节必须出现在 .dex 文件的开头,以便系统将其原样识别。该值会特意包含一个换行符("\n"0x0a)和空字节("\0"0x00),以便协助检测某些形式的损坏问题。该值还可以将格式版本号编码为 3 个十进制数字;随着格式的演变,预计该值会单调递增。

ubyte[8] DEX_FILE_MAGIC = { 0x64 0x65 0x78 0x0a 0x30 0x33 0x38 0x00 }
                        = "dex\n038\0"

注意:至少有两种早期版本的格式已在广泛提供的公开软件版本中使用。例如,009 版本已用于 M3 版 Android 平台(2007 年 11 月至 12 月),013 版本已用于 M5 版 Android 平台(2008 年 2 月至 3 月)。在有些方面,这些早期版本的格式与本文档中所述的版本存在很大差异。

注意:Android 8.0 版本中新增了对 038 版格式的支持。038 版本中添加了新字节码(invoke-polymorphicinvoke-custom)和用于方法句柄的数据。

注意:Android 7.0 版本中新增了对 037 版格式的支持。在 037 版本之前,大多数 Android 版本都使用过 035 版格式。035 版与 037 版之间的唯一区别是,是否添加默认方法以及是否调整 invoke

ENDIAN_CONSTANT 和 REVERSE_ENDIAN_CONSTANT

在 header_item 中嵌入

常量 ENDIAN_CONSTANT 用于表示在文件中发现的字节序。虽然标准的 .dex 格式采用小端字节序,但具体实现可能会选择执行字节交换。如果实现遇到其 endian_tagREVERSE_ENDIAN_CONSTANT(而非 ENDIAN_CONSTANT)的标头,则会识别该文件已从预期格式进行过字节交换。

uint ENDIAN_CONSTANT = 0x12345678;
uint REVERSE_ENDIAN_CONSTANT = 0x78563412;

NO_INDEX

在 class_def_item 和 debug_info_item 中嵌入

常量 NO_INDEX 用于表示索引值不存在。

注意:此值不会被定义为 0,因为一般来说,此值通常是一个有效索引。

NO_INDEX 的选定值可表示为 uleb128p1 编码中的单个字节。

uint NO_INDEX = 0xffffffff;    // == -1 if treated as a signed int

access_flags 定义

在 class_def_item、encoded_field、encoded_method 和 InnerClass 中嵌入

这些标记的位字段用于表示类和类成员的可访问性和整体属性。

名称 对于类(和 InnerClass 注释) 对于字段 对于方法
ACC_PUBLIC 0x1 public:全部可见 public:全部可见 public:全部可见
ACC_PRIVATE 0x2 *private:仅对定义类可见 private:仅对定义类可见 private:仅对定义类可见
ACC_PROTECTED 0x4 *protected:对软件包和子类可见 protected:对软件包和子类可见 protected:对软件包和子类可见
ACC_STATIC 0x8 *static:未通过外部 this 引用进行构建 static:对定义类全局可见 static:不采用 this 参数
ACC_FINAL 0x10 final:不可子类化 final:构建后不可变 final:不可覆盖
ACC_SYNCHRONIZED 0x20     synchronized:调用此方法时自动获得关联锁定。

注意:这一项仅在同时设置 ACC_NATIVE 的情况下才有效。

ACC_VOLATILE 0x40   volatile:有助于确保线程安全的特殊访问规则  
ACC_BRIDGE 0x40     桥接方法,由编译器自动添加为类型安全桥
ACC_TRANSIENT 0x80   transient:不会通过默认序列化保存  
ACC_VARARGS 0x80     最后一个参数应被编译器解译为“rest”参数
ACC_NATIVE 0x100     native:在本机代码中实现
ACC_INTERFACE 0x200 interface:可多倍实现的抽象类    
ACC_ABSTRACT 0x400 abstract:不可直接实例化   abstract:不通过此类实现
ACC_STRICT 0x800     strictfp:严格的浮点运算规则
ACC_SYNTHETIC 0x1000 不在源代码中直接定义 不在源代码中直接定义 不在源代码中直接定义
ACC_ANNOTATION 0x2000 声明为注释类    
ACC_ENUM 0x4000 声明为枚举类型 声明为枚举值  
(未使用) 0x8000      
ACC_CONSTRUCTOR 0x10000     构造函数方法(类或实例初始化器)
ACC_DECLARED_
SYNCHRONIZED
0x20000     声明了 synchronized

注意:此项对执行没有任何影响(除了反映此标记本身之外)。

* 仅允许用于 InnerClass 注释,且一律不得在 class_def_item 中使用。

MUTF-8(修改后的 UTF-8)编码

考虑到继续对旧版提供支持,.dex 格式会采用按实际标准修改后的 UTF-8 形式(下文称为 MUTF-8)对其字符串数据进行编码。除以下几点以外,此形式与标准 UTF-8 形式是完全相同的:

  • 仅使用单字节、双字节和三字节编码。
  • U+10000U+10ffff 范围中的代码点被编码为代理对,其中每个代码点均表示为一个三字节编码值。
  • 代码点 U+0000 采用双字节形式进行编码。
  • 纯 Null 字节(值 0)表示字符串的末尾,这是标准的 C 语言解释。

上述前两项可以概括为:MUTF-8 是用于 UTF-16 的编码格式,而不是用于 Unicode 字符的更直接的编码格式。

后两项说明,MUTF-8 既可在字符串中包含代码点 U+0000,同时仍可将其作为 C 样式的 Null 终止字符串进行操作。

不过,特殊编码 U+0000 意味着,与一般 UTF-8 不同的是,针对一对 MUTF-8 字符串调用标准 C 函数 strcmp() 的结果并不一定表示不相等字符串的带有正确符号的比较结果。当需要考虑排序问题(而不仅仅是相等问题)时,用于比较 MUTF-8 字符串的最简单方法是对其字符进行逐个解码,然后比较解码后的值(不过,也许会有更智能的实现方法)。

有关字符编码的详情,请参阅 Unicode 标准。实际上,MUTF-8 比 UTF-8 本身更接近相对而言不太为人熟知的编码 CESU-8

encoded_value 编码

在 annotation_element 和 encoded_array_item 中嵌入

encoded_value 是(几乎)任意层次结构数据的编码片。这种编码非常精简,易于解析。

名称 格式 说明
(value_arg << 5) | value_type ubyte 一种字节,用于表示紧跟后面的 value 及高 3 位中可选澄清参数的类型。请参阅下文,了解各种 value 定义。在大多数情况下,value_arg 会以字节为单位将紧跟后面的 value 的长度编码为 (size - 1);例如,0 表示该值需要 1 个字节,7 表示该值需要 8 个字节;不过,也存在下述例外情况。
value ubyte[] 用于表示值的字节,不同 value_type 字节的长度不同且采用不同的解译方式;不过一律采用小端字节序。有关详情,请参阅下文中的各种值定义。

值格式

类型名称 value_type value_arg 格式 value 格式 说明
VALUE_BYTE 0x00 (无;必须为 0 ubyte[1] 有符号的单字节整数值
VALUE_SHORT 0x02 size - 1 (0…1) ubyte[size] 有符号的双字节整数值,符号扩展
VALUE_CHAR 0x03 size - 1 (0…1) ubyte[size] 无符号的双字节整数值,零扩展
VALUE_INT 0x04 size - 1 (0…3) ubyte[size] 有符号的四字节整数值,符号扩展
VALUE_LONG 0x06 size - 1 (0…7) ubyte[size] 有符号的八字节整数值,符号扩展
VALUE_FLOAT 0x10 size - 1 (0…3) ubyte[size] 四字节位模式,向右零扩展,系统会将其解译为 IEEE754 32 位浮点值
VALUE_DOUBLE 0x11 size - 1 (0…7) ubyte[size] 八字节位模式,向右零扩展,系统会将其解译为 IEEE754 64 位浮点值
VALUE_METHOD_TYPE 0x15 size - 1 (0…3) ubyte[size] 无符号(零扩展)四字节整数值,会被解译为要编入 proto_ids 节的索引;表示方法类型值
VALUE_METHOD_HANDLE 0x16 size - 1 (0…3) ubyte[size] 无符号(零扩展)四字节整数值,会被解译为要编入 method_handles 节的索引;表示方法句柄值
VALUE_STRING 0x17 size - 1 (0…3) ubyte[size] 无符号(零扩展)四字节整数值,会被解译为要编入 string_ids 节的索引;表示字符串值
VALUE_TYPE 0x18 size - 1 (0…3) ubyte[size] 无符号(零扩展)四字节整数值,会被解译为要编入 type_ids 节的索引;表示反射类型/类值
VALUE_FIELD 0x19 size - 1 (0…3) ubyte[size] 无符号(零扩展)四字节整数值,会被解译为要编入 field_ids 节的索引;表示反射字段值
VALUE_METHOD 0x1a size - 1 (0…3) ubyte[size] 无符号(零扩展)四字节整数值,会被解译为要编入 method_ids 节的索引;表示反射方法值
VALUE_ENUM 0x1b size - 1 (0…3) ubyte[size] 无符号(零扩展)四字节整数值,会被解译为要编入 field_ids 节的索引;表示枚举类型常量的值
VALUE_ARRAY 0x1c (无;必须为 0 encoded_array 值的数组,采用下文“encoded_array 格式”所指定的格式。value 的大小隐含在编码中。
VALUE_ANNOTATION 0x1d (无;必须为 0 encoded_annotation 子注释,采用下文“encoded_annotation 格式”所指定的格式。value 的大小隐含在编码中。
VALUE_NULL 0x1e (无;必须为 0 (无) null 引用值
VALUE_BOOLEAN 0x1f 布尔值 (0…1) (无) 一位值;0 表示 false1 表示 true。该位在 value_arg 中有所表示。

encoded_array 格式

名称 格式 说明
size uleb128 数组中的元素数量
values encoded_value[size] 采用本节所指定格式的一系列 size encoded_value 字节序列;依序连接。

encoded_annotation 格式

名称 格式 说明
type_idx uleb128 注释的类型。这种类型必须是“类”(而非“数组”或“基元”)。
size uleb128 此注释中 name-value 映射的数量
elements annotation_element[size] 注释的元素,直接以内嵌形式(不作为偏移量)表示。元素必须按 string_id 索引以升序进行排序。

annotation_element 格式

名称 格式 说明
name_idx uleb128 元素名称,表示为要编入 string_ids 节的索引。该字符串必须符合上文定义的 MemberName 的语法。
value encoded_value 元素值

字符串语法

.dex 文件中有几种类型的项最终会引用字符串。以下 BNF 样式的定义指出了这些字符串可接受的语法。

SimpleName

SimpleName 是其他内容的名称语法的基础。.dex 格式在这方面具有相当大的宽容度(比大多数常见源语言更大)。简而言之,一个简单的名称包含任意低 ASCII 范围的字母字符或数字、几个特定的低 ASCII 范围的符号,以及不属于控件、空格或特殊字符的大多数非 ASCII 代码点。请注意,代理代码点(位于 U+d800U+dfff 范围内)本身不会被视为有效名称字符,但 Unicode 补充字符会被视为有效字符(由 SimpleNameChar 规则的最终替代方案表示),它们应在文件中表示为 MUTF-8 编码中的代理代码点对。

SimpleName
SimpleNameChar (SimpleNameChar)*
SimpleNameChar
'A''Z'
| 'a''z'
| '0''9'
| '$'
| '-'
| '_'
| U+00a1U+1fff
| U+2010U+2027
| U+2030U+d7ff
| U+e000U+ffef
| U+10000U+10ffff

MemberName

由 field_id_item 和 method_id_item 使用

MemberName 是某个类的成员的名称,成员是指字段、方法和内部类。

MemberName →
SimpleName
| '<' SimpleName '>'

FullClassName

FullClassName 是完全限定的类名称,包含一个可选的软件包说明符,后跟一个必需名称。

FullClassName →
OptionalPackagePrefix SimpleName
OptionalPackagePrefix →
(SimpleName '/')*

TypeDescriptor

由 type_id_item 使用

TypeDescriptor 是任何类型的表示形式,包括基元、类、数组和 void请参阅下文,了解各版本的含义。

TypeDescriptor →
'V'
| FieldTypeDescriptor
FieldTypeDescriptor →
NonArrayFieldTypeDescriptor
| ('[' * 1…255) NonArrayFieldTypeDescriptor
NonArrayFieldTypeDescriptor→
'Z'
| 'B'
| 'S'
| 'C'
| 'I'
| 'J'
| 'F'
| 'D'
| 'L' FullClassName ';'

ShortyDescriptor

由 proto_id_item 使用

ShortyDescriptor 是方法原型的简写形式,包括返回类型和参数类型,只不过各种引用(类或数组)类型之间没有区别,而是所有引用类型均由一个 'L' 字符表示。

ShortyDescriptor →
ShortyReturnType (ShortyFieldType)*
ShortyReturnType →
'V'
| ShortyFieldType
ShortyFieldType →
'Z'
| 'B'
| 'S'
| 'C'
| 'I'
| 'J'
| 'F'
| 'D'
| 'L'

TypeDescriptor 语义

以下是 TypeDescriptor 各个变体的含义。

语法 含义
V void;仅对返回类型有效
Z boolean
B byte
S short
C char
I int
J long
F float
D double
Lfully/qualified/Name; fully.qualified.Name
[descriptor descriptor 的数组,可递归地用于“数组的数组”,但维数不能超过 255。

项和相关结构

本部分包含可能在 .dex 文件中出现的各个顶级项的定义。

header_item

在标头区段中显示

对齐:4 个字节

名称 格式 说明
magic ubyte[8] = DEX_FILE_MAGIC 魔法值。更多详情,请参阅上文中“DEX_FILE_MAGIC”下的讨论。
checksum uint 文件剩余内容(除 magic 和此字段之外的所有内容)的 adler32 校验和;用于检测文件损坏情况
signature ubyte[20] 文件剩余内容(除 magicchecksum 和此字段之外的所有内容)的 SHA-1 签名(哈希);用于对文件进行唯一标识
file_size uint 整个文件(包括标头)的大小,以字节为单位
header_size uint = 0x70 标头(整个区段)的大小,以字节为单位。这一项允许至少一定程度的向后/向前兼容性,而不必让格式失效。
endian_tag uint = ENDIAN_CONSTANT 字节序标记。更多详情,请参阅上文中“ENDIAN_CONSTANTREVERSE_ENDIAN_CONSTANT”下的讨论。
link_size uint 链接区段的大小;如果此文件未进行静态链接,则该值为 0
link_off uint 从文件开头到链接区段的偏移量;如果 link_size == 0,则该值为 0。该偏移量(如果为非零值)应该是到 link_data 区段的偏移量。本文档尚未指定此处所指的数据格式;此标头字段(和之前的字段)会被保留为钩子,以供运行时实现使用。
map_off uint 从文件开头到映射项的偏移量。该偏移量(必须为非零)应该是到 data 区段的偏移量,而数据应采用下文中“map_list”指定的格式。
string_ids_size uint 字符串标识符列表中的字符串数量
string_ids_off uint 从文件开头到字符串标识符列表的偏移量;如果 string_ids_size == 0(不可否认是一种奇怪的极端情况),则该值为 0。该偏移量(如果为非零值)应该是到 string_ids 区段开头的偏移量。
type_ids_size uint 类型标识符列表中的元素数量,最多为 65535
type_ids_off uint 从文件开头到类型标识符列表的偏移量;如果 type_ids_size == 0(不可否认是一种奇怪的极端情况),则该值为 0。该偏移量(如果为非零值)应该是到 type_ids 区段开头的偏移量。
proto_ids_size uint 原型标识符列表中的元素数量,最多为 65535
proto_ids_off uint 从文件开头到原型标识符列表的偏移量;如果 proto_ids_size == 0(不可否认是一种奇怪的极端情况),则该值为 0。该偏移量(如果为非零值)应该是到 proto_ids 区段开头的偏移量。
field_ids_size uint 字段标识符列表中的元素数量
field_ids_off uint 从文件开头到字段标识符列表的偏移量;如果 field_ids_size == 0,则该值为 0。该偏移量(如果为非零值)应该是到 field_ids 区段开头的偏移量。
method_ids_size uint 方法标识符列表中的元素数量
method_ids_off uint 从文件开头到方法标识符列表的偏移量;如果 method_ids_size == 0,则该值为 0。该偏移量(如果为非零值)应该是到 method_ids 区段开头的偏移量。
class_defs_size uint 类定义列表中的元素数量
class_defs_off uint 从文件开头到类定义列表的偏移量;如果 class_defs_size == 0(不可否认是一种奇怪的极端情况),则该值为 0。该偏移量(如果为非零值)应该是到 class_defs 区段开头的偏移量。
data_size uint data 区段的大小(以字节为单位)。该数值必须是 sizeof(uint) 的偶数倍。
data_off uint 从文件开头到 data 区段开头的偏移量。

map_list

在数据区段中显示

引用自 header_item

对齐:4 个字节

这是文件全部内容(依序显示)的列表。该列表包含关于 header_item 的一些冗余信息,但这些冗余信息存在的目的是提供一种用于遍历整个文件的简单方式。指定类型在映射中最多只能出现一次,但除了格式其余部分所隐含的限制条件(例如,header 区段必须先显示,随后是 string_ids 区段等等)之外,对于类型可以什么顺序显示,则没有任何限制。此外,映射条目必须按初始偏移量进行排序,不得重叠。

名称 格式 说明
size uint 列表的大小(以条目数表示)
list map_item[size] 列表的元素

map_item 格式

名称 格式 说明
type ushort 项的类型;见下表
unused ushort (未使用)
size uint 在指定偏移量处找到的项数量
offset uint 从文件开头到相关项的偏移量

类型代码

项类型 常量 项大小(以字节为单位)
header_item TYPE_HEADER_ITEM 0x0000 0x70
string_id_item TYPE_STRING_ID_ITEM 0x0001 0x04
type_id_item TYPE_TYPE_ID_ITEM 0x0002 0x04
proto_id_item TYPE_PROTO_ID_ITEM 0x0003 0x0c
field_id_item TYPE_FIELD_ID_ITEM 0x0004 0x08
method_id_item TYPE_METHOD_ID_ITEM 0x0005 0x08
class_def_item TYPE_CLASS_DEF_ITEM 0x0006 0x20
call_site_id_item TYPE_CALL_SITE_ID_ITEM 0x0007 0x04
method_handle_item TYPE_METHOD_HANDLE_ITEM 0x0008 0x08
map_list TYPE_MAP_LIST 0x1000 4 + (item.size * 12)
type_list TYPE_TYPE_LIST 0x1001 4 + (item.size * 2)
annotation_set_ref_list TYPE_ANNOTATION_SET_REF_LIST 0x1002 4 + (item.size * 4)
annotation_set_item TYPE_ANNOTATION_SET_ITEM 0x1003 4 + (item.size * 4)
class_data_item TYPE_CLASS_DATA_ITEM 0x2000 隐式;必须解析
code_item TYPE_CODE_ITEM 0x2001 隐式;必须解析
string_data_item TYPE_STRING_DATA_ITEM 0x2002 隐式;必须解析
debug_info_item TYPE_DEBUG_INFO_ITEM 0x2003 隐式;必须解析
annotation_item TYPE_ANNOTATION_ITEM 0x2004 隐式;必须解析
encoded_array_item TYPE_ENCODED_ARRAY_ITEM 0x2005 隐式;必须解析
annotations_directory_item TYPE_ANNOTATIONS_DIRECTORY_ITEM 0x2006 隐式;必须解析

string_id_item

在 string_ids 区段中显示

对齐:4 个字节

名称 格式 说明
string_data_off uint 从文件开头到此项的字符串数据的偏移量。该偏移量应该是到 data 区段中某个位置的偏移量,而数据应采用下文中“string_data_item”指定的格式。没有偏移量对齐要求。

string_data_item

在数据区段中显示

对齐:无(字节对齐)

名称 格式 说明
utf16_size uleb128 此字符串的大小;以 UTF-16 代码单元(在许多系统中为“字符串长度”)为单位。也就是说,这是该字符串的解码长度(编码长度隐含在 0 字节的位置)。
data ubyte[] 一系列 MUTF-8 代码单元(又称八位字节),后跟一个值为 0 的字节。请参阅上文中的“MUTF-8(修改后的 UTF-8)编码”,了解有关该数据格式的详情和讨论。

注意:在 UTF-16 中进行 Unicode 常规编码时,字符串可以包含(编码形式的)UTF-16 代理代码单元(即 U+d800U+dfff),这些代码单元既可以单独出现,也可以乱序显示。在适用的情况下,可以进阶使用字符串来拒绝这类无效编码。

type_id_item

在 type_ids 区段中显示

对齐:4 个字节

名称 格式 说明
descriptor_idx uint 此类描述符字符串的 string_ids 列表中的索引。该字符串必须符合上文定义的 TypeDescriptor 的语法。

proto_id_item

在 proto_ids 区段中显示

对齐:4 个字节

名称 格式 说明
shorty_idx uint 此原型的简短式描述符字符串的 string_ids 列表中的索引。该字符串必须符合上文定义的 ShortyDescriptor 的语法,而且必须与该项的返回类型和参数相对应。
return_type_idx uint 此原型的返回类型的 type_ids 列表中的索引。
parameters_off uint 从文件开头到此原型的参数类型列表的偏移量;如果此原型没有参数,则该值为 0。该偏移量(如果为非零值)应该位于 data 区段中,且其中的数据应采用下文中“"type_list"”指定的格式。此外,不得对列表中的类型 void 进行任何引用。

field_id_item

在 field_ids 区段中显示

对齐:4 个字节

名称 格式 说明
class_idx ushort 此字段的定义符的 type_ids 列表中的索引。此项必须是“类”类型,而不能是“数组”或“基元”类型。
type_idx ushort 此字段的类型的 type_ids 列表中的索引。
name_idx uint 此字段的名称的 string_ids 列表中的索引。该字符串必须符合上文定义的 MemberName 的语法。

method_id_item

在 method_ids 区段中显示

对齐:4 个字节

名称 格式 说明
class_idx ushort 此方法的定义符的 type_ids 列表中的索引。此项必须是“类”或“数组”类型,而不能是“基元”类型。
proto_idx ushort 此方法的原型的 proto_ids 列表中的索引。
name_idx uint 此方法名称的 string_ids 列表中的索引。该字符串必须符合上文定义的 MemberName 的语法。

class_def_item

在 class_defs 区段中显示

对齐:4 个字节

名称 格式 说明
class_idx uint 此类的 type_ids 列表中的索引。此项必须是“类”类型,而不能是“数组”或“基元”类型。
access_flags uint 类的访问标记(publicfinal 等)。有关详情,请参阅“access_flags 定义”。
superclass_idx uint 超类的 type_ids 列表中的索引。如果此类没有超类(即它是根类,例如 Object),则该值为常量值 NO_INDEX。如果此类存在超类,则此项必须是“类”类型,而不能是“数组”或“基元”类型。
interfaces_off uint 从文件开头到接口列表的偏移量;如果没有接口,则该值为 0。该偏移量应该位于 data 区段,且其中的数据应采用下文中“type_list”指定的格式。该列表的每个元素都必须是“类”类型(而不能是“数组”或“基元”类型),并且不得包含任何重复项。
source_file_idx uint 文件(包含这个类(至少大部分)的原始来源)名称的 string_ids 列表中的索引;或者该值为特殊值 NO_INDEX,以表示缺少这种信息。任何指定方法的 debug_info_item 都可以覆盖此源文件,但预期情况是大多数类只能来自一个源文件。
annotations_off uint 从文件开头到此类的注释结构的偏移量;如果此类没有注释,则该值为 0。该偏移量(如果为非零值)应该位于 data 区段,且其中的数据应采用下文中“annotations_directory_item”指定的格式,同时所有项将此类作为定义符进行引用。
class_data_off uint 从文件开头到此项的关联类数据的偏移量;如果此类没有类数据,则该值为 0(这种情况有可能出现,例如,如果此类是标记接口)。该偏移量(如果为非零值)应该位于 data 区段,且其中的数据应采用下文中“class_data_item”指定的格式,同时所有项将此类作为定义符进行引用。
static_values_off uint 从文件开头到 static 字段的初始值列表的偏移量;如果没有该列表(并且所有 static 字段都将使用 0null 进行初始化),则该值为 0。该偏移量应该位于 data 区段,且其中的数据应采用下文中“encoded_array_item”指定的格式。该数组的大小不得超出此类所声明的 static 字段的数量,且 static 字段所对应的元素应采用相对应的 field_list 中所声明的顺序每个数组元素的类型均必须与其相应字段的声明类型相匹配。如果该数组中的元素比 static 字段中的少,则剩余字段将使用适当类型 0null 进行初始化。

call_site_id_item

在 call_site_ids 区段中显示

对齐:4 个字节

名称 格式 说明
call_site_off uint 从文件开头到调用点定义的偏移量。该偏移量应位于数据区段中,且其中的数据应采用下文中“call_site_item”指定的格式。

call_site_item

在数据区段中显示

对齐:无(字节对齐)

call_site_item 是一个 encoded_array_item,其元素与提供给引导程序链接器方法的参数相对应。前 3 个参数为:

  1. 表示引导程序链接器方法的方法句柄 (VALUE_METHOD_HANDLE)。
  2. 引导程序链接器应解析的方法名称 (VALUE_STRING)。
  3. 与要解析的方法名称类型相对应的方法类型 (VALUE_METHOD_TYPE)。

所有附加参数均为传递给引导程序链接器方法的常量值。这些参数会按顺序传递,而不进行任何类型转换。

表示引导程序链接器方法的方法句柄必须具有返回类型 java.lang.invoke.CallSite。前 3 个参数类型为:

  1. java.lang.invoke.Lookup
  2. java.lang.String
  3. java.lang.invoke.MethodType

任何附加参数的参数类型均由其常量值确定。

method_handle_item

在 method_handles 区段中显示

对齐:4 个字节

名称 格式 说明
method_handle_type ushort 方法句柄的类型;见下表
unused ushort (未使用)
field_or_method_id ushort 字段或方法 ID 取决于方法句柄类型是访问器还是方法调用器
unused ushort (未使用)

方法句柄类型代码

常量 说明
METHOD_HANDLE_TYPE_STATIC_PUT 0x00 方法句柄是静态字段设置器(访问器)
METHOD_HANDLE_TYPE_STATIC_GET 0x01 方法句柄是静态字段获取器(访问器)
METHOD_HANDLE_TYPE_INSTANCE_PUT 0x02 方法句柄是实例字段设置器(访问器)
METHOD_HANDLE_TYPE_INSTANCE_GET 0x03 方法句柄是实例字段获取器(访问器)
METHOD_HANDLE_TYPE_INVOKE_STATIC 0x04 方法句柄是静态方法调用器
METHOD_HANDLE_TYPE_INVOKE_INSTANCE 0x05 方法句柄是实例方法调用器

class_data_item

引用自 class_def_item

在数据区段中显示

对齐:无(字节对齐)

名称 格式 说明
static_fields_size uleb128 此项中定义的静态字段的数量
instance_fields_size uleb128 此项中定义的实例字段的数量
direct_methods_size uleb128 此项中定义的直接方法的数量
virtual_methods_size uleb128 此项中定义的虚拟方法的数量
static_fields encoded_field[static_fields_size] 定义的静态字段;以一系列编码元素的形式表示。这些字段必须按 field_idx 以升序进行排序。
instance_fields encoded_field[instance_fields_size] 定义的实例字段;以一系列编码元素的形式表示。这些字段必须按 field_idx 以升序进行排序。
direct_methods encoded_method[direct_methods_size] 定义的直接(staticprivate 或构造函数的任何一个)方法;以一系列编码元素的形式表示。这些方法必须按 method_idx 以升序进行排序。
virtual_methods encoded_method[virtual_methods_size] 定义的虚拟(非 staticprivate 或构造函数)方法;以一系列编码元素的形式表示。此列表不得包括继承方法,除非被此项所表示的类覆盖。这些方法必须按 method_idx 以升序进行排序。虚拟方法的 method_idx 不得与任何直接方法相同。

注意:所有元素的 field_idmethod_id 都必须引用相同的定义类。

encoded_field 格式

名称 格式 说明
field_idx_diff uleb128 此字段标识(包括名称和描述符)的 field_ids 列表中的索引;它会表示为与列表中前一个元素的索引之间的差值。列表中第一个元素的索引则直接表示出来。
access_flags uleb128 字段的访问标记(publicfinal 等)。有关详情,请参阅“access_flags 定义”。

encoded_method 格式

名称 格式 说明
method_idx_diff uleb128 此方法标识(包括名称和描述符)的 method_ids 列表中的索引;它会表示为与列表中前一个元素的索引之间的差值。列表中第一个元素的索引则直接表示出来。
access_flags uleb128 方法的访问标记(publicfinal 等)。有关详情,请参阅“access_flags 定义”。
code_off uleb128 从文件开头到此方法代码结构的偏移量;如果此方法是 abstractnative,则该值为 0。该偏移量应该是到 data 区段中某个位置的偏移量。数据格式由下文的“code_item”指定。

type_list

引用自 class_def_item 和 proto_id_item

在数据区段中显示

对齐:4 个字节

名称 格式 说明
size uint 列表的大小(以条目数表示)
list type_item[size] 列表的元素

type_item 格式

名称 格式 说明
type_idx ushort type_ids 列表中的索引

code_item

引用自 encoded_method

在数据区段中显示

对齐:4 个字节

名称 格式 说明
registers_size ushort 此代码使用的寄存器数量
ins_size ushort 此代码所用方法的传入参数的字数
outs_size ushort 此代码进行方法调用所需的传出参数空间的字数
tries_size ushort 此实例的 try_item 数量。如果此值为非零值,则这些项会显示为 tries 数组(正好位于此实例中 insns 的后面)。
debug_info_off uint 从文件开头到此代码的调试信息(行号 + 局部变量信息)序列的偏移量;如果没有任何信息,则该值为 0。该偏移量(如果为非零值)应该是到 data 区段中某个位置的偏移量。数据格式由下文的“debug_info_item”指定。
insns_size uint 指令列表的大小(以 16 位代码单元为单位)
insns ushort[insns_size] 字节码的实际数组。insns 数组中代码的格式由随附文档 Dalvik 字节码指定。请注意,尽管此项被定义为 ushort 的数组,但仍有一些内部结构倾向于采用四字节对齐方式。此外,如果此项恰好位于某个字节序交换文件中,则交换操作将只在单个 ushort 上进行,而不是在较大的内部结构上进行。
padding ushort(可选)= 0 使 tries 实现四字节对齐的两字节填充。只有 tries_size 为非零值且 insns_size 是奇数时,此元素才会存在。
tries try_item[tries_size](可选) 用于表示在代码中捕获异常的位置以及如何对异常进行处理的数组。该数组的元素在范围内不得重叠,且数值地址按照从低到高的顺序排列。只有 tries_size 为非零值时,此元素才会存在。
handlers encoded_catch_handler_list(可选) 用于表示“捕获类型列表和关联处理程序地址”的列表的字节。每个 try_item 都具有到此结构的分组偏移量。只有 tries_size 为非零值时,此元素才会存在。

try_item 格式

名称 格式 说明
start_addr uint 此条目涵盖的代码块的起始地址。该地址是到第一个所涵盖指令开头部分的 16 位代码单元的计数。
insn_count ushort 此条目所覆盖的 16 位代码单元的数量。所涵盖(包含)的最后一个代码单元是 start_addr + insn_count - 1
handler_off ushort 从关联的 encoded_catch_hander_list 开头部分到此条目的 encoded_catch_handler 的偏移量(以字节为单位)。此偏移量必须是到 encoded_catch_handler 开头部分的偏移量。

encoded_catch_handler_list 格式

名称 格式 说明
size uleb128 列表的大小(以条目数表示)
list encoded_catch_handler[handlers_size] 处理程序列表的实际列表,直接表示(不作为偏移量)并依序连接

encoded_catch_handler 格式

名称 格式 说明
size sleb128 此列表中捕获类型的数量。如果为非正数,则该值是捕获类型数量的负数,捕获数量后跟一个“全部捕获”处理程序。例如,size0 表示捕获类型为“全部捕获”,而没有明确类型的捕获。size2 表示有两个明确类型的捕获,但没有“全部捕获”类型的捕获。size-1 表示有一个明确类型的捕获和一个“全部捕获”类型的捕获。
handlers encoded_type_addr_pair[abs(size)] abs(size) 编码项的信息流(一种捕获类型对应一项);按照应对类型进行测试的顺序排列。
catch_all_addr uleb128(可选) “全部捕获”处理程序的字节码地址。只有当 size 为非正数时,此元素才会存在。

encoded_type_addr_pair 格式

名称 格式 说明
type_idx uleb128 要捕获的异常类型的 type_ids 列表中的索引
addr uleb128 关联的异常处理程序的字节码地址

debug_info_item

引用自 code_item

在数据区段中显示

对齐:无(字节对齐)

每个 debug_info_item 都会定义一个基于 DWARF3 的字节码状态机,在解译时,系统会发出 (emit) code_item 的位置表,并可能会发出 (emit) 其局部变量信息。该序列的开头是一个可变长度的标头(其长度取决于方法参数的数量),后跟状态机字节码,最后以 DBG_END_SEQUENCE 字节结尾。

该状态机由 5 个寄存器组成。address 寄存器表示关联的 insns_item 中的指令偏移量(以 16 位代码单元为单位)。address 寄存器在每个 debug_info 序列的开头处都是从 0 开始,而且只能单调递增。line 寄存器表示应与状态机发出 (emit) 的下一个位置表条目相关联的源行号。它在序列标头中进行初始化,并可能会正向或负向发生更改,但绝不能小于 1source_file 寄存器表示行号条目引用的源文件。它在 class_def_item 中被初始化为 source_file_idx 的值。另外两个变量(prologue_endepilogue_begin)是布尔值标记(已初始化为 false),它们表示所发出的下一个位置是否应视为方法前序或结尾。此外,该状态机还必须跟踪用于 DBG_RESTART_LOCAL 代码的每个寄存器中最后一个局部变量的名称和类型。

标头如下所示:

名称 格式 说明
line_start uleb128 状态机的 line 寄存器的初始值。不表示实际的位置条目。
parameters_size uleb128 已编码的参数名称的数量。每个方法参数都应该有一个名称,但不包括实例方法的 this(如果有)。
parameter_names uleb128p1[parameters_size] 方法参数名称的字符串索引。NO_INDEX 的编码值表示该关联参数没有可用的名称。该类型描述符和签名隐含在方法描述符和签名中。

字节码值如下:

名称 格式 参数 说明
DBG_END_SEQUENCE 0x00 (无) 终止 code_item 的调试信息序列
DBG_ADVANCE_PC 0x01 uleb128 addr_diff addr_diff:添加到地址寄存器的数量 使地址寄存器指向下一个地址,而不发出 (emit) 位置条目
DBG_ADVANCE_LINE 0x02 sleb128 line_diff line_diff:要更改的行寄存器数量 使行寄存器指向下一个地址,而不发出 (emit) 位置条目
DBG_START_LOCAL 0x03 uleb128 register_num
uleb128p1 name_idx
uleb128p1 type_idx
register_num:将包含本地变量的寄存器
name_idx:该名称的字符串索引
type_idx:该类型的类型索引
在当前地址中引入一个本地变量。name_idxtype_idx 都可能是 NO_INDEX,用于表示该值是未知的。
DBG_START_LOCAL_EXTENDED 0x04 uleb128 register_num
uleb128p1 name_idx
uleb128p1 type_idx
uleb128p1 sig_idx
register_num:将包含本地变量的寄存器
name_idx:该名称的字符串索引
type_idx:该类型的类型索引
sig_idx:该类型签名的字符串索引
在当前地址中引入一个带有类型签名的本地变量。name_idxtype_idxsig_idx 中的任何一个都可能是 NO_INDEX,用于表示该值是未知的(即便 sig_idx-1,使用操作码 DBG_START_LOCAL 也可以更有效地表示相同的数据)。

注意:请参阅 dalvik.annotation.Signature 下的讨论,了解关于处理签名的注意事项。

DBG_END_LOCAL 0x05 uleb128 register_num register_num:包含本地变量的寄存器 在当前地址中将当前存在的本地变量标记为超出范围
DBG_RESTART_LOCAL 0x06 uleb128 register_num register_num:要重新启动的寄存器 在当前地址中重新引入一个本地变量。名称和类型与指定寄存器中存在的最后一个本地变量相同。
DBG_SET_PROLOGUE_END 0x07 (无) 设置 prologue_end 状态机寄存器;表示所添加的下一个位置条目应被视为方法前序的结尾(方法断点的适当位置)。prologue_end 寄存器已被任何特殊的 (>= 0x0a) 操作码清除。
DBG_SET_EPILOGUE_BEGIN 0x08 (无) 设置 epilogue_begin 状态机寄存器;表示所添加的下一个位置条目应被视为方法结尾的开头(要在方法退出之前暂停执行的适当位置)。epilogue_begin 寄存器已被任何特殊的 (>= 0x0a) 操作码清除。
DBG_SET_FILE 0x09 uleb128p1 name_idx name_idx:源文件名称的字符串索引;如果未知,则此项为 NO_INDEX 表示所有后续行号条目均引用此源文件名称,而不是 code_item 中指定的默认名称
特殊操作码 0x0a…0xff (无) 使 lineaddress 寄存器指向下一个地址,发出 (emit) 一个位置条目,并清除 prologue_endepilogue_begin。请参阅下文中的说明。

特殊操作码

值在 0x0a0xff(含)之间的操作码会将 lineaddress 寄存器移动一小部分,然后发出 (emit) 一个新的位置表条目。这些增量的公式如下所示:

DBG_FIRST_SPECIAL = 0x0a  // the smallest special opcode
DBG_LINE_BASE   = -4      // the smallest line number increment
DBG_LINE_RANGE  = 15      // the number of line increments represented

adjusted_opcode = opcode - DBG_FIRST_SPECIAL

line += DBG_LINE_BASE + (adjusted_opcode % DBG_LINE_RANGE)
address += (adjusted_opcode / DBG_LINE_RANGE)

annotations_directory_item

引用自 class_def_item

在数据区段中显示

对齐:4 个字节

名称 格式 说明
class_annotations_off uint 从文件开头到直接在该类上所做的注释的偏移量;如果该类没有任何直接注释,则该值为 0。该偏移量(如果为非零值)应该是到 data 区段中某个位置的偏移量。数据格式由下文的“annotation_set_item”指定。
fields_size uint 此项所注释的字段数量
annotated_methods_size uint 此项所注释的方法数量
annotated_parameters_size uint 此项所注释的方法参数列表的数量
field_annotations field_annotation[fields_size](可选) 所关联字段的注释列表。该列表中的元素必须按 field_idx 以升序进行排序。
method_annotations method_annotation[methods_size](可选) 所关联方法的注释列表。该列表中的元素必须按 method_idx 以升序进行排序。
parameter_annotations parameter_annotation[parameters_size](可选) 所关联方法参数的注释列表。该列表中的元素必须按 method_idx 以升序进行排序。

注意:所有元素的 field_idmethod_id 都必须引用相同的定义类。

field_annotation 格式

名称 格式 说明
field_idx uint 字段(带注释)标识的 field_ids 列表中的索引
annotations_off uint 从文件开头到该字段的注释列表的偏移量。该偏移量应该是到 data 区段中某个位置的偏移量。数据格式由下文的“annotation_set_item”指定。

method_annotation 格式

名称 格式 说明
method_idx uint 方法(带注释)标识的 method_ids 列表中的索引
annotations_off uint 从文件开头到该方法注释列表的偏移量。该偏移量应该是到 data 区段中某个位置的偏移量。数据格式由下文的“annotation_set_item”指定。

parameter_annotation 格式

名称 格式 说明
method_idx uint 方法(其参数带注释)标识的 method_ids 列表中的索引
annotations_off uint 从文件开头到该方法参数的注释列表的偏移量。该偏移量应该是到 data 区段中某个位置的偏移量。数据格式由下文的“annotation_set_ref_list”指定。

annotation_set_ref_list

引用自 parameter_annotations_item

在数据区段中显示

对齐:4 个字节

名称 格式 说明
size uint 列表的大小(以条目数表示)
list annotation_set_ref_item[size] 列表的元素

annotation_set_ref_item 格式

名称 格式 说明
annotations_off uint 从文件开头到所引用注释集的偏移量;如果此元素没有任何注释,则该值为 0。该偏移量(如果为非零值)应该是到 data 区段中某个位置的偏移量。数据格式由下文的“annotation_set_item”指定。

annotation_set_item

引用自 annotations_directory_item、field_annotations_item、method_annotations_item 和 annotation_set_ref_item

在数据区段中显示

对齐:4 个字节

名称 格式 说明
size uint 该集合的大小(以条目数表示)
entries annotation_off_item[size] 该集合的元素。这些元素必须按 type_idx 以升序进行排序。

annotation_off_item 格式

名称 格式 说明
annotation_off uint 从文件开头到注释的偏移量。该偏移量应该是到 data 区段中某个位置的偏移量,且该位置的数据格式由下文的“annotation_item”指定。

annotation_item

引用自 annotation_set_item

在数据区段中显示

对齐:无(字节对齐)

名称 格式 说明
visibility ubyte 此注释的预期可见性(见下文)
annotation encoded_annotation 已编码的注释内容;采用上文的“encoded_value 编码”下的“encoded_annotation 格式”所述的格式。

可见值

以下是 annotation_itemvisibility 字段的选项:

名称 说明
VISIBILITY_BUILD 0x00 预计仅在构建(例如,在编译其他代码期间)时可见
VISIBILITY_RUNTIME 0x01 预计在运行时可见
VISIBILITY_SYSTEM 0x02 预计在运行时可见,但仅对基本系统(而不是常规用户代码)可见

encoded_array_item

引用自 class_def_item

在数据区段中显示

对齐:无(字节对齐)

名称 格式 说明
value encoded_array 用于表示编码数组值的字节,采用上文的“encoded_value 编码”下的“encoded_array 格式”指定的格式。

系统注释

系统注释用于表示关于类(以及方法和字段)的各种反射信息。这类信息通常只能通过客户端(非系统)代码来间接获取。

系统注释在 .dex 文件中表示为注释,可见性设为 VISIBILITY_SYSTEM

dalvik.annotation.AnnotationDefault

在注释界面的方法中显示

AnnotationDefault 注释会附加到各个注释界面,用于表示默认绑定。

名称 格式 说明
value Annotation 此注释的默认绑定,表示为此类型的注释。该注释不需要包含由注释定义的所有名称;缺少的名称根本没有默认值。

dalvik.annotation.EnclosingClass

在类中显示

EnclosingClass 注释会附加到各个类,这些类会被定义为其他类本身的成员,或者匿名显示但不在方法正文中定义(例如,合成的内部类)。具有此注释的各个类还必须具有 InnerClass 注释。此外,一个类不得同时包含 EnclosingClassEnclosingMethod 注释。

名称 格式 说明
value Class 在词法作用域最接近此类的类

dalvik.annotation.EnclosingMethod

在类中显示

EnclosingMethod 注释会附加到已在方法正文中定义的各个类。具有此注释的各个类还必须具有 InnerClass 注释。此外,一个类不得同时包含 EnclosingClassEnclosingMethod 注释。

名称 格式 说明
value Method 在词法作用域最接近此类的方法

dalvik.annotation.InnerClass

在类中显示

InnerClass 注释会附加到已在其他类定义的词法作用域中定义的各个类。具有此注释的所有类还必须具有 EnclosingClass 注释或 EnclosingMethod 注释。

名称 格式 说明
name String 此类最初声明的简单名称(不包含任何软件包前缀)。如果此类是匿名显示,则名称为 null
accessFlags int 此类最初声明的访问标记(由于源语言与目标虚拟机之间的执行模型不匹配,该标记可能与有效标记不同)

dalvik.annotation.MemberClasses

在类中显示

MemberClasses 注释会附加到声明成员类(成员类是指具有名称的直接内部类)的各个类。

名称 格式 说明
value Class[] 成员类的数组

dalvik.annotation.MethodParameters

在方法中显示

注意:此注释在 Android 7.1 之后的版本中添加。早期 Android 版本中存在的这类注释将被忽略。

MethodParameters 注释是可选项,并可用于提供参数元数据(例如参数名称和修饰符)。

当运行时不需要参数元数据时,可在方法或构造函数中放心地省略这项注释。 java.lang.reflect.Parameter.isNamePresent() 可用于检查某个参数中是否存在元数据;如果不存在这种信息,则关联的反射方法(例如 java.lang.reflect.Parameter.getName())将在运行时回退到默认行为。

如果编译器包含参数元数据,则必须包含已生成类(如枚举)的信息,因为参数元数据会指明参数是合成参数还是强制参数。

MethodParameters 注释仅用于描述单个方法的参数。因此,为了权衡代码大小和运行时效率,编译器可能会完全省略不含参数的构造函数和方法的注释。

下面记录的数组必须与该方法所关联的 method_id_item dex 结构具有相同的大小,否则运行时会抛出 java.lang.reflect.MalformedParametersException

即:method_id_item.proto_idx -> proto_id_item.parameters_off -> type_list.size 必须与 names().lengthaccessFlags().length 相同。

由于 MethodParameters 说明了所有形式方法参数,甚至包括源代码中没有明确声明或隐式声明的参数,因此数组的大小可能不同于签名或其他元数据信息(仅基于源代码中声明的显式参数)的大小。此外,MethodParameters 也不包含任何关于实际方法签名中不存在的类型注释接收器参数的信息。

名称 格式 说明
names String[] 关联方法的形式参数的名称。数组不得为空;但如果没有任何形式参数,则该项必须为空。如果使用该索引的形式参数没有名称,则数组中的值必须为空。
如果参数名称字符串为空或包含“.”、“;”、“[”或“/”,则运行时会抛出 java.lang.reflect.MalformedParametersException
accessFlags int[] 关联方法的形式参数的访问标记。数组不得为空;但如果没有任何形式参数,则该项必须为空。
该值是包含以下值的位掩码:
  • 0x0010:final,表示该参数被声明为 final
  • 0x1000:synthetic,表示该参数由编译器引入
  • 0x8000:mandated,表示该参数是合成参数,但同样由语言规范所暗示
如果任何位在此集合之外进行设置,则运行时会抛出 java.lang.reflect.MalformedParametersException

dalvik.annotation.Signature

在类、字段和方法中显示

Signature 注释会附加到各个类、字段或方法(按照比 type_id_item 所表示的类型更复杂的类型进行定义)。.dex 格式不定义签名的格式;它仅仅能够表示源语言成功实现该语言的语义所需要的任何签名。因此,签名通常不会通过虚拟机实现进行解析(或验证)。这些签名只会传递给更高级别的 API 和工具(如调试程序)。因此,每次使用签名时都应该记录下来,以免就只接收有效签名作出任何假设,从而明确防止出现句法无效的签名。

由于签名字符串往往包含很多重复内容,因此 Signature 注释会被定义为字符串的数组,其中的重复元素会自然地引用相同的基本数据,而签名则被视为该数组中所有字符串的连接。对于如何将签名分割成单独的字符串,则没有任何规则;这完全取决于生成 .dex 文件的工具。

名称 格式 说明
value String[] 该类或成员的签名,用作要连接在一起的字符串的数组

dalvik.annotation.Throws

在方法中显示

Throws 注释会附加到已声明要抛出一个或多个异常类型的各个方法。

名称 格式 说明
value Class[] 已抛出的异常类型的数组