本文說明 .dex
檔案的版面配置和內容,這類檔案用於保存一組類別定義及其相關聯的附加資料。
類型指南
名稱 | 說明 |
---|---|
byte | 8 位元帶正負號整數 |
ubyte | 8 位元不帶正負號的整數 |
short | 16 位元帶正負號整數,小端序 |
ushort | 16 位元不帶正負號的 int,小端序 |
int | 32 位元帶正負號整數,小端序 |
uint | 32 位元不帶正負號的 int,小端序 |
long | 64 位元帶正負號整數,小端序 |
ulong | 64 位元不帶正負號整數,小端序 |
sleb128 | 已簽署的 LEB128,長度可變 (請參閱下文) |
uleb128 | 未簽署的 LEB128,長度可變 (請參閱下文) |
uleb128p1 | 未簽署的 LEB128,外加 1 ,長度可變 (請見下文) |
LEB128
LEB128 (「小端序基底 128」) 是任意有號或無號整數量的可變長度編碼。格式是從 DWARF3 規格借用而來。在 .dex
檔案中,LEB128 一律只用於編碼 32 位元數量。
每個 LEB128 編碼值都由一到五個位元組組成,共同代表單一 32 位元值。每個位元組都會設定最高有效位元,但序列中的最後一個位元組除外,該位元組會清除最高有效位元。每個位元組的其餘七個位元都是酬載,第一個位元組是數量的最低有效七個位元,第二個位元組是下一個七個位元,依此類推。如果是已簽署的 LEB128 (sleb128
),序列中最後一個位元組的最高有效位元酬載會經過符號擴充,產生最終值。在未簽署的情況下 (uleb128
),任何未明確表示的位元都會解讀為 0
。
雙位元組 LEB128 值的位元圖 | |||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
第一個位元組 | 第二個位元組 | ||||||||||||||
1 |
位元6 | bit5 | bit4 | bit3 | 位元2 | bit1 | bit0 | 0 |
bit13 | bit12 | bit11 | 位元10 | bit9 | bit8 | 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[] | 方法會處理清單。這個檔案參照的所有方法控制代碼清單,無論是否定義於檔案中。這份清單未經過排序,且可能含有重複項目,這些項目在邏輯上會對應至不同的方法控制代碼例項。 |
資料 | 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 16 版新增支援格式的 041
版,支援容器格式。
注意:Android 10.0 版新增支援 040
格式,並擴充 SimpleNames 中允許的字元集。
注意:Android 9.0 版本新增了對 039
格式的支援,並導入兩個新的位元碼:const-method-handle
和 const-method-type
。(這些項目都會在「位元碼集摘要」表格中說明)。在 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
。
注意:至少有幾個較早版本的格式已用於廣泛發布的公開軟體。舉例來說,Android 平台 M3 版本 (2007 年 11 月至 12 月) 使用 009
版,Android 平台 M5 版本 (2008 年 2 月至 3 月) 則使用 013
版。在許多方面,這些舊版格式與本文所述版本有顯著差異。
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
存取旗標定義
嵌入 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
會以雙位元組形式編碼。 - 如為標準 C 語言解讀,一般空值位元組 (值
0
) 表示字串結尾。
上述前兩項可歸納為: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 則表示需要八個位元組;不過,如下所述,也有例外情形。
|
值 | ubyte[] | 代表值的位元組,長度可變,且對於不同的 value_type 位元組,解讀方式也不同,但一律為小端序。詳情請參閱下方的各種值定義。
|
值格式
類型名稱 | value_type |
value_arg 格式 |
value 格式 |
說明 |
---|---|---|---|---|
VALUE_BYTE | 0x00 | (無;必須為 0 ) |
ubyte[1] | 帶正負號的單一位元組整數值 |
VALUE_SHORT | 0x02 | 大小 - 1 (0…1) | ubyte[size] | 帶正負號的雙位元組整數值,經過正負號擴充 |
VALUE_CHAR | 0x03 | 大小 - 1 (0…1) | ubyte[size] | 不帶正負號的雙位元組整數值,以零擴充 |
VALUE_INT | 0x04 | 大小 - 1 (0…3) | ubyte[size] | 帶正負號的四位元組整數值,經過正負號擴充 |
VALUE_LONG | 0x06 | 大小 - 1 (0…7) | ubyte[size] | 帶正負號的八位元組整數值,經過正負號擴充 |
VALUE_FLOAT | 0x10 | 大小 - 1 (0…3) | ubyte[size] | 四位元組位元模式,向右以零擴充,並解讀為 IEEE754 32 位元浮點值 |
VALUE_DOUBLE | 0x11 | 大小 - 1 (0…7) | ubyte[size] | 八位元組位元模式,向右以零擴充,並解讀為 IEEE754 64 位元浮點值 |
VALUE_METHOD_TYPE | 0x15 | 大小 - 1 (0…3) | ubyte[size] | 未簽署 (以零擴充) 的四位元組整數值,解讀為 proto_ids 區段的索引,代表方法型別值 |
VALUE_METHOD_HANDLE | 0x16 | 大小 - 1 (0…3) | ubyte[size] | 未簽署 (以零擴充) 的四位元組整數值,解讀為 method_handles 區段的索引,代表方法控制代碼值 |
VALUE_STRING | 0x17 | 大小 - 1 (0…3) | ubyte[size] | 未簽署 (以零擴充) 的四位元組整數值,解讀為 string_ids 區段的索引,代表字串值 |
VALUE_TYPE | 0x18 | 大小 - 1 (0…3) | ubyte[size] | 未簽署 (以零擴充) 四位元組整數值,解讀為 type_ids 區段的索引,代表反射型別/類別值 |
VALUE_FIELD | 0x19 | 大小 - 1 (0…3) | ubyte[size] | 未簽署 (以零擴充) 四位元組整數值,解讀為 field_ids 區段的索引,代表反射欄位值 |
VALUE_METHOD | 0x1a | 大小 - 1 (0…3) | ubyte[size] | 未簽署 (以零擴充) 的四位元組整數值,解讀為 method_ids 區段的索引,代表反射方法值 |
VALUE_ENUM | 0x1b | 大小 - 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 代表 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 索引排序。 |
註解元素格式
名稱 | 格式 | 說明 |
---|---|---|
name_idx | uleb128 | 元素名稱,以 string_ids 區段的索引表示。這個字串必須符合上述定義的 MemberName 語法。 |
值 | encoded_value | 元素值 |
字串語法
.dex
檔案中的項目種類繁多,但最終都會參照字串。下列 BNF 樣式的定義指出這些字串可接受的語法。
SimpleName
SimpleName 是其他項目名稱語法的基礎。.dex
格式在此處允許相當大的自由度 (遠超過大多數常見來源語言)。簡單來說,簡單名稱包含任何低 ASCII 字母或數字、幾個特定的低 ASCII 符號,以及大多數非 ASCII 程式碼點 (不屬於控制、空格或特殊字元)。從 040
版開始,格式也允許使用空格字元 (Unicode Zs
類別)。請注意,替代碼點 (範圍為 U+d800
… U+dfff
) 本身並非有效名稱字元,但 Unicode 補充字元是有效字元 (以 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 |
日 | short |
C | char |
I | int |
J | long |
F | 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 或更早版本) 從這個標頭的開頭到下一個標頭或整個檔案 (容器) 結尾的距離 (以位元組為單位)。(v41 以上版本) |
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 | 從檔案開頭到連結部分的位移,或
0 (如果 link_size == 0 )。如果偏移量不是零,則應為 link_data 區段的偏移量。這份文件未指定所指資料的格式;這個標頭欄位 (和前一個欄位) 會保留為供執行階段實作使用的掛鉤。 |
map_off | uint | 從檔案開頭到對應地圖項目的偏移量。位移必須為非零值,應是 data 區段的位移,且資料應採用下方「map_list 」指定的格式。 |
string_ids_size | uint | 字串 ID 清單中的字串數量 |
string_ids_off | uint | 從檔案開頭到字串 ID 清單的位移,或 0 (誠然是奇怪的極端情況)。string_ids_size == 0 如果偏移量不為零,則應為 string_ids 區段的開頭。
|
type_ids_size | uint | 型別 ID 清單中的元素數量,最多 65535 個 |
type_ids_off | uint | 從檔案開頭到型別 ID 清單的偏移量,或 0 (確實是奇怪的極端情況)。type_ids_size == 0 如果偏移量不為零,則應為 type_ids 區段的開頭。
|
proto_ids_size | uint | 原型 ID 清單中的元素數量,最多 65535 個 |
proto_ids_off | uint | 從檔案開頭到原型 ID 清單的偏移量,或 0 (誠實地說,這是奇怪的極端情況)。proto_ids_size == 0 如果偏移量不為零,則應為 proto_ids 區段的開頭。
|
field_ids_size | uint | 欄位 ID 清單中的元素數量 |
field_ids_off | uint | 從檔案開頭到欄位 ID 清單的位移,或 0 (如果 field_ids_size == 0 )。如果偏移量不為零,則應指向 field_ids 區段的開頭。 |
method_ids_size | uint | 方法 ID 清單中的元素數量 |
method_ids_off | uint | 從檔案開頭到方法 ID 清單的位移,或 0 (如果 method_ids_size == 0 )。如果偏移量不為零,則應指向 method_ids 區段的開頭。 |
class_defs_size | uint | 類別定義清單中的元素數量 |
class_defs_off | uint | 從檔案開頭到類別定義清單的位移,或 0 (確實是奇怪的極端情況)。class_defs_size == 0 如果偏移量不為零,則應為 class_defs 區段的開頭。
|
data_size | uint |
未使用 (v41 以上版本) |
data_off | uint |
從檔案開頭到 未使用 (v41 以上版本) |
container_size | uint |
這個欄位不存在。可假設等於 整個檔案的大小 (包括其他 DEX 標頭及其資料)。 (v41 以上版本) |
header_offset | uint |
這個欄位不存在。可假設等於 從檔案開頭到這個標頭開頭的偏移量。 (v41 以上版本) |
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 位元組的位置所隱含)。 |
資料 | 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 | index into the type_ids list for the return type
of this prototype
|
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 | index into the string_ids list for the name of this
field. 這個字串必須符合上述定義的 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 欄位初始值清單的偏移量,如果沒有任何初始值 (且所有 static 欄位都要以 0 或 null 初始化),則為 0 。這個偏移量應位於 data 區段,且該處的資料應採用下方「encoded_array_item 」指定的格式。陣列大小不得超過這個類別宣告的 static 欄位數量,且元素對應的 static 欄位順序必須與相應 field_list 中宣告的順序相同。每個陣列元素類型都必須與對應欄位的宣告類型相符。如果陣列中的元素數量少於 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) 對應的方法類型。
任何其他引數都是傳遞至啟動連結器方法的常數值。這些引數會依序傳遞,且不會進行任何類型轉換。
代表啟動載入連結器方法的處理常式方法必須具有 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 | 方法控制代碼是靜態欄位設定器 (存取子) |
METHOD_HANDLE_TYPE_STATIC_GET | 0x01 | 方法控制代碼是靜態欄位 Getter (存取子) |
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
顯示在「資料」部分
對齊方式:無 (位元組對齊)
名稱 | 格式 | 說明 |
---|---|---|
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 | 索引到這個方法的 ID 的 method_ids 清單中 (包括名稱和描述元),以清單中前一個元素的索引差異表示。清單中第一個元素的索引會直接表示。 |
access_flags | uleb128 | 方法的存取權標記 (public 、final 等)。詳情請參閱「access_flags 定義」。
|
code_off | uleb128 | 從檔案開頭到這個方法的程式碼結構的位移,或 0 (如果這個方法是 abstract 或 native )。偏移量應指向 data 部分中的位置。資料格式由「code_item 」指定,如下所示:
"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 (optional) = 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 | 這份清單中的捕捉類型數量。如果為非正數,則這是擷取型別數量的負數,且擷取作業後會接續執行擷取所有項目的處理常式。舉例來說,size 的 0 表示有 catch-all,但沒有明確型別的 catches。size 為 2 表示有兩個明確型別的 catch,但沒有 catch-all。而 size 的 -1
表示有一個已輸入的擷取內容和一個擷取所有內容。
|
處理常式 | encoded_type_addr_pair[abs(size)] | abs(size) 編碼項目的串流,每個擷取的型別各有一個項目,順序應與型別的測試順序相同。 |
catch_all_addr | uleb128 (選用) | 全部接收處理常式的位元組碼位址。只有在 size 為非正數時,才會出現這個元素。
|
encoded_type_addr_pair 格式
名稱 | 格式 | 說明 |
---|---|---|
type_idx | uleb128 | index into the type_ids list for the type of the
exception to catch
|
addr | uleb128 | 相關聯例外狀況處理常式的位元碼位址 |
debug_info_item
參照自 code_item
顯示在「資料」部分
對齊方式:無 (位元組對齊)
每個 debug_info_item
都會定義 DWARF3 啟發的位元組編碼狀態機器,解譯時會發出位置資料表和 (可能) code_item
的本機變數資訊。序列開頭為長度可變的標頭 (長度取決於方法參數數量),後面接著狀態機位元組碼,結尾為 DBG_END_SEQUENCE
位元組。
狀態機器包含五個暫存器。address
暫存器代表相關聯 insns_item
中的指令偏移,以 16 位元程式碼單元表示。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 :包含本機的暫存器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 :包含本機的暫存器name_idx :名稱的字串索引type_idx :類型的類型索引sig_idx :類型簽章的字串索引
|
在目前位址導入具有型別簽章的區域。
name_idx 、type_idx 或 sig_idx 都可以是 NO_INDEX ,表示該值不明。(不過,如果 sig_idx 是 -1 ,則可使用運算碼 DBG_START_LOCAL 更有效率地表示相同資料)。注意:請參閱下方「 |
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 狀態機暫存器,指出新增的下一個位置項目應視為方法序言的結尾 (方法中斷點的適當位置)。任何特殊 (>= 0x0a ) 不透明指令碼都會清除 prologue_end 暫存器。 |
|
DBG_SET_EPILOGUE_BEGIN | 0x08 | (無) | 會設定 epilogue_begin 狀態機暫存器,指出新增的下一個位置項目應視為方法結尾的開頭 (適合在方法結束前暫停執行的位置)。任何特殊 (>= 0x0a ) 不正確的運算碼都會清除 epilogue_begin 暫存器。
|
|
DBG_SET_FILE | 0x09 | uleb128p1 name_idx | name_idx :來源檔案名稱的字串索引;如果不明,則為 NO_INDEX
|
表示後續所有行號項目都會參照這個來源檔案名稱,而非 code_item 中指定的預設名稱。 |
特殊運算碼 | 0x0a…0xff | (無) | 推進 line 和 address 暫存器、發出位置項目,並清除 prologue_end 和 epilogue_begin 。說明如下。
|
特殊運算碼
值介於 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 | 這個項目註解的方法參數清單數量 |
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 」指定,如下所示:
"annotation_set_item "。
|
method_annotation 格式
名稱 | 格式 | 說明 |
---|---|---|
method_idx | uint | 方法註解的 ID method_ids 清單索引 |
annotations_off | uint | 從檔案開頭到方法註解清單的位移。偏移量應指向 data 部分中的位置。資料格式由「annotation_set_item 」指定,如下所示:
"annotation_set_item "。
|
parameter_annotation 格式
名稱 | 格式 | 說明 |
---|---|---|
method_idx | uint | 索引至 method_ids 清單,找出要為參數加上註解的方法身分 |
annotations_off | uint | 從檔案開頭到方法參數註解清單的位移。偏移量應指向 data 部分中的位置。資料格式由「annotation_set_ref_list 」指定,如下所示:
"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 "。
|
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
顯示在「資料」部分
對齊方式:無 (位元組對齊)
名稱 | 格式 | 說明 |
---|---|---|
顯示設定 | 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
這個部分包含每個類別使用的受限介面資料。
注意: Android 10.0 導入了隱藏 API 功能,且僅適用於啟動類別路徑中類別的 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[] | 擲回的例外狀況類型陣列 |