O estilo de código HIDL se assemelha ao código C++ na estrutura do Android, com recuos de 4 espaços e nomes de arquivo com maiúsculas e minúsculas. Declarações de pacote, importações e docstrings são semelhantes às de Java, com pequenas modificações.
Os exemplos a seguir para IFoo.hal
e types.hal
ilustram 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
Nomes de funções, nomes de variáveis e nomes de arquivos devem ser descritivos; evitar abreviaturas excessivas. Trate as siglas como palavras (por exemplo, use INfc
em vez de INFC
).
Estrutura de diretórios e nomeação de arquivos
A estrutura de diretórios deve aparecer da seguinte forma:
-
ROOT-DIRECTORY
-
MODULE
-
SUBMODULE
(opcional, pode ter mais de um nível)-
VERSION
-
Android.mk
-
I INTERFACE_1 .hal
-
I INTERFACE_2 .hal
-
…
-
I INTERFACE_N .hal
-
types.hal
(opcional)
-
-
-
-
Onde:
-
ROOT-DIRECTORY
é:-
hardware/interfaces
para pacotes HIDL principais. -
vendor/ VENDOR /interfaces
para pacotes de fornecedores, ondeVENDOR
se refere a um fornecedor de SoC ou a um OEM/ODM.
-
-
MODULE
deve ser uma palavra minúscula 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 aninhamento. -
VERSION
deve ser exatamente a mesma versão (major.minor) conforme descrito em Versions . -
I INTERFACE_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
-
-
-
Nota: Todos os arquivos devem ter permissões não executáveis (no Git).
Nomes de pacotes
Os nomes dos pacotes devem usar o seguinte formato de nome totalmente qualificado (FQN) (referido como PACKAGE-NAME
):
PACKAGE.MODULE[.SUBMODULE[.SUBMODULE[…]]]@VERSION
Onde:
-
PACKAGE
é o pacote que mapeia para oROOT-DIRECTORY
. Em particular,PACKAGE
é:-
android.hardware
para pacotes HIDL principais (mapeamento parahardware/interfaces
). -
vendor. VENDOR .hardware
para pacotes de fornecedores, ondeVENDOR
se refere a um fornecedor de SoC ou a um OEM/ODM (mapeamento paravendor/ VENDOR /interfaces
).
-
-
MODULE [. SUBMODULE [. SUBMODULE […]]]@ VERSION
são exatamente os mesmos nomes de pastas na estrutura descrita em Estrutura de diretórios . - Os nomes dos pacotes devem ser minúsculos. Se tiverem mais de uma palavra, as palavras devem 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 pacotes.
Versões
As versões devem ter o seguinte formato:
MAJOR.MINOR
Tanto a versão MAJOR quanto a versão MINOR devem ser um único inteiro. HIDL usa regras de versão semântica .
Importações
Uma importação tem um dos três formatos a seguir:
- Importações de pacote inteiro:
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 Package names . O types.hal
do pacote atual (se existir) é importado automaticamente (não o importe explicitamente).
Nomes totalmente qualificados (FQNs)
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 pacote. Um FQN não deve 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 completo.
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 recuada. Agrupe as importações na seguinte ordem:
- Outros pacotes
android.hardware
(use nomes totalmente qualificados). - Outro
vendor. VENDOR
Pacotesvendor. VENDOR
(use nomes totalmente qualificados).- Cada fornecedor deve ser um grupo.
- Encomende 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 interface
Os nomes de interface devem começar com um I
, seguido por um nome UpperCamelCase
/ PascalCase
. Uma interface com o nome IFoo
deve ser definida no arquivo IFoo.hal
. Este arquivo pode conter definições apenas para a interface IFoo
(a interface I NAME
deve estar em I NAME .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 de campo de estrutura/união
Para nomes de campo struct/union, use lowerCamelCase
. Exemplo:
struct FooReply { vec<uint8_t> replyData; }
Nomes de tipos
Os nomes de tipo referem-se a definições de struct/union, definições de tipo 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 devem ser UPPER_CASE_WITH_UNDERSCORES
. Ao passar valores enum como argumentos de função e retorná-los como retornos de função, use o tipo enum 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 enum é declarado explicitamente após os dois pontos. Como não depende do compilador, usar o tipo de enumeração real é mais claro.
Para nomes totalmente qualificados para valores enum, dois pontos são usados entre o nome do tipo enum e o nome do valor enum:
PACKAGE-NAME::UDT[.UDT[.UDT[…]]:ENUM_VALUE_NAME
Não deve haver espaços dentro de um nome totalmente qualificado. Use um nome totalmente qualificado somente quando necessário e omita as 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 bons.
// This is a single line comment /* This is also single line comment */ /** This is documentation comment */
- Use
/* */
para comentários. Embora o HIDL suporte//
para comentários, eles são desencorajados porque não aparecem na saída gerada. - Use
/** */
para documentação gerada. Eles podem ser aplicados apenas a declarações de tipo, método, campo e valor de 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. Finalize o comentário com*/
em uma linha separada, alinhando os asteriscos. Exemplo:/** * My multi-line * comment */
- O aviso de licenciamento e os logs de alterações devem iniciar 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 devem se alinhar). Exemplo:/* * Copyright (C) 2017 The Android Open Source Project * ... */ /* * Changelog: * ... */
Comentários do arquivo
Inicie cada arquivo com o aviso de licenciamento apropriado. Para HALs principais, esta deve ser a licença Apache AOSP em development/docs/copyright-templates/c.txt
. Lembre-se de atualizar o ano e usar comentários de várias linhas no estilo /* */
conforme explicado acima.
Opcionalmente, você pode colocar uma linha vazia após o aviso de licença, seguida por um registro de alterações/informações de versão. Use comentários de várias linhas no estilo /* */
como explicado acima, coloque a linha vazia após o changelog e siga com a declaração do pacote.
Comentários de TODO
TODOs devem incluir a string TODO
em maiúsculas seguida de dois pontos. Exemplo:
// TODO: remove this code before foo is checked in.
Comentários TODO são permitidos apenas durante o desenvolvimento; eles não devem existir em interfaces publicadas.
Comentários de interface/função (docstrings)
Use /** */
para docstrings de várias linhas e de linha única. Não use //
para docstrings.
Docstrings para interfaces devem descrever mecanismos gerais da interface, lógica de design, propósito, etc. Docstrings para funções devem ser específicas para a função (documentação em nível de pacote vai em um arquivo README no diretório de pacotes).
/** * 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(); };
Você deve adicionar @param
s e @return
s para cada parâmetro/valor de retorno:
-
@param
deve ser adicionado para cada parâmetro. Deve ser seguido pelo nome do parâmetro e depois pela docstring. -
@return
deve ser adicionado para cada valor de retorno. Deve ser seguido pelo nome do valor de retorno e depois 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);
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 devem conter espaços em branco.
- Espaços vs. tabulações . Use apenas espaços.
- Tamanho do recuo . Use 4 espaços para blocos e 8 espaços para quebras de linha
- Reforço . Exceto para valores de anotação , uma chave de abertura vai na mesma linha do código anterior, mas uma chave de fechamento e o ponto e vírgula seguinte ocupam a linha inteira. Exemplo:
interface INfc { close(); };
Declaração do pacote
A declaração do pacote deve estar no topo do arquivo após o aviso de licença, deve ocupar toda a linha e não deve ser recuada. Os pacotes são declarados usando o seguinte formato (para formatação de nome, consulte Nomes de pacote ):
package PACKAGE-NAME;
Exemplo:
package android.hardware.nfc@1.0;
Declarações de função
O nome da função, parâmetros, generates
e valores de retorno devem estar na mesma linha se eles 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 valores de retorno no mesmo nível de recuo e diferencie generate
para ajudar o leitor a ver rapidamente os parâmetros e os 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.
- Sem 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 há alimentação de linha entre eles.
- Se
generates
estiver na mesma linha do parêntese de fechamento anterior, use um espaço anterior. Segenerates
está na mesma linha que o próximo parêntese aberto, siga com um espaço. - Alinhe todos os parâmetros e valores de retorno (se possível).
- O recuo padrão é de 4 espaços.
- Os parâmetros agrupados são alinhados aos primeiros parâmetros da linha anterior, caso contrário, eles têm um recuo de 8 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
Certifique-se de que uma anotação ocupe toda a linha. Exemplos:
/* Good */ @entry @exit /* Bad */ @entry @exit
Se as anotações não couberem na mesma linha, recue com 8 espaços. Exemplo:
@annotate( keyword = value, keyword = { value, value }, keyword = value)
Se todo o array de valores não couber na mesma linha, coloque quebras de linha após chaves abertas {
e após cada vírgula dentro do array. Coloque parênteses de fechamento imediatamente após o último valor. Não coloque as chaves se houver apenas um valor.
Se a matriz de valores inteira puder caber na mesma linha, não use espaços após abrir chaves 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 deve haver linhas vazias entre as anotações e a declaração da função. Exemplos:
/* Good */ @entry foo(); /* Bad */ @entry foo();
Declarações de enumeração
Use as seguintes regras para declarações enum:
- Se as declarações enum forem compartilhadas com outro pacote, coloque as declarações em
types.hal
em vez de embutir dentro de uma interface. - Use um espaço antes e depois dos dois pontos e espaço após o tipo subjacente antes da chave aberta.
- O último valor enum pode ou não ter uma vírgula extra.
Declarações de estrutura
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 embutir dentro de uma interface. - Use um espaço após o nome do tipo de estrutura antes da chave de abertura.
- Alinhar nomes de campo (opcional). Exemplo:
struct MyStruct { vec<uint8_t> data; int32_t someInt; }
Declarações de matriz
Não coloque espaços entre o seguinte:
- Tipo de elemento e colchete aberto.
- Abra o colchete e o tamanho da matriz.
- Tamanho da matriz e colchetes próximos.
- Fechar colchete e o próximo colchete aberto, se existir 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 o seguinte:
-
vec
e suporte de ângulo aberto. - Colchete de ângulo aberto e tipo de elemento ( Exceção: o tipo de elemento também é um
vec
). - Tipo de elemento e colchete angular fechado ( 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;