Ta strona określa język definicji interfejsu usługi pojazdu (VSIDL) przy użyciu rozszerzonej formy Backusa-Naura (EBNF) ISO/IEC 14977 i protobuf. Ta strona koncentruje się na gramatyce języka niezależnej od kontekstu oraz na znaczeniu elementów języka.
Hierarchia języka
Zgodnie z Meta Object Facility (MOF) kompilator VSIDL (VSIDLC) używa języków pokazanych na rysunku 1:
Rysunek 1. Języki VSIDLC.
VSIDLC opiera się głównie na języku bufora protokołu (protobuf). Protobuf służy do określania typów danych, które są wymieniane za pomocą wywołań publikowania-subskrybowania i zdalnych wywołań procedur (RPC). Z technicznego punktu widzenia modele VSIDL to pliki TextProto, w których składnia VSIDL jest zdefiniowana w pliku protobuf (syntax.proto). Zarówno pliki protobuf do określania typów danych, jak i modele VSIDL służą do generowania kodu Rust. Wygenerowany kod zawiera głównie struktury, które implementują struktury danych dla wymienianych wiadomości, oraz funkcje Rust, które implementują funkcje tworzenia jednostek usług w Rust bez automatycznego wywoływania tych jednostek. Wygenerowany kod Rust jest uzupełniany niestandardowym kodem Rust, który używa wygenerowanego kodu do tworzenia instancji jednostek usług i implementowania logiki biznesowej aplikacji.
Składnia abstrakcyjna
Na rysunku 2 przedstawiono podstawowe typy wiadomości w VSIDL:
Rysunek 2. Podstawowe typy wiadomości w VSIDL.
Wpis VSIDL
W tej sekcji opisujemy typ wiadomości wpisu VSIDL.
Gramatyka EBNF
start VsidlEntry =
"package" , ":" , String , ";" ,
{ "service_bundle" , ServiceBundle } ,
{ "extension" , ":" , Any } ,
{ "some_ip_mapping" , ":" , SomeIpMapping } ,
{ "vhal_mapping" , ":" , VhalMapping }
;
Definicja 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;
}
Przykład zastosowania
package: "com.android.sdv.sample.vsidl"
service_bundle {
name: "Manager"
publisher {
message: "TirePressure"
topic: "front-left"
topic: "front-right"
capacity: 10
}
}
Wyjaśnienie
Wiadomość VsidlEntry służy jako kontener główny pliku VSIDL (z rozszerzeniem .vsidl). Ta wiadomość zawiera wszystkie definicje i konfiguracje w jednym pliku VSIDL. VsidlEntry to element najwyższego poziomu, który wiąże ze sobą wszystkie inne elementy.
Cel:
- Określa ogólną strukturę pliku VSIDL.
- Określa przestrzeń nazw pakietu dla wszystkich jednostek w pliku.
- Zawiera zbiór definicji pakietów usług.
- Umożliwia niestandardowe rozszerzenia modelu VSIDL.
- Zawiera reguły mapowania dla SOME/IP i VHAL.
Ograniczenia
- Nazwa pakietu (E211): nazwa pakietu nie może przekraczać 127 znaków.
- Pliki bez odniesień (E10B): wszystkie pliki w katalogu muszą być przywoływane w grupie plików
Android.bp.
Pakiet usług
W tej sekcji opisujemy typ wiadomości pakietu usług.
Gramatyka 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
;
Definicja 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;
}
Przykład zastosowania
service_bundle {
name: "SeatController"
publisher {
message: "SeatHeating"
topic: "driver-seat"
capacity: 10
}
}
Wyjaśnienie
Pakiet usług definiuje logiczne grupowanie powiązanych usług, wydawców, subskrybentów, serwerów RPC i klientów RPC. Pakiet usług pełni rolę kontenera dla określonego zestawu funkcji i ich interakcji.
Ograniczenia
- Wymagania dotyczące nazwy pakietu (E209, E20A, E20B, E20C):
- Pakiet usług musi mieć wypełnioną nazwę.
- Nazwa musi zaczynać się od prawidłowego znaku Unicode, który może rozpoczynać identyfikator (zwykle litery).
- Kolejne znaki w nazwie muszą być prawidłowymi znakami Unicode, które mogą występować w identyfikatorze (zwykle litery lub cyfry).
- Nazwa nie może być słowem zastrzeżonym w języku Rust, Java ani C++.
- Globalna unikalność pakietu (E309): każdy pakiet usług musi mieć unikalną pełną i jednoznaczną nazwę (na podstawie pakietu i nazwy).
- Unikalność wewnętrzna (E100, E300, E302, E303, E308):
- W ramach jednego pakietu usług każda usługa RPC może być obsługiwana przez co najwyżej 1 definicję serwera.
- W ramach jednego pakietu usług każdy typ publikacji
MULTI_PUBmoże być publikowany przez co najwyżej 1 definicję wydawcy. - W ramach jednego pakietu usług wszystkie nazwy jednostek usług zdefiniowane przez użytkownika (dla wydawców lub serwerów) muszą być unikalne.
- W ramach jednego pakietu usług wszystkie nazwy jednostek usług (zdefiniowane przez użytkownika lub wygenerowane automatycznie) muszą być unikalne.
- Konwencje nazewnictwa celu kompilacji (E205, E206, E207, E208): jeśli podano niestandardową nazwę celu kompilacji (
build_cfg.target_name), musi ona być zgodna z formatem snake case (małe litery, cyfry i pojedyncze podkreślenia, nie zaczynające się ani nie kończące podkreśleniem). - Unikalność nazwy celu kompilacji (E301): nazwa celu kompilacji zdefiniowana przez użytkownika nie może kolidować z żadnymi nazwami celów wygenerowanymi automatycznie dla innych pakietów usług.
Wydawca
W tej sekcji opisujemy typ wiadomości wydawcy.
Gramatyka EBNF
Publisher = "{" , { PublisherElement } , "}" ;
PublisherElement =
"message" , ":" , String |
"topic" , ":" , String |
"capacity" , ":" , Integer |
"service_unit_name" , ":" , String
;
Definicja 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;
}
Przykład zastosowania
publisher {
message: "SeatHeating"
topic: "driver-heating"
capacity: 10
}
Wyjaśnienie
Typ wiadomości Publisher definiuje źródło danych, które udostępnia ServiceBundle. Ten typ wiadomości określa typ publikowanych danych oraz konkretne tematy i pojemność tych danych.
Tematy
Każda instancja Publisher ma pole message, które odnosi się do publikowanej wiadomości proto. Musi określać temat (reprezentowany przez topic) i pojemność (reprezentowaną przez capacity).
- Temat: unikalny identyfikator tematu publikacji. Musi być zgodny z formatem lowercase dash-case (np.
my-topic). - Pojemność: określa rozmiar kolejki, czyli liczbę wiadomości, które mogą się w niej znajdować, zanim nieprzeczytane wiadomości zostaną odrzucone. Musi to być liczba parzysta większa lub równa 2.
Nazwy zdefiniowane przez użytkownika
Wydawcy mogą mieć nazwy jednostek usług zdefiniowane przez użytkownika, które zastępują nazwy jednostek usług wybrane automatycznie. Umożliwia to wybieranie krótszych nazw. Jeśli wydawca używa nazwy jednostki usługi zdefiniowanej przez użytkownika, może używać tylko jednej instancji, tak aby nazwa jednostki usługi była jednoznacznie przypisana do jednej instancji.
# 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"
}
Ograniczenia
- Umieszczenie wydawcy (E300): wydawcy tego samego typu
MULTI_PUBmuszą być zdefiniowani w osobnych pakietach usług. - Unikalność nazwy lokalnej (E302): w ramach jednego pakietu usług wszyscy wydawcy muszą mieć unikalne nazwy jednostek usług zdefiniowane przez użytkownika.
- Unikalność nazwy globalnej (E304): wydawcy tego samego typu publikacji muszą mieć globalnie unikalne nazwy jednostek usług zdefiniowane przez użytkownika we wszystkich pakietach usług.
- Nazewnictwo pojedynczych kanałów (E306): nazwy jednostek usług zdefiniowane przez użytkownika można przypisywać tylko do wydawców, którzy obsługują dokładnie 1 instancję.
- Limit pojedynczego wydawcy (E307): wiadomość protobuf oznaczona jako
SINGLE_PUBmoże być publikowana tylko przez 1 wydawcę w całym systemie. - Unikalność nazwy jednostki usługi (E308): wszystkie nazwy jednostek usług (wygenerowane lub zdefiniowane przez użytkownika) muszą być unikalne w ramach pakietu usług. Nazwy zdefiniowane przez użytkownika powinny być używane do rozwiązywania konfliktów z nazwami wygenerowanymi.
- Wymaganie dotyczące specyfikacji wariantu (E501): gdy wydawca używa nazwy zdefiniowanej przez użytkownika dla typu z wieloma wariantami, musi wyraźnie określić wariant, który publikuje.
- Istnienie wydawcy dla subskrybentów (E504): każdy zdefiniowany subskrybent wymaga co najmniej 1 odpowiedniego wydawcy dla określonego typu i wariantu.
- Prawidłowy typ wydawcy (E601): wydawca musi odwoływać się do typu, który odpowiada istniejącej wiadomości protobuf.
- Wymaganie dotyczące adnotacji publikacji (E602): typ wiadomości protobuf, do którego odwołuje się wydawca, musi zawierać adnotację
SdvPublication. - Prawidłowe użycie wariantu (E606): jeśli wydawca określa wariant (instancję), ten wariant musi istnieć w
instances_enumzdefiniowanym dla typu publikacji w protobuf. - Warunek specyfikacji wariantu (E607): wydawca może określić wyraźny wariant (instancję) tylko wtedy, gdy typ publikacji definiuje
instances_enumw protobuf. - Nazewnictwo tematów (E20D, E20F): tematy muszą być w formacie lowercase dash-case i nie mogą przekraczać 127 znaków.
- Unikalność tematu (E314): tematy muszą być globalnie unikalne we wszystkich wydawcach.
- Wymagania dotyczące pojemności (E406, E407): pojemność jest obowiązkowa i musi być liczbą parzystą >= 2.
Subskrybent
W tej sekcji opisujemy typ wiadomości subskrybenta.
Gramatyka EBNF
Subscriber = "{" , { SubscriberElement } , "}" ;
SubscriberElement =
"message" , ":" , String |
"topic" , ":" , String
;
Definicja 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;
}
Przykład zastosowania
subscriber {
message: "SeatHeating"
topic: "driver-seat"
}
Wyjaśnienie
Wiadomość Subscriber definiuje odbiorcę publikacji, którego udostępnia ServiceBundle. Ta wiadomość określa typ danych, które są subskrybowane, oraz konkretne tematy tej publikacji. Jeśli temat ma wielu wydawców, subskrybent otrzymuje wiadomości publikowane przez wszystkich z nich.
Ograniczenia
- Istnienie wydawcy (E504): dla każdego zdefiniowanego subskrybenta musi istnieć co najmniej 1 odpowiedni wydawca, który publikuje określony typ i wariant publikacji.
- Prawidłowy typ subskrypcji (E608): subskrybent musi odwoływać się do typu, który odpowiada istniejącej wiadomości protobuf zdefiniowanej za pomocą adnotacji
SdvPublication. - Prawidłowa subskrypcja wariantu (E609): jeśli subskrybent określa wariant (instancję), ten wariant musi być prawidłową wartością zdefiniowaną w
instances_enumodpowiedniego typu publikacji protobuf. - Temat obowiązkowy (E408): temat jest obowiązkowy dla subskrybentów.
- Ponowne deklarowanie tematu (E311): tematy subskrybentów nie powinny być ponownie deklarowane w tym samym pakiecie usług.
Serwer RPC
W tej sekcji opisujemy typ wiadomości serwera RPC.
Gramatyka EBNF
Server = "{" , { ServerElement } , "}" ;
ServerElement =
"service" , ":" , String |
"channel" , ":" , String |
"service_unit_name" , ":" , String
;
Definicja 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;
}
Przykład zastosowania
server {
service: "SetTemperature"
channel: "temp-setter"
}
Wyjaśnienie
Wiadomość Server definiuje serwer RPC, który udostępnia ServiceBundle. Ta wiadomość określa usługę, którą implementuje serwer, oraz kanał RPC.
Serwer RPC udostępnia zestaw metod, które klienci mogą wywoływać zdalnie. Pole service określa nazwę usługi RPC, którą implementuje serwer. Ta usługa jest zdefiniowana w pliku proto i zaimplementowana w niestandardowym kodzie Rust. Usługi RPC mogą obejmować metody jednoargumentowe, metody przesyłania strumieniowego po stronie klienta i metody przesyłania strumieniowego po stronie serwera, zgodnie z definicją usługi protobuf. Pole channel definiuje punkt końcowy komunikacji i jest obowiązkowe (E409).
Ograniczenia
- Definicja usługi (E603): serwer RPC musi określać wartość
service, która odpowiada istniejącej wartościserviceRPC protobuf. - Limit serwerów na usługę (E100): w ramach jednego pakietu usług określona usługa RPC
servicemoże być obsługiwana przez co najwyżej 1 definicję serwera. - Nazewnictwo kanałów (E20E): kanały RPC muszą być w formacie lowercase dash-case.
- Kanał obowiązkowy (E409): kanał RPC jest obowiązkowy.
- Unikalność kanału (E40B): kanał RPC może być używany tylko przez 1 usługę.
Klient RPC
W tej sekcji opisujemy typ wiadomości klienta RPC.
Gramatyka EBNF
Client = "{" , { ClientElement } , "}" ;
ClientElement =
"service" , ":" , String |
"channel" , ":" , String
;
Definicja 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;
}
Przykład zastosowania
client {
service: "SetTemperature"
channel: "temp-setter"
}
Wyjaśnienie
client definiuje klienta RPC, który korzysta z ServiceBundle. client określa usługę, z którą klient wchodzi w interakcję, oraz kanał, z którym ma się połączyć. W zależności od definicji usługi klient może wchodzić w interakcję z metodami jednoargumentowymi, metodami przesyłania strumieniowego po stronie klienta i metodami przesyłania strumieniowego po stronie serwera.
Ograniczenia
- Definicja usługi (E60A): klient RPC musi określać
service, która odpowiada istniejącej definicjiserviceprotobuf. - Unikalne źródło usługi (E60B): definicja
serviceprotobuf, do której odwołuje sięserviceklienta RPC, musi być zdefiniowana w sposób unikalny (nie może być zdefiniowana wielokrotnie) we wszystkich plikach protobuf. - Kanał obowiązkowy (E409): kanał RPC jest obowiązkowy.
Konfiguracja kompilacji
W tej sekcji opisujemy typ wiadomości konfiguracji kompilacji.
Gramatyka EBNF
BuildConfiguration = "{" , BuildConfigurationElement, "}" ;
BuildConfigurationElement =
"target_name" , ":" , String |
"skip_codegen" , ":" , Boolean
;
Definicja 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;
}
Przykład zastosowania
build_cfg {
target_name: "my_custom_target_name"
skip_codegen: false
}
Wyjaśnienie
BuildConfiguration konfiguruje niestandardowe parametry ServiceBundle na potrzeby generowania kodu. Wszystkie konfiguracje kompilacji są opcjonalne.
target_name(opcjonalnystring): określa nazwę celu kompilacji w plikachAndroid.bp. Użyj tej opcji, aby ustawić nazwy celów krótsze niż nazwy wybrane automatycznie.skip_codegen(opcjonalnybool): wskazuje, czy generowanie kodu ma zostać pominięte w przypadku tego pakietu usług. Jeśli ustawisz wartośćtrue, dla tego pakietu usług nie zostanie wygenerowany żaden kod. Może to być przydatne w przypadku pakietów usług, które są implementowane ręcznie. Domyślnie ta opcja jest ustawiona nafalse.
Ograniczenia
- Format nazwy celu (E205, E206, E207, E208): jeśli podano niestandardową nazwę celu kompilacji (
build_cfg.target_name), musi ona być zgodna z formatem snake case:- Może zawierać tylko małe litery (
a–z), cyfry (0–9) i podkreślenia (_). - Nie może zawierać kolejnych podkreśleń (
__). - Nie może zaczynać się od podkreślenia.
- Nie może kończyć się podkreśleniem.
- Może zawierać tylko małe litery (
- Unikalność nazwy celu (E301): nazwa
build_cfg.target_namezdefiniowana przez użytkownika musi być unikalna w systemie kompilacji i nie może kolidować z żadnymi nazwami celów wygenerowanymi automatycznie na podstawie definicji innych pakietów usług.