O estilo de código HIDL se assemelha ao código C++ na estrutura Android, com recuos de 4 espaços e nomes de arquivos com letras maiúsculas e minúsculas. Declarações de pacotes, importações e docstrings são semelhantes aos 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 de 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; evite abreviações excessivas. Trate os 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 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 for necessária mais de uma palavra, useSUBMODULE
aninhado. Pode haver mais de um nível de aninhamento. -
VERSION
deve ser exatamente a mesma versão (major.minor) descrita em Versões . -
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 pasta na estrutura descrita em Estrutura de diretórios . - Os nomes dos pacotes devem estar em letras minúsculas. 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 MINOR devem ser um único número inteiro. HIDL usa regras de versionamento semântico .
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 Nomes de pacotes . O types.hal
do pacote atual (se existir) é importado automaticamente (não importe-o explicitamente).
Nomes totalmente qualificados (FQNs)
Use nomes completos 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, utilize apenas o nome completo.
Agrupando e ordenando 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.
- Ordene os 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 das interfaces devem começar com I
, seguido por um nome UpperCamelCase
/ PascalCase
. Uma interface com 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 campos de estrutura/união
Para nomes de campos struct/union, use lowerCamelCase
. Exemplo:
struct FooReply { vec<uint8_t> replyData; }
Digite nomes
Os nomes dos tipos referem-se a definições de struct/união, 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 enum 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 };
Nota: O tipo subjacente de um tipo enum é declarado explicitamente após os dois pontos. Como não depende do compilador, o uso do tipo enum real é mais claro.
Para nomes completos 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 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 /** */
estão bem.
// 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 enum. 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. Termine o comentário com*/
em uma linha separada, alinhando os asteriscos. Exemplo:/** * My multi-line * comment */
- O aviso de licenciamento e os changelogs devem começar uma nova linha com
/*
(um único asterisco), usar*
no início de cada linha e colocar*/
na última linha sozinho (os asteriscos devem estar alinhados). 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 AOSP Apache 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 informações de changelog/versionamento. Use comentários de várias linhas no estilo /* */
conforme explicado acima, coloque a linha vazia após o changelog e siga com a declaração do pacote.
TODO comentários
TODOs devem incluir a string TODO
em letras 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 multilinhas 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 (a documentação em nível de pacote vai 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(); };
Você deve adicionar @param
se @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 nas linhas; linhas vazias não devem conter espaços em branco.
- Espaços versus guias . Use apenas espaços.
- Tamanho do recuo . Use 4 espaços para blocos e 8 espaços para quebras de linha
- Preparação . Exceto para valores de anotação , uma chave de abertura fica 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 de 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 nomes, 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 devem 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 distinguir 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); }
Detalhes adicionais:
- Um parêntese aberto está sempre na mesma linha do nome da função.
- Não há espaços entre o nome da função e os parênteses abertos.
- Não há espaços entre parênteses e parâmetros , exceto quando há avanços de linha entre eles.
- Se
generates
estiver na mesma linha do parêntese de fechamento anterior, use um espaço anterior. Segenerates
estiver na mesma linha do próximo parêntese aberto, coloque um espaço em seguida. - Alinhe todos os parâmetros e retorne valores (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 terão 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 dos 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 toda a matriz de valores não couber na mesma linha, coloque quebras de linha após colchetes {
e após cada vírgula dentro da matriz. Coloque parênteses de fechamento imediatamente após o último valor. Não coloque colchetes se houver apenas um valor.
Se toda a matriz de valores couber na mesma linha, não use espaços após colchetes abertos e antes de colchetes de fechamento 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 incorporá-las 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 enum pode ou não ter uma vírgula extra.
Declarações estruturais
Use as seguintes regras para declarações struct:
- Se as declarações struct forem compartilhadas com outro pacote, coloque as declarações em
types.hal
em vez de incorporar dentro de uma interface. - Use um espaço após o nome do tipo de estrutura 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 o seguinte:
- Tipo de elemento e colchete aberto.
- Abra colchetes e tamanho da matriz.
- Tamanho da matriz e colchete próximo.
- Feche o 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 colchete angular aberto. - Abra o colchete angular e o tipo de elemento ( Exceção: o tipo de elemento também é um
vec
). - Tipo de elemento e colchete angular próximo ( 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;