Este documento descreve o layout e o conteúdo dos arquivos .dex
, que são usados para armazenar um conjunto de definições de classe e os dados
adjuntos associados.
Guia de tipos
Nome | Descrição |
---|---|
byte | Int de 8 bits assinado |
ubyte | Int de 8 bits sem assinatura |
short | Int assinado de 16 bits, little-endian |
ushort | Int não assinado de 16 bits, little-endian |
int | Int assinado de 32 bits, little-endian |
uint | Int sem sinal de 32 bits, little-endian |
long | Int assinado de 64 bits, little-endian |
ulong | Int não assinado de 64 bits, little-endian |
sleb128 | LEB128 assinado, comprimento variável (consulte abaixo) |
uleb128 | LEB128 não assinado, de comprimento variável (consulte abaixo) |
uleb128p1 | LEB128 não assinado mais 1 , comprimento variável (consulte abaixo) |
LEB128
LEB128 ("Little-Endian Base 128") é uma
codificação de comprimento variável para
quantidades de números inteiros assinadas ou não assinadas arbitrárias. O formato foi
emprestado da especificação
DWARF3. Em um arquivo .dex
, o LEB128 é usado apenas para
codificar quantidades de 32 bits.
Cada valor codificado LEB128 consiste em um a cinco
bytes, que juntos representam um único valor de 32 bits. Cada
byte tem o bit mais significativo definido, exceto o byte final da
sequência, que tem o bit mais significativo definido. Os sete bits restantes de cada byte são payload, com os sete bits menos significativos da quantidade no primeiro byte, os próximos sete no segundo byte e assim por diante. No caso de um LEB128 assinado (sleb128
),
o bit de payload mais significativo do byte final na sequência é
estendido para produzir o valor final. No caso não assinado
(uleb128
), todos os bits não representados explicitamente são
interpretados como 0
.
Diagrama de bits de um valor LEB128 de dois bytes | |||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Primeiro byte | Segundo byte | ||||||||||||||
1 |
bit6 | bit5 | bit4 | bit3 | bit2 | bit1 | bit0 | 0 |
bit13 | bit12 | bit11 | bit10 | bit9 | bit8 | bit7 |
A variante uleb128p1
é usada para representar um valor
assinado, em que a representação é do valor mais um codificado
como uleb128
. Isso faz com que a codificação de -1
(considerada como o valor não assinado 0xffffffff
)
— mas nenhum outro número negativo — seja um único byte e seja
útil exatamente nos casos em que o número representado precisa ser
não negativo ou -1
(ou 0xffffffff
)
e em que nenhum outro valor negativo é permitido (ou em que valores não assinados grandes
provavelmente não serão necessários).
Confira alguns exemplos de formatos:
Sequência codificada | Como sleb128 |
Como uleb128 |
Como uleb128p1 |
---|---|---|---|
00 | 0 | 0 | -1 |
01 | 1 | 1 | 0 |
7f | -1 | 127 | 126 |
80 7f | -128 | 16256 | 16255 |
Layout do arquivo
Nome | Formato | Descrição |
---|---|---|
cabeçalho | header_item | o cabeçalho |
string_ids | string_id_item[] | lista de identificadores de string. São identificadores de todas as strings usadas por esse arquivo, seja para nomenclatura interna (por exemplo, descritores de tipo) ou como objetos constantes referenciados pelo código. Essa lista precisa ser classificada pelo conteúdo da string, usando valores de ponto de código UTF-16 (não de forma específica para a localidade) e não pode conter entradas duplicadas. |
type_ids | type_id_item[] | Lista de identificadores de tipo. Esses são identificadores de todos os tipos (classes,
matrizes ou tipos primitivos) mencionados por este arquivo, definidos
ou não. Essa lista precisa ser classificada pelo índice string_id
e não pode conter entradas duplicadas.
|
proto_ids | proto_id_item[] | lista de identificadores de protótipos de método. São identificadores de todos
protótipos mencionados neste arquivo. Essa lista precisa ser classificada em
ordem principal do tipo de retorno (por índice type_id ) e, em seguida,
por lista de argumentos (ordenação alfabética, argumentos individuais
ordenados por índice type_id ). A lista não pode
conter entradas duplicadas.
|
field_ids | field_id_item[] | lista de identificadores de campo. São identificadores de todos os campos
a que este arquivo faz referência, definidos ou não no arquivo. Essa
lista precisa ser classificada, em que o tipo de definição (pelo índice type_id )
é a ordem principal, o nome do campo (pelo índice string_id )
é a ordem intermediária e o tipo (pelo índice type_id )
é a ordem secundária. A lista não pode conter entradas duplicadas.
|
method_ids | method_id_item[] | lista de identificadores de método. São identificadores de todos os métodos
referenciados por este arquivo, definidos ou não no arquivo. Essa
lista precisa ser classificada, em que o tipo de definição (pelo índice
type_id ) é a ordem principal, o nome do método (pelo índice
string_id ) é a ordem intermediária e o protótipo do método (pelo
índice proto_id ) é a ordem secundária. A lista não pode
conter entradas duplicadas.
|
class_defs | class_def_item[] | lista de definições de classe. As classes precisam ser ordenadas de modo que a superclasse de uma determinada classe e as interfaces implementadas apareçam na lista antes da classe de referência. Além disso, é inválido que uma definição para a classe com o mesmo nome apareça mais de uma vez na lista. |
call_site_ids | call_site_id_item[] | lista de identificadores de chamadas do site. São identificadores de todos os locais de chamada
a que este arquivo faz referência, definidos ou não no arquivo. Essa lista
precisa ser classificada em ordem crescente de call_site_off .
|
method_handles | method_handle_item[] | lista de identificadores de método. Uma lista de todos os identificadores de método referidos por este arquivo, definidos ou não no arquivo. Essa lista não é classificada e pode conter duplicatas que correspondem logicamente a diferentes instâncias de identificador de método. |
dados | ubyte[] | área de dados, que contém todos os dados de suporte das tabelas listadas acima. Itens diferentes têm requisitos de alinhamento diferentes, e bytes de preenchimento são inseridos antes de cada item, se necessário, para alcançar o alinhamento adequado. |
link_data | ubyte[] | dados usados em arquivos vinculados de forma estática. O formato dos dados nesta seção não é especificado neste documento. Essa seção está vazia em arquivos não vinculados, e as implementações do ambiente de execução podem usá-la como acharem melhor. |
Formato do contêiner
A versão 41 apresenta um novo formato de contêiner para dados DEX com o objetivo de economizar espaço. Esse formato de contêiner permite que vários arquivos DEX lógicos sejam combinados em um único arquivo físico. O novo formato é basicamente uma concatenação simples de arquivos no formato anterior, com algumas diferenças:
- O
file_size
é o tamanho do arquivo lógico, não do arquivo físico. Ele pode ser usado para iterar sobre todos os arquivos lógicos no contêiner. - Os arquivos dex lógicos podem fazer referência a dados posteriores no contêiner, mas não anteriores. Isso permite que os arquivos dex compartilhem dados, como strings, entre eles.
- Todos os deslocamentos são relativos ao arquivo físico. Nenhum deslocamento é relativo ao cabeçalho. Isso garante que as seções com deslocamentos possam ser compartilhadas entre arquivos lógicos.
- O cabeçalho adiciona dois novos campos para descrever os limites do contêiner. Essa é uma verificação de consistência adicional e facilita a transferência de código para o novo formato.
data_size
edata_off
não são mais usados. Os dados podem ser distribuídos em vários arquivos lógicos e não precisam ser contíguos.
Definições de bit, string e constantes
DEX_FILE_MAGIC
Incorporado em header_item
A matriz/string constante DEX_FILE_MAGIC
é a lista de
bytes que precisa aparecer no início de um arquivo .dex
para que ele seja reconhecido como tal. O valor intencionalmente
contém uma nova linha ("\n"
ou 0x0a
) e um
byte nulo ("\0"
ou 0x00
) para ajudar
na detecção de determinadas formas de corrupção. O valor também
codifica um número de versão de formato como três dígitos decimais, que
deve aumentar monotonicamente ao longo do tempo conforme o formato evolui.
ubyte[8] DEX_FILE_MAGIC = { 0x64 0x65 0x78 0x0a 0x30 0x33 0x39 0x00 } = "dex\n039\0"
Observação:o suporte à versão 040
do
formato foi adicionado na versão do Android 10.0, que estendeu o conjunto de caracteres
permitidos em SimpleNames.
Observação:o suporte à versão 039
do
formato foi adicionado na versão do Android 9.0, que introduziu dois
novos bytecodes, const-method-handle
e
const-method-type
. Elas são descritas na tabela
Resumo do conjunto de bytecode. No Android 10, a versão 039
estende o formato de arquivo DEX para incluir informações de API
ocultas que só são aplicáveis a arquivos DEX no caminho da classe de inicialização.
Observação:o suporte à versão
038
do formato foi adicionado na versão
Android 8.0. A versão 038
adicionou novos bytecodes
(invoke-polymorphic
e invoke-custom
) e
dados para identificadores de método.
Observação:o suporte para a versão 037
do
formato foi adicionado na versão do Android 7.0. Antes da versão 037
, a maioria
das versões do Android usava a versão 035
do formato. A única
diferença entre as versões 035
e 037
é a
adição de métodos padrão e o ajuste do invoke
.
Observação:pelo menos algumas versões anteriores do formato foram
usadas em lançamentos de software públicos amplamente disponíveis. Por exemplo,
a versão 009
foi usada para as versões M3 da
plataforma Android (novembro a dezembro de 2007),
e a versão 013
foi usada para as versões M5 da
plataforma Android (fevereiro a março de 2008). Em vários aspectos, essas versões
anteriores do formato são significativamente diferentes da versão descrita neste
documento.
ENDIAN_CONSTANT e REVERSE_ENDIAN_CONSTANT
Incorporado em header_item
A constante ENDIAN_CONSTANT
é usada para indicar o
endianidade do arquivo em que ela é encontrada. Embora o formato
.dex
padrão seja little-endian, as implementações podem escolher
realizar a troca de bytes. Se uma implementação encontrar um
cabeçalho com endian_tag
como REVERSE_ENDIAN_CONSTANT
em vez de ENDIAN_CONSTANT
, ela saberá que o arquivo
foi trocado de bytes do formulário esperado.
uint ENDIAN_CONSTANT = 0x12345678; uint REVERSE_ENDIAN_CONSTANT = 0x78563412;
NO_INDEX
Incorporado em class_def_item e debug_info_item
A constante NO_INDEX
é usada para indicar que
um valor de índice está ausente.
Observação:esse valor não é definido como
0
, porque esse é, na verdade, um índice válido.
O valor escolhido para NO_INDEX
pode ser
representado como um único byte na codificação uleb128p1
.
uint NO_INDEX = 0xffffffff; // == -1 if treated as a signed int
definições de access_flags
Incorporado em class_def_item, encoded_field, encoded_method e InnerClass
Os campos de bits dessas flags são usados para indicar a acessibilidade e as propriedades gerais de classes e membros de classe.
Nome | Valor | Para classes (e anotações InnerClass ) |
Para campos | Para métodos |
---|---|---|---|---|
ACC_PUBLIC | 0x1 | public : visível em todos os lugares |
public : visível em todos os lugares |
public : visível em todos os lugares |
ACC_PRIVATE | 0x2 | private : visível apenas para a classe de definição
|
private : visível apenas para a classe de definição |
private : visível apenas para a classe de definição |
ACC_PROTECTED | 0x4 | protected : visível para pacotes e subclasses
|
protected : visível para pacotes e subclasses |
protected : visível para pacotes e subclasses |
ACC_STATIC | 0x8 | static : não é construído com uma referência
this externa |
static : global para definir a classe |
static : não aceita um argumento this |
ACC_FINAL | 0x10 | final : não pode ser subclassificado |
final : imutável após a construção |
final : não pode ser substituído |
ACC_SYNCHRONIZED | 0x20 | synchronized : bloqueio associado adquirido automaticamente
durante a chamada para este método. Observação:isso só é válido quando
|
||
ACC_VOLATILE | 0x40 | volatile : regras de acesso especiais para ajudar com a segurança
de linhas de execução |
||
ACC_BRIDGE | 0x40 | método de ponte, adicionado automaticamente pelo compilador como uma ponte segura para tipos | ||
ACC_TRANSIENT | 0x80 | transient : não ser salvo pela serialização padrão |
||
ACC_VARARGS | 0x80 | O último argumento precisa ser tratado como um argumento "rest" pelo compilador | ||
ACC_NATIVE | 0x100 | native : implementado em código nativo |
||
ACC_INTERFACE | 0x200 | interface : classe abstrata com várias implementações |
||
ACC_ABSTRACT | 0x400 | abstract : não pode ser instanciado diretamente |
abstract : não implementado por esta classe |
|
ACC_STRICT | 0x800 | strictfp : regras rigorosas para a aritmética de ponto flutuante |
||
ACC_SYNTHETIC | 0x1000 | não está definido diretamente no código-fonte | não está definido diretamente no código-fonte | não está definido diretamente no código-fonte |
ACC_ANNOTATION | 0x2000 | declarada como uma classe de anotação | ||
ACC_ENUM | 0x4000 | declarado como um tipo enumerado | declarado como um valor enumerado | |
(não usado) | 0x8000 | |||
ACC_CONSTRUCTOR | 0x10000 | método construtor (inicializador de classe ou de instância) | ||
ACC_DECLARED_ SYNCHRONIZED |
0x20000 | declarou synchronized . Observação:isso não tem efeito na execução (exceto na reflexão dessa flag). |
InnerClass
e não pode ser usado em class_def_item
.
Codificação UTF-8 modificada
Para facilitar o suporte legado, o formato .dex
codifica os dados de string em um formato UTF-8 modificado padrão de fato, chamado de MUTF-8. Esse formulário é idêntico ao UTF-8 padrão, exceto:
- Somente as codificações de um, dois e três bytes são usadas.
- Os pontos de código no intervalo
U+10000
…U+10ffff
são codificados como um par substituto, cada um representado como um valor codificado de três bytes. - O ponto de código
U+0000
é codificado na forma de dois bytes. - Um byte nulo simples (valor
0
) indica o fim de uma string, como é a interpretação padrão da linguagem C.
Os dois primeiros itens acima podem ser resumidos como: MUTF-8 é um formato de codificação para UTF-16, em vez de ser um formato de codificação mais direto para caracteres Unicode.
Os dois últimos itens acima permitem incluir
o ponto de código U+0000
em uma string e ainda manipulá-lo
como uma string terminada em nulo no estilo C.
No entanto, a codificação especial de U+0000
significa que, ao contrário do
UTF-8 normal, o resultado de chamar a função C padrão
strcmp()
em um par de strings MUTF-8 nem sempre
indica o resultado assinado corretamente da comparação de strings diferentes.
Quando a ordenação (não apenas a igualdade) é uma preocupação, a maneira mais direta
de comparar strings MUTF-8 é decodificá-las caractere por caractere
e comparar os valores decodificados. No entanto, implementações mais inteligentes também
são possíveis.
Consulte O padrão Unicode para mais informações sobre a codificação de caracteres. O MUTF-8 é mais parecido com a codificação CESU-8 (relativamente menos conhecida) do que com o UTF-8 em si.
encoded_value encoding
Incorporado em annotation_element e encoded_array_item
Um encoded_value
é um pedaço codificado de dados (quase)
arbitrários estruturados hierarquicamente. A codificação precisa
ser compacta e simples de analisar.
Nome | Formato | Descrição |
---|---|---|
(value_arg << 5) | value_type | ubyte | Byte que indica o tipo do value imediatamente
subsequente, além
de um argumento de esclarecimento opcional nos três bits de ordem alta.
Confira abaixo as várias definições de value .
Na maioria dos casos, value_arg codifica o comprimento do
value imediatamente subsequente em bytes, como
(size - 1) , por exemplo, 0 significa que
o valor requer um byte, e 7 significa que ele requer
oito bytes. No entanto, há exceções, conforme observado abaixo.
|
value | ubyte[] | bytes que representam o valor, variável em comprimento e interpretado
de maneira diferente para diferentes bytes value_type , embora
sempre little-endian. Confira as várias definições de valor abaixo para
mais detalhes.
|
Formatos de valor
Nome do tipo | value_type |
Formato value_arg |
Formato value |
Descrição |
---|---|---|---|---|
VALUE_BYTE | 0x00 | (nenhum; precisa ser 0 ) |
ubyte[1] | valor inteiro de um byte assinado |
VALUE_SHORT | 0x02 | size - 1 (0…1) | ubyte[size] | Valor inteiro de dois bytes assinado, com extensão de sinal |
VALUE_CHAR | 0x03 | size - 1 (0…1) | ubyte[size] | Valor inteiro de dois bytes não assinado, com extensão de zero |
VALUE_INT | 0x04 | size - 1 (0…3) | ubyte[size] | valor inteiro assinado de quatro bytes, com extensão de sinal |
VALUE_LONG | 0x06 | size - 1 (0…7) | ubyte[size] | valor inteiro assinado de oito bytes, com sinal estendido |
VALUE_FLOAT | 0x10 | size - 1 (0…3) | ubyte[size] | padrão de quatro bytes, estendido a zero à direita e interpretado como um valor de ponto flutuante de 32 bits IEEE754 |
VALUE_DOUBLE | 0x11 | size - 1 (0…7) | ubyte[size] | padrão de bits de oito bytes, estendido a zero à direita e interpretado como um valor de ponto flutuante de 64 bits IEEE754 |
VALUE_METHOD_TYPE | 0x15 | size - 1 (0…3) | ubyte[size] | Valor inteiro de quatro bytes sem sinal (com extensão de zero),
interpretado como um índice na
seção proto_ids e que representa um valor de tipo de método
|
VALUE_METHOD_HANDLE | 0x16 | size - 1 (0…3) | ubyte[size] | Valor inteiro de quatro bytes sem sinal (com extensão zero),
interpretado como um índice na
seção method_handles e que representa um valor de identificador de método
|
VALUE_STRING | 0x17 | size - 1 (0…3) | ubyte[size] | Valor inteiro de quatro bytes sem sinal (com extensão de zero),
interpretado como um índice na
seção string_ids e que representa um valor de string
|
VALUE_TYPE | 0x18 | size - 1 (0…3) | ubyte[size] | Valor inteiro de quatro bytes sem sinal (com extensão de zero),
interpretado como um índice na
seção type_ids e que representa um valor
de tipo/classe reflexivo
|
VALUE_FIELD | 0x19 | size - 1 (0…3) | ubyte[size] | Valor inteiro de quatro bytes sem sinal (com extensão de zero),
interpretado como um índice na
seção field_ids e que representa um valor de campo
reflexivo
|
VALUE_METHOD | 0x1a | size - 1 (0…3) | ubyte[size] | Valor inteiro de quatro bytes sem sinal (com extensão de zero),
interpretado como um índice na
seção method_ids e que representa um valor de método
reflexivo.
|
VALUE_ENUM | 0x1b | size - 1 (0…3) | ubyte[size] | Valor inteiro de quatro bytes sem sinal (com extensão de zero),
interpretado como um índice na
seção field_ids e que representa o valor de
uma constante de tipo enumerado
|
VALUE_ARRAY | 0x1c | (nenhum; precisa ser 0 ) |
encoded_array | uma matriz de valores, no formato especificado por
"formato encoded_array " abaixo. O tamanho
do value está implícito na codificação.
|
VALUE_ANNOTATION | 0x1d | (nenhum; precisa ser 0 ) |
encoded_annotation | uma subanotação, no formato especificado por
"formato encoded_annotation " abaixo. O tamanho
do value está implícito na codificação.
|
VALUE_NULL | 0x1e | (nenhum; precisa ser 0 ) |
(nenhuma) | Valor de referência null |
VALUE_BOOLEAN | 0x1f | booleano (0…1) | (nenhuma) | valor de um bit: 0 para false e
1 para true . O bit é representado em
value_arg .
|
formato encoded_array
Nome | Formato | Descrição |
---|---|---|
size | uleb128 | número de elementos na matriz |
valores | encoded_value[size] | uma série de sequências de bytes encoded_value size
no formato especificado por esta seção, concatenadas
sequencialmente.
|
formato encoded_annotation
Nome | Formato | Descrição |
---|---|---|
type_idx | uleb128 | tipo da anotação. Ele precisa ser um tipo de classe (não matriz ou primitivo). |
size | uleb128 | número de mapeamentos de nome-valor nesta anotação |
elementos | annotation_element[size] | elementos da anotação, representados diretamente em linha (não como
deslocamentos). Os elementos precisam ser classificados em ordem crescente pelo
índice string_id .
|
formato do annotation_element
Nome | Formato | Descrição |
---|---|---|
name_idx | uleb128 | nome do elemento, representado como um índice na
seção string_ids . A string precisa estar em conformidade com a
sintaxe de MemberName, definida acima.
|
value | encoded_value | valor do elemento |
Sintaxe de strings
Há vários tipos de itens em um arquivo .dex
que
se referem a uma string. As definições no estilo BNF a seguir
indicam a sintaxe aceitável para essas strings.
SimpleName
Um SimpleName é a base para a sintaxe dos nomes de outras
coisas. O formato .dex
permite uma certa margem de manobra
aqui (muito maior do que a maioria dos idiomas de origem mais comuns). Em resumo, um nome
simples consiste em qualquer caractere alfabético ou dígito de ASCII de baixo nível, alguns
símbolos específicos de ASCII de baixo nível e a maioria dos pontos de código não ASCII que não são
caracteres de controle, espaço ou especiais. A partir da versão 040
,
o formato também permite caracteres de espaço (categoria Unicode Zs
). Os pontos de código substituto
(no intervalo U+d800
…U+dfff
) não são
considerados caracteres de nome válidos, mas os caracteres suplementares
Unicode são válidos (representados pela alternativa final
da regra para SimpleNameChar) e precisam ser
representados em um arquivo como pares de pontos de código substituto na codificação
MUTF-8.
SimpleName → | ||
SimpleNameChar (SimpleNameChar)* | ||
SimpleNameChar → | ||
'A' … 'Z' |
||
| | 'a' … 'z' |
|
| | '0' … '9' |
|
| | ' ' |
desde a versão 040 do DEX |
| | '$' |
|
| | '-' |
|
| | '_' |
|
| | U+00a0 |
desde a versão 040 do DEX |
| | U+00a1 … U+1fff |
|
| | U+2000 … U+200a |
desde a versão 040 do DEX |
| | U+2010 … U+2027 |
|
| | U+202f |
desde a versão 040 do DEX |
| | U+2030 … U+d7ff |
|
| | U+e000 … U+ffef |
|
| | U+10000 … U+10ffff |
MemberName
usado por field_id_item e method_id_item
Um MemberName é o nome de um membro de uma classe, sendo campos, métodos e classes internas.
MemberName → | |
SimpleName | |
| | '<' SimpleName '>' |
FullClassName
Um FullClassName é um nome de classe totalmente qualificado, incluindo um especificador de pacote opcional seguido por um nome obrigatório.
FullClassName → | |
OptionalPackagePrefix SimpleName | |
OptionalPackagePrefix → | |
(SimpleName '/' )* |
TypeDescriptor
Usado por type_id_item
Um TypeDescriptor é a representação de qualquer tipo, incluindo
primitivos, classes, matrizes e void
. Confira abaixo o significado das várias versões.
TypeDescriptor → | |
'V' |
|
| | FieldTypeDescriptor |
FieldTypeDescriptor → | |
NonArrayFieldTypeDescriptor | |
| | ('[' * 1…255)
NonArrayFieldTypeDescriptor |
NonArrayFieldTypeDescriptor→ | |
'Z' |
|
| | 'B' |
| | 'S' |
| | 'C' |
| | 'I' |
| | 'J' |
| | 'F' |
| | 'D' |
| | 'L' FullClassName ';' |
ShortyDescriptor
Usado por proto_id_item
Um ShortyDescriptor é a representação em forma curta de um protótipo
de método, incluindo tipos de retorno e de parâmetro, exceto que não há
diferença entre vários tipos de referência (classe ou matriz). Em vez disso,
todos os tipos de referência são representados por um único caractere 'L'
.
ShortyDescriptor → | |
ShortyReturnType (ShortyFieldType)* | |
ShortyReturnType → | |
'V' |
|
| | ShortyFieldType |
ShortyFieldType → | |
'Z' |
|
| | 'B' |
| | 'S' |
| | 'C' |
| | 'I' |
| | 'J' |
| | 'F' |
| | 'D' |
| | 'L' |
Semântica de TypeDescriptor
Este é o significado de cada uma das variantes de TypeDescriptor.
Sintaxe | Significado |
---|---|
V | void : válido apenas para tipos de retorno |
Z | boolean |
B | byte |
S | short |
C | char |
I | int |
J | long |
F | float |
D | double |
Lfully/qualified/Name; | a classe fully.qualified.Name |
[descriptor | matriz de descriptor , que pode ser usada de forma recursiva para
matrizes de matrizes, embora seja inválido ter mais de 255
dimensões.
|
Itens e estruturas relacionadas
Esta seção inclui definições para cada um dos itens de nível superior que
podem aparecer em um arquivo .dex
.
header_item
Aparece na seção do cabeçalho
Alinhamento: 4 bytes
Nome | Formato | Descrição |
---|---|---|
mágica | ubyte[8] = DEX_FILE_MAGIC | valor mágico. Consulte a discussão acima em "DEX_FILE_MAGIC "
para mais detalhes.
|
checksum | uint | Soma de verificação adler32 do restante do arquivo (tudo, exceto
magic e este campo); usada para detectar a corrupção do arquivo
|
assinatura | ubyte[20] | Assinatura SHA-1 (hash) do restante do arquivo (tudo, exceto
magic , checksum e este campo); usada
para identificar arquivos de maneira exclusiva
|
file_size | uint |
tamanho do arquivo inteiro (incluindo o cabeçalho), em bytes (v40 ou anterior) Distância em bytes do início deste cabeçalho até o próximo cabeçalho ou até o fim de todo o arquivo (o contêiner). (v41 ou mais recente) |
header_size | uint |
tamanho do cabeçalho (toda a seção), em bytes. Isso permite pelo menos uma quantidade limitada de compatibilidade com versões anteriores/posteriores sem invalidar o formato. Precisa ser 0x70 (112) bytes (v40 ou anterior) Precisa ser 0x78 (120) bytes (v41 ou mais recente) |
endian_tag | uint = ENDIAN_CONSTANT | tag de endianidade. Consulte a discussão acima em "ENDIAN_CONSTANT
e REVERSE_ENDIAN_CONSTANT " para mais detalhes.
|
link_size | uint | tamanho da seção de link ou 0 se o arquivo não estiver
vinculado de forma estática |
link_off | uint | deslocamento do início do arquivo até a seção do link ou
0 se link_size == 0 . O deslocamento, se diferente de zero,
precisa ser um deslocamento para a seção link_data . O
formato dos dados apontados não é especificado neste documento.
Esse campo de cabeçalho (e o anterior) são deixados como ganchos para uso por
implementações de tempo de execução.
|
map_off | uint | deslocamento do início do arquivo para o item do mapa. O deslocamento, que precisa
ser diferente de zero, precisa ser um deslocamento na seção data ,
e os dados precisam estar no formato especificado por "map_list "
abaixo.
|
string_ids_size | uint | contagem de strings na lista de identificadores de string |
string_ids_off | uint | deslocamento do início do arquivo para a lista de identificadores de string ou
0 se string_ids_size == 0 (um caso extremo
estranho). O deslocamento, se diferente de zero,
precisa estar no início da seção string_ids .
|
type_ids_size | uint | contagem de elementos na lista de identificadores de tipo, no máximo 65.535 |
type_ids_off | uint | deslocamento do início do arquivo para a lista de identificadores de tipo ou
0 se type_ids_size == 0 (um caso extremo
estranho). O deslocamento, se diferente de zero,
precisa ser o início da seção
type_ids .
|
proto_ids_size | uint | contagem de elementos na lista de identificadores de protótipo, no máximo 65.535 |
proto_ids_off | uint | deslocamento do início do arquivo para a lista de identificadores de protótipo ou
0 se proto_ids_size == 0 (um caso extremo
estranho). O deslocamento, se diferente de zero,
precisa ser o início da seção
proto_ids .
|
field_ids_size | uint | contagem de elementos na lista de identificadores de campo |
field_ids_off | uint | deslocamento da lista de identificadores de campo até o início do arquivo ou
0 se field_ids_size == 0 . O deslocamento, se
diferente de zero, precisa ser o início da seção
field_ids . |
method_ids_size | uint | contagem de elementos na lista de identificadores de método |
method_ids_off | uint | deslocamento do início do arquivo para a lista de identificadores de método ou
0 se method_ids_size == 0 . O deslocamento, se
diferente de zero, precisa ser o início da seção
method_ids . |
class_defs_size | uint | contagem de elementos na lista de definições de classe |
class_defs_off | uint | deslocamento do início do arquivo para a lista de definições de classe ou
0 se class_defs_size == 0 (um caso extremo
estranho). O deslocamento, se diferente de zero,
precisa estar no início da seção class_defs .
|
data_size | uint |
Tamanho da seção Não utilizado (v41 ou mais recente) |
data_off | uint |
deslocamento do início do arquivo até o início da seção Não utilizado (v41 ou mais recente) |
container_size | uint |
este campo não existe. Pode-se presumir que ele é igual a tamanho de todo o arquivo (incluindo outros cabeçalhos dex e os dados deles). (v41 ou mais recente) |
header_offset | uint |
este campo não existe. Pode-se presumir que ele é igual a deslocamento do início do arquivo até o início deste cabeçalho. (v41 ou mais recente) |
map_list
Aparece na seção de dados
Referência de header_item
Alinhamento: 4 bytes
Esta é uma lista de todo o conteúdo de um arquivo, em ordem. Ele
contém alguma redundância em relação ao header_item
,
mas tem como objetivo ser uma forma fácil de iterar um arquivo
inteiro. Um determinado tipo precisa aparecer no máximo uma vez em um mapa, mas não há
restrição sobre quais tipos de ordem podem aparecer, exceto as
restrições implícitas no restante do formato (por exemplo, uma
seção header
precisa aparecer primeiro, seguida por uma
seção string_ids
etc.). Além disso, as entradas do mapa precisam
ser ordenadas por deslocamento inicial e não podem se sobrepor.
Nome | Formato | Descrição |
---|---|---|
size | uint | tamanho da lista, em entradas |
list | map_item[size] | elementos da lista |
formato de map_item
Nome | Formato | Descrição |
---|---|---|
type | ushort | tipo dos itens. Consulte a tabela abaixo |
unused | ushort | (não usado) |
size | uint | contagem do número de itens a serem encontrados no deslocamento indicado |
compensação | uint | deslocamento do início do arquivo para os itens em questão |
Códigos de tipo
Tipo de item | Constante | Valor | Tamanho do item em bytes |
---|---|---|---|
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 | implícita; precisa ser analisada |
code_item | TYPE_CODE_ITEM | 0x2001 | implícita; precisa ser analisada |
string_data_item | TYPE_STRING_DATA_ITEM | 0x2002 | implícita; precisa ser analisada |
debug_info_item | TYPE_DEBUG_INFO_ITEM | 0x2003 | implícita; precisa ser analisada |
annotation_item | TYPE_ANNOTATION_ITEM | 0x2004 | implícita; precisa ser analisada |
encoded_array_item | TYPE_ENCODED_ARRAY_ITEM | 0x2005 | implícita; precisa ser analisada |
annotations_directory_item | TYPE_ANNOTATIONS_DIRECTORY_ITEM | 0x2006 | implícita; precisa ser analisada |
hiddenapi_class_data_item | TYPE_HIDDENAPI_CLASS_DATA_ITEM | 0xF000 | implícita; precisa ser analisada |
string_id_item
Aparece na seção string_ids
Alinhamento: 4 bytes
Nome | Formato | Descrição |
---|---|---|
string_data_off | uint | deslocamento do início do arquivo para os dados da string desse
item. O deslocamento precisa ser para um local
na seção data , e os dados precisam estar no
formato especificado por "string_data_item " abaixo.
Não há requisito de alinhamento para o deslocamento.
|
string_data_item
Aparece na seção de dados
Alinhamento: nenhum (alinhamento de byte)
Nome | Formato | Descrição |
---|---|---|
utf16_size | uleb128 | tamanho dessa string, em unidades de código UTF-16, que é a "string
length" em muitos sistemas. Ou seja, esse é o comprimento decodificado da
cadeia. O comprimento codificado é implícito pela posição do
byte 0 . |
dados | ubyte[] | uma série de unidades de código MUTF-8 (também conhecidas como octetos ou bytes)
seguidas por um byte de valor 0 . Consulte "Codificação MUTF-8 (UTF-8 modificado)" acima para mais detalhes e discussão sobre o formato de dados.
Observação:é aceitável ter uma string que inclua
(a forma codificada de) unidades de código substituto UTF-16 (ou seja,
|
type_id_item
Aparece na seção "type_ids"
Alinhamento: 4 bytes
Nome | Formato | Descrição |
---|---|---|
descriptor_idx | uint | índice na lista string_ids para a string de descritor
desse tipo. A string precisa estar em conformidade com a sintaxe de
TypeDescriptor, definida acima.
|
proto_id_item
Aparece na seção proto_ids
Alinhamento: 4 bytes
Nome | Formato | Descrição |
---|---|---|
shorty_idx | uint | índice na lista string_ids para a string de descritor
abreviada desse protótipo. A string precisa estar em conformidade com a
sintaxe de ShortyDescriptor, definida acima, e precisa corresponder
ao tipo de retorno e aos parâmetros desse item.
|
return_type_idx | uint | índice na lista type_ids para o tipo de retorno
deste protótipo
|
parameters_off | uint | deslocamento do início do arquivo para a lista de tipos de parâmetro
do protótipo ou 0 se o protótipo não tiver
parâmetros. Esse deslocamento, se diferente de zero, precisa estar na
seção data , e os dados precisam estar no
formato especificado por "type_list" abaixo. Além disso, não
deve haver referência ao tipo void na lista.
|
field_id_item
Aparece na seção field_ids
Alinhamento: 4 bytes
Nome | Formato | Descrição |
---|---|---|
class_idx | ushort | índice na lista type_ids para o definidor desse campo. Ele precisa ser um tipo de classe, e não um tipo primitivo ou matriz.
|
type_idx | ushort | índice na lista type_ids para o tipo de
campo
|
name_idx | uint | índice na lista string_ids para o nome desse campo. A string precisa estar em conformidade com a sintaxe de MemberName,
definida acima.
|
method_id_item
Aparece na seção method_ids
Alinhamento: 4 bytes
Nome | Formato | Descrição |
---|---|---|
class_idx | ushort | índice na lista type_ids para o definidor desse
método. Ele precisa ser um tipo de classe ou matriz, e não um tipo primitivo.
|
proto_idx | ushort | índice na lista proto_ids para o protótipo deste método
|
name_idx | uint | índice na lista string_ids para o nome desse
método. A string precisa estar em conformidade com a sintaxe de MemberName,
definida acima.
|
class_def_item
Aparece na seção class_defs
Alinhamento: 4 bytes
Nome | Formato | Descrição |
---|---|---|
class_idx | uint | índice na lista type_ids para essa classe.
Ele precisa ser um tipo de classe, e não um tipo primitivo ou matriz.
|
access_flags | uint | flags de acesso para a classe (public , final etc.). Consulte "Definições de access_flags " para mais detalhes.
|
superclass_idx | uint | índice na lista type_ids da superclasse ou
o valor constante NO_INDEX se essa classe não tiver
uma superclasse (ou seja, se for uma classe raiz, como Object ).
Se presente, esse valor precisa ser um tipo de classe, e não uma matriz ou um tipo primitivo.
|
interfaces_off | uint | deslocamento do início do arquivo para a lista de interfaces ou
0 se não houver nenhuma. Esse deslocamento
precisa estar na seção data , e os dados
precisam estar no formato especificado por
"type_list " abaixo. Cada um dos elementos da lista
precisa ser um tipo de classe (não um array ou tipo primitivo) e não
pode ter duplicatas.
|
source_file_idx | uint | índice na lista string_ids para o nome do
arquivo que contém a origem original (pelo menos a maioria) dessa classe,
ou o valor especial NO_INDEX para representar a falta
dessas informações. O debug_info_item de qualquer método
pode substituir esse arquivo de origem, mas a expectativa é que a maioria das classes
venha apenas de um arquivo de origem.
|
annotations_off | uint | deslocamento do início do arquivo para a estrutura de anotações
dessa classe ou 0 se não houver anotações
nessa classe. Esse deslocamento, se diferente de zero, precisa estar na
seção data , e os dados precisam estar no
formato especificado por "annotations_directory_item " abaixo,
com todos os itens que se referem a essa classe como o definidor.
|
class_data_off | uint | Deslocamento do início do arquivo para os dados de classe
associados a esse item ou 0 se não houver dados de
classe para essa classe. Isso pode acontecer, por exemplo, se essa classe
for uma interface de marcador. O deslocamento, se diferente de zero, precisa estar na
seção data , e os dados precisam estar no
formato especificado por "class_data_item " abaixo, com todos
os itens que se referem a essa classe como o definidor.
|
static_values_off | uint | deslocamento do início do arquivo para a lista de valores iniciais
para campos static ou 0 se não houver nenhum (e todos os campos static forem inicializados com
0 ou null ). Esse deslocamento precisa estar na
seção data , e os dados precisam estar no
formato especificado por "encoded_array_item " abaixo. O tamanho
da matriz não pode ser maior que o número de campos static
declarados por essa classe, e os elementos correspondem aos
campos static na mesma ordem declarada no
field_list correspondente. O tipo de cada elemento
de matriz precisa corresponder ao tipo declarado do campo correspondente.
Se houver menos elementos na matriz do que campos
static , os campos restantes serão inicializados
com um 0 ou null adequado ao tipo.
|
call_site_id_item
Aparece na seção call_site_ids
Alinhamento: 4 bytes
Nome | Formato | Descrição |
---|---|---|
call_site_off | uint | deslocamento do início do arquivo para chamar a definição do site. O deslocamento precisa estar na seção de dados, e os dados precisam estar no formato especificado por "call_site_item" abaixo. |
call_site_item
Aparece na seção de dados
Alinhamento: nenhum (alinhamento de byte)
O call_site_item é um item de matriz codificado cujos elementos correspondem aos argumentos fornecidos a um método de vinculação de inicialização. Os três primeiros argumentos são:
- Um identificador de método que representa o método de vinculação de inicialização (VALUE_METHOD_HANDLE).
- Um nome de método que o linkador de inicialização precisa resolver (VALUE_STRING).
- Um tipo de método correspondente ao tipo do nome do método a ser resolvido (VALUE_METHOD_TYPE).
Todos os argumentos adicionais são valores constantes transmitidos para o método de vinculação de inicialização. Esses argumentos são transmitidos em ordem e sem conversões de tipo.
O gerenciador de método que representa o método do vinculador de inicialização precisa ter o tipo de retorno java.lang.invoke.CallSite
. Os três primeiros tipos de parâmetro são:
java.lang.invoke.Lookup
java.lang.String
java.lang.invoke.MethodType
Os tipos de parâmetro de outros argumentos são determinados pelos valores constantes.
method_handle_item
Aparece na seção method_handles
Alinhamento: 4 bytes
Nome | Formato | Descrição |
---|---|---|
method_handle_type | ushort | tipo do identificador do método. Consulte a tabela abaixo. |
unused | ushort | (não usado) |
field_or_method_id | ushort | ID de campo ou método, dependendo se o tipo de identificador de método é um acessador ou um invocador de método. |
unused | ushort | (não usado) |
Códigos de tipo de manipulador de método
Constante | Valor | Descrição |
---|---|---|
METHOD_HANDLE_TYPE_STATIC_PUT | 0x00 | O handle de método é um setter de campo estático (acessor) |
METHOD_HANDLE_TYPE_STATIC_GET | 0x01 | O handle de método é um getter de campo estático (acessador) |
METHOD_HANDLE_TYPE_INSTANCE_PUT | 0x02 | O identificador de método é um setter de campo de instância (acessador) |
METHOD_HANDLE_TYPE_INSTANCE_GET | 0x03 | O handle de método é um getter de campo de instância (acessório) |
METHOD_HANDLE_TYPE_INVOKE_STATIC | 0x04 | O handle de método é um invocador de método estático |
METHOD_HANDLE_TYPE_INVOKE_INSTANCE | 0x05 | O manipulador de método é um invocador de método de instância |
METHOD_HANDLE_TYPE_INVOKE_CONSTRUCTOR | 0x06 | O handle de método é um invocador de método construtor |
METHOD_HANDLE_TYPE_INVOKE_DIRECT | 0x07 | O handle de método é um invocador de método direto |
METHOD_HANDLE_TYPE_INVOKE_INTERFACE | 0x08 | O handle de método é um invocador de método de interface |
class_data_item
Referência de class_def_item
Aparece na seção de dados
Alinhamento: nenhum (alinhamento de byte)
Nome | Formato | Descrição |
---|---|---|
static_fields_size | uleb128 | o número de campos estáticos definidos neste item |
instance_fields_size | uleb128 | o número de campos de instância definidos neste item |
direct_methods_size | uleb128 | o número de métodos diretos definidos neste item |
virtual_methods_size | uleb128 | o número de métodos virtuais definidos neste item |
static_fields | encoded_field[static_fields_size] | os campos estáticos definidos, representados como uma sequência de
elementos codificados. Os campos precisam ser classificados por
field_idx em ordem crescente.
|
instance_fields | encoded_field[instance_fields_size] | os campos de instância definidos, representados como uma sequência de
elementos codificados. Os campos precisam ser classificados por
field_idx em ordem crescente.
|
direct_methods | encoded_method[direct_methods_size] | os métodos diretos definidos (qualquer um de static , private
ou construtor), representados como uma sequência de
elementos codificados. Os métodos precisam ser classificados por
method_idx em ordem crescente.
|
virtual_methods | encoded_method[virtual_methods_size] | os métodos virtuais definidos (nenhum de static , private
ou construtor), representados como uma sequência de
elementos codificados. Essa lista não deve incluir métodos
herdados, a menos que sejam substituídos pela classe que o item representa. Os
métodos precisam ser classificados por method_idx em ordem crescente.
O method_idx de um método virtual não pode ser o mesmo
que qualquer método direto.
|
Observação:todas as instâncias field_id
e
method_id
dos elementos precisam se referir à mesma classe de definição.
formato do encoded_field
Nome | Formato | Descrição |
---|---|---|
field_idx_diff | uleb128 | índice na lista field_ids para a identidade desse campo (inclui o nome e o descritor), representado como uma diferença em relação ao índice do elemento anterior na lista. O índice do
primeiro elemento de uma lista é representado diretamente.
|
access_flags | uleb128 | flags de acesso para o campo (public , final etc.). Consulte "Definições de access_flags " para mais detalhes.
|
formato encoded_method
Nome | Formato | Descrição |
---|---|---|
method_idx_diff | uleb128 | índice na lista method_ids para a identidade deste
método (inclui o nome e o descritor), representado como uma diferença
do índice do elemento anterior na lista. O índice do
primeiro elemento de uma lista é representado diretamente.
|
access_flags | uleb128 | flags de acesso para o método (public , final etc.). Consulte "Definições de access_flags " para mais detalhes.
|
code_off | uleb128 | deslocamento do início do arquivo para a estrutura de código desse
método ou 0 se esse método for abstract
ou native . O deslocamento precisa ser para um local na seção data . O formato dos dados é especificado por
"code_item " abaixo.
|
type_list
Referenciado em class_def_item e proto_id_item
Aparece na seção de dados
Alinhamento: 4 bytes
Nome | Formato | Descrição |
---|---|---|
size | uint | tamanho da lista, em entradas |
list | type_item[size] | elementos da lista |
formato de type_item
Nome | Formato | Descrição |
---|---|---|
type_idx | ushort | índice na lista type_ids |
code_item
Referência de encoded_method
Aparece na seção de dados
Alinhamento: 4 bytes
Nome | Formato | Descrição |
---|---|---|
registers_size | ushort | o número de registros usados por esse código |
ins_size | ushort | o número de palavras de argumentos recebidos para o método a que este código se destina |
outs_size | ushort | o número de palavras de espaço de argumento de saída necessárias para essa invocação de método |
tries_size | ushort | o número de try_item s para essa instância. Se não for zero,
eles vão aparecer como a matriz tries logo após o
insns nesta instância.
|
debug_info_off | uint | deslocamento do início do arquivo até a sequência de informações de depuração (números de linha +
informações de variáveis locais) para esse código ou 0 se
não houver informações. O deslocamento, se diferente de zero, precisa ser
para um local na seção data . O formato dos dados é especificado por "debug_info_item " abaixo.
|
insns_size | uint | tamanho da lista de instruções, em unidades de código de 16 bits |
insns | ushort[insns_size] | matriz real de bytecode. O formato do código em uma matriz insns
é especificado pelo documento complementar
Dalvik bytecode. Observe
que, embora isso seja definido como uma matriz de ushort , há
algumas estruturas internas que preferem o alinhamento de quatro bytes. Além disso,
se isso acontecer em um arquivo com troca de endian, a troca será
feita apenas em instâncias ushort individuais, e não nas
estruturas internas maiores.
|
preenchimento | ushort (opcional) = 0 | dois bytes de preenchimento para alinhar tries com quatro bytes.
Esse elemento só está presente se tries_size for diferente de zero
e insns_size for ímpar.
|
tentativas | try_item[tries_size] (opcional) | matriz que indica onde as exceções do código são capturadas e
como processá-las. Os elementos da matriz não podem se sobrepor no
intervalo e precisam estar em ordem de endereço de baixo para alto. Esse elemento só estará
presente se tries_size for diferente de zero.
|
gerenciadores | encoded_catch_handler_list (opcional) | Bytes que representam uma lista de listas de tipos de captura e endereços de manipulador
associados. Cada try_item tem um deslocamento por byte
nessa estrutura. Esse elemento só está presente se
tries_size for diferente de zero.
|
try_item format
Nome | Formato | Descrição |
---|---|---|
start_addr | uint | endereço inicial do bloco de código coberto por essa entrada. O endereço é uma contagem de unidades de código de 16 bits até o início da primeira instrução coberta. |
insn_count | ushort | número de unidades de código de 16 bits cobertas por essa entrada. A última unidade de código
coberta (inclusive) é start_addr + insn_count - 1 .
|
handler_off | ushort | deslocamento em bytes do início do
encoded_catch_hander_list associado ao
encoded_catch_handler para essa entrada. Precisa ser um
deslocamento para o início de um encoded_catch_handler .
|
formato encoded_catch_handler_list
Nome | Formato | Descrição |
---|---|---|
size | uleb128 | tamanho desta lista, em entradas |
list | encoded_catch_handler[handlers_size] | Lista real de listas de manipuladores, representada diretamente (não como deslocamentos) e concatenada sequencialmente |
formato encoded_catch_handler
Nome | Formato | Descrição |
---|---|---|
size | sleb128 | número de tipos de capturas nesta lista. Se não for positivo, será
negativo do número de tipos de captura, e as capturas serão seguidas
por um gerenciador de capturas gerais. Por exemplo: um size de 0
significa que há um catch-all, mas não há capturas explicitamente digitadas.
Um size de 2 significa que há duas capturas explicitamente
definidas e nenhuma captura geral. E um size de -1
significa que há uma captura digitada com uma captura geral.
|
gerenciadores | encoded_type_addr_pair[abs(size)] | fluxo de itens codificados abs(size) , um para cada tipo
detectado, na ordem em que os tipos precisam ser testados.
|
catch_all_addr | uleb128 (opcional) | endereço de bytecode do gerenciador "pega-tudo". Esse elemento só estará
presente se size não for positivo.
|
formato encoded_type_addr_pair
Nome | Formato | Descrição |
---|---|---|
type_idx | uleb128 | índice na lista type_ids para o tipo de
excpeção a ser detectada
|
addr | uleb128 | endereço de bytecode do manipulador de exceções associado |
debug_info_item
Referência de code_item
Aparece na seção de dados
Alinhamento: nenhum (alinhamento de byte)
Cada debug_info_item
define uma máquina de estados codificada em bytes
inspirada no DWARF3 que, quando interpretada, emite a tabela
de posições e (potencialmente) as informações de variáveis locais para um
code_item
. A sequência começa com um cabeçalho de comprimento variável,
cujo comprimento depende do número de parâmetros
do método, é seguido pelos bytecodes da máquina de estados e termina
com um byte DBG_END_SEQUENCE
.
A máquina de estados consiste em cinco registros. O
registro address
representa o deslocamento de instrução no
insns_item
associado em unidades de código de 16 bits. O
registro address
começa em 0
no início de cada
sequência debug_info
e precisa aumentar de forma monotonicamente.
O registro line
representa qual número de linha de origem
deve ser associado à próxima entrada de tabela de posições emitida pela
máquina de estados. Ele é inicializado no cabeçalho da sequência e pode
mudar em direções positivas ou negativas, mas nunca pode ser menor que
1
. O registro source_file
representa o
arquivo de origem a que as entradas de número de linha se referem. Ele é inicializado para
o valor de source_file_idx
em class_def_item
.
As outras duas variáveis, prologue_end
e
epilogue_begin
, são flags booleanas (inicializadas como
false
) que indicam se a próxima posição emitida
deve ser considerada um prólogo ou epílogo de método. A máquina de estados
também precisa rastrear o nome e o tipo da última variável local em
cada registro para o código DBG_RESTART_LOCAL
.
O cabeçalho é o seguinte:
Nome | Formato | Descrição |
---|---|---|
line_start | uleb128 | o valor inicial do registro line da máquina de estados.
Não representa uma entrada de posições real.
|
parameters_size | uleb128 | o número de nomes de parâmetros codificados. Deve haver
um por parâmetro de método, excluindo o this de um método de instância,
se houver.
|
parameter_names | uleb128p1[parameters_size] | índice de string do nome do parâmetro do método. Um valor codificado de
NO_INDEX indica que nenhum nome
está disponível para o parâmetro associado. O descritor de tipo
e a assinatura são implícitos no descritor e na assinatura do método.
|
Os valores do código de byte são os seguintes:
Nome | Valor | Formato | Argumentos | Descrição |
---|---|---|---|---|
DBG_END_SEQUENCE | 0x00 | (nenhuma) | encerra uma sequência de informações de depuração para um code_item |
|
DBG_ADVANCE_PC | 0x01 | uleb128 addr_diff | addr_diff : valor a ser adicionado ao registro de endereço |
avança o registro de endereço sem emitir uma entrada de posições |
DBG_ADVANCE_LINE | 0x02 | sleb128 line_diff | line_diff : valor para mudar o registro de linha |
avança o registro de linha sem emitir uma entrada de posições |
DBG_START_LOCAL | 0x03 | uleb128 register_num uleb128p1 name_idx uleb128p1 type_idx |
register_num : registro que vai conter localname_idx : índice de string do nometype_idx : índice de tipo do tipo
|
introduz uma variável local no endereço atual. name_idx ou type_idx podem ser
NO_INDEX para indicar que o valor é desconhecido.
|
DBG_START_LOCAL_EXTENDED | 0x04 | uleb128 register_num uleb128p1 name_idx uleb128p1 type_idx uleb128p1 sig_idx |
register_num : registro que vai conter localname_idx : índice de string do nometype_idx : índice de tipo do tiposig_idx : índice de string da assinatura do tipo
|
introduz um local com uma assinatura de tipo no endereço atual.
Qualquer um dos valores name_idx , type_idx ou
sig_idx pode ser NO_INDEX
para indicar que o valor é desconhecido. No entanto, se sig_idx for
-1 , os mesmos dados poderão ser representados de forma mais
eficiente usando o opcode DBG_START_LOCAL .
Observação:consulte a discussão em
" |
DBG_END_LOCAL | 0x05 | uleb128 register_num | register_num : registro que continha local |
marca uma variável local ativa como fora do escopo no endereço atual |
DBG_RESTART_LOCAL | 0x06 | uleb128 register_num | register_num : registro para reiniciar |
introduz novamente uma variável local no endereço atual. O nome e o tipo são iguais ao último local ativo no registro especificado. |
DBG_SET_PROLOGUE_END | 0x07 | (nenhuma) | define o registro da máquina de estados prologue_end ,
indicando que a próxima entrada de posição adicionada precisa ser
considerada o fim do prólogo de um método (um local adequado para
um ponto de interrupção de método). O registro prologue_end é
apagado por qualquer opcode especial (>= 0x0a ).
|
|
DBG_SET_EPILOGUE_BEGIN | 0x08 | (nenhuma) | define o registro da máquina de estados epilogue_begin ,
indicando que a próxima entrada de posição adicionada precisa ser
considerada o início de um epílogo de método (um lugar adequado
para suspender a execução antes da saída do método).
O registro epilogue_begin é limpo por qualquer opcode
especial (>= 0x0a ).
|
|
DBG_SET_FILE | 0x09 | uleb128p1 name_idx | name_idx : índice de string do nome do arquivo de origem;
NO_INDEX se desconhecido
|
indica que todas as entradas de número de linha subsequentes fazem referência a esse
nome de arquivo de origem, em vez do nome padrão especificado em
code_item
|
Opcodes especiais | 0x0a…0xff | (nenhuma) | avança os registros line e address ,
emite uma entrada de posição e limpa prologue_end e
epilogue_begin . Confira a descrição abaixo.
|
Operadores de código especiais
Opcodes com valores entre 0x0a
e 0xff
(inclusive) movem os registros line
e address
por uma pequena quantidade e emitem uma nova entrada de tabela de posição.
A fórmula para os incrementos é a seguinte:
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
Referência de class_def_item
Aparece na seção de dados
Alinhamento: 4 bytes
Nome | Formato | Descrição |
---|---|---|
class_annotations_off | uint | deslocamento do início do arquivo para as anotações feitas diretamente
na classe ou 0 se a classe não tiver anotações diretas.
O deslocamento, se diferente de zero, precisa ser para um local na
seção data . O formato dos dados é especificado
por "annotation_set_item " abaixo.
|
fields_size | uint | contagem de campos anotados por este item |
annotated_methods_size | uint | contagem de métodos anotados por este item |
annotated_parameters_size | uint | contagem de listas de parâmetros de método anotadas por este item |
field_annotations | field_annotation[fields_size] (opcional) | lista de anotações de campo associadas. Os elementos da lista precisam
ser classificados em ordem crescente, por field_idx .
|
method_annotations | method_annotation[methods_size] (opcional) | lista de anotações de método associadas. Os elementos da lista precisam
ser classificados em ordem crescente, por method_idx .
|
parameter_annotations | parameter_annotation[parameters_size] (opcional) | lista de anotações de parâmetros de método associados. Os elementos da
lista precisam ser classificados em ordem crescente, por method_idx .
|
Observação:todas as instâncias field_id
e
method_id
dos elementos precisam se referir à mesma classe de definição.
formato de field_annotation
Nome | Formato | Descrição |
---|---|---|
field_idx | uint | Índice na lista field_ids para a identidade do
campo que está sendo anotado
|
annotations_off | uint | deslocamento do início do arquivo para a lista de anotações do campo. O deslocamento precisa ser para um local na seção data . O formato dos dados é especificado por
"annotation_set_item " abaixo.
|
formato de method_annotation
Nome | Formato | Descrição |
---|---|---|
method_idx | uint | índice na lista method_ids para a identidade do
método que está sendo anotado
|
annotations_off | uint | deslocamento do início do arquivo para a lista de anotações do
método. O deslocamento precisa ser para um local na seção data . O formato dos dados é especificado por
"annotation_set_item " abaixo.
|
formato de parameter_annotation
Nome | Formato | Descrição |
---|---|---|
method_idx | uint | índice na lista method_ids para a identidade do
método cujos parâmetros estão sendo anotados
|
annotations_off | uint | deslocamento do início do arquivo para a lista de anotações dos
parâmetros do método. O deslocamento precisa ser para um local na seção data . O formato dos dados é especificado por
"annotation_set_ref_list " abaixo.
|
annotation_set_ref_list
Referência de parameter_annotations_item
Aparece na seção de dados
Alinhamento: 4 bytes
Nome | Formato | Descrição |
---|---|---|
size | uint | tamanho da lista, em entradas |
list | annotation_set_ref_item[size] | elementos da lista |
formato annotation_set_ref_item
Nome | Formato | Descrição |
---|---|---|
annotations_off | uint | deslocamento do início do arquivo até o conjunto de anotações referenciado
ou 0 se não houver anotações para esse elemento.
O deslocamento, se diferente de zero, precisa ser para um local na seção
data . O formato dos dados é especificado por
"annotation_set_item " abaixo.
|
annotation_set_item
Referência de annotations_directory_item, field_annotations_item, method_annotations_item e annotation_set_ref_item
Aparece na seção de dados
Alinhamento: 4 bytes
Nome | Formato | Descrição |
---|---|---|
size | uint | tamanho do conjunto, em entradas |
entries | annotation_off_item[size] | elementos do conjunto. Os elementos precisam ser classificados em ordem crescente,
por type_idx .
|
formato annotation_off_item
Nome | Formato | Descrição |
---|---|---|
annotation_off | uint | deslocamento do início do arquivo para uma anotação.
O deslocamento precisa ser para um local na seção data ,
e o formato dos dados nesse local é especificado por
"annotation_item " abaixo.
|
annotation_item
Referência de annotation_set_item
Aparece na seção de dados
Alinhamento: nenhum (alinhamento de byte)
Nome | Formato | Descrição |
---|---|---|
visibilidade | ubyte | visibilidade pretendida desta anotação (confira abaixo) |
annotation | encoded_annotation | conteúdo da anotação codificada, no formato descrito por
"formato encoded_annotation " em
"codificação encoded_value " acima.
|
Valores de visibilidade
Estas são as opções para o campo visibility
em um
annotation_item
:
Nome | Valor | Descrição |
---|---|---|
VISIBILITY_BUILD | 0x00 | destinado a ficar visível apenas no momento da build (por exemplo, durante a compilação de outro código) |
VISIBILITY_RUNTIME | 0x01 | que será visível no momento da execução |
VISIBILITY_SYSTEM | 0x02 | que fica visível no tempo de execução, mas apenas para o sistema (e não para o código do usuário comum) |
encoded_array_item
Referência de class_def_item
Aparece na seção de dados
Alinhamento: nenhum (alinhamento de byte)
Nome | Formato | Descrição |
---|---|---|
value | encoded_array | Bytes que representam o valor da matriz codificada, no formato especificado
por "Formato encoded_array " em "Codificação
encoded_value " acima.
|
hiddenapi_class_data_item
Esta seção contém dados sobre interfaces restritas usadas por cada classe.
Observação:o recurso de API oculto foi introduzido no Android 10.0 e só é aplicável aos arquivos DEX de classes no caminho da classe de inicialização. A lista de flags descrita abaixo pode ser ampliada nas versões futuras do Android. Para mais informações, consulte Restrições para interfaces que não são SDK.
Nome | Formato | Descrição |
---|---|---|
size | uint | tamanho total da seção |
compensações | uint[] | matriz de deslocamentos indexados por class_idx .
Uma entrada de matriz zero no índice class_idx significa que
não há dados para esse class_idx ou que todas as flags de API
ocultas são zero.
Caso contrário, a entrada da matriz não é igual a zero e contém um deslocamento do
início da seção para uma matriz de flags de API ocultas
para essa class_idx .
|
flags | uleb128[] | matrizes concatenadas de flags de API ocultas para cada classe. Os possíveis valores de flag estão descritos na tabela abaixo. As flags são codificadas na mesma ordem em que os campos e métodos são codificados nos dados da classe. |
Tipos de flag de restrição:
Nome | Valor | Descrição |
---|---|---|
lista de permissões | 0 | São interfaces que podem ser usadas livremente e são aceitas como parte do Índice de pacote do framework do Android oficialmente documentado. |
lista cinza | 1 | São interfaces externas ao SDK que podem ser usadas independentemente do nível da API de destino do aplicativo. |
lista de proibições | 2 | São interfaces externas ao SDK que não podem ser usadas, independentemente do nível da API de destino do aplicativo. O acesso a uma dessas interfaces causa um erro de execução. |
greylist-max-o | 3 | São interfaces não SDK que podem ser usadas no Android 8.x e versões anteriores, a menos que sejam restritas. |
greylist-max-p | 4 | São interfaces não SDK que podem ser usadas para o Android 9.x, a menos que sejam restritas. |
greylist-max-q | 5 | Interfaces não SDK que podem ser usadas no Android 10.x, a menos que sejam restritas. |
greylist-max-r | 6 | Interfaces não SDK que podem ser usadas no Android 11.x, a menos que sejam restritas. |
Anotações do sistema
As anotações do sistema são usadas para representar várias informações reflexivas sobre classes (e métodos e campos). Essas informações geralmente são acessadas apenas indiretamente pelo código do cliente (não do sistema).
As anotações do sistema são representadas em arquivos .dex
como
anotações com visibilidade definida como VISIBILITY_SYSTEM
.
dalvik.annotation.AnnotationDefault
Aparece em métodos em interfaces de anotação
Uma anotação AnnotationDefault
é anexada a cada
interface de anotação que quer indicar vinculações padrão.
Nome | Formato | Descrição |
---|---|---|
value | Annotation | as vinculações padrão para essa anotação, representadas como uma anotação desse tipo. A anotação não precisa incluir todos os nomes definidos por ela. Os nomes ausentes simplesmente não têm padrões. |
dalvik.annotation.EnclosingClass
Aparece nas turmas
Uma anotação EnclosingClass
é anexada a cada classe
que é definida como um membro de outra classe, por si só, ou é
anônima, mas não definida em um corpo de método (por exemplo, uma classe
interna sintética). Todas as classes que têm essa anotação também precisam ter uma
anotação InnerClass
. Além disso, uma classe não pode ter
uma anotação EnclosingClass
e uma
EnclosingMethod
.
Nome | Formato | Descrição |
---|---|---|
value | Classe | a classe que tem o escopo lexical mais próximo desta classe |
dalvik.annotation.EnclosingMethod
Aparece nas turmas
Uma anotação EnclosingMethod
é anexada a cada classe
definida dentro do corpo de um método. Todas as classes que têm essa
anotação também precisam ter uma anotação InnerClass
.
Além disso, uma classe não pode ter uma anotação EnclosingClass
e uma EnclosingMethod
.
Nome | Formato | Descrição |
---|---|---|
value | Método | O método que tem o escopo lexical mais próximo dessa classe |
dalvik.annotation.InnerClass
Aparece nas turmas
Uma anotação InnerClass
é anexada a cada classe,
que é definida no escopo lexical da definição de outra classe.
Qualquer classe que tenha essa anotação também precisa ter uma anotação
EnclosingClass
ou uma
EnclosingMethod
.
Nome | Formato | Descrição |
---|---|---|
nome | String | o nome simples declarado originalmente dessa classe (sem incluir
prefixo de pacote). Se essa classe for anônima, o nome será
null .
|
accessFlags | int | as flags de acesso declaradas originalmente da classe (que podem ser diferentes das flags efetivas devido a uma incompatibilidade entre os modelos de execução da linguagem de origem e da máquina virtual de destino) |
dalvik.annotation.MemberClasses
Aparece nas turmas
Uma anotação MemberClasses
é anexada a cada classe
que declara classes de membros. Uma classe de membro é uma classe interna direta
que tem um nome.
Nome | Formato | Descrição |
---|---|---|
value | Class[] | matriz das classes de membros |
dalvik.annotation.MethodParameters
Aparece em métodos
Observação:essa anotação foi adicionada após o Android 7.1. A presença dele em versões anteriores do Android será ignorada.
Uma anotação MethodParameters
é opcional e pode ser usada para
fornecer metadados de parâmetro, como nomes e modificadores.
A anotação pode ser omitida de um método ou construtor com segurança quando os
metadados do parâmetro não são necessários no momento da execução.
java.lang.reflect.Parameter.isNamePresent()
pode ser usado para verificar
se os metadados estão presentes em um parâmetro, e os métodos de reflexão
associados, como java.lang.reflect.Parameter.getName()
, vão retornar
ao comportamento padrão no momento da execução se as informações não estiverem presentes.
Ao incluir metadados de parâmetro, os compiladores precisam incluir informações para classes geradas, como enumerações, já que os metadados de parâmetro incluem se um parâmetro é sintético ou obrigatório.
Uma anotação MethodParameters
descreve apenas parâmetros de método
individuais. Portanto, os compiladores podem omitir a anotação por completo
para construtores e métodos que não têm parâmetros, para fins de tamanho de código
e eficiência de execução.
As matrizes documentadas abaixo precisam ter o mesmo tamanho da
estrutura dex method_id_item
associada ao método. Caso contrário, uma java.lang.reflect.MalformedParametersException
será gerada no
tempo de execução.
Ou seja: method_id_item.proto_idx
->
proto_id_item.parameters_off
->
type_list.size
precisa ser igual a names().length
e
accessFlags().length
.
Como MethodParameters
descreve todos os parâmetros de método formais, mesmo aqueles que não são declarados explicitamente ou implicitamente no código-fonte,
o tamanho das matrizes pode ser diferente da assinatura ou de outras informações de metadados
que se baseiam apenas em parâmetros explícitos declarados no código-fonte. MethodParameters
também não inclui informações sobre
parâmetros do receptor de anotação de tipo que não existem na assinatura
do método real.
Nome | Formato | Descrição |
---|---|---|
nomes | String[] | Os nomes dos parâmetros formais para o método associado. A matriz
não pode ser nula, mas precisa estar vazia se não houver parâmetros formais. Um valor na
matriz precisa ser nulo se o parâmetro formal com esse índice não tiver nome. Se as strings de nome de parâmetro estiverem vazias ou contiverem ".", "?", "[" ou "/", uma java.lang.reflect.MalformedParametersException será gerada no
tempo de execução.
|
accessFlags | int[] | As flags de acesso dos parâmetros formais para o método associado. A
matriz não pode ser nula, mas precisa estar vazia se não houver parâmetros formais. O valor é uma máscara de bits com os seguintes valores:
java.lang.reflect.MalformedParametersException será gerada no momento da execução.
|
dalvik.annotation.Signature
Aparece em classes, campos e métodos
Uma anotação Signature
é anexada a cada classe,
campo ou método que é definido em termos de um tipo mais complicado
do que o que pode ser representado por um type_id_item
. O formato
.dex
não define o formato para assinaturas. Ele
apenas representa as assinaturas que um idioma
de origem exige para a implementação bem-sucedida da semântica
desse idioma. Por isso, as assinaturas geralmente não são analisadas (ou verificadas)
por implementações de máquina virtual. As assinaturas são simplesmente transmitidas
para APIs e ferramentas de nível mais alto (como depuradores). Portanto, qualquer uso de uma
assinatura precisa ser escrito de modo a não fazer
suposições sobre receber apenas assinaturas válidas, protegendo-se
explicitamente contra a possibilidade de encontrar uma assinatura sintaticamente
inválida.
Como as strings de assinatura tendem a ter muito conteúdo duplicado,
uma anotação Signature
é definida como uma matriz de
strings, em que os elementos duplicados se referem naturalmente aos mesmos
dados, e a assinatura é considerada a concatenação de
todas as strings na matriz. Não há regras sobre como separar
uma assinatura em strings separadas. Isso depende totalmente das
ferramentas que geram arquivos .dex
.
Nome | Formato | Descrição |
---|---|---|
value | String[] | a assinatura dessa classe ou membro, como uma matriz de strings que será concatenada |
dalvik.annotation.Throws
Aparece em métodos
Uma anotação Throws
é anexada a cada método que é
declarado para gerar um ou mais tipos de exceção.
Nome | Formato | Descrição |
---|---|---|
value | Class[] | a matriz de tipos de exceção gerados |