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 编码值由一到五个字节组成,这些字节共同表示一个 32 位值。每个字节的最高有效位都已设置,但序列中的最后一个字节除外,它的最高有效位已清除。每个字节的剩余七位是有效负载,数量的最低有效七位在第一个字节中,接下来的七位在第二个字节中,依此类推。在有符号 LEB128 (sleb128) 的情况下,序列中最后一个字节的最高有效负载位会进行符号扩展,以生成最终值。在无符号情况下 (uleb128),任何未明确表示的位都解释为 0

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

变体 uleb128p1 用于表示有符号值,其中表示形式是值加一,编码为 uleb128。这使得 -1(也可以认为是无符号值 0xffffffff)的编码(但没有其他负数)成为单字节,并且在表示的数字必须是非负数或 -1(或 0xffffffff),并且不允许其他负值(或不太可能需要大的无符号值)的情况下非常有用。

以下是一些格式示例

编码序列 作为 sleb128 作为 uleb128 作为 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[] 静态链接文件中使用的数据。本文档未指定此部分中数据的格式。此部分在未链接的文件中为空,运行时实现可以根据需要使用它。

容器格式

版本 41 引入了一种新的 DEX 数据容器格式,旨在节省空间。此容器格式允许将多个逻辑 DEX 文件组合成单个物理文件。新格式主要只是先前格式文件的简单连接,但有一些不同之处

  • file_size 是逻辑文件的大小,而不是物理文件的大小。它可用于迭代容器中的所有逻辑文件。
  • 逻辑 dex 文件可以引用容器中任何后续数据(但不能引用更早的数据)。这允许 dex 文件在它们之间共享数据,例如字符串。
  • 所有偏移量都相对于物理文件。没有偏移量是相对于标头的。这确保了具有偏移量的节可以在逻辑文件之间共享。
  • 标头添加了两个新字段来描述容器的边界。这是一个额外的完整性检查,使代码移植到新格式更容易。
  • data_sizedata_off 现在未使用。数据可以分布在多个逻辑文件中,而不必是连续的。

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

DEX_FILE_MAGIC

嵌入在 header_item 中

常量数组/字符串 DEX_FILE_MAGIC 是必须出现在 .dex 文件开头才能被识别为此类文件的字节列表。该值有意包含换行符 ("\n"0x0a) 和空字节 ("\0"0x00),以帮助检测某些形式的损坏。该值还以三个十进制数字编码格式版本号,随着格式的演变,预计该版本号会单调递增。

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

注意: Android 10.0 版本中添加了对格式版本 040 的支持,该版本扩展了 SimpleNames 中允许的字符集。

注意: Android 9.0 版本中添加了对格式版本 039 的支持,该版本引入了两个新的字节码,const-method-handleconst-method-type。(这些都在字节码集摘要表中进行了描述。)在 Android 10 中,版本 039 扩展了 DEX 文件格式,以包含隐藏的 API 信息,该信息仅适用于引导类路径上的 DEX 文件。

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

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

注意: 至少在广泛可用的公共软件版本中使用了几个早期版本的格式。例如,版本 009 用于 Android 平台的 M3 版本(2007 年 11 月至 12 月),版本 013 用于 Android 平台的 M5 版本(2008 年 2 月至 3 月)。在某些方面,这些早期版本的格式与本文档中描述的版本有很大不同。

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 中出现。

Modified UTF-8 编码

作为对更轻松的旧版支持的让步,.dex 格式以事实上的标准 modified UTF-8 形式编码其字符串数据,以下简称 MUTF-8。此形式与标准 UTF-8 相同,但有以下例外

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

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

以上最后两项使其可以同时在字符串中包含代码点 U+0000 并且仍然将其作为 C 风格的空终止字符串进行操作。

但是,U+0000 的特殊编码意味着,与正常的 UTF-8 不同,在 MUTF-8 字符串对上调用标准 C 函数 strcmp() 的结果并不总是指示不相等字符串比较的正确有符号结果。当排序(不仅仅是相等性)是一个问题时,比较 MUTF-8 字符串最直接的方法是逐字符解码它们,并比较解码后的值。(但是,也可能有更巧妙的实现。)

