O estilo de código HIDL se assemelha ao código C++ no framework do Android, com recuos de quatro espaços e nomes de arquivos com letras maiúsculas e minúsculas. As declarações, importações e docstrings de pacotes são semelhantes às do Java, com pequenas modificações.
Os exemplos a seguir para IFoo.hal
e types.hal
ilustram os estilos de código HIDL e fornecem links rápidos para detalhes sobre cada estilo
(IFooClientCallback.hal
, IBar.hal
e
IBaz.hal
foram omitidos).
hardware/interfaces/foo/1.0/IFoo.hal |
---|
/* * (License Notice) */ package android.hardware.foo@1.0; import android.hardware.bar@1.0::IBar; import IBaz; import IFooClientCallback; /** * IFoo is an interface that… */ interface IFoo { /** * This is a multiline docstring. * * @return result 0 if successful, nonzero otherwise. */ foo() generates (FooStatus result); /** * Restart controller by power cycle. * * @param bar callback interface that… * @return result 0 if successful, nonzero otherwise. */ powerCycle(IBar bar) generates (FooStatus result); /** Single line docstring. */ baz(); /** * The bar function. * * @param clientCallback callback after function is called * @param baz related baz object * @param data input data blob */ bar(IFooClientCallback clientCallback, IBaz baz, FooData data); }; |
hardware/interfaces/foo/1.0/types.hal |
---|
/* * (License Notice) */ package android.hardware.foo@1.0; /** Replied status. */ enum Status : int32_t { OK, /* invalid arguments */ ERR_ARG, /* note, no transport related errors */ ERR_UNKNOWN = -1, }; struct ArgData { int32_t[20] someArray; vec<uint8_t> data; }; |
Convenções de nomenclatura
Os nomes de função, variáveis e arquivos precisam ser descritivos. Evite
abreviações excessivas. Tratar acrônimos como palavras (por exemplo, use INfc
em vez
de INFC
).
Estrutura de diretórios e nomenclatura de arquivos
A estrutura de diretórios vai aparecer assim:
ROOT-DIRECTORY
MODULE
SUBMODULE
(opcional, pode haver mais de um nível)VERSION
Android.mk
IINTERFACE_1.hal
IINTERFACE_2.hal
…
IINTERFACE_N.hal
types.hal
(opcional)
Em que:
ROOT-DIRECTORY
é:hardware/interfaces
para pacotes principais de HIDL.vendor/VENDOR/interfaces
para pacotes de fornecedores, em queVENDOR
se refere a um fornecedor de SoC ou a um OEM/ODM.
MODULE
precisa ser uma palavra em letras minúsculas que descreva o subsistema (por exemplo,nfc
). Se mais de uma palavra for necessária, useSUBMODULE
aninhado. Pode haver mais de um nível de anilhamento.- O
VERSION
precisa ser exatamente a mesma versão (major.minor), conforme descrito em Versões. IINTERFACE_X
deve ser o nome da interface comUpperCamelCase
/PascalCase
(por exemplo,INfc
), conforme descrito em Nomes de interface.
Exemplo:
hardware/interfaces
nfc
1.0
Android.mk
INfc.hal
INfcClientCallback.hal
types.hal
Observação:todos os arquivos precisam ter permissões não executáveis (no Git).
Nomes de pacote
Os nomes de pacote precisam usar o seguinte formato de nome totalmente qualificado
(FQN, na sigla em inglês) (chamado de PACKAGE-NAME
):
PACKAGE.MODULE[.SUBMODULE[.SUBMODULE[…]]]@VERSION
Em que:
PACKAGE
é o pacote que mapeia para oROOT-DIRECTORY
. Em particular,PACKAGE
é:android.hardware
para pacotes principais de HIDL (mapeamento parahardware/interfaces
).vendor.VENDOR.hardware
para pacotes do fornecedor, em queVENDOR
se refere a um fornecedor de SoC ou OEM/ODM (mapeamento paravendor/VENDOR/interfaces
).
MODULE[.SUBMODULE[.SUBMODULE[…]]]@VERSION
são os mesmos nomes de pastas na estrutura descrita em Estrutura de diretórios.- Os nomes dos pacotes precisam estar em letras minúsculas. Se tiverem mais de uma palavra, as
palavras precisam ser usadas como submódulos ou escritas em
snake_case
. - Espaços não são permitidos.
O FQN é sempre usado em declarações de pacote.
Versões
As versões precisam ter o seguinte formato:
MAJOR.MINOR
As versões MAJOR e MINOR precisam ser um único número inteiro. O HIDL usa regras de versionamento semântico.
Importações
Uma importação tem um dos três formatos a seguir:
- Importações de pacotes inteiros:
import PACKAGE-NAME;
- Importações parciais:
import PACKAGE-NAME::UDT;
(ou, se o tipo importado estiver no mesmo pacote,import UDT;
- Importações somente de tipos:
import PACKAGE-NAME::types;
O PACKAGE-NAME
segue o formato em
Nomes de pacotes. O types.hal
do pacote atual (se existir) é importado automaticamente (não importe
explicitamente).
Nomes totalmente qualificados (FQNs)
Use nomes totalmente qualificados para uma importação de tipo definida pelo usuário somente quando necessário.
Omita PACKAGE-NAME
se o tipo de importação estiver no mesmo
pacote. Um FQN não pode conter espaços. Exemplo de um nome totalmente qualificado:
android.hardware.nfc@1.0::INfcClientCallback
Em outro arquivo em android.hardware.nfc@1.0
, consulte a
interface acima como INfcClientCallback
. Caso contrário, use apenas o
nome totalmente qualificado.
Agrupar e ordenar importações
Use uma linha vazia após a declaração do pacote (antes das importações). Cada importação precisa ocupar uma única linha e não pode ter recuo. Agrupe as importações na seguinte ordem:
- Outros pacotes
android.hardware
(use nomes totalmente qualificados). - Outros pacotes
vendor.VENDOR
(use nomes totalmente qualificados).- Cada fornecedor precisa ser um grupo.
- Ordenar os fornecedores em ordem alfabética.
- Importações de outras interfaces no mesmo pacote (use nomes simples).
Use uma linha vazia entre os grupos. Dentro de cada grupo, classifique as importações em ordem alfabética. Exemplo:
import android.hardware.nfc@1.0::INfc; import android.hardware.nfc@1.0::INfcClientCallback; /* Importing the whole module. */ import vendor.barvendor.bar@3.1; import vendor.foovendor.foo@2.2::IFooBar; import vendor.foovendor.foo@2.2::IFooFoo; import IBar; import IFoo;
Nomes de interfaces
Os nomes da interface precisam começar com I
, seguido de um nome
UpperCamelCase
/PascalCase
. Uma interface com o nome
IFoo
precisa ser definida no arquivo IFoo.hal
. Esse arquivo
pode conter definições apenas para a interface IFoo
(a interface
INAME
precisa estar em INAME.hal
).
Funções
Para nomes de função, argumentos e nomes de variáveis de retorno, use
lowerCamelCase
. Exemplo:
open(INfcClientCallback clientCallback) generates (int32_t retVal); oneway pingAlive(IFooCallback cb);
Nomes de campos de struct e union
Para nomes de campos de struct ou union, use lowerCamelCase
. Exemplo:
struct FooReply { vec<uint8_t> replyData; }
Nomes de tipo
Os nomes de tipo se referem a definições de struct ou união, definições de tipo de enumeração e
typedef
s. Para esses nomes, use
UpperCamelCase
/PascalCase
. Exemplos:
enum NfcStatus : int32_t { /*...*/ }; struct NfcData { /*...*/ };
Valores de enumeração
Os valores de enumeração precisam ser UPPER_CASE_WITH_UNDERSCORES
. Ao transmitir
valores de tipo enumerado como argumentos de função e retornar como retornos de função, use
o tipo de tipo enumerado real (não o tipo de inteiro subjacente). Exemplo:
enum NfcStatus : int32_t { HAL_NFC_STATUS_OK = 0, HAL_NFC_STATUS_FAILED = 1, HAL_NFC_STATUS_ERR_TRANSPORT = 2, HAL_NFC_STATUS_ERR_CMD_TIMEOUT = 3, HAL_NFC_STATUS_REFUSED = 4 };
Observação:o tipo de um tipo de enumeração é declarado explicitamente após os dois-pontos. Como não depende do compilador, o uso do tipo de enumeração real é mais claro.
Para nomes totalmente qualificados de valores de tipo enumerado, um dois-pontos é usado entre o nome do tipo e o nome do valor:
PACKAGE-NAME::UDT[.UDT[.UDT[…]]:ENUM_VALUE_NAME
Não pode haver espaços dentro de um nome totalmente qualificado. Use um nome totalmente qualificado apenas quando necessário e omita partes desnecessárias. Exemplo:
android.hardware.foo@1.0::IFoo.IFooInternal.FooEnum:ENUM_OK
Comentários
Para um comentário de linha única, //
, /* */
e /** */
são adequados.
// This is a single line comment /* This is also single line comment */ /** This is documentation comment */
-
Use
/* */
para comentários. Embora o HIDL ofereça suporte a//
para comentários, eles não são recomendados porque não aparecem na saída gerada. - Use
/** */
para a documentação gerada. Elas podem ser aplicadas apenas a declarações de tipo, método, campo e valor de tipo enumerado. Exemplo:/** Replied status */ enum TeleportStatus { /** Object entirely teleported. */ OK = 0, /** Methods return this if teleportation is not completed. */ ERROR_TELEPORT = 1, /** * Teleportation could not be completed due to an object * obstructing the path. */ ERROR_OBJECT = 2, ... }
- Comece os comentários de várias linhas com
/**
em uma linha separada. Use*
no início de cada linha. Termine o comentário com*/
em uma linha separada, alinhando os asteriscos. Exemplo:/** * My multi-line * comment */
- O aviso de licenciamento e os registros de mudanças precisam começar uma nova linha com
/*
(um único asterisco), usar*
no início de cada linha e colocar*/
na última linha por conta própria (os asteriscos precisam estar alinhados). Exemplo:/* * Copyright (C) 2017 The Android Open Source Project * ... */ /* * Changelog: * ... */
Comentários em arquivos
Comece cada arquivo com o aviso de licenciamento apropriado. Para HALs principais, essa
deve ser a licença Apache do AOSP em
development/docs/copyright-templates/c.txt
.
Atualize o ano e use comentários de várias linhas no estilo /* */
,
conforme explicado acima.
Você pode colocar uma linha vazia após o aviso de licença, seguido
por informações de registro de alterações/versão. Use comentários de várias linhas
no estilo /* */
, conforme explicado acima. Coloque a linha vazia após o
registro de alterações e siga com a declaração do pacote.
Comentários TODO
Os TODOs precisam incluir a string TODO
em todas as letras maiúsculas, seguidas por dois pontos. Exemplo:
// TODO: remove this code before foo is checked in.
Os comentários TODO são permitidos apenas durante o desenvolvimento. Eles não podem existir em interfaces publicadas.
Comentários de interface e função (docstrings)
Use /** */
para docstrings de várias linhas e de linha única. Não use
//
para docstrings.
As strings de documentação de interfaces precisam descrever mecanismos gerais da interface, justificativa de design, finalidade etc. As strings de documentação de funções precisam ser específicas para a função (a documentação no nível do pacote vai para um arquivo README no diretório do pacote).
/** * IFooController is the controller for foos. */ interface IFooController { /** * Opens the controller. * * @return status HAL_FOO_OK if successful. */ open() generates (FooStatus status); /** Close the controller. */ close(); };
Adicione @param
s e @return
s para cada
parâmetro/valor de retorno:
@param
precisa ser adicionado para cada parâmetro. Ele precisa ser seguido pelo nome do parâmetro e depois pelo docstring.@return
precisa ser adicionado para cada valor de retorno. Ele deve ser seguido pelo nome do valor de retorno e do docstring.
Exemplo:
/** * Explain what foo does. * * @param arg1 explain what arg1 is * @param arg2 explain what arg2 is * @return ret1 explain what ret1 is * @return ret2 explain what ret2 is */ foo(T arg1, T arg2) generates (S ret1, S ret2);
Regras de formatação
As regras de formatação gerais incluem:
- Comprimento da linha. Cada linha de texto precisa ter no máximo 100 colunas.
- Espaços em branco. Não há espaços em branco finais nas linhas; as linhas vazias não podem conter espaços em branco.
- Espaços e tabulações. Use apenas espaços.
- Tamanho do recuo. Use 4 espaços para blocos e 8 espaços para uniões de linha.
- Preparação. Exceto para valores de
anotação, uma chave aberta vai para a mesma linha que o código
anterior, mas uma chave fechada e o ponto e vírgula seguinte ocupam
a linha inteira. Exemplo:
interface INfc { close(); };
Declaração de pacote
A declaração de pacote precisa estar na parte de cima do arquivo após o aviso de licença, ocupar a linha inteira e não ter recuo. Os pacotes são declarados usando o seguinte formato (para formatação de nome, consulte Nomes de pacotes):
package PACKAGE-NAME;
Exemplo:
package android.hardware.nfc@1.0;
Declarações de função
O nome da função, os parâmetros, generates
e os valores de retorno precisam
estar na mesma linha se couberem. Exemplo:
interface IFoo { /** ... */ easyMethod(int32_t data) generates (int32_t result); };
Se eles não couberem na mesma linha, tente colocar parâmetros e valores de retorno
no mesmo nível de recuo e diferencie generate
para ajudar
o leitor a ver rapidamente os parâmetros e valores de retorno. Exemplo:
interface IFoo { suchALongMethodThatCannotFitInOneLine(int32_t theFirstVeryLongParameter, int32_t anotherVeryLongParameter); anEvenLongerMethodThatCannotFitInOneLine(int32_t theFirstLongParameter, int32_t anotherVeryLongParameter) generates (int32_t theFirstReturnValue, int32_t anotherReturnValue); superSuperSuperSuperSuperSuperSuperLongMethodThatYouWillHateToType( int32_t theFirstVeryLongParameter, // 8 spaces int32_t anotherVeryLongParameter ) generates ( int32_t theFirstReturnValue, int32_t anotherReturnValue ); /* method name is even shorter than 'generates' */ foobar(AReallyReallyLongType aReallyReallyLongParameter, AReallyReallyLongType anotherReallyReallyLongParameter) generates (ASuperLongType aSuperLongReturnValue, // 4 spaces ASuperLongType anotherSuperLongReturnValue); }
Mais detalhes:
- Um parêntese aberto está sempre na mesma linha que o nome da função.
- Não há espaços entre o nome da função e o parêntese aberto.
- Não há espaços entre os parênteses e os parâmetros exceto quando há quebras de linha entre eles.
- Se
generates
estiver na mesma linha do parêntese de fechamento anterior, use um espaço antes. Segenerates
estiver na mesma linha que o próximo parêntese aberto, siga com um espaço. - Alinhe todos os parâmetros e retorne valores (se possível).
- A indentação padrão é de quatro espaços.
- Os parâmetros agrupados são alinhados aos primeiros parâmetros na linha anterior. Caso contrário, eles têm uma indentação de oito espaços.
Anotações
Use o seguinte formato para anotações:
@annotate(keyword = value, keyword = {value, value, value})
Classifique as anotações em ordem alfabética e use espaços em torno de sinais de igualdade. Exemplo:
@callflow(key = value) @entry @exit
Verifique se uma anotação ocupa toda a linha. Exemplos:
/* Good */ @entry @exit /* Bad */ @entry @exit
Se as anotações não couberem na mesma linha, recue com oito espaços. Exemplo:
@annotate( keyword = value, keyword = { value, value }, keyword = value)
Se a matriz de valores inteira não couber na mesma linha, coloque quebras de linha após
chaves abertas {
e após cada vírgula dentro da matriz. Coloque o parêntese
de fechamento imediatamente após o último valor. Não coloque os colchetes se houver
apenas um valor.
Se a matriz de valores inteira couber na mesma linha, não use espaços após chaves abertas e antes de chaves fechadas e use um espaço após cada vírgula. Exemplos:
/* Good */ @callflow(key = {"val", "val"}) /* Bad */ @callflow(key = { "val","val" })
NÃO pode haver linhas vazias entre as anotações e a declaração da função. Exemplos:
/* Good */ @entry foo(); /* Bad */ @entry foo();
Declarações de tipo enumerado
Use as seguintes regras para declarações de tipo enumerado:
- Se as declarações de tipo enumerado forem compartilhadas com outro pacote, coloque as declarações
em
types.hal
em vez de incorporá-las a uma interface. - Use um espaço antes e depois do dois-pontos e um espaço após o tipo antes da chave de abertura.
- O último valor de tipo enumerado pode não ter uma vírgula extra.
Declarações de struct
Use as seguintes regras para declarações de struct:
- Se as declarações de struct forem compartilhadas com outro pacote, coloque as declarações
em
types.hal
em vez de incorporá-las a uma interface. - Use um espaço após o nome do tipo de struct antes da chave de abertura.
- Alinhe os nomes dos campos (opcional). Exemplo:
struct MyStruct { vec<uint8_t> data; int32_t someInt; }
Declarações de matriz
Não coloque espaços entre os seguintes elementos:
- Tipo de elemento e colchete aberto.
- Abra o colchete e o tamanho da matriz.
- Tamanho da matriz e fechamento de colchetes.
- Fechar colchetes e o próximo colchete aberto, se houver mais de uma dimensão.
Exemplos:
/* Good */ int32_t[5] array; /* Good */ int32_t[5][6] multiDimArray; /* Bad */ int32_t [ 5 ] [ 6 ] array;
Vetores
Não coloque espaços entre os seguintes elementos:
vec
e sinal de menor que.- Parêntese angular aberto e tipo de elemento (Exceção: o tipo de elemento também é um
vec
). - Tipo de elemento e parêntese angular de fechamento (Exceção: o tipo de elemento também é um
vec
).
Exemplos:
/* Good */ vec<int32_t> array; /* Good */ vec<vec<int32_t>> array; /* Good */ vec< vec<int32_t> > array; /* Bad */ vec < int32_t > array; /* Bad */ vec < vec < int32_t > > array;