O estilo de código HIDL é semelhante ao código C++ do framework do Android, com 4 espaços recuos e nomes de arquivo com letras maiúsculas e minúsculas. Declarações, importações e docstrings de pacotes são semelhantes aos do Java, com pequenas modificações.
Os seguintes exemplos para IFoo.hal
e types.hal
ilustrar os estilos de código HIDL e fornecer links rápidos com 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ções, variáveis e nomes de arquivos devem ser descritivos. evitar
abreviatura excessiva. Trate acrônimos como palavras (por exemplo, use INfc
de INFC
).
Estrutura de diretórios e nomenclatura de arquivos
A estrutura do diretório deve ser semelhante a esta:
ROOT-DIRECTORY
MODULE
SUBMODULE
(opcional, pode ser 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 HIDL principais.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 minúscula que descreva o subsistema (por exemplo,nfc
). Se mais de uma palavra for necessária, useSUBMODULE
aninhada. Pode haver mais de um nível o aninhamento.VERSION
precisa ser exatamente a mesma versão (principal.secundária), conforme descrito em Versões.IINTERFACE_X
precisa 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 devem ter arquivos (no Git).
Nomes de pacote
Os nomes de pacotes precisam usar o seguinte nome totalmente qualificado
(FQN) (referido como PACKAGE-NAME
):
PACKAGE.MODULE[.SUBMODULE[.SUBMODULE[…]]]@VERSION
Em que:
PACKAGE
é o pacote que mapeia para oROOT-DIRECTORY
. Especificamente,PACKAGE
é:android.hardware
para os principais pacotes HIDL (mapeando parahardware/interfaces
).vendor.VENDOR.hardware
para pacotes de fornecedores, em queVENDOR
refere-se a um fornecedor de SoC ou a um OEM/ODM (mapeamento paravendor/VENDOR/interfaces
).
MODULE[.SUBMODULE[.SUBMODULE[…]]]@VERSION
têm exatamente os mesmos nomes de pastas na estrutura descrita em Estrutura do diretório.- Os nomes dos pacotes precisam estar em letras minúsculas. Se tiverem mais de uma palavra, o
as palavras precisam ser usadas como submódulos ou escritas em
snake_case
. - Não são permitidos espaços.
O FQN é sempre usado em declarações de pacote.
Versões
As versões devem ter o seguinte formato:
MAJOR.MINOR
As versões de MAJOR e MINOR precisam ser únicas inteiro. O HIDL usa tipos semânticos controle de versões.
Importações
Uma importação tem um dos três formatos a seguir:
- Importações de todo o pacote:
import PACKAGE-NAME;
- Importações parciais:
import PACKAGE-NAME::UDT;
(ou, se o valor importado o tipo está no mesmo pacote,import UDT;
- Importações somente de tipos:
import PACKAGE-NAME::types;
O PACKAGE-NAME
segue o formato
Nomes de pacote. O valor
types.hal
(se existir) é importado automaticamente (não importar)
explicitamente).
Nomes totalmente qualificados (FQNs, na sigla em inglês)
Use nomes totalmente qualificados para uma importação de tipo definido pelo usuário somente quando necessário.
Omita PACKAGE-NAME
se o tipo de importação estiver no mesmo
. 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 o
acima da interface como INfcClientCallback
. Caso contrário, use apenas o
nome totalmente qualificado.
Como agrupar e ordenar importações
Use uma linha vazia após a declaração do pacote (antes das importações). Cada importação deve ocupar uma única linha e não deve ser recuado. Importações de grupos na seguinte ordem:
- Outros pacotes
android.hardware
(usam nomes totalmente qualificados). - Outros pacotes
vendor.VENDOR
(use totalmente qualificados) nomes de domínio).- Cada fornecedor deve ser um grupo.
- Ordenar fornecedores em ordem alfabética.
- Importa 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 interface
Os nomes de interface precisam começar com I
, seguido por uma
UpperCamelCase
/PascalCase
. Uma interface com nome
IFoo
precisa ser definido no arquivo IFoo.hal
. Este arquivo
pode conter definições apenas para a interface IFoo
(a interface
INAME
precisa estar em INAME.hal
).
Funções
Para nomes de funções, argumentos e nomes de variáveis de retorno, use
lowerCamelCase
: Exemplo:
open(INfcClientCallback clientCallback) generates (int32_t retVal); oneway pingAlive(IFooCallback cb);
Nomes dos campos de estrutura e união
Para nomes de campos de struct ou união, 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 enum 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 passar
valores enum como argumentos de função e retornando-os como retornos da função, use
o tipo de enumeração real (não o tipo 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 subjacente de um tipo enumerado é explicitamente declarado depois dos dois pontos. Como não depende do compilador, usar o tipo de tipo enumerado real é mais claro.
Para nomes totalmente qualificados para valores de enumeração, são usados dois-pontos. entre o nome do tipo e do valor da enumeração:
PACKAGE-NAME::UDT[.UDT[.UDT[…]]:ENUM_VALUE_NAME
Não pode haver espaços dentro de um nome totalmente qualificado. Use um endereço de e-mail nomear somente quando necessário e omitir as partes desnecessárias. Exemplo:
android.hardware.foo@1.0::IFoo.IFooInternal.FooEnum:ENUM_OK
Comentários
Para um comentário de uma única linha, //
, /* */
e /** */
que não tem problema.
// This is a single line comment /* This is also single line comment */ /** This is documentation comment */
-
Use
/* */
para comentários. O HIDL oferece suporte a//
para comentários, elas não são recomendadas, porque não aparecem na saída gerada. - Use
/** */
para a documentação gerada. Elas podem ser aplicadas somente para declarações de tipo, método, campo e enumeração. 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, ... }
- Inicie comentários de várias linhas com
/**
em uma linha separada. Use*
no início de cada linha. Encerre o comentário com*/
em uma linha separada, alinhando os asteriscos aos asteriscos. Exemplo:/** * My multi-line * comment */
- O aviso de licenciamento e os registros de alterações precisam começar uma nova linha com
/*
(um único asterisco), use*
no início de cada linha e coloque*/
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 de núcleo, este
é a licença do AOSP Apache no
development/docs/copyright-templates/c.txt
Atualize o ano e use comentários de várias linhas no estilo /* */
conforme explicado acima.
Você tem a opção de colocar uma linha vazia após o aviso de licença, seguida
por informações de log de mudanças/controle de versão. Usar o estilo /* */
comentários de várias linhas, como explicado acima, coloque a linha vazia após o
o log de mudanças e a declaração do pacote.
Comentários TODO
Os TODOs precisam incluir a string TODO
em letras maiúsculas seguidas por uma
dois-pontos. Exemplo:
// TODO: remove this code before foo is checked in.
Comentários TODO são permitidos somente durante o desenvolvimento. eles precisam não existem em interfaces publicadas.
Comentários sobre interface e função (docstrings)
Use /** */
para docstrings de linha única e de várias linhas. Não usar
//
para docstrings.
As Docstrings para interfaces devem descrever mecanismos gerais do interface, justificativa, propósito etc. Docstrings para funções devem ser específica da função (a documentação no nível do pacote se encontra em 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(); };
É necessário adicionar @param
s e @return
s para cada
parâmetro/valor de retorno:
@param
precisa ser adicionado para cada parâmetro. Deve ser seguido pelo nome do parâmetro e, em seguida, pelo docstring.@return
precisa ser adicionado para cada valor de retorno. Ela deve ser seguido pelo nome do valor de retorno e, em seguida, pela 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 gerais de formatação incluem:
- Comprimento da linha. Cada linha de texto deve ter no máximo 100 colunas.
- Espaços em branco. Nenhum espaço em branco à direita nas linhas. linhas vazias não pode conter espaços em branco.
- Espaços x guias. Use apenas espaços.
- Tamanho do recuo. Use 4 espaços para blocos e 8 espaços para quebras de linha
- Contração. Exceto pela anotação
valores, uma chave open vai na mesma linha que a anterior
mas uma chave close e o seguinte ponto e vírgula ocupa
da linha inteira. Exemplo:
interface INfc { close(); };
Declaração do pacote
A declaração do pacote precisa estar na parte de cima do arquivo após a licença deve ocupar a linha inteira e não deve ser recuado. Os pacotes são declarado com o seguinte formato (para formatação de nomes, consulte Nomes de pacote):
package PACKAGE-NAME;
Exemplo:
package android.hardware.nfc@1.0;
Declarações de função
Nome da função, parâmetros, generates
e valores de retorno precisam
estejam na mesma linha se encaixarem. Exemplo:
interface IFoo { /** ... */ easyMethod(int32_t data) generates (int32_t result); };
Se eles não couberem na mesma linha, tente colocar parâmetros e retornar
valores no mesmo nível de recuo e distinguir generate
para ajudar
o leitor a vê 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); }
Detalhes adicionais:
- 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 parênteses e parâmetros, exceto quando não há feeds de linha entre eles.
- Se
generates
estiver na mesma linha que o fechamento anterior parênteses, use um espaço no início. Segenerates
estiver no mesmo como o próximo parêntese aberto, seguido por um espaço. - Alinhe todos os parâmetros e retorne valores (se possível).
- O recuo padrão tem quatro espaços.
- Os parâmetros com wrapper estão alinhados aos primeiros parâmetros na linha anterior, caso contrário, terão um recuo 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 igual. Exemplo:
@callflow(key = value) @entry @exit
Garantir que uma anotação ocupe a linha inteira. 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 toda a matriz de valores não couber na mesma linha, coloque quebras de linha após
abra as chaves {
e depois de cada vírgula dentro da matriz. Lugar fechado
parênteses imediatamente após o último valor. Não coloque as chaves se houver
apenas um valor.
Se toda a matriz de valores couber na mesma linha, não use espaços após de abertura e antes de fechar chaves 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 função declaração de serviço. Exemplos:
/* Good */ @entry foo(); /* Bad */ @entry foo();
Declarações de enumeração
Use as seguintes regras para declarações de tipo enumerado:
- Se as declarações de tipo enumerado forem compartilhadas com outro pacote, coloque-as
em
types.hal
em vez de incorporar em uma interface. - Use um espaço antes e depois dos dois-pontos e um espaço após o tipo subjacente. antes da chave aberta.
- O último valor de tipo enumerado pode não ter uma vírgula a mais.
Declarações de struct
Use as regras abaixo para declarações de struct:
- Se as declarações de struct forem compartilhadas com outro pacote, coloque-as
em
types.hal
em vez de incorporar em uma interface. - Use um espaço após o nome do tipo de struct antes da chave aberta.
- Alinhar 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:
- Tipo de elemento e colchete aberto.
- Abra o colchete e o tamanho da matriz.
- Tamanho da matriz e colchete fechado.
- Fechar colchete e o próximo colchete aberto, se houver mais de um existe.
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:
vec
e colchete angular de abertura.- Colchete angular e tipo de elemento (Exceção: o tipo do elemento também é um
vec
). - Tipo de elemento e colchete angular de fechamento (Exceção: o tipo do 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;