Especificación del idioma

En esta página, se especifica el Lenguaje de Definición de Interfaz de Servicio de Vehículo (VSIDL) con la forma Backus-Naur extendida (EBNF) ISO/IEC 14977 y protobuf. Esta página se enfoca en la gramática independiente del contexto del lenguaje y el significado de los elementos del lenguaje.

Jerarquía de lenguaje

Según el Meta Object Facility (MOF), el compilador VSIDL (VSIDLC) usa los lenguajes que se muestran en la Figura 1:

Idiomas de VSIDLC

Figura 1: Lenguajes VSIDLC

VSIDLC se basa principalmente en el lenguaje de búferes de protocolo (protobuf). Protobuf se usa para especificar los tipos de datos que se intercambian con llamadas de publicación-suscripción y llamadas de procedimiento remoto (RPC). Desde un punto de vista técnico, los modelos VSIDL son archivos TextProto, en los que la sintaxis de VSIDL se define en un archivo protobuf (syntax.proto). Los archivos protobuf para especificar tipos de datos y los modelos VSIDL se usan para generar código Rust. El código generado contiene principalmente structs que implementan las estructuras de datos para los mensajes intercambiados y las funciones de Rust que implementan funciones para crear unidades de servicio en Rust, sin llamar a estas unidades de servicio automáticamente. Este código Rust generado se acompaña de código Rust personalizado que usa el código generado para crear instancias de unidades de servicio y, también, implementar la lógica empresarial de la aplicación.

Sintaxis abstracta

En la Figura 2, se muestran los tipos de mensajes principales en VSIDL:

Tipos de mensajes principales en VSIDL

Figura 2: Tipos de mensajes principales en VSIDL

Entrada de VSIDL

En esta sección, se explica el tipo de mensaje de entrada de VSIDL.

Gramática EBNF

start VsidlEntry =
  "package" , ":" , String , ";" ,
  { "service_bundle" , ServiceBundle } ,
  { "extension" , ":" , Any } ,
  { "some_ip_mapping" , ":" , SomeIpMapping } ,
  { "vhal_mapping" , ":" , VhalMapping }
;

Definición de Proto

// The root message for VSIDL files
message VsidlEntry {
  // Required. Package name for entities mentioned in the file.
  string package = 1;
  // Enables custom extensions beyond the standard VSIDL model.
  repeated google.protobuf.Any extension = 3;

  // SOMEIP mapping rules
  repeated sdv.someip.v1.SomeIpMapping some_ip_mapping = 4;
  // VHAL mapping rules
  repeated VhalMapping vhal_mapping = 5;
  // List of SDV service bundles defined in the file.
  repeated ServiceBundle service_bundle = 6;
}

Ejemplo de uso

package: "com.android.sdv.sample.vsidl"

service_bundle {
  name: "Manager"

  publisher {
    message: "TirePressure"
    topic: "front-left"
    topic: "front-right"
    capacity: 10
  }
}

Explicación

El mensaje VsidlEntry sirve como contenedor raíz para el archivo VSIDL (con la extensión .vsidl). Este mensaje encapsula todas las definiciones y configuraciones en un solo archivo VSIDL. VsidlEntry es el elemento de nivel superior que vincula todo lo demás.

Propósito:

  • Define la estructura general de un archivo VSIDL.
  • Especifica el espacio de nombres del paquete para todas las entidades dentro del archivo.
  • Contiene una colección de definiciones de paquetes de servicios.
  • Permite extensiones personalizadas al modelo VSIDL.
  • Incluye reglas de asignación para SOME/IP y VHAL.

Limitaciones

  • Nombre del paquete (E211): El nombre del paquete no debe superar los 127 caracteres.
  • Archivos colgantes (E10B): Se debe hacer referencia a todos los archivos de un catálogo en un grupo de archivos Android.bp.

Paquete de servicios

En esta sección, se explica el tipo de mensaje de paquete de servicios.

Gramática EBNF

ServiceBundle = "{" , { ServiceBundleElement } , "}" ;

ServiceBundleElement =
  "name" , ":" , String |
  "publisher" , Publisher |
  "subscriber" , Subscriber |
  "server" , Server |
  "client" , Client |
  "extension" , ":" , Any |
  "diagnostics_declaration" , DiagnosticsDeclaration |
  "build_cfg" , BuildConfiguration |
  "register_reflection_metadata" , Boolean
;

Definición de Proto

// Defines an SDV service
message ServiceBundle {
  // Required. Name of the service bundle (without the package name).
  string name = 1;
  // List of publications the service bundle provides.
  repeated Publisher publisher = 2;
  // List of publications a service bundle subscribes to.
  repeated Subscriber subscriber = 3;
  // RPC services offered by a service bundle.
  repeated Server server = 4;
  // RPC services consumed by a service bundle.
  repeated Client client = 5;
  // Enables custom extensions beyond the standard VSIDL model.
  repeated google.protobuf.Any extension = 7;

  // Diagnostics declarations
  sdv.diagnostics.v1.DiagnosticsDeclaration diagnostics_declaration = 8;

  // Build Configuration
  optional BuildConfiguration build_cfg = 9;

  // Register metadata for service units provided by this service bundle.
  // Setting this to true will increase the memory footprint
  // and network load significantly.
  bool register_reflection_metadata = 10;
}

Ejemplo de uso

service_bundle {
    name: "SeatController"

    publisher {
      message: "SeatHeating"
      topic: "driver-seat"
      capacity: 10
    }
}

Explicación

Un paquete de servicios define una agrupación lógica de servicios, publicadores, suscriptores, servidores RPC y clientes RPC relacionados. Un paquete de servicios actúa como un contenedor para un conjunto específico de funcionalidades y sus interacciones.

Limitaciones

  • Requisitos para los nombres de paquetes (E209, E20A, E20B, E20C):
    • Un paquete de servicios debe tener un nombre propagado.
    • El nombre debe comenzar con un carácter de inicio de identificador Unicode válido (por lo general, una letra).
    • Los caracteres posteriores del nombre deben ser caracteres de continuación de identificador Unicode válidos (por lo general, letras o números).
    • El nombre no debe ser una palabra clave reservada en Rust, Java o C++.
  • Unicidad global del paquete (E309): Cada paquete de servicios debe tener un nombre completamente calificado único (según su paquete y nombre).
  • Unicidad interna (E100, E300, E302, E303, E308):
    • Dentro de un solo paquete de servicios, cada servicio RPC puede publicarse en, como máximo, una definición de servidor.
    • Dentro de un solo paquete de servicios, cada tipo de publicación MULTI_PUB puede publicarse en, como máximo, una definición de publicador.
    • Dentro de un solo paquete de servicios, todos los nombres de unidades de servicio definidos por el usuario (para publicadores o servidores) deben ser únicos.
    • Dentro de un solo paquete de servicios, todos los nombres de unidades de servicio (ya sean definidos por el usuario o generados automáticamente) deben ser únicos.
  • Convenciones de nomenclatura de destino de compilación (E205, E206, E207, E208): Si se proporciona un nombre de destino de compilación personalizado (build_cfg.target_name), debe cumplir con el formato snake case (letras minúsculas, números y guiones bajos únicos, sin comenzar ni terminar con un guion bajo).
  • Unicidad del nombre de destino de compilación (E301): Un nombre de destino de compilación definido por el usuario no debe entrar en conflicto con ningún nombre de destino generado automáticamente para otros paquetes de servicios.

Publisher

En esta sección, se explica el tipo de mensaje Publisher.

Gramática EBNF

Publisher = "{" , { PublisherElement } , "}" ;

PublisherElement =
  "message" , ":" , String |
  "topic" , ":" , String |
  "capacity" , ":" , Integer |
  "service_unit_name" , ":" , String
;

Definición de Proto

// Represents a publisher within a service bundle.
message Publisher {
  // Name of the service unit. Name may only use characters from [a-z0-9\-]+,
  // must start with [a-z], may not end with a hyphen,
  // and may not contain consecutive hyphens.
  string service_unit_name = 3;
  // Required. The type of data being published.
  string message = 4;
  // Required. The number of messages a publication queue can hold.
  // Must be an even number >= 2.
  int64 capacity = 6;
  // Required. Unique identifier for the publication topic.
  // Must be in lowercase dash-case.
  repeated string topic = 7;
}

Ejemplo de uso

publisher {
  message: "SeatHeating"
  topic: "driver-heating"
  capacity: 10
}

Explicación

El tipo de mensaje Publisher define una fuente de datos que proporciona ServiceBundle. Este tipo de mensaje especifica el tipo de datos que se publican y los temas y la capacidad específicos de esos datos.

Temas

Cada instancia Publisher tiene un campo message que hace referencia al mensaje proto que se publica. Debe especificar un tema (representado por topic) y una capacidad (representada por capacity).

  • Tema: Un identificador único para el tema de publicación. Debe seguir el formato dash-case en minúscula (por ejemplo, my-topic).
  • Capacidad: Especifica el tamaño de la cola, es decir, cuántos mensajes puede contener la cola antes de que se descarten los mensajes no leídos. Debe ser un número par igual o mayor que 2.

Nombres definidos por el usuario

Los publicadores pueden tener nombres de unidades de servicio definidos por el usuario que anulan los nombres de unidades de servicio elegidos automáticamente. Esta indicación visual permite elegir nombres más cortos. Si un publicador usa un nombre de unidad de servicio definido por el usuario, es posible que solo use una instancia, de modo que el nombre de la unidad de servicio se asigne de forma única a una instancia.

# VALID: A publisher assigns a user-defined name to a single instance
publisher {
  message: "SeatHeating"
  topic: "seat-heating-status"
  service_unit_name: "heating-is-off"
}

# ERROR: user-defined names are only allowed if there's only a single instance
publisher {
  message: "SeatHeating"
  topic: "seat-heating-status"
  service_unit_name: "heating-status"
}

Limitaciones

  • Ubicación del publicador (E300): Los publicadores del mismo tipo MULTI_PUB deben definirse en paquetes de servicios separados.
  • Unicidad del nombre local (E302): Dentro de un solo paquete de servicios, todos los publicadores deben tener nombres de unidades de servicio definidos por el usuario únicos.
  • Unicidad del nombre global (E304): Los publicadores del mismo tipo de publicación deben tener nombres de unidades de servicio definidos por el usuario únicos a nivel global en todos los paquetes de servicios.
  • Nombres de canales únicos (E306): Los nombres de unidades de servicio definidos por el usuario solo se pueden asignar a los publicadores que controlan exactamente una instancia.
  • Límite de publicador único (E307): Un mensaje protobuf marcado como SINGLE_PUB solo puede ser publicado por un publicador en todo el sistema.
  • Unicidad del nombre de la unidad de servicio (E308): Todos los nombres de unidades de servicio (ya sean generados o definidos por el usuario) deben ser únicos dentro de su paquete de servicios. Los nombres definidos por el usuario se deben usar para resolver conflictos con los nombres generados.
  • Requisito de especificación de variante (E501): Cuando un publicador usa un nombre definido por el usuario para un tipo con varias variantes, debe especificar explícitamente la variante que publica.
  • Existencia del publicador para los suscriptores (E504): Cada suscriptor definido requiere al menos un publicador correspondiente para el tipo y la variante especificados.
  • Tipo de publicador válido (E601): Un publicador debe hacer referencia a un tipo que corresponda a un mensaje protobuf existente.
  • Requisito de anotación de publicación (E602): El tipo de mensaje protobuf al que hace referencia un publicador debe incluir la anotación SdvPublication.
  • Uso de variantes válidas (E606): Si un publicador especifica una variante (instancia), esa variante debe existir dentro de instances_enum definida para el tipo de publicación en protobuf.
  • Condición de especificación de variante (E607): Un publicador puede especificar una variante explícita (instancia) solo si el tipo de publicación define un instances_enum en protobuf.
  • Nombres de temas (E20D, E20F): Los temas deben estar en formato dash-case en minúscula y no superar los 127 caracteres.
  • Unicidad del tema (E314): Los temas deben ser únicos a nivel global en todos los publicadores.
  • Requisitos de capacidad (E406, E407): La capacidad es obligatoria y debe ser un número par >= 2.

Suscriptor

En esta sección, se explica el tipo de mensaje Subscriber.

Gramática EBNF

Subscriber = "{" , { SubscriberElement } , "}" ;

SubscriberElement =
  "message" , ":" , String |
  "topic" , ":" , String
;

Definición de Proto

// Represents a subscriber within a service bundle.
message Subscriber {
  // Required. The type of data being subscribed to.
  string message = 4;
  // Required. Specific topic(s) of the message to subscribe to.
  // Must match the publisher's topic.
  repeated string topic = 6;
}

Ejemplo de uso

subscriber {
  message: "SeatHeating"
  topic: "driver-seat"
}

Explicación

El mensaje Subscriber define un receptor de publicación que proporciona ServiceBundle. Este mensaje especifica el tipo de datos al que se suscribe y los temas específicos de esa publicación. Si hay varios publicadores para un tema, el suscriptor recibe los mensajes publicados por todos ellos.

Limitaciones

  • Existencia del publicador (E504): Para cada suscriptor definido, debe existir al menos un publicador correspondiente que publique el tipo y la variante de publicación especificados.
  • Tipo de suscripción válido (E608): Un suscriptor debe hacer referencia a un tipo que corresponda a un mensaje protobuf existente definido con la anotación SdvPublication.
  • Suscripción de variante válida (E609): Si un suscriptor especifica una variante (instancia), esa variante debe ser un valor válido definido dentro de instances_enum del tipo de publicación protobuf correspondiente.
  • Tema obligatorio (E408): El tema es obligatorio para los suscriptores.
  • Redeclaración de tema (E311): Los temas de suscriptores no se deben redeclarar en el mismo paquete de servicios.

Servidor RPC

En esta sección, se explica el tipo de mensaje de servidor RPC.

Gramática EBNF

Server = "{" , { ServerElement } , "}" ;

ServerElement =
  "service" , ":" , String |
  "channel" , ":" , String |
  "service_unit_name" , ":" , String
;

Definición de Proto

// Represents an RPC server within a service bundle.
message Server {
  // Deprecated. Name of the service unit.
  string service_unit_name = 3 [ deprecated = true ];
  // Required. Name of the RPC service.
  string service = 4;
  // Required. Name of the RPC channel.
  // Must be in lowercase dash-case.
  string channel = 5;
}

Ejemplo de uso

server {
  service: "SetTemperature"
  channel: "temp-setter"
}

Explicación

El mensaje Server define un servidor RPC que proporciona ServiceBundle. Este mensaje especifica el servicio que implementa el servidor y el canal RPC.

Un servidor RPC expone un conjunto de métodos que los clientes pueden invocar de forma remota. El campo service especifica el nombre del servicio RPC que implementa el servidor. Este servicio se define en un archivo proto y se implementa en código Rust personalizado. Los servicios RPC pueden incluir métodos unarios, de transmisión por secuencias del cliente y de transmisión por secuencias del servidor, como se define en la definición del servicio protobuf. El campo channel define el extremo de comunicación y es obligatorio (E409).

Limitaciones

  • Definición de servicio (E603): Un servidor RPC debe especificar un valor service que corresponda a un valor service RPC protobuf existente.
  • Límite de servidor por servicio (E100): Dentro de un solo paquete de servicios, un service RPC específico puede publicarse en, como máximo, una definición de servidor.
  • Nombres de canales (E20E): Los canales RPC deben estar en formato dash-case en minúscula.
  • Canal obligatorio (E409): El canal RPC es obligatorio.
  • Unicidad del canal (E40B): El canal RPC debe ser usado por un solo servicio.

Cliente RPC

En esta sección, se explica el tipo de mensaje de cliente RPC.

Gramática EBNF

Client = "{" , { ClientElement } , "}" ;

ClientElement =
  "service" , ":" , String |
  "channel" , ":" , String
;

Definición de Proto

// Represents an RPC client within a service bundle.
message Client {
  // Required. Name of the RPC service.
  string service = 2;
  // Required. Name of the RPC channel.
  // Must match the server's channel and be in lowercase dash-case.
  string channel = 3;
}

Ejemplo de uso

client {
  service: "SetTemperature"
  channel: "temp-setter"
}

Explicación

client define un cliente RPC que consume ServiceBundle. client especifica el servicio con el que interactúa el cliente y el canal al que se conectará. El cliente puede interactuar con métodos unarios, de transmisión por secuencias del cliente y de transmisión por secuencias del servidor, según la definición del servicio.

Limitaciones

  • Definición de servicio (E60A): Un cliente RPC debe especificar un service que corresponda a una definición service protobuf existente.
  • Fuente de servicio única (E60B): La definición service protobuf a la que hace referencia el service de un cliente RPC debe definirse de forma única (no se define varias veces) en todos los archivos protobuf.
  • Canal obligatorio (E409): El canal RPC es obligatorio.

Configuración de compilación

En esta sección, se explica el tipo de mensaje de configuración de compilación.

Gramática EBNF

BuildConfiguration = "{" , BuildConfigurationElement, "}" ;

BuildConfigurationElement =
  "target_name" , ":" , String |
  "skip_codegen" , ":" , Boolean
;

Definición de Proto

// Defines additional information used to configure build settings
message BuildConfiguration {
  /// Build target name
  optional string target_name = 1;
  // Do not generate code for this service bundle
  optional bool skip_codegen = 2;
}

Ejemplo de uso

build_cfg {
  target_name: "my_custom_target_name"
  skip_codegen: false
}

Explicación

BuildConfiguration configura parámetros no estándar de ServiceBundle para la generación de código. Todas las configuraciones de compilación son opcionales.

  • target_name (string opcional): Especifica el nombre del destino de compilación en los archivos Android.bp. Úsalo para establecer nombres de destino con nombres más cortos que los elegidos automáticamente.
  • skip_codegen (bool opcional): Indica si se debe omitir la generación de código para este paquete de servicios. Si se establece en true, no se genera código para este paquete de servicios en particular. Esto puede ser útil para los paquetes de servicios que se implementan de forma manual. De forma predeterminada, se establece en false.

Limitaciones

  • Formato del nombre de destino (E205, E206, E207, E208): Si se proporciona un nombre de destino de compilación personalizado (build_cfg.target_name), debe seguir estrictamente el formato snake case:
    • Debe contener solo letras minúsculas (a a z), números (0 a 9) y guiones bajos (_).
    • No debe contener guiones bajos consecutivos (__).
    • No debe comenzar con un guion bajo.
    • No debe terminar con un guion bajo.
  • Unicidad del nombre de destino (E301): Un build_cfg.target_name definido por el usuario debe ser único en todo el sistema de compilación y no debe entrar en conflicto con ningún nombre de destino generado automáticamente derivado de otras definiciones de paquetes de servicios.