Guía de estilo de código

El estilo de código HIDL se asemeja al código C++ en el framework de Android, con 4 espacios las sangrías y los nombres de archivo en mayúsculas y minúsculas. Declaraciones de paquetes, importaciones y docstrings son similares a las de Java, con pequeñas modificaciones.

Los siguientes ejemplos para IFoo.hal y types.hal ilustrar los estilos de código HIDL y proporcionar vínculos rápidos a los detalles de cada estilo (IFooClientCallback.hal, IBar.hal y se omitieron IBaz.hal).

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;
};

Convenciones de nombres

Los nombres de funciones, de variables y de archivos deben ser descriptivos. evitar sobre la abreviatura. Trata los acrónimos como palabras (por ejemplo, usa INfc en su lugar). de INFC).

Estructura de directorios y nomenclatura de archivos

La estructura del directorio debería aparecer de la siguiente manera:

  • ROOT-DIRECTORY
    • MODULE
      • SUBMODULE (opcional, podría ser más de uno) a nivel)
        • VERSION
          • Android.mk
          • IINTERFACE_1.hal
          • IINTERFACE_2.hal
          • IINTERFACE_N.hal
          • types.hal (opcional)

donde:

  • ROOT-DIRECTORY es:
    • hardware/interfaces para los paquetes principales de HIDL
    • vendor/VENDOR/interfaces para paquetes de proveedores en el que VENDOR se refiere a un proveedor de SoC o a un OEM/ODM
  • MODULE debe ser una palabra minúscula que describa el subsistema (por ejemplo, nfc). Si se necesita más de una palabra, usa SUBMODULE anidada. Puede haber más de un nivel durante el período de anidación.
  • VERSION debe ser exactamente la misma versión (major.minor), como se describe en Versiones.
  • IINTERFACE_X debe ser el nombre de la interfaz con UpperCamelCase/PascalCase (por ejemplo, INfc) como se describe en Nombres de interfaces.

Ejemplo:

  • hardware/interfaces
    • nfc
      • 1.0
        • Android.mk
        • INfc.hal
        • INfcClientCallback.hal
        • types.hal

Nota: Todos los archivos no deben tener permisos ejecutables permisos (en Git).

Nombres de los paquetes

Los nombres de los paquetes deben contener el siguiente nombre completamente calificado (FQN) (denominado PACKAGE-NAME):

PACKAGE.MODULE[.SUBMODULE[.SUBMODULE[…]]]@VERSION

donde:

  • PACKAGE es el paquete que se asigna al ROOT-DIRECTORY En particular, PACKAGE es:
    • android.hardware para los paquetes principales de HIDL (asignación a hardware/interfaces).
    • vendor.VENDOR.hardware para paquetes de proveedores, en los que VENDOR hace referencia a un proveedor de SoC o a un OEM/ODM (asignación a vendor/VENDOR/interfaces).
  • MODULE[.SUBMODULE[.SUBMODULE[…]]]@VERSION sean exactamente los mismos nombres de carpetas en la estructura descrita en Estructura del directorio.
  • Los nombres de los paquetes deben estar en minúscula. Si tienen más de una palabra, el las palabras deben usarse como submódulos o escribirse en snake_case.
  • No se permiten espacios.

El FQN siempre se usa en las declaraciones de paquetes.

Versiones

Las versiones deben tener el siguiente formato:

MAJOR.MINOR

Tanto la versión MAJOR como la MINOR deben ser una sola entero. El HIDL usa semántica control de versiones.

Importaciones

