Dalvik 可執行格式

本文將說明 .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
0000-1
01110
7f-1127126
80 7f-1281625616255

檔案版面配置

名稱 格式 說明
標頭 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_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。(請參閱「Bytecode 集合摘要」表格,瞭解各個集合的說明。)在 Android 10 中,039 版本會擴充 DEX 檔案格式,納入僅適用於引導程式類別路徑的 DEX 檔案的隱藏 API 資訊。

注意: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     編譯器應將最後一個引數視為「其餘」引數
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+10000U+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 代表 false1 代表 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+d800U+dfff) 本身不視為有效的名稱字元,但萬國碼輔助字元「是」有效 (由 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
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 簽章 (雜湊) (除了 magicchecksum 和這個欄位之外的所有內容);用於唯一識別檔案
file_size uint

整個檔案 (包括標頭) 的大小 (以位元組為單位) (v40 或更早版本)

從這個標頭開始到下一個標頭或整個檔案 (容器) 結尾的位元組距離。(41 以上版本)

header_size uint

標頭 (整個部分) 的大小,以位元組為單位。這樣一來,至少可以提供有限的回溯/前向相容性,而不會使格式失效。

必須是 0x70 (112) 個位元組 (v40 以下版本)

必須是 0x78 (120) 個位元組 (v41 以上版本)

endian_tag uint = ENDIAN_CONSTANT endianness 標記。詳情請參閱上方「ENDIAN_CONSTANTREVERSE_ENDIAN_CONSTANT」一節的討論。
link_size uint 連結區大小,或如果此檔案未靜態連結,則為 0
link_off uint 從檔案開頭到連結部分的偏移量,如果是 link_size == 0,則為 0。如果偏移量非零,則應為 link_data 區段中的偏移量。這份文件未指定所指向資料的格式;這個標頭欄位 (以及前一個標頭欄位) 會保留做為執行階段實作項目的鉤子。
map_off uint 從檔案開頭到地圖項目的偏移量。偏移量必須為非零值,且應偏移至 data 區段,資料應採用下方「map_list」指定的格式。
string_ids_size uint 字串 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 == 00 時 (這是奇怪的邊緣情況)。如果偏移量不為零,則應為 class_defs 區段的開頭。
data_size uint

data 區段的大小,以位元組為單位。必須是 sizeof(uint) 的偶數倍。(v40 或更早版本)

未使用 (v41 以上版本)

data_off uint

從檔案開頭到 data 區段開頭的偏移量 (v40 以下版本)

未使用 (v41 以上版本)

container_size uint

這個欄位不存在。可以假設它等於 file_size(v40 或更早版本)

整個檔案的大小 (包括其他 dex 標頭及其資料)。(41 以上版本)

header_offset uint

這個欄位不存在。可以假設它等於 0(v40 或更早版本)

從檔案開頭到這個標頭開頭的偏移量。(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 代理程式碼單元 (即 U+d800U+dfff) 的編碼形式,但必須是獨立或不按順序編碼,才能將萬國碼編碼為 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 欄位初始值清單的偏移量,如果沒有初始值,則為 0 (所有 static 欄位都會使用 0null 進行初始化)。這個偏移量應位於 data 部分,且其中的資料應採用下方「encoded_array_item」所指定的格式。陣列的大小不得大於此類別宣告的 static 欄位數量,且元素必須與對應 field_list 中宣告的 static 欄位保持相同順序。每個陣列元素的類型都必須與其對應欄位的宣告類型相符。如果陣列中的元素少於 static 欄位,則系統會使用類型相符的 0null 初始化剩餘的欄位。

call_site_id_item

會顯示在 call_site_ids 部分

對齊方式:4 個位元組

名稱 格式 說明
call_site_off uint 從檔案開頭到呼叫網站定義的偏移量。偏移量應位於資料部分,且資料應採用下方「call_site_item」指定的格式。

call_site_item

顯示在資料部分

對齊方式:無 (位元組對齊)

call_site_item 是 encoded_array_item,其元素對應至提供給引導程式連結器方法的引數。前三個引數如下:

  1. 代表引導連結器方法 (VALUE_METHOD_HANDLE) 的方法句柄。
  2. 引導連結器應解析的方法名稱 (VALUE_STRING)。
  3. 與要解析的方法名稱類型 (VALUE_METHOD_TYPE) 相對應的方法類型。

任何額外引數都是傳遞至 Bootstrap 連結器方法的常數值。這些引數會依序傳遞,且不會進行任何類型轉換。

代表引導程式連結器方法的方法句柄,必須具有 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 方法句柄是靜態欄位 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] 定義的直接 (任何 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 清單,以便取得此方法的 ID (包括名稱和描述符),以清單中前一項元素的索引差異表示。清單中第一個元素的索引會直接顯示。
access_flags uleb128 方法的存取標記 (publicfinal 等)。詳情請參閱「access_flags 定義」。
code_off uleb128 從檔案開頭到此方法的程式碼結構的偏移量,如果此方法為 abstractnative,則為 0。偏移量應為 data 部分中的某個位置。資料格式由下方的「code_item」指定。

type_list

由 class_def_item 和 proto_id_item 參照

顯示在資料部分

對齊方式:4 個位元組

名稱 格式 說明
size uint 清單的大小 (以項目為單位)
清單 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 處理常式。舉例來說,size0 表示有 catch-all,但沒有明確指定類型的 catch。size2 表示有兩個明確指定的 catch,且沒有 catch-all。而 -1size 表示有一個型別的 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 註冊代表應與狀態機器所發出的下一個位置表格項目相關聯的來源行號。這項值會在序列標頭中初始化,且可能會在正向或負向方向變更,但絕對不能低於 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:將包含 local
的註冊項 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:將包含 local
name_idx:名稱的字串索引
type_idx:類型的類型索引
sig_idx:類型簽名的字串索引
在目前的地址中引入具有類型簽章的本機。name_idxtype_idxsig_idx 的任何值都可能為 NO_INDEX,表示該值不明。(不過,如果 sig_idx-1,則可使用 DBG_START_LOCAL opcode 更有效率地呈現相同資料)。

注意:如要瞭解處理簽名時的注意事項,請參閱下方「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 狀態機制註冊器,表示新增的下一個位置項目應視為方法尾聲的開頭 (在方法結束前暫停執行的適當位置)。任何特殊 (>= 0x0a) 運算碼都會清除 epilogue_begin 註冊。
DBG_SET_FILE 0x09 uleb128p1 name_idx name_idx:來源檔案名稱的字串索引;如果不明,則為 NO_INDEX 表示後續所有行號項目都會參照這個來源檔案名稱,而非 code_item 中指定的預設名稱
特殊 Opcodes 0x0a…0xff (無) 會推進 lineaddress 登錄項目,發出位置項目,並清除 prologue_endepilogue_begin。詳情請參閱下文。

特殊 Opcode

值介於 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 參照

顯示在資料部分

對齊方式: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_idmethod_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_itemvisibility 欄位的選項:

名稱 說明
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 註解。此外,類別不得同時具有 EnclosingClassEnclosingMethod 註解。

名稱 格式 說明
類別 最接近這個類別的字彙層級

dalvik.annotation.EnclosingMethod

顯示在課程

每個在方法主體中定義的類別都會附加 EnclosingMethod 註解。每個含有此註解的類別都必須有 InnerClass 註解。此外,類別不得同時具有 EnclosingClassEnclosingMethod 註解。

名稱 格式 說明
方法 最接近這個類別的字彙範圍方法

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().lengthaccessFlags().length 相同。

由於 MethodParameters 會描述所有正式方法參數,即使這些參數未在原始程式碼中明確或隱含宣告,陣列的大小也可能與簽名或其他中繼資料資訊不同,因為這些資訊只會根據在原始程式碼中宣告的明確參數。MethodParameters 也不會納入任何關於類型註解接收器參數的資訊,因為這些參數不存在於實際方法簽章中。

名稱 格式 說明
名稱 String[] 關聯方法的正式參數名稱。陣列不得為空值,但如果沒有正式參數,則必須為空白。如果該索引的正式參數沒有名稱,陣列中的值就必須為空值。
如果參數名稱字串為空白,或包含「.」,「'」,「[」或「/」字元,則會在執行階段擲回 java.lang.reflect.MalformedParametersException
accessFlags int[] 關聯方法的形式參數存取旗標。陣列不得為空值,但如果沒有正式參數,則必須為空白。
這個值是位元遮罩,其中包含以下值:
  • 0x0010:final,參數已宣告為 final
  • 0x1000:合成,參數是由編譯器引入
  • 0x8000:強制規定,參數是合成的,但也暗示符合語言規格
如果有任何位元設在這個集合之外,則會在執行階段擲回 java.lang.reflect.MalformedParametersException

dalvik.annotation.Signature

會顯示在類別、欄位和方法上

每個類別、欄位或方法都會附加 Signature 註解,這些類別、欄位或方法的定義類型比 type_id_item 更複雜,.dex 格式並未定義簽章的格式,而是僅能代表來源語言所需的任何簽章,以便成功實作該語言的語意。因此,虛擬機器實作通常不會剖析 (或驗證) 簽章。簽章會直接交由較高層級的 API 和工具 (例如偵錯工具) 處理。因此,任何使用簽名的情況都應以不假設只會收到有效簽名的方式編寫,明確防範遇到語法無效簽名的可能性。

由於簽章字串通常含有大量重複內容,因此 Signature 註解會定義為字串的陣列,其中重複的元素自然會參照相同的基礎資料,而簽章則視為陣列中所有字串的串接。系統並未提供任何規則,說明如何將簽章拆解為個別字串;這完全取決於產生 .dex 檔案的工具。

名稱 格式 說明
String[] 這個類別或成員的簽章,做為要串連在一起的字串陣列

dalvik.annotation.Throws

顯示在方法上

每個方法都會附加 Throws 註解,這些方法會宣告擲回一或多個例外狀況類型。

名稱 格式 說明
Class[] 擲回的例外狀況類型陣列