本文將說明 .dex
檔案的版面配置和內容,這些檔案用於保存一組類別定義及其相關的附加資料。
類型指南
名稱 | 說明 |
---|---|
byte | 8 位元帶正負號的 int |
ubyte | 8 位元無符號整數 |
short | 16 位元帶正負號整數,小端序 |
ushort | 16 位元不帶正負號整數,小端序 |
int | 32 位元帶正負號整數,小端序 |
uint | 32 位元不帶正負號整數,小端序 |
long | 64 位元帶正負號 int,小端序 |
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 |
位元6 | bit5 | 位元4 | bit3 | 位元2 | 位元1 | 位元 0 | 0 |
位元13 | 位元12 | bit11 | 位元10 | 位元9 | 位元8 | bit7 |
變體 uleb128p1
用於表示帶符號值,其中的表示法是將值「加一」編碼為 uleb128
。這會讓 -1
的編碼 (或視為無符號值 0xffffffff
) 為單一位元組,但其他負數則不行。這種做法在以下情況特別實用:表示的數字必須為非負數或 -1
(或 0xffffffff
),且不允許其他負數 (或不太可能需要大型無符號值)。
以下列舉幾個格式範例:
已編碼的序列 | sleb128 |
uleb128 |
uleb128p1 |
---|---|---|---|
00 | 0 | 0 | -1 |
01 | 1 | 1 | 0 |
7f | -1 | 127 | 126 |
80 7f | -128 | 16256 | 16255 |
檔案版面配置
名稱 | 格式 | 說明 |
---|---|---|
標頭 | header_item | 標頭 |
string_ids | string_id_item[] | 字串 ID 清單。這些是此檔案所使用的所有字串的 ID,可用於內部命名 (例如類型描述元),或用作程式碼參照的常數物件。此清單必須依照 UTF-16 代碼點值 (而非依照語言代碼敏感方式) 排序字串內容,且不得包含任何重複的項目。 |
type_ids | type_id_item[] | 類型 ID 清單。這些是此檔案參照的所有類型 (類別、陣列或基本類型) 的 ID,不論是否已在檔案中定義。這個清單必須依 string_id 索引排序,且不得包含任何重複的項目。 |
proto_ids | proto_id_item[] | 方法原型 ID 清單。這些是此檔案參照的所有原型 ID。這個清單必須依傳回類型 (依 type_id 索引) 排序,然後依引數清單 (字母順序排序,個別引數依 type_id 索引排序) 排序。清單中不得有重複的項目。 |
field_ids | field_id_item[] | 欄位 ID 清單。這些是此檔案參照的所有欄位 ID,無論是否已在檔案中定義。此清單必須排序,其中定義類型 (依 type_id 索引) 為主要順序、欄位名稱 (依 string_id 索引) 為中間順序,而類型 (依 type_id 索引) 為次要順序。清單中不得有重複的項目。 |
method_ids | method_id_item[] | 方法 ID 清單。這些是此檔案參照的所有方法的 ID,無論是否在檔案中定義。此清單必須排序,其中定義型別 (依 type_id 索引) 為主要順序、方法名稱 (依 string_id 索引) 為中間順序,而方法原型 (依 proto_id 索引) 為次要順序。清單中不得有重複的項目。 |
class_defs | class_def_item[] | 類別定義清單。類別必須依序排列,以便在清單中先顯示指定類別的超類和已實作的介面,再顯示參照類別。此外,清單中不得出現同名類別的定義。 |
call_site_ids | call_site_id_item[] | 呼叫網站 ID 清單。這些是此檔案參照的所有呼叫網址的 ID,無論是否已在檔案中定義。這份清單必須依 call_site_off 遞增排序。 |
method_handles | method_handle_item[] | 方法句柄清單。此檔案所參照的所有方法句柄清單,無論是否已在檔案中定義。這份清單未經排序,且可能包含重複項目,這些項目在邏輯上會對應至不同的方法句柄例項。 |
data | ubyte[] | 資料區域,其中包含上述表格的所有支援資料。不同的項目有不同的對齊需求,如果需要,系統會在每個項目前插入填充位元組,以便正確對齊。 |
link_data | ubyte[] | 在靜態連結檔案中使用的資料。本文件未指定此部分的資料格式。在未連結的檔案中,這個部分會是空白,而執行階段實作可能會視情況使用這個部分。 |
容器格式
41 版推出了新的 DEX 資料容器格式,目的是節省空間。這個容器格式可將多個邏輯 DEX 檔案合併為單一實體檔案。新格式大多只是將舊格式的檔案簡單連接,但仍有些差異:
file_size
是邏輯檔案的大小,而非實體檔案。可用於遍歷容器中的所有邏輯檔案。- 邏輯 dex 檔案可參照容器中的任何後續資料 (但不能參照先前的資料)。這可讓 dex 檔案在彼此之間共用資料,例如字串。
- 所有偏移量皆相對於實體檔案。相對於標頭,沒有偏移。這樣可確保在邏輯檔案之間共用有偏移的區段。
- 標頭會新增兩個欄位,用於描述容器的邊界。這是額外的一致性檢查,可讓您更輕鬆地將程式碼移植至新格式。
data_size
和data_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-handle
和 const-method-type
。(請參閱「Bytecode 集合摘要」表格,瞭解各個集合的說明。)在 Android 10 中,039
版本會擴充 DEX 檔案格式,納入僅適用於引導程式類別路徑的 DEX 檔案的隱藏 API 資訊。
注意:Android 8.0 版本新增了對 038
格式版本的支援。版本 038
新增了新的位元碼 (invoke-polymorphic
和 invoke-custom
),以及方法句柄的資料。
注意:Android 7.0 版本新增了對 037
格式版本的支援。在 037
之前,大多數 Android 版本都使用 035
格式。035
和 037
版本唯一的差異,就是新增預設方法和調整 invoke
。
注意:至少有幾個早期格式版本已用於廣泛發布的公開軟體版本。舉例來說,009
版本用於 Android 平台的 M3 版本 (2007 年 11 月至 12 月),013
版本則用於 Android 平台的 M5 版本 (2008 年 2 月至 3 月)。在某些方面,這些早期格式版本與本文所述版本有明顯差異。
ENDIAN_CONSTANT 和 REVERSE_ENDIAN_CONSTANT
嵌入 header_item
常數 ENDIAN_CONSTANT
用於指出檔案的字節序。雖然標準 .dex
格式是小端格式,但實作可能會選擇執行位元組交換。如果實作項目遇到標頭,而標頭的 endian_tag
為 REVERSE_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_VOLATILE | 0x40 | volatile :特殊存取規則,有助於確保執行緒安全 |
||
ACC_BRIDGE | 0x40 | 橋接方法,由編譯器自動新增為型別安全的橋接 | ||
ACC_TRANSIENT | 0x80 | transient :預設序列化不會儲存 |
||
ACC_VARARGS | 0x80 | 編譯器應將最後一個引數視為「其餘」引數 | ||
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
中開啟。
修改過的 UTF-8 編碼
為了讓舊版支援更容易,.dex
格式會以實際標準的修改版 UTF-8 格式編碼字串資料,以下稱為 MUTF-8。這份表單與標準 UTF-8 相同,但有以下差異:
- 只使用一、二和三位元組編碼。
- 範圍為
U+10000
…U+10ffff
的碼點會編碼為替代字元組,每個組合都會以三個位元組的編碼值表示。 - 程式碼點
U+0000
是以兩位元組形式編碼。 - 標準的空值位元組 (值
0
) 表示字串結尾,這也是標準的 C 語言解讀方式。
上述前兩項內容可歸納為:MUTF-8 是 UTF-16 的編碼格式,而非萬國碼字元的直接編碼格式。
上述最後兩項項目可讓您同時在字串中加入程式碼點 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 表示值需要八個位元組;不過,如以下所述,也有例外狀況。 |
值 | ubyte[] | 位元組代表值,長度可變,且會根據不同的 value_type 位元組進行不同解讀,但一律採用小端序。詳情請參閱下方的各種值定義。 |
值格式
類型名稱 | value_type |
value_arg 格式 |
value 格式 |
說明 |
---|---|---|---|---|
VALUE_BYTE | 0x00 | (none;必須為 0 ) |
ubyte[1] | 帶正負號的 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 | (none;必須為 0 ) |
encoded_array | 值陣列,格式為下方「encoded_array 格式」所指定。編碼中會隱含 value 的大小。 |
VALUE_ANNOTATION | 0x1d | (none;必須為 0 ) |
encoded_annotation | 子註解,格式如下列「encoded_annotation 格式」所述。編碼中會隱含 value 的大小。 |
VALUE_NULL | 0x1e | (none;必須為 0 ) |
(無) | null 參照值 |
VALUE_BOOLEAN | 0x1f | 布林值 (0 到 1) | (無) | 一位元值;0 代表 false ,1 代表 true 。位元會以 value_arg 表示。 |
encoded_array 格式
名稱 | 格式 | 說明 |
---|---|---|
size | uleb128 | 陣列中的元素數量 |
值 | encoded_value[size] | 一系列 size encoded_value 位元組序列,格式符合本節指定的格式,並依序連接。 |
encoded_annotation 格式
名稱 | 格式 | 說明 |
---|---|---|
type_idx | uleb128 | 註解類型。這必須是類別 (而非陣列或基本類型) 類型。 |
size | uleb128 | 此註解中名稱/值對應的數量 |
元素 | annotation_element[size] | 元素,直接以內嵌方式表示 (而非以偏移方式表示)。元素必須依 string_id 索引以遞增順序排序。 |
annotation_element 格式
名稱 | 格式 | 說明 |
---|---|---|
name_idx | uleb128 | 元素名稱,以 string_ids 區段的索引表示。字串必須符合上述定義的 MemberName 語法。 |
值 | encoded_value | 元素值 |
字串語法
.dex
檔案中含有多種項目,最終都會參照字串。下列 BNF 樣式定義指出這些字串可接受的語法。
SimpleName
SimpleName 是其他名稱語法的基礎。.dex
格式可提供相當程度的彈性 (比大多數常見的來源語言多得多)。簡而言之,簡單名稱包含任何低 ASCII 字母字元或數字、少數特定低 ASCII 符號,以及大部分非 ASCII 控制碼點、空格或特殊字元。自 040
版本起,此格式還允許使用空格字元 (Unicode Zs
類別)。請注意,替代碼點 (範圍為 U+d800
… U+dfff
) 本身不視為有效的名稱字元,但萬國碼輔助字元「是」有效 (由 SimpleNameChar 規則的最後一個替代項目表示),且應在檔案中以 MUTF-8 編碼的替代碼點組合表示。
SimpleName → | ||
SimpleNameChar (SimpleNameChar)* | ||
SimpleNameChar → | ||
'A' … 'Z' |
||
| | 'a' … 'z' |
|
| | '0' … '9' |
|
| | ' ' |
自 DEX 040 版起 |
| | '$' |
|
| | '-' |
|
| | '_' |
|
| | U+00a0 |
自 DEX 040 版起 |
| | U+00a1 … U+1fff |
|
| | U+2000 … U+200a |
自 DEX 040 版起 |
| | U+2010 … U+2027 |
|
| | U+202f |
自 DEX 040 版起 |
| | U+2030 … U+d7ff |
|
| | U+e000 … U+ffef |
|
| | U+10000 … U+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 |
五 | float |
D | double |
Lfully/qualified/Name; | 類別 fully.qualified.Name |
[descriptor | descriptor 陣列,可遞迴使用陣列的陣列,但如果維度超過 255 個,則會無效。 |
項目和相關結構
本節包含 .dex
檔案中可能出現的各個頂層項目定義。
header_item
顯示在頁首區段
對齊方式:4 個位元組
名稱 | 格式 | 說明 |
---|---|---|
魔法 | ubyte[8] = DEX_FILE_MAGIC | 魔術值。詳情請參閱上文「DEX_FILE_MAGIC 」下方的討論內容。 |
檢查碼 | uint | 檔案其餘部分的 adler32 總和檢查碼 (除了 magic 和這個欄位以外的所有內容);用於偵測檔案毀損 |
簽名 | ubyte[20] | 檔案其餘部分的 SHA-1 簽章 (雜湊) (除了 magic 、checksum 和這個欄位之外的所有內容);用於唯一識別檔案 |
file_size | uint |
整個檔案 (包括標頭) 的大小 (以位元組為單位) (v40 或更早版本) 從這個標頭開始到下一個標頭或整個檔案 (容器) 結尾的位元組距離。(41 以上版本) |
header_size | uint |
標頭 (整個部分) 的大小,以位元組為單位。這樣一來,至少可以提供有限的回溯/前向相容性,而不會使格式失效。 必須是 0x70 (112) 個位元組 (v40 以下版本) 必須是 0x78 (120) 個位元組 (v41 以上版本) |
endian_tag | uint = ENDIAN_CONSTANT | endianness 標記。詳情請參閱上方「ENDIAN_CONSTANT 和 REVERSE_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 | 字串 ID 清單中的字串數量 |
string_ids_off | uint | 從檔案開頭到字串 ID 清單的偏移量,如果 string_ids_size == 0 則為 0 (這是奇怪的邊緣情況)。如果偏移量不為零,則應為 string_ids 區段的開頭。 |
type_ids_size | uint | 類型 ID 清單中的元素數量,最多 65535 |
type_ids_off | uint | 從檔案開頭到型別 ID 清單的偏移量,如果是 type_ids_size == 0 ,則為 0 (這是奇怪的邊緣情況)。如果偏移量不為零,則應為 type_ids 區段的開頭。 |
proto_ids_size | uint | 原型 ID 清單中的元素數量,最多 65535 |
proto_ids_off | uint | 從檔案開頭到原型 ID 清單的偏移量,如果是 proto_ids_size == 0 ,則為 0 (這是很奇怪的邊緣情況)。如果偏移量不為零,則應為 proto_ids 區段的開頭。 |
field_ids_size | uint | 欄位 ID 清單中的元素數量 |
field_ids_off | uint | 從檔案開頭到欄位 ID 清單的偏移量,如果是 field_ids_size == 0 ,則為 0 。如果偏移量不為零,則應為 field_ids 部分的開頭。 |
method_ids_size | uint | 方法 ID 清單中的元素數量 |
method_ids_off | uint | 從檔案開頭到方法 ID 清單的偏移量,或如果是 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 |
未使用 (v41 以上版本) |
data_off | uint |
從檔案開頭到 未使用 (v41 以上版本) |
container_size | uint |
這個欄位不存在。可以假設它等於 整個檔案的大小 (包括其他 dex 標頭及其資料)。(41 以上版本) |
header_offset | uint |
這個欄位不存在。可以假設它等於 從檔案開頭到這個標頭開頭的偏移量。(41 以上版本) |
map_list
顯示在資料部分
由 header_item 參照
對齊方式:4 個位元組
這是檔案的完整內容清單,並按順序排列。它與 header_item
相比含有部分重複內容,但其目的是提供簡單的形式,以便對整個檔案進行迴迭。特定類型在地圖中最多只能出現一次,但除了格式其餘部分暗示的限制外,不限制類型出現的順序。舉例來說,header
區段必須先出現,接著才是 string_ids
區段,以此類推。此外,地圖項目必須依初始偏移量排序,且不得重疊。
名稱 | 格式 | 說明 |
---|---|---|
size | uint | 清單的大小 (以項目為單位) |
清單 | map_item[size] | 清單的元素 |
map_item 格式
名稱 | 格式 | 說明 |
---|---|---|
類型 | ushort | 項目類型 (請參閱下表) |
unused | ushort | (未使用) |
size | uint | 在指定偏移處找到的項目數量 |
碳補償 | 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
顯示在資料部分
對齊方式:無 (位元組對齊)
名稱 | 格式 | 說明 |
---|---|---|
utf16_size | uleb128 | 這個字串的大小,以 UTF-16 程式碼單位 (在許多系統中為「字串長度」) 為單位。也就是字串的解碼長度。(編碼長度會根據 0 位元組的位置隱含)。 |
data | ubyte[] | 一系列 MUTF-8 編碼單位 (又稱八位元組、位元組),後面接著一個值為 0 的位元組。如要進一步瞭解資料格式,請參閱上方的「MUTF-8 (修改版 UTF-8) 編碼」。注意:字串可包含 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 | 類別的存取旗標 (public 、final 等)。詳情請參閱「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 欄位初始值清單的偏移量,如果沒有初始值,則為 0 (所有 static 欄位都會使用 0 或 null 進行初始化)。這個偏移量應位於 data 部分,且其中的資料應採用下方「encoded_array_item 」所指定的格式。陣列的大小不得大於此類別宣告的 static 欄位數量,且元素必須與對應 field_list 中宣告的 static 欄位保持相同順序。每個陣列元素的類型都必須與其對應欄位的宣告類型相符。如果陣列中的元素少於 static 欄位,則系統會使用類型相符的 0 或 null 初始化剩餘的欄位。 |
call_site_id_item
會顯示在 call_site_ids 部分
對齊方式:4 個位元組
名稱 | 格式 | 說明 |
---|---|---|
call_site_off | uint | 從檔案開頭到呼叫網站定義的偏移量。偏移量應位於資料部分,且資料應採用下方「call_site_item」指定的格式。 |
call_site_item
顯示在資料部分
對齊方式:無 (位元組對齊)
call_site_item 是 encoded_array_item,其元素對應至提供給引導程式連結器方法的引數。前三個引數如下:
- 代表引導連結器方法 (VALUE_METHOD_HANDLE) 的方法句柄。
- 引導連結器應解析的方法名稱 (VALUE_STRING)。
- 與要解析的方法名稱類型 (VALUE_METHOD_TYPE) 相對應的方法類型。
任何額外引數都是傳遞至 Bootstrap 連結器方法的常數值。這些引數會依序傳遞,且不會進行任何類型轉換。
代表引導程式連結器方法的方法句柄,必須具有 java.lang.invoke.CallSite
的傳回類型。前三種參數類型如下:
java.lang.invoke.Lookup
java.lang.String
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 | 方法句柄是靜態欄位 setter (存取子) |
METHOD_HANDLE_TYPE_STATIC_GET | 0x01 | 方法句柄是靜態欄位 getter (存取子) |
METHOD_HANDLE_TYPE_INSTANCE_PUT | 0x02 | 方法句柄是例項欄位 setter (存取子) |
METHOD_HANDLE_TYPE_INSTANCE_GET | 0x03 | 方法句柄是例項欄位 getter (存取子) |
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 參照
顯示在資料部分
對齊方式:無 (位元組對齊)
名稱 | 格式 | 說明 |
---|---|---|
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] | 定義的直接 (任何 static 、private 或建構函式) 方法,以一系列已編碼元素表示。方法必須依 method_idx 以遞增順序排序。 |
virtual_methods | encoded_method[virtual_methods_size] | 定義的虛擬 (非 static 、private 或建構函式) 方法,以一系列編碼元素表示。除非此項目所代表的類別已覆寫,否則這份清單「不應」包含已繼承的方法。方法必須依 method_idx 以遞增順序排序。虛擬方法的 method_idx 不得與任何直接方法不一樣。 |
注意:所有元素的 field_id
和 method_id
例項都必須參照相同的定義類別。
encoded_field 格式
名稱 | 格式 | 說明 |
---|---|---|
field_idx_diff | uleb128 | 索引進入 field_ids 清單,以便取得這個欄位的身分 (包括名稱和描述符),以清單中先前元素的索引差異表示。清單中第一個元素的索引會直接顯示。 |
access_flags | uleb128 | 欄位的存取標記 (public 、final 等)。詳情請參閱「access_flags 定義」。 |
encoded_method 格式
名稱 | 格式 | 說明 |
---|---|---|
method_idx_diff | uleb128 | 索引進入 method_ids 清單,以便取得此方法的 ID (包括名稱和描述符),以清單中前一項元素的索引差異表示。清單中第一個元素的索引會直接顯示。 |
access_flags | uleb128 | 方法的存取標記 (public 、final 等)。詳情請參閱「access_flags 定義」。 |
code_off | uleb128 | 從檔案開頭到此方法的程式碼結構的偏移量,如果此方法為 abstract 或 native ,則為 0 。偏移量應為 data 部分中的某個位置。資料格式由下方的「code_item 」指定。 |
type_list
由 class_def_item 和 proto_id_item 參照
顯示在資料部分
對齊方式:4 個位元組
名稱 | 格式 | 說明 |
---|---|---|
size | uint | 清單的大小 (以項目為單位) |
清單 | 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 數量。如果不為零,則會在本例中 insns 後方顯示為 tries 陣列。 |
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 非零值時,這個元素才會出現。 |
處理常式 | 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 | 這個清單的大小 (以項目為單位) |
清單 | encoded_catch_handler[handlers_size] | 實際的處理常式清單,直接表示 (而非偏移),並依序串連 |
encoded_catch_handler 格式
名稱 | 格式 | 說明 |
---|---|---|
size | sleb128 | 此清單中的 catch 類型數量。如果不是正數,則為 catch 類型數量的負值,且 catch 後面會接著 catch-all 處理常式。舉例來說,size 的 0 表示有 catch-all,但沒有明確指定類型的 catch。size 的 2 表示有兩個明確指定的 catch,且沒有 catch-all。而 -1 的 size 表示有一個型別的 catch 和一個 catch-all。 |
處理常式 | encoded_type_addr_pair[abs(size)] | abs(size) 編碼項目的串流,每個捕獲類型各一個,依類型應進行測試的順序排列。 |
catch_all_addr | uleb128 (選用) | 全部接收處理程序的 bytecode 位址。只有在 size 非正值時,這個元素才會出現。 |
encoded_type_addr_pair 格式
名稱 | 格式 | 說明 |
---|---|---|
type_idx | uleb128 | 索引至 type_ids 清單,以便擷取要擷取的例外狀況類型 |
addr | uleb128 | 關聯例外狀況處理常式的 bytecode 位址 |
debug_info_item
參照自 code_item
顯示在資料部分
對齊方式:無 (位元組對齊)
每個 debug_info_item
都會定義 DWARF3 風格的位元組編碼狀態機器,在解譯時會為 code_item
發出位置表和 (可能的) 本機變數資訊。這個序列以可變長度的標頭 (長度取決於方法參數數量) 開頭,後面接著狀態機器 bytecode,最後以 DBG_END_SEQUENCE
位元組結尾。
狀態機器由五個暫存器組成。address
登錄器代表 16 位元程式碼單位中相關 insns_item
的指令偏移量。address
登錄會從每個 debug_info
序列開頭的 0
開始,且只能單調遞增。line
註冊代表應與狀態機器所發出的下一個位置表格項目相關聯的來源行號。這項值會在序列標頭中初始化,且可能會在正向或負向方向變更,但絕對不能低於 1
。source_file
註冊表代表行號項目參照的來源檔案。系統會將其初始化為 class_def_item
中的 source_file_idx
值。其他兩個變數 prologue_end
和 epilogue_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 :將包含 local的註冊項 name_idx :名稱的字串索引type_idx :類型的類型索引
|
在目前的地址中引入本機變數。name_idx 或 type_idx 可以是 NO_INDEX ,表示該值不明。 |
DBG_START_LOCAL_EXTENDED | 0x04 | uleb128 register_num uleb128p1 name_idx uleb128p1 type_idx uleb128p1 sig_idx |
register_num :將包含 localname_idx :名稱的字串索引type_idx :類型的類型索引sig_idx :類型簽名的字串索引 |
在目前的地址中引入具有類型簽章的本機。name_idx 、type_idx 或 sig_idx 的任何值都可能為 NO_INDEX ,表示該值不明。(不過,如果 sig_idx 是 -1 ,則可使用 DBG_START_LOCAL opcode 更有效率地呈現相同資料)。注意:如要瞭解處理簽名時的注意事項,請參閱下方「 |
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 狀態機制註冊器,表示新增的下一個位置項目應視為方法尾聲的開頭 (在方法結束前暫停執行的適當位置)。任何特殊 (>= 0x0a ) 運算碼都會清除 epilogue_begin 註冊。 |
|
DBG_SET_FILE | 0x09 | uleb128p1 name_idx | name_idx :來源檔案名稱的字串索引;如果不明,則為 NO_INDEX |
表示後續所有行號項目都會參照這個來源檔案名稱,而非 code_item 中指定的預設名稱 |
特殊 Opcodes | 0x0a…0xff | (無) | 會推進 line 和 address 登錄項目,發出位置項目,並清除 prologue_end 和 epilogue_begin 。詳情請參閱下文。 |
特殊 Opcode
值介於 0x0a
和 0xff
之間 (含兩者) 的運算碼會將 line
和 address
暫存器移動一小段距離,然後發出新的位址表項目。增量公式如下:
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 | 這個項目註解的 method 參數清單數量 |
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_id
和 method_id
例項都必須參照相同的定義類別。
field_annotation 格式
名稱 | 格式 | 說明 |
---|---|---|
field_idx | uint | 索引至 field_ids 清單,以便識別要加註的欄位 |
annotations_off | uint | 從檔案開頭到欄位註解清單的偏移量。偏移量應為 data 部分中的某個位置。資料格式由下方的「annotation_set_item 」指定。 |
method_annotation 格式
名稱 | 格式 | 說明 |
---|---|---|
method_idx | uint | 索引至 method_ids 清單,以取得註解方法的 ID |
annotations_off | uint | 從檔案開頭到方法註解清單的偏移量。偏移量應為 data 部分中的某個位置。資料格式由下方的「annotation_set_item 」指定。 |
parameter_annotation 格式
名稱 | 格式 | 說明 |
---|---|---|
method_idx | uint | 索引至 method_ids 清單,以便找出要為其參數加上註解的方法的 ID |
annotations_off | uint | 從檔案開頭到方法參數注解清單的偏移量。偏移量應為 data 部分中的某個位置。資料格式由下方的「annotation_set_ref_list 」指定。 |
annotation_set_ref_list
參照自 parameter_annotations_item
顯示在資料部分
對齊方式:4 個位元組
名稱 | 格式 | 說明 |
---|---|---|
size | uint | 清單的大小 (以項目為單位) |
清單 | 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 | 集合的大小 (以項目為單位) |
項目 | annotation_off_item[size] | 集合的元素。元素必須依 type_idx 以遞增順序排序。 |
annotation_off_item 格式
名稱 | 格式 | 說明 |
---|---|---|
annotation_off | uint | 從檔案開頭到註解的偏移量。偏移量應為 data 區段中的某個位置,而該位置的資料格式則由下方的「annotation_item 」指定。 |
annotation_item
參照自 annotation_set_item
顯示在資料部分
對齊方式:無 (位元組對齊)
名稱 | 格式 | 說明 |
---|---|---|
顯示設定 | ubyte | 這個註解的預期可見度 (請見下方) |
Annotation | encoded_annotation | 以上述「encoded_value 編碼」下方「encoded_annotation 格式」所述的格式,編碼註解內容。 |
瀏覽權限值
以下是 annotation_item
中 visibility
欄位的選項:
名稱 | 值 | 說明 |
---|---|---|
VISIBILITY_BUILD | 0x00 | 僅在建構期間顯示 (例如在編譯其他程式碼時) |
VISIBILITY_RUNTIME | 0x01 | 在執行階段顯示 |
VISIBILITY_SYSTEM | 0x02 | 在執行階段顯示,但只會向底層系統顯示 (而非向一般使用者程式碼顯示) |
encoded_array_item
由 class_def_item 參照
顯示在資料部分
對齊方式:無 (位元組對齊)
名稱 | 格式 | 說明 |
---|---|---|
值 | encoded_array | 代表已編碼陣列值的位元組,格式為上方「encoded_value 編碼」下方「encoded_array 格式」所指定的格式。 |
hiddenapi_class_data_item
本節包含各個類別使用的受限介面相關資料。
注意:隱藏的 API 功能是在 Android 10.0 中推出,僅適用於啟動類別路徑中類別的 DEX 檔案。下方說明的旗標清單可能會在日後的 Android 版本中擴充。詳情請參閱「非 SDK 介面的限制」。
名稱 | 格式 | 說明 |
---|---|---|
size | uint | 區段的總大小 |
偏移 | uint[] | 由 class_idx 編入索引的偏移量陣列。索引 class_idx 中的零陣列項目表示這個 class_idx 沒有資料,或是所有隱藏的 API 旗標都為零。否則陣列項目會設為非零值,並包含從該區段開頭到此 class_idx 隱藏 API 標記陣列的偏移量。 |
flag | uleb128[] | 將每個類別的隱藏 API 標記串連成陣列。下表說明可能的標記值。旗標的編碼順序與類別資料中欄位和方法的編碼順序相同。 |
限制標記類型:
名稱 | 值 | 說明 |
---|---|---|
許可清單 | 0 | 可自由使用的介面,現已列入 Android 架構「套件索引」中正式記錄的項目並獲得支援。 |
可疑項目清單 | 1 | 無論應用程式的目標 API 級別為何,皆可使用的非 SDK 介面。 |
列入黑名單 | 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
註解。
名稱 | 格式 | 說明 |
---|---|---|
值 | 註解 | 此註解的預設繫結,以此類型的註解表示。註解不必包含註解定義的所有名稱;缺少的名稱就沒有預設值。 |
dalvik.annotation.EnclosingClass
顯示在課程
每個類別都會附加 EnclosingClass
註解,這些類別會視為另一個類別的成員,或是匿名,但未在方法主體中定義 (例如合成內部類別)。每個含有此註解的類別都必須有 InnerClass
註解。此外,類別不得同時具有 EnclosingClass
和 EnclosingMethod
註解。
名稱 | 格式 | 說明 |
---|---|---|
值 | 類別 | 最接近這個類別的字彙層級 |
dalvik.annotation.EnclosingMethod
顯示在課程
每個在方法主體中定義的類別都會附加 EnclosingMethod
註解。每個含有此註解的類別都必須有 InnerClass
註解。此外,類別不得同時具有 EnclosingClass
和 EnclosingMethod
註解。
名稱 | 格式 | 說明 |
---|---|---|
值 | 方法 | 最接近這個類別的字彙範圍方法 |
dalvik.annotation.InnerClass
顯示在課程
每個類別都會附加 InnerClass
註解,這些類別是在其他類別定義的字彙範圍中定義。任何含有此註解的類別都必須同時具備 EnclosingClass
註解或 EnclosingMethod
註解。
名稱 | 格式 | 說明 |
---|---|---|
name | 字串 | 這個類別原本宣告的簡單名稱 (不含任何套件前置字串)。如果這個類別是匿名的,則名稱為 null 。 |
accessFlags | int | 原先宣告的類別存取旗標 (可能與有效旗標不同,因為原始語言和目標虛擬機器的執行模型不相符) |
dalvik.annotation.MemberClasses
顯示在課程
每個宣告成員類別的類別都會附加 MemberClasses
註解。(成員類別是具有名稱的直接內部類別)。
名稱 | 格式 | 說明 |
---|---|---|
值 | 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().length
和 accessFlags().length
相同。
由於 MethodParameters
會描述所有正式方法參數,即使這些參數未在原始程式碼中明確或隱含宣告,陣列的大小也可能與簽名或其他中繼資料資訊不同,因為這些資訊只會根據在原始程式碼中宣告的明確參數。MethodParameters
也不會納入任何關於類型註解接收器參數的資訊,因為這些參數不存在於實際方法簽章中。
名稱 | 格式 | 說明 |
---|---|---|
名稱 | String[] | 關聯方法的正式參數名稱。陣列不得為空值,但如果沒有正式參數,則必須為空白。如果該索引的正式參數沒有名稱,陣列中的值就必須為空值。 如果參數名稱字串為空白,或包含「.」,「'」,「[」或「/」字元,則會在執行階段擲回 java.lang.reflect.MalformedParametersException 。 |
accessFlags | int[] | 關聯方法的形式參數存取旗標。陣列不得為空值,但如果沒有正式參數,則必須為空白。 這個值是位元遮罩,其中包含以下值:
java.lang.reflect.MalformedParametersException 。 |
dalvik.annotation.Signature
會顯示在類別、欄位和方法上
每個類別、欄位或方法都會附加 Signature
註解,這些類別、欄位或方法的定義類型比 type_id_item
更複雜,.dex
格式並未定義簽章的格式,而是僅能代表來源語言所需的任何簽章,以便成功實作該語言的語意。因此,虛擬機器實作通常不會剖析 (或驗證) 簽章。簽章會直接交由較高層級的 API 和工具 (例如偵錯工具) 處理。因此,任何使用簽名的情況都應以不假設只會收到有效簽名的方式編寫,明確防範遇到語法無效簽名的可能性。
由於簽章字串通常含有大量重複內容,因此 Signature
註解會定義為字串的陣列,其中重複的元素自然會參照相同的基礎資料,而簽章則視為陣列中所有字串的串接。系統並未提供任何規則,說明如何將簽章拆解為個別字串;這完全取決於產生 .dex
檔案的工具。
名稱 | 格式 | 說明 |
---|---|---|
值 | String[] | 這個類別或成員的簽章,做為要串連在一起的字串陣列 |
dalvik.annotation.Throws
顯示在方法上
每個方法都會附加 Throws
註解,這些方法會宣告擲回一或多個例外狀況類型。
名稱 | 格式 | 說明 |
---|---|---|
值 | Class[] | 擲回的例外狀況類型陣列 |