有关字符编码的更多信息,请参阅 Unicode 标准。MUTF-8 实际上更接近于(相对不太知名的)编码 CESU-8,而不是 UTF-8 本身。

encoded_value 编码

嵌入在 annotation_element 和 encoded_array_item 中

encoded_value 是编码的一段(几乎)任意分层结构化数据。该编码旨在既紧凑又易于解析。

名称 格式 说明
(value_arg << 5) | value_type ubyte 指示紧随其后的 value 类型的字节,以及高三位中的可选澄清参数。请参阅下文了解各种 value 定义。在大多数情况下,value_arg 以字节为单位编码紧随其后的 value 的长度,如 (size - 1),例如,0 表示该值需要一个字节,7 表示它需要八个字节;但是,如下所述,也有例外。
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] 一系列 sizeencoded_value 字节序列,格式由此部分指定,并按顺序连接。

encoded_annotation 格式

名称 格式 说明
type_idx uleb128 注解的类型。这必须是类(而不是数组或原始)类型。
size uleb128 size
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 代码点组成,这些代码点不是控制字符、空格字符或特殊字符。从版本 040 开始,该格式还允许空格字符(Unicode Zs 类别)。请注意,代理代码点(在范围 U+d800U+dfff 中)本身不被视为有效的名称字符,但 Unicode 补充字符有效的(由 SimpleNameChar 规则的最后一个备选项表示),并且它们应在文件中表示为 MUTF-8 编码中的代理代码点对。

SimpleName
SimpleNameChar (SimpleNameChar)*
SimpleNameChar
'A''Z'
| 'a''z'
| '0''9'
| ' ' 自 DEX 版本 040 起
| '$'
| '-'
| '_'
| U+00a0 自 DEX 版本 040 起
| U+00a1U+1fff
| U+2000U+200a 自 DEX 版本 040 起
| U+2010U+2027
| U+202f 自 DEX 版本 040 起
| 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
byte short
S char
I int
int long
J 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

整个文件的大小(包括标头),以字节为单位 (v40 或更早版本)

从该标头的开头到下一个标头或整个文件(容器)的结尾的字节距离。(v41 或更高版本)

header_size uint

标头的大小(整个部分),以字节为单位。这允许至少有限的向前/向后兼容性,而不会使格式失效。

必须为 0x70 (112) 字节 (v40 或更早版本)

必须为 0x78 (120) 字节 (v41 或更高版本)

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 从文件开头到 map item 的偏移量。偏移量(必须为非零值)应指向 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) 的偶数倍。(v40 或更早版本)

未使用 (v41 或更高版本)

data_off uint

从文件开始到 data 区段开始位置的偏移量 (v40 或更早版本)

未使用 (v41 或更高版本)

container_size uint

此字段不存在。可以假定它等于 file_size(v40 或更早版本)

整个文件的大小(包括其他 dex 头部及其数据)。(v41 或更高版本)

header_offset uint

此字段不存在。可以假定它等于 0(v40 或更早版本)

从文件开始到此头部开始位置的偏移量。(v41 或更高版本)

map_list

出现在 data 区段中

从 header_item 引用

对齐:4 字节

这是文件中所有内容的列表,按顺序排列。它相对于 header_item 有一些冗余,但旨在成为一种易于使用的形式,用于遍历整个文件。给定类型在一个 map 中最多出现一次,但对类型的出现顺序没有限制,除了格式的其余部分所暗示的限制(例如,header 区段必须首先出现,然后是 string_ids 区段等)。此外,map 条目必须按初始偏移量排序,并且不得重叠。

名称 格式 说明
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 隐式;必须解析
hiddenapi_class_data_item TYPE_HIDDENAPI_CLASS_DATA_ITEM 0xF000 隐式;必须解析

string_id_item

出现在 string_ids 区段中

对齐:4 字节

名称 格式 说明
string_data_off uint 从文件开始到此条目的字符串数据的偏移量。偏移量应指向 data 区段中的某个位置,并且数据应采用下面 "string_data_item" 指定的格式。偏移量没有对齐要求。

string_data_item

出现在 data 区段中

对齐方式:无(字节对齐)

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