Una importación tiene uno de los siguientes tres formatos:

  • Importaciones de paquetes completos: import PACKAGE-NAME;
  • Importaciones parciales: import PACKAGE-NAME::UDT; (o, si el valor importado está en el mismo paquete,import UDT;
  • Importaciones de solo tipos: import PACKAGE-NAME::types;

PACKAGE-NAME sigue el formato de Nombres de paquetes. La propiedad del paquete actual types.hal (si existe) se importa automáticamente (no importar explícitamente).

Nombres completamente calificados (FQN)

Usa nombres completos para una importación de tipos definidos por el usuario solo cuando sea necesario. Omite PACKAGE-NAME si el tipo de importación está en el mismo . Un FQN no debe contener espacios. Ejemplo de un nombre completamente calificado:

android.hardware.nfc@1.0::INfcClientCallback

En otro archivo en android.hardware.nfc@1.0, consulta el arriba de la interfaz como INfcClientCallback. De lo contrario, usa solo el nombre completamente calificado.

Agrupa y ordena importaciones

Usa una línea vacía después de la declaración del paquete (antes de las importaciones). Cada importación deben ocupar una sola línea y no deben tener sangría. Agrupa las importaciones siguiente orden:

  1. Otros paquetes android.hardware (usa nombres completamente calificados).
  2. Otros paquetes de vendor.VENDOR (usa completamente calificados nombres).
    • Cada proveedor debe ser un grupo.
    • Ordena los proveedores alfabéticamente.
  3. Importaciones desde otras interfaces en el mismo paquete (usa nombres simples).

Usa una línea vacía entre grupos. Ordena las importaciones dentro de cada grupo alfabéticamente. Ejemplo:

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;

Nombres de la interfaz

Los nombres de la interfaz deben comenzar con un I, seguido de un Nombre UpperCamelCase/PascalCase. Una interfaz con nombre IFoo debe definirse en el archivo IFoo.hal. Este archivo Puede contener definiciones solo para la interfaz IFoo (la interfaz INAME debe estar en INAME.hal).

Funciones

Para nombres de funciones, argumentos y nombres de variables que se devuelven, usa lowerCamelCase. Ejemplo:

open(INfcClientCallback clientCallback) generates (int32_t retVal);
oneway pingAlive(IFooCallback cb);

Nombres de campos de struct y union

Para los nombres de campos de struct o unión, usa lowerCamelCase. Ejemplo:

struct FooReply {
    vec<uint8_t> replyData;
}

Nombres de tipos

Los nombres de tipo hacen referencia a definiciones de struct o unión, definiciones de tipos de enumeración y typedef Para estos nombres, usa UpperCamelCase por PascalCase. Ejemplos:

enum NfcStatus : int32_t {
    /*...*/
};
struct NfcData {
    /*...*/
};

Enum. de valores

Los valores de enumeración deben ser UPPER_CASE_WITH_UNDERSCORES. Al pasar enum como argumentos de funciones y los mostrarás como resultado de la función, usa el tipo de enumeración real (no el tipo de número entero subyacente). Ejemplo:

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: El tipo subyacente de un tipo enum es declarada explícitamente después de los dos puntos. Como no depende del compilador, usa el el tipo enum real es más claro.

En el caso de los nombres completamente calificados para los valores de enumeración, se usa dos puntos. entre el nombre del tipo de enumeración y el nombre del valor de enumeración:

PACKAGE-NAME::UDT[.UDT[.UDT[…]]:ENUM_VALUE_NAME

No debe haber espacios dentro de un nombre completamente calificado. Usa una solución completamente calificada el nombre solo cuando sea necesario y omitir las partes innecesarias. Ejemplo:

android.hardware.foo@1.0::IFoo.IFooInternal.FooEnum:ENUM_OK

Comentarios

Para un comentario de una sola línea, //, /* */ y /** */ están bien.

// This is a single line comment
/* This is also single line comment */
/** This is documentation comment */
  • Usa /* */ para los comentarios. Si bien HIDL admite // para los comentarios, no se recomienda porque no aparecen en la salida generada.
  • Usa /** */ para la documentación generada. Estas se pueden aplicar solo para declaraciones de tipo, método, campo y enum. Ejemplo:
    /** 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,
        ...
    }
    
  • Inicia comentarios de varias líneas con /** en una línea separada. Usa * al comienzo de cada línea. Finaliza el comentario con */ en una línea separada y alinea los asteriscos. Ejemplo:
    /**
     * My multi-line
     * comment
     */
    
  • El aviso de licencia y los registros de cambios deben comenzar una nueva línea con /*. (un solo asterisco), utiliza * al principio de cada línea y coloca */ en la última línea por su cuenta (los asteriscos deben alinearse). Ejemplo:
    /*
     * Copyright (C) 2017 The Android Open Source Project
     * ...
     */
    
    /*
     * Changelog:
     * ...
     */
    

Comentarios de archivos

Inicia cada archivo con el aviso de licencia correspondiente. Para las HAL principales, este debería ser la licencia Apache del AOSP en development/docs/copyright-templates/c.txt Recuerda actualizar el año y usar comentarios de varias líneas del estilo /* */ como se explicó anteriormente.

También puedes colocar una línea vacía después del aviso de licencia, seguido de por un registro de cambios o información sobre el control de versiones. Usar el estilo /* */ comentarios de varias líneas, como se explicó anteriormente, coloca la línea vacía después del el registro de cambios y continúa con la declaración del paquete.

Comentarios TODO

Los comentarios "TODO" deben incluir la cadena TODO en mayúsculas seguida de un dos puntos. Ejemplo:

// TODO: remove this code before foo is checked in.

Los comentarios "TODO" solo se permiten durante el desarrollo; deben no existen en las interfaces publicadas.

Comentarios de interfaz y función (docstrings)

Usa /** */ para docstrings de una o varias líneas. No utilizar // para docstrings.

Las docstrings para interfaces deben describir mecanismos generales de la interfaz, la lógica del diseño, el propósito, etc. Las docstrings para las funciones deben ser específicas de la función (la documentación a nivel del paquete va en un archivo README en el directorio del paquete).

/**
 * 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();
};

Debes agregar elementos @param y @return para cada uno. valor del parámetro o que se muestra:

  • Se debe agregar @param para cada parámetro. Debe ser seguido del nombre del parámetro y, luego, la docstring.
  • Se debe agregar @return para cada valor que se muestra. Integra debe estar seguido por el nombre del valor que se devuelve y, luego, por la docstring.

Ejemplo:

/**
 * 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);

Reglas de formato

Las reglas de formato generales incluyen lo siguiente:

  • Longitud de la línea: Cada línea de texto debe tener, como máximo, 100 columnas de longitud
  • Espacios en blanco. No debe haber espacios en blanco al final en las líneas. líneas vacías No debe contener espacios en blanco.
  • Espacios frente a pestañas. Usa solo espacios.
  • Tamaño de sangría. Usa 4 espacios para los bloques y 8 espacios para las uniones de líneas
  • Antigüedad. Excepto por la anotación valores, una llave open va en la misma línea que la anterior pero una llave de cerrar y ocupar el siguiente punto y coma toda la línea. Ejemplo:
    interface INfc {
        close();
    };
    

Declaración del paquete

La declaración del paquete debe aparecer en la parte superior del archivo después de la licencia debe ocupar toda la línea y no debe tener sangría. Los paquetes son declarada con el siguiente formato (para el formato de nombre, consulta Nombres de paquetes):

package PACKAGE-NAME;

Ejemplo:

package android.hardware.nfc@1.0;

Declaraciones de funciones

El nombre de la función, los parámetros, generates y los valores que se muestran deben estar en la misma línea si encajan. Ejemplo:

interface IFoo {
    /** ... */
    easyMethod(int32_t data) generates (int32_t result);
};

Si no caben en la misma línea, intenta colocar los parámetros y devolver valores en el mismo nivel de sangría y distinguir generate para ayudar el lector a ver rápidamente los parámetros y devolver valores. Ejemplo:

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);
}

Detalles adicionales:

  • Un paréntesis abierto siempre está en la misma línea que el nombre de la función.
  • No debe haber espacios entre el nombre de la función y el paréntesis abierto.
  • Sin espacios entre paréntesis y parámetros, excepto cuando haya hay feeds de líneas entre ellos.
  • Si generates está en la misma línea que el cierre anterior paréntesis, utiliza un espacio precedente. Si generates está en el mismo como el siguiente paréntesis de apertura y luego con un espacio.
  • Alinea todos los parámetros y devuelve los valores (si es posible).
  • La sangría predeterminada es de 4 espacios.
  • Los parámetros unidos se alinean con los primeros parámetros de la línea anterior, de lo contrario, tendrán una sangría de 8 espacios.

Anotaciones

Usa el siguiente formato para las anotaciones:

@annotate(keyword = value, keyword = {value, value, value})

Ordena las anotaciones por orden alfabético y usa espacios alrededor del signo igual. Ejemplo:

@callflow(key = value)
@entry
@exit

Asegúrate de que una anotación ocupe toda la línea. Ejemplos:

/* Good */
@entry
@exit

/* Bad */
@entry @exit

Si las anotaciones no caben en la misma línea, aplica una sangría de 8 espacios. Ejemplo:

@annotate(
        keyword = value,
        keyword = {
                value,
                value
        },
        keyword = value)

Si toda la matriz de valores no cabe en la misma línea, coloca saltos de línea después. Abre las llaves { y, después de cada coma dentro del array. Cierre del lugar paréntesis inmediatamente después del último valor. No coloques las llaves si hay solo un valor.

Si todo el array de valores puede caber en la misma línea, no uses espacios después de abra las llaves y, antes de cerrarlas, y use un espacio después de cada coma. Ejemplos:

/* Good */
@callflow(key = {"val", "val"})

/* Bad */
@callflow(key = { "val","val" })

NO debe haber líneas vacías entre las anotaciones y la función declaración. Ejemplos:

/* Good */
@entry
foo();

/* Bad */
@entry

foo();

Declaraciones de enumeración

Usa las siguientes reglas para las declaraciones enum:

  • Si se comparten declaraciones de enumeración con otro paquete, colócalas. en types.hal en lugar de incorporarlos en una interfaz.
  • Se debe usar un espacio antes y después de los dos puntos y un espacio después del tipo subyacente antes de la llave de apertura.
  • Es posible que el último valor de enumeración no tenga una coma adicional.

Declaraciones struct

Usa las siguientes reglas para las declaraciones de struct:

  • Si las declaraciones de struct se comparten con otro paquete, colócalas. en types.hal en lugar de incorporarlos en una interfaz.
  • Usa un espacio después del nombre del tipo de struct antes de la llave de apertura.
  • Alinea los nombres de los campos (opcional). Ejemplo:
    struct MyStruct {
        vec<uint8_t>   data;
        int32_t        someInt;
    }
    

Declaraciones de arrays

No coloques espacios entre los siguientes elementos:

  • Tipo de elemento y corchete de apertura.
  • Abra el corchete cuadrado y el tamaño del array.
  • Tamaño del array y corchete de cierre
  • Corchete de cierre y el siguiente corchete de apertura (si hay más de uno) existe una dimensión.

Ejemplos:

/* Good */
int32_t[5] array;

/* Good */
int32_t[5][6] multiDimArray;

/* Bad */
int32_t [ 5 ] [ 6 ] array;

Vectores

No coloques espacios entre los siguientes elementos:

  • vec y abre un corchete angular.
  • Abra el corchete angular y el tipo de elemento (Excepción: El tipo de elemento también es una vec).
  • Tipo de elemento y corchete angular de cierre (Excepción: El tipo de elemento también es un vec).

Ejemplos:

/* 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;