Specifiche della lingua

Questa pagina specifica il linguaggio di definizione dell'interfaccia di servizio del veicolo (VSIDL) utilizzando la forma Backus-Naur estesa (EBNF) ISO/IEC 14977 e protobuf. Questa pagina si concentra sulla grammatica libera dal contesto del linguaggio e sul significato degli elementi del linguaggio.

Gerarchia delle lingue

Secondo Meta Object Facility (MOF), il compilatore VSIDL (VSIDLC) utilizza le lingue mostrate nella Figura 1:

Lingue VSIDLC

Figura 1. Lingue VSIDLC.

VSIDLC si basa principalmente sul linguaggio del buffer di protocollo (protobuf). Protobuf viene utilizzato per specificare i tipi di dati scambiati tramite la pubblicazione/sottoscrizione e le chiamate di procedura remota (RPC). Da un punto di vista tecnico, i modelli VSIDL sono file TextProto, in cui la sintassi di VSIDL è definita in un file protobuf (syntax.proto). Sia i file protobuf per specificare i tipi di dati sia i modelli VSIDL vengono utilizzati per generare codice Rust. Il codice generato contiene principalmente struct che implementano le strutture di dati per i messaggi scambiati e funzioni Rust che implementano funzioni per la creazione di unità di servizio in Rust, senza chiamare automaticamente queste unità di servizio. Questo codice Rust generato è accompagnato da codice Rust personalizzato che utilizza il codice generato per creare istanze di unità di servizio e implementare la logica di business dell'applicazione.

Sintassi astratta

La Figura 2 mostra i tipi di messaggi principali in VSIDL:

Tipi di messaggi principali in VSIDL

Figura 2. Tipi di messaggi principali in VSIDL.

Voce VSIDL

Questa sezione spiega il tipo di messaggio di voce VSIDL.

Grammatica EBNF

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

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

Esempio di utilizzo

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

service_bundle {
  name: "Manager"

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

Spiegazione

Il messaggio VsidlEntry funge da contenitore principale per il file VSIDL (con estensione .vsidl). Questo messaggio racchiude tutte le definizioni e le configurazioni in un unico file VSIDL. VsidlEntry è l'elemento di primo livello che lega tutto il resto.

Finalità:

  • Definisce la struttura generale di un file VSIDL.
  • Specifica lo spazio dei nomi del pacchetto per tutte le entità all'interno del file.
  • Contiene una raccolta di definizioni di bundle di servizi.
  • Consente estensioni personalizzate al modello VSIDL.
  • Include regole di mappatura per SOME/IP e VHAL.

Vincoli

  • Nome pacchetto (E211): il nome del pacchetto non deve superare i 127 caratteri.
  • File orfani (E10B): tutti i file di un catalogo devono essere inclusi in un Android.bp filegroup.

Pacchetto di servizi

Questa sezione spiega il tipo di messaggio del pacchetto di servizi.

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

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

Esempio di utilizzo

service_bundle {
    name: "SeatController"

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

Spiegazione

Un bundle di servizi definisce un raggruppamento logico di servizi, editori, abbonati, server RPC e client RPC correlati. Un bundle di servizi funge da container per un insieme specifico di funzionalità e le relative interazioni.

Vincoli

  • Requisiti per il nome del bundle (E209, E20A, E20B, E20C):
    • Un pacchetto di servizi deve avere un nome compilato.
    • Il nome deve iniziare con un carattere iniziale di identificatore Unicode valido (in genere una lettera).
    • I caratteri successivi nel nome devono essere caratteri di continuazione validi dell'identificatore Unicode (in genere lettere o numeri).
    • Il nome non deve essere una parola chiave riservata in Rust, Java o C++.
  • Unicità del bundle globale (E309): ogni bundle di servizi deve avere un nome completo univoco (in base al pacchetto e al nome).
  • Unicità interna (E100, E300, E302, E303, E308):
    • All'interno di un singolo bundle di servizi, ogni servizio RPC può essere gestito da al massimo una definizione di server.
    • All'interno di un singolo pacchetto di servizi, ogni tipo di pubblicazione MULTI_PUB può essere pubblicato da al massimo una definizione di editore.
    • All'interno di un singolo bundle di servizi, tutti i nomi delle unità di servizio definite dall'utente (per publisher o server) devono essere univoci.
    • All'interno di un singolo pacchetto di servizi, tutti i nomi delle unità di servizio (definiti dall'utente o generati automaticamente) devono essere univoci.
  • Convenzioni di denominazione dei target di build (E205, E206, E207, E208): se viene fornito un nome di target di build personalizzato (build_cfg.target_name), deve rispettare il formato snake case (lettere minuscole, numeri e singoli trattini bassi, senza iniziare o terminare con un trattino basso).
  • Crea un nome di target univoco (E301): un nome di target di build definito dall'utente non deve entrare in conflitto con i nomi di target generati automaticamente per altri bundle di servizi.

Publisher

Questa sezione descrive il tipo di messaggio dell'editore.

Grammatica EBNF

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

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

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

Esempio di utilizzo

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

Spiegazione

Il tipo di messaggio Publisher definisce un'origine dati che ServiceBundle fornisce. Questo tipo di messaggio specifica il tipo di dati pubblicati e gli argomenti e la capacità specifici di questi dati.

Argomenti

Ogni istanza Publisher ha un campo message che fa riferimento al messaggio proto che viene pubblicato. Deve specificare un argomento (rappresentato da topic) e una capacità (rappresentata da capacity).

  • Argomento: un identificatore univoco per l'argomento della pubblicazione. Deve seguire il formato con trattino e lettere minuscole (ad esempio, my-topic).
  • Capacità:specifica le dimensioni della coda, ovvero il numero di messaggi che la coda può contenere prima che i messaggi non letti vengano eliminati. Deve essere un numero pari maggiore o uguale a 2.

Nomi definiti dall'utente

I publisher possono avere nomi di unità di servizio definiti dall'utente che sostituiscono i nomi di unità di servizio scelti automaticamente. Questa funzionalità consente di scegliere nomi più brevi. Se un publisher utilizza un nome di unità di servizio definito dall'utente, potrebbe utilizzare una sola istanza, in modo che il nome dell'unità di servizio venga assegnato in modo univoco a un'istanza.

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

Vincoli

  • Posizionamento del publisher (E300): i publisher per lo stesso tipo MULTI_PUB devono essere definiti in bundle di servizi separati.
  • Unicità del nome locale (E302): all'interno di un singolo bundle di servizi, tutti gli editori devono avere nomi di unità di servizio univoci definiti dall'utente.
  • Unicità del nome globale (E304): gli editori dello stesso tipo di pubblicazione devono avere nomi di unità di servizio definiti dall'utente univoci a livello globale in tutti i bundle di servizi.
  • Denominazione di singoli canali (E306): i nomi delle unità di servizio definite dall'utente possono essere assegnati solo agli editori che gestiscono esattamente un'istanza.
  • Limite per singolo publisher (E307): un messaggio protobuf contrassegnato come SINGLE_PUB può essere pubblicato da un solo publisher nell'intero sistema.
  • Unicità del nome dell'unità di servizio (E308): tutti i nomi delle unità di servizio (generati o definiti dall'utente) devono essere univoci all'interno del bundle di servizi; i nomi definiti dall'utente devono essere utilizzati per risolvere i conflitti con i nomi generati.
  • Requisito di specifica della variante (E501): quando un publisher utilizza un nome definito dall'utente per un tipo con più varianti, deve specificare esplicitamente la variante che pubblica.
  • Esistenza dell'editore per gli abbonati (E504): ogni abbonato definito richiede almeno un editore corrispondente per il tipo e la variante specificati.
  • Tipo di publisher valido (E601): un publisher deve fare riferimento a un tipo che corrisponde a un messaggio protobuf esistente.
  • Requisito di annotazione della pubblicazione (E602): il tipo di messaggio protobuf a cui fa riferimento un publisher deve includere l'annotazione SdvPublication.
  • Utilizzo valido della variante (E606): se un editore specifica una variante (istanza), questa deve esistere all'interno di instances_enum definito per il tipo di pubblicazione in protobuf.
  • Condizione di specifica della variante (E607): un editore può specificare una variante (istanza) esplicita solo se il tipo di pubblicazione definisce un instances_enum in protobuf.
  • Denominazione degli argomenti (E20D, E20F): gli argomenti devono essere in formato dash-case minuscolo e non superare i 127 caratteri.
  • Unicità dell'argomento (E314): gli argomenti devono essere univoci a livello globale per tutti i publisher.
  • Requisiti di capacità (E406, E407): la capacità è obbligatoria e deve essere un numero pari >= 2.

Sottoscrittore

Questa sezione descrive il tipo di messaggio Abbonato.

Grammatica EBNF

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

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

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

Esempio di utilizzo

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

Spiegazione

Il messaggio Subscriber definisce un destinatario della pubblicazione fornito da ServiceBundle. Questo messaggio specifica il tipo di dati a cui è stato effettuato l'abbonamento e gli argomenti specifici della pubblicazione. Se ci sono più editori per un argomento, l'abbonato riceve i messaggi pubblicati da tutti.

Vincoli

  • Esistenza editore (E504): per ogni abbonato definito, deve esistere almeno un editore corrispondente che pubblica il tipo e la variante di pubblicazione specificati.
  • Tipo di abbonamento valido (E608): un abbonato deve fare riferimento a un tipo che corrisponde a un messaggio protobuf esistente definito con l'annotazione SdvPublication.
  • Abbonamento a una variante valido (E609): se un abbonato specifica una variante (istanza), questa deve essere un valore valido definito all'interno di instances_enum del tipo di pubblicazione protobuf corrispondente.
  • Argomento obbligatorio (E408): l'argomento è obbligatorio per gli abbonati.
  • Dichiarazione di nuovo dell'argomento (E311): gli argomenti degli abbonati non devono essere dichiarati di nuovo nello stesso pacchetto di servizi.

Server RPC

Questa sezione spiega il tipo di messaggio del server RPC.

Grammatica EBNF

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

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

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

Esempio di utilizzo

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

Spiegazione

Il messaggio Server definisce un server RPC fornito da ServiceBundle. Questo messaggio specifica il servizio implementato dal server e il canale RPC.

Un server RPC espone un insieme di metodi che i client possono richiamare da remoto. Il campo service specifica il nome del servizio RPC implementato dal server. Questo servizio è definito in un file proto e implementato in codice Rust personalizzato. I servizi RPC possono includere metodi unari, di streaming dal client e di streaming dal server, come definito nella definizione del servizio protobuf. Il campo channel definisce l'endpoint di comunicazione ed è obbligatorio (E409).

Vincoli

  • Definizione del servizio (E603): un server RPC deve specificare un valore service che corrisponda a un valore service RPC protobuf esistente.
  • Limite di server per servizio (E100): all'interno di un singolo bundle di servizi, una RPC specifica service può essere gestita da al massimo una definizione di server.
  • Denominazione dei canali (E20E): i canali RPC devono essere in formato dash-case minuscolo.
  • Canale obbligatorio (E409): il canale RPC è obbligatorio.
  • Unicità del canale (E40B): il canale RPC deve essere utilizzato da un solo servizio.

Client RPC

Questa sezione spiega il tipo di messaggio del client RPC.

Grammatica EBNF

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

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

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

Esempio di utilizzo

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

Spiegazione

client definisce un client RPC che ServiceBundle utilizza. client specifica il servizio con cui interagisce il client e il canale a cui connettersi. Il client può interagire con i metodi di streaming unari, client e server, a seconda della definizione del servizio.

Vincoli

  • Definizione del servizio (E60A): un client RPC deve specificare un service che corrisponde a una definizione service protobuf esistente.
  • Origine del servizio univoca (E60B): la definizione protobuf service a cui fa riferimento service di un client RPC deve essere definita in modo univoco (non più volte) in tutti i file protobuf.
  • Canale obbligatorio (E409): il canale RPC è obbligatorio.

Configurazione build

Questa sezione descrive il tipo di messaggio di configurazione della build.

Grammatica EBNF

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

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

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

Esempio di utilizzo

build_cfg {
  target_name: "my_custom_target_name"
  skip_codegen: false
}

Spiegazione

BuildConfiguration configura i parametri non standard di ServiceBundle per la generazione di codice. Tutte le configurazioni di build sono facoltative.

  • target_name (facoltativo string): specifica il nome del target di build nei file Android.bp. Utilizza questa opzione per impostare nomi di destinazione più brevi rispetto a quelli scelti automaticamente.
  • skip_codegen (facoltativo bool): indica se la generazione del codice deve essere ignorata per questo pacchetto di servizi. Se impostato su true, non viene generato alcun codice per questo particolare pacchetto di servizi. Questa opzione può essere utile per i pacchetti di servizi implementati manualmente. Per impostazione predefinita, questo valore è impostato su false.

Vincoli

  • Formato del nome del target (E205, E206, E207, E208): se viene fornito un nome di target di build personalizzato (build_cfg.target_name), deve seguire rigorosamente la formattazione snake case:
    • Deve contenere solo lettere minuscole (da a a z), numeri (da 0 a 9) e trattini bassi (_).
    • Non deve contenere trattini bassi consecutivi (__).
    • Non deve iniziare con un trattino basso.
    • Non deve terminare con un trattino basso.
  • Unicità del nome target (E301): un build_cfg.target_name definito dall'utente deve essere univoco in tutto il sistema di compilazione e non deve entrare in conflitto con i nomi target generati automaticamente derivati da altre definizioni di bundle di servizi.