注意: 包含(UTF-16 代理代码单元的编码形式)的字符串是可以接受的(即,U+d800U+dfff),无论是单独存在还是相对于 Unicode 的通常 UTF-16 编码而言乱序。如果合适,由字符串的更高级别用途来拒绝此类无效编码。

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 字段的数量,并且元素与相应的 field_list 中声明的 static 字段顺序相同。每个数组元素的类型必须与其对应的字段的声明类型匹配。如果数组中的元素少于 static 字段的数量,则剩余字段将使用类型适当的 0null 初始化。

call_site_id_item

出现在 call_site_ids 区段中

对齐:4 字节

名称 格式 说明
call_site_off uint 从文件开始到调用站点定义的偏移量。偏移量应在 data 区段中,并且那里的数据应采用下面 "call_site_item" 指定的格式。

call_site_item

出现在 data 区段中

对齐方式:无(字节对齐)

call_site_item 是一个 encoded_array_item,其元素对应于提供给引导链接器方法的参数。前三个参数是

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

任何其他参数都是传递给引导链接器方法的常量值。这些参数按顺序传递,不进行任何类型转换。

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

  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 方法句柄是实例方法调用器
METHOD_HANDLE_TYPE_INVOKE_CONSTRUCTOR 0x06 方法句柄是构造函数方法调用器
METHOD_HANDLE_TYPE_INVOKE_DIRECT 0x07 方法句柄是直接方法调用器
METHOD_HANDLE_TYPE_INVOKE_INTERFACE 0x08 方法句柄是接口方法调用器

class_data_item

从 class_def_item 引用

出现在 data 区段中

对齐方式:无(字节对齐)

名称 格式 说明
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 引用

出现在 data 区段中

对齐:4 字节

名称 格式 说明
size uint 列表中条目的数量
list type_item[size] 列表的元素

type_item 格式

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

code_item

从 encoded_method 引用

出现在 data 区段中

对齐: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 此列表中捕获类型的数量。如果为非正数,则这是捕获类型的数量的负数,并且捕获之后会跟一个 catch-all 处理程序。例如:size0 表示存在 catch-all,但没有显式类型的捕获。size2 表示存在两个显式类型的捕获,并且没有 catch-all。size-1 表示存在一个类型化的捕获以及一个 catch-all。
handlers encoded_type_addr_pair[abs(size)] abs(size) 编码条目的流,每种捕获类型一个,按应测试类型的顺序排列。
catch_all_addr uleb128 (可选) catch-all 处理程序的字节码地址。仅当 size 为非正数时,此元素才存在。

encoded_type_addr_pair 格式

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

debug_info_item

从 code_item 引用

出现在 data 区段中

对齐方式:无(字节对齐)

每个 debug_info_item 定义一个受 DWARF3 启发的字节码状态机,该状态机在解释时会为 code_item 发射位置表和(可能)局部变量信息。该序列以可变长度头部开始(其长度取决于方法参数的数量),后跟状态机字节码,并以 DBG_END_SEQUENCE 字节结束。

状态机由五个寄存器组成。address 寄存器表示关联的 insns_item 中的指令偏移量,以 16 位代码单元为单位。address 寄存器在每个 debug_info 序列开始时从 0 开始,并且只能单调递增。line 寄存器表示应与状态机发射的下一个位置表条目关联的源行号。它在序列头部中初始化,并且可能会在正方向或负方向上更改,但绝不能小于 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:要添加到地址寄存器的量 在不发射位置条目的情况下前进地址寄存器
DBG_ADVANCE_LINE 0x02 sleb128 line_diff line_diff:行寄存器要更改的量 在不发射位置条目的情况下前进行寄存器
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 寄存器,发射位置条目,并清除 prologue_endepilogue_begin。有关描述,请参见下文。

特殊操作码

值介于 0x0a0xff(包括)之间的操作码会少量移动 lineaddress 寄存器,然后发射新的位置表条目。增量的公式如下:

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 引用

出现在 data 区段中

对齐: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

出现在 data 区段中

对齐: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

出现在 data 区段中

对齐:4 字节

名称 格式 说明
size uint 集合的大小,以条目数计
条目 annotation_off_item[size] 集合的元素。元素必须按 type_idx 升序排序。

annotation_off_item 格式

名称 格式 说明
annotation_off uint 从文件起始位置到注解的偏移量。此偏移量应指向 data 部分中的某个位置,并且该位置的数据格式由下文的“annotation_item”指定。

annotation_item

引用自 annotation_set_item

出现在 data 区段中

对齐方式:无(字节对齐)

名称 格式 说明
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 引用

出现在 data 区段中

对齐方式:无(字节对齐)

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

hiddenapi_class_data_item

本节包含每个类使用的受限接口的数据。

注意: 隐藏 API 功能是在 Android 10.0 中引入的,仅适用于启动类路径中类的 DEX 文件。下文描述的标志列表可能会在 Android 的未来版本中扩展。如需了解详情,请参阅关于非 SDK 接口限制的说明

名称 格式 说明
size uint 节的总大小
offsets uint[] class_idx 索引的偏移量数组。索引 class_idx 处的零数组条目表示此 class_idx 没有数据,或者所有隐藏 API 标志均为零。否则,数组条目为非零,并包含从此节开头到此 class_idx 的隐藏 API 标志数组的偏移量。
flags uleb128[] 每个类的隐藏 API 标志的串联数组。可能的标志值在下表中描述。标志的编码顺序与字段和方法在类数据中的编码顺序相同。

限制标志类型

名称 说明
whitelist 0 可以自由使用并作为正式文档化的 Android 框架 软件包索引 的一部分受到支持的接口。
greylist 1 无论应用的 目标 API 级别 如何,都可以使用的非 SDK 接口。
blacklist 2 无论应用的 目标 API 级别 如何,都不能使用的非 SDK 接口。访问其中一个接口会导致运行时错误
greylist‑max‑o 3 除非受到限制,否则可用于 Android 8.x 及更低版本的非 SDK 接口。
greylist‑max‑p 4 除非受到限制,否则可用于 Android 9.x 的非 SDK 接口。
greylist‑max‑q 5 除非受到限制,否则可用于 Android 10.x 的非 SDK 接口。
greylist‑max‑r 6 除非受到限制,否则可用于 Android 11.x 的非 SDK 接口。

系统注解

系统注解用于表示关于类(以及方法和字段)的各种反射信息。客户端(非系统)代码通常只能间接访问此信息。

系统注解在 .dex 文件中表示为可见性设置为 VISIBILITY_SYSTEM 的注解。

dalvik.annotation.AnnotationDefault

出现在注解接口的方法中

每个希望指示默认绑定的注解接口都附加有 AnnotationDefault 注解。

名称 格式 说明
value Annotation 此注解的默认绑定,表示为此类型的注解。注解无需包含注解定义的所有名称;缺少的名称只是没有默认值。

dalvik.annotation.EnclosingClass

出现在类中

每个被定义为另一个类的成员的类,或者匿名但未在方法体中定义的类(例如,合成内部类),都附加有 EnclosingClass 注解。每个具有此注解的类还必须具有 InnerClass 注解。此外,一个类不能同时具有 EnclosingClass 注解和 EnclosingMethod 注解。

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

dalvik.annotation.EnclosingMethod

出现在类中

每个在方法体内部定义的类都附加有 EnclosingMethod 注解。每个具有此注解的类还必须具有 InnerClass 注解。此外,一个类不能同时具有 EnclosingClass 注解和 EnclosingMethod 注解。

名称 格式 说明
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 描述了所有形式方法参数,甚至包括那些在源代码中未显式或隐式声明的参数,因此数组的大小可能与仅基于源代码中声明的显式参数的 Signature 或其他元数据信息不同。MethodParameters 也不包含关于实际方法签名中不存在的类型注解接收器参数的任何信息。

名称 格式 说明
names String[] 关联方法的形式参数名称。数组不得为 null,但如果没有形式参数,则必须为空。如果具有该索引的形式参数没有名称,则数组中的值必须为 null。
如果参数名称字符串为空或包含“.”、“;”、“[”或“/”,则将在运行时抛出 java.lang.reflect.MalformedParametersException
accessFlags int[] 关联方法的形式参数的访问标志。数组不得为 null,但如果没有形式参数,则必须为空。
该值是具有以下值的位掩码
  • 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[] 抛出的异常类型数组