Especificação de idioma

Esta página especifica a linguagem de definição de interface de serviço de veículo (VSIDL) usando a forma de Backus-Naur estendida (EBNF) ISO/IEC 14977 e protobuf. Esta página se concentra na gramática livre de contexto da linguagem e no significado dos elementos dela.

Hierarquia de idiomas

De acordo com a Meta Object Facility (MOF), o compilador VSIDL (VSIDLC) usa as linguagens mostradas na Figura 1:

Idiomas do VSIDLC

Figura 1. Idiomas do VSIDLC.

O VSIDLC é baseado principalmente na linguagem de buffer de protocolo (protobuf). O Protobuf é usado para especificar os tipos de dados trocados usando publicação/assinatura e chamadas de procedimento remoto (RPCs). Do ponto de vista técnico, os modelos VSIDL são arquivos TextProto, em que a sintaxe do VSIDL é definida em um arquivo protobuf (syntax.proto). Os arquivos protobuf para especificar tipos de dados e os modelos VSIDL são usados para gerar código Rust. O código gerado contém principalmente structs que implementam as estruturas de dados para as mensagens trocadas e funções do Rust que implementam funções para criar unidades de serviço em Rust, sem chamar essas unidades de serviço automaticamente. Esse código Rust gerado é acompanhado de um código Rust personalizado que usa o código gerado para instanciar unidades de serviço e implementar a lógica de negócios do aplicativo.

Sintaxe abstrata

A Figura 2 mostra os principais tipos de mensagens em VSIDL:

Principais tipos de mensagens em VSIDL

Figura 2. Tipos de mensagens principais em VSIDL.

Entrada VSIDL

Esta seção explica o tipo de mensagem de entrada do VSIDL.

Gramática EBNF

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

Definição 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;
}

Exemplo de uso

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

service_bundle {
  name: "Manager"

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

Explicação

A mensagem VsidlEntry serve como o contêiner raiz do arquivo VSIDL (com a extensão .vsidl). Essa mensagem encapsula todas as definições e configurações em um único arquivo VSIDL. O VsidlEntry é o elemento de nível superior que vincula todo o resto.

Finalidade:

  • Define a estrutura geral de um arquivo VSIDL.
  • Especifica o namespace do pacote para todas as entidades no arquivo.
  • Contém uma coleção de definições de pacote de serviços.
  • Permite extensões personalizadas ao modelo VSIDL.
  • Inclui regras de mapeamento para SOME/IP e VHAL.

Restrições

  • Nome do pacote (E211): o nome do pacote não pode exceder 127 caracteres.
  • Arquivos soltos (E10B): todos os arquivos em um catálogo precisam ser referenciados em um grupo de arquivos Android.bp.

Pacote de serviços

Esta seção explica o tipo de mensagem do pacote de serviços.

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
;

Definição 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;
}

Exemplo de uso

service_bundle {
    name: "SeatController"

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

Explicação

Um pacote de serviços define um agrupamento lógico de serviços, editores, assinantes, servidores RPC e clientes RPC relacionados. Um pacote de serviços funciona como um contêiner para um conjunto específico de funcionalidades e interações.

Restrições

  • Requisitos para nome do pacote (E209, E20A, E20B, E20C):
    • Um pacote de serviços precisa ter um nome preenchido.
    • O nome precisa começar com um caractere inicial de identificador Unicode válido (normalmente uma letra).
    • Os caracteres subsequentes no nome precisam ser caracteres de continuação de identificador Unicode válidos (normalmente letras ou números).
    • O nome não pode ser uma palavra-chave reservada em Rust, Java ou C++.
  • Unicidade global do pacote (E309): cada pacote de serviços precisa ter um nome totalmente qualificado exclusivo (com base no pacote e no nome).
  • Unicidade interna (E100, E300, E302, E303, E308):
    • Em um único pacote de serviços, cada serviço RPC pode ser veiculado por no máximo uma definição de servidor.
    • Em um único pacote de serviços, cada tipo de publicação MULTI_PUB pode ser publicado por no máximo uma definição de editor.
    • Em um único pacote de serviços, todos os nomes de unidades de serviço definidos pelo usuário (para editores ou servidores) precisam ser exclusivos.
    • Em um único pacote de serviços, todos os nomes de unidades de serviço (definidos pelo usuário ou gerados automaticamente) precisam ser exclusivos.
  • Convenções de nomenclatura de destino de build (E205, E206, E207, E208): se um nome de destino de build personalizado (build_cfg.target_name) for fornecido, ele precisará seguir o formato snake case (letras minúsculas, números e sublinhados únicos, sem começar ou terminar com um sublinhado).
  • Unicidade do nome da build target (E301): um nome de build target definido pelo usuário não pode entrar em conflito com nenhum nome de destino gerado automaticamente para outros pacotes de serviços.

Editor

Esta seção explica o tipo de mensagem do publisher.

Gramática EBNF

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

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

Definição 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;
}

Exemplo de uso

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

Explicação

O tipo de mensagem Publisher define uma fonte de dados que o ServiceBundle fornece. Esse tipo de mensagem especifica o tipo de dados que estão sendo publicados e os tópicos e a capacidade específicos desses dados.

Tópicos

Cada instância Publisher tem um campo message que se refere à mensagem proto publicada. Ele precisa especificar um tópico (representado por topic) e uma capacidade (representada por capacity).

  • Tema:um identificador exclusivo do tema da publicação. Ele precisa seguir o formato minúsculo com traços (por exemplo, my-topic).
  • Capacidade:especifica o tamanho da fila, ou seja, quantas mensagens ela pode armazenar antes que as mensagens não lidas sejam descartadas. Precisa ser um número par maior ou igual a 2.

Nomes definidos pelo usuário

Os editores podem ter nomes de unidade de serviço definidos pelo usuário que substituem os nomes escolhidos automaticamente. Isso permite escolher nomes mais curtos. Se um publisher usar um nome de unidade de serviço definido pelo usuário, ele poderá usar apenas uma instância para que o nome da unidade de serviço seja atribuído exclusivamente a uma instância.

# 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"
}

Restrições

  • Posicionamento do editor (E300): os editores do mesmo tipo MULTI_PUB precisam ser definidos em pacotes de serviços separados.
  • Exclusividade do nome local (E302): em um único pacote de serviços, todos os editores precisam ter nomes de unidades de serviço exclusivos definidos pelo usuário.
  • Unicidade global de nomes (E304): os editores do mesmo tipo de publicação precisam ter nomes de unidades de serviço definidos pelo usuário globalmente exclusivos em todos os pacotes de serviços.
  • Nomeação de canais únicos (E306): os nomes de unidades de serviço definidos pelo usuário só podem ser atribuídos a editores que processam exatamente uma instância.
  • Limite de um único editor (E307): uma mensagem protobuf marcada como SINGLE_PUB só pode ser publicada por um editor em todo o sistema.
  • Exclusividade do nome da unidade de serviço (E308): todos os nomes de unidades de serviço (gerados ou definidos pelo usuário) precisam ser exclusivos no pacote de serviços. Os nomes definidos pelo usuário devem ser usados para resolver conflitos com nomes gerados.
  • Requisito de especificação de variante (E501): quando um editor usa um nome definido pelo usuário para um tipo com várias variantes, ele precisa especificar explicitamente a variante que publica.
  • Existência do editor para assinantes (E504): cada assinante definido exige pelo menos um editor correspondente para o tipo e a variante especificados.
  • Tipo de editor válido (E601): um editor precisa fazer referência a um tipo que corresponda a uma mensagem protobuf existente.
  • Requisito de anotação de publicação (E602): o tipo de mensagem protobuf referenciado por um publisher precisa incluir a anotação SdvPublication.
  • Uso válido de variantes (E606): se um publisher especificar uma variante (instância), ela precisará existir no instances_enum definido para o tipo de publicação em protobuf.
  • Condição de especificação da variante (E607): um editor só pode especificar uma variante explícita (instância) se o tipo de publicação definir um instances_enum em protobuf.
  • Nomenclatura de tópicos (E20D, E20F): os tópicos precisam estar em minúsculas com traços e não podem exceder 127 caracteres.
  • Exclusividade do tema (E314): os temas precisam ser globalmente exclusivos em todos os editores.
  • Requisitos de capacidade (E406, E407): a capacidade é obrigatória e precisa ser um número par >= 2.

Assinante

Esta seção explica o tipo de mensagem "Subscriber".

Gramática EBNF

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

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

Definição 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;
}

Exemplo de uso

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

Explicação

A mensagem Subscriber define um receptor de publicação que o ServiceBundle fornece. Essa mensagem especifica o tipo de dados a que o usuário está se inscrevendo e os tópicos específicos da publicação. Se houver vários editores para um tópico, o assinante vai receber as mensagens publicadas por todos eles.

Restrições

  • Existência do editor (E504): para cada assinante definido, é necessário que exista pelo menos um editor correspondente que publique o tipo e a variante de publicação especificados.
  • Tipo de assinatura válido (E608): um assinante precisa fazer referência a um tipo que corresponde a uma mensagem protobuf definida com a anotação SdvPublication.
  • Assinatura de variante válida (E609): se um assinante especificar uma variante (instância), ela precisará ser um valor válido definido em instances_enum do tipo de publicação protobuf correspondente.
  • Tópico obrigatório (E408): o tópico é obrigatório para os assinantes.
  • Redeclaração de tópico (E311): os tópicos do assinante não podem ser redeclarados no mesmo pacote de serviços.

Servidor RPC

Esta seção explica o tipo de mensagem do servidor RPC.

Gramática EBNF

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

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

Definição 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;
}

Exemplo de uso

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

Explicação

A mensagem Server define um servidor RPC que o ServiceBundle fornece. Essa mensagem especifica o serviço que o servidor implementa e o canal RPC.

Um servidor RPC expõe um conjunto de métodos que os clientes podem invocar remotamente. O campo service especifica o nome do serviço RPC que o servidor implementa. Esse serviço é definido em um arquivo proto e implementado em código Rust personalizado. Os serviços RPC podem incluir métodos unários, de streaming do cliente e de streaming do servidor, conforme definido na definição de serviço do protobuf. O campo channel define o endpoint de comunicação e é obrigatório (E409).

Restrições

  • Definição de serviço (E603): um servidor RPC precisa especificar um valor service que corresponda a um valor service RPC protobuf existente.
  • Limite de servidor por serviço (E100): em um único pacote de serviços, uma RPC service específica pode ser atendida por no máximo uma definição de servidor.
  • Nomenclatura de canais (E20E): os canais RPC precisam estar em letras minúsculas e separados por traços.
  • Canal obrigatório (E409): o canal RPC é obrigatório.
  • Unicidade do canal (E40B): o canal RPC só pode ser usado por um serviço.

Cliente RPC

Esta seção explica o tipo de mensagem do cliente RPC.

Gramática EBNF

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

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

Definição 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;
}

Exemplo de uso

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

Explicação

client define um cliente RPC que ServiceBundle consome. client especifica o serviço com que o cliente interage e o canal a que se conectar. O cliente pode interagir com métodos unários, de streaming do cliente e de streaming do servidor, dependendo da definição do serviço.

Restrições

  • Definição de serviço (E60A): um cliente RPC precisa especificar um service que corresponda a uma definição de service protobuf existente.
  • Origem de serviço única (E60B): a definição de service protobuf referenciada pelo service de um cliente RPC precisa ser definida de forma exclusiva (não várias vezes) em todos os arquivos protobuf.
  • Canal obrigatório (E409): o canal RPC é obrigatório.

Configuração do build

Esta seção explica o tipo de mensagem de configuração do build.

Gramática EBNF

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

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

Definição 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;
}

Exemplo de uso

build_cfg {
  target_name: "my_custom_target_name"
  skip_codegen: false
}

Explicação

BuildConfiguration configura parâmetros não padrão de ServiceBundle para geração de código. Todas as configurações de build são opcionais.

  • target_name (opcional string): especifica o nome do destino de build nos arquivos Android.bp. Use isso para definir nomes de destino mais curtos do que os escolhidos automaticamente.
  • skip_codegen (opcional bool): indica se a geração de código precisa ser ignorada para este pacote de serviços. Se definido como true, nenhum código será gerado para esse pacote de serviços específico. Isso pode ser útil para pacotes de serviços implementados manualmente. Por padrão, essa opção é definida como false.

Restrições

  • Formato do nome da segmentação (E205, E206, E207, E208): se um nome de segmentação de build personalizado (build_cfg.target_name) for fornecido, ele precisará seguir estritamente a formatação snake_case:
    • Ele precisa conter apenas letras minúsculas (de a a z), números (de 0 a 9) e sublinhados (_).
    • Não pode conter sublinhados consecutivos (__).
    • Não pode começar com um sublinhado.
    • Não pode terminar com um sublinhado.
  • Unicidade do nome de destino (E301): um build_cfg.target_name definido pelo usuário precisa ser exclusivo em todo o sistema de build e não pode entrar em conflito com nenhum nome de destino gerado automaticamente derivado de outras definições de pacote de serviços.