Спецификация языка

На этой странице представлен язык определения интерфейса сервисов транспортных средств (VSIDL) с использованием расширенной формы Бэкуса-Наура (EBNF) стандарта ISO/IEC 14977 и протокола protobuf. Основное внимание на этой странице уделяется контекстно-свободной грамматике языка и значению языковых элементов.

Языковая иерархия

Согласно протоколу Meta Object Facility (MOF) , компилятор VSIDL (VSIDLC) использует языки, показанные на рисунке 1:

Языки VSIDLC

Рисунок 1. Языки VSIDLC.

VSIDLC в основном основан на языке протокола буфера (protobuf) . Protobuf используется для определения типов данных, которыми обмениваются с помощью операций публикации-подписки и удаленных вызовов процедур (RPC). С технической точки зрения, модели VSIDL представляют собой файлы TextProto, где синтаксис VSIDL определяется в файле protobuf ( syntax.proto ). И файлы protobuf для определения типов данных, и модели VSIDL используются для генерации кода Rust. Сгенерированный код в основном содержит структуры, реализующие структуры данных для обмениваемых сообщений, и функции Rust, реализующие функции для создания сервисных блоков в Rust без автоматического вызова этих сервисных блоков. Этот сгенерированный код Rust сопровождается пользовательским кодом Rust, который использует сгенерированный код для создания экземпляров сервисных блоков и реализации бизнес-логики приложения.

Абстрактный синтаксис

На рисунке 2 показаны основные типы сообщений в VSIDL:

Основные типы сообщений в VSIDL

Рисунок 2. Основные типы сообщений в VSIDL.

Вступление VSIDL

В этом разделе объясняется тип входного сообщения VSIDL.

EBNF грамматика

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

Прото-определение

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

Пример использования

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

service_bundle {
  name: "Manager"

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

Объяснение

Сообщение VsidlEntry служит корневым контейнером для VSIDL-файла (с расширением .vsidl ). Это сообщение инкапсулирует все определения и конфигурации в одном VSIDL-файле. VsidlEntry — это элемент верхнего уровня, который связывает все остальное.

Цель:

  • Определяет общую структуру файла VSIDL.
  • Указывает пространство имен пакета для всех сущностей в файле.
  • Содержит набор определений пакетов служб.
  • Позволяет добавлять пользовательские расширения к модели VSIDL.
  • Включает правила сопоставления для SOME/IP и VHAL.

Ограничения

  • Название пакета (E211): Название пакета не должно превышать 127 символов.
  • Висячие файлы (E10B): Все файлы в каталоге должны быть указаны в файловой группе Android.bp .

пакет услуг

В этом разделе объясняется тип сообщения пакета услуг.

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
;

Прото-определение

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

Пример использования

service_bundle {
    name: "SeatController"

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

Объяснение

Пакет сервисов определяет логическую группировку связанных сервисов, издателей, подписчиков, RPC-серверов и RPC-клиентов. Пакет сервисов выступает в качестве контейнера для определенного набора функций и их взаимодействия.

Ограничения

  • Требования к названиям пакетов (E209, E20A, E20B, E20C):
    • Пакет служб должен иметь заполненное имя.
    • Имя должно начинаться с допустимого символа идентификатора Unicode (обычно это буква).
    • Последующие символы в имени должны быть допустимыми символами продолжения идентификатора Unicode (обычно это буквы или цифры).
    • Имя не должно быть зарезервированным ключевым словом в Rust, Java или C++.
  • Уникальность глобального пакета услуг (E309): Каждый пакет услуг должен иметь уникальное полное имя (на основе его пакета и имени).
  • Внутренняя уникальность (E100, E300, E302, E303, E308):
    • В рамках одного пакета услуг каждая служба RPC может обслуживаться не более чем одним определением сервера.
    • В рамках одного пакета услуг каждый тип публикации MULTI_PUB может быть опубликован не более чем одним определением издателя.
    • В рамках одного пакета услуг все определяемые пользователем имена сервисных единиц (для издателей или серверов) должны быть уникальными.
    • В рамках одного пакета услуг все имена сервисных единиц (как заданные пользователем, так и сгенерированные автоматически) должны быть уникальными.
  • Правила именования целей сборки (E205, E206, E207, E208): Если указано пользовательское имя цели сборки ( build_cfg.target_name ), оно должно соответствовать формату snake case (строчные буквы, цифры и одинарные подчеркивания, не начинающиеся и не заканчивающиеся подчеркиванием).
  • Уникальность имени целевого объекта сборки (E301): заданное пользователем имя целевого объекта сборки не должно конфликтовать с автоматически сгенерированными именами целевых объектов для других пакетов служб.

Издатель

В этом разделе объясняется, что такое тип сообщения «Издатель».

EBNF грамматика

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

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

Прото-определение

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

Пример использования

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

Объяснение

The Publisher message type defines a data source that ServiceBundle provides. This message type specifies the type of data being published and the specific topics and capacity of that data.

Темы

Каждый экземпляр Publisher имеет поле message , которое ссылается на публикуемое прототипное сообщение. В нем должны быть указаны тема (обозначаемая как topic ) и емкость (обозначаемая как capacity ).

  • Тема: Уникальный идентификатор темы публикации. Он должен следовать за дефисом в нижнем регистре (например, my-topic ).
  • Емкость: Задает размер очереди, то есть, сколько сообщений может вместить очередь, прежде чем непрочитанные сообщения будут отброшены. Это должно быть четное число, большее или равное 2.

Имена, заданные пользователем

Издатели могут использовать определяемые пользователем имена сервисных единиц, которые переопределяют автоматически выбранные имена сервисных единиц. Эта возможность позволяет выбирать более короткие имена. Если издатель использует определяемое пользователем имя сервисной единицы, он может использовать только один экземпляр, так что имя сервисной единицы будет уникально присвоено только одному экземпляру.

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

Ограничения

  • Размещение издателей (E300): Издатели для одного и того же типа MULTI_PUB должны быть определены в отдельных пакетах услуг.
  • Уникальность локальных имен (E302): В рамках любого пакета услуг все издатели должны иметь уникальные имена определяемых пользователем единиц услуг.
  • Уникальность глобальных имен (E304): Издатели одного типа публикаций должны иметь глобально уникальные имена определяемых пользователем единиц обслуживания для всех пакетов услуг.
  • Именование отдельных каналов (E306): Пользовательские имена сервисных единиц могут быть назначены только издателям, которые обрабатывают ровно один экземпляр.
  • Ограничение на количество издателей (E307): сообщение protobuf, помеченное как SINGLE_PUB может быть опубликовано только одним издателем во всей системе.
  • Уникальность имен сервисных блоков (E308): Все имена сервисных блоков (сгенерированные или определенные пользователем) должны быть уникальными в рамках своего сервисного пакета; для разрешения конфликтов с сгенерированными именами следует использовать имена, определенные пользователем.
  • Требование к указанию варианта (E501): Если издатель использует определяемое пользователем имя для типа с несколькими вариантами, он должен явно указать тот вариант, который он публикует.
  • Наличие издателя для подписчиков (E504): Каждый определенный подписчик должен иметь как минимум одного соответствующего издателя для указанного типа и варианта.
  • Допустимый тип издателя (E601): Издатель должен ссылаться на тип, соответствующий существующему сообщению protobuf.
  • Требование к аннотации публикации (E602): Тип сообщения protobuf, на который ссылается издатель, должен включать аннотацию SdvPublication .
  • Допустимое использование вариантов (E606): Если издатель указывает вариант (экземпляр), этот вариант должен существовать в перечислении instances_enum определенном для типа публикации в protobuf.
  • Variant specification condition (E607): A publisher can specify an explicit variant (instance) only if the publication type defines an instances_enum in protobuf.
  • Названия тем (E20D, E20F): Темы должны быть написаны строчными буквами с дефисом и не превышать 127 символов.
  • Уникальность темы (E314): Темы должны быть уникальными во всем мире для всех издателей.
  • Требования к вместимости (E406, E407): Вместимость является обязательной и должна быть четным числом >= 2.

Подписчик

В этом разделе объясняется, что такое сообщение подписчика.

EBNF грамматика

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

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

Прото-определение

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

Пример использования

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

Объяснение

Сообщение Subscriber определяет получателя публикаций, предоставляемого ServiceBundle . В этом сообщении указывается тип данных, на которые осуществляется подписка, и конкретные темы данной публикации. Если для темы существует несколько издателей, подписчик получает сообщения, опубликованные всеми ими.

Ограничения

  • Наличие издателя (E504): Для каждого определенного подписчика должен существовать как минимум один соответствующий издатель, публикующий указанный тип и вариант публикации.
  • Допустимый тип подписки (E608): Подписчик должен ссылаться на тип, соответствующий существующему сообщению protobuf, определенному с помощью аннотации SdvPublication .
  • Подтверждение подписки на вариант (E609): Если подписчик указывает вариант (экземпляр), этот вариант должен быть допустимым значением, определенным в instances_enum соответствующего типа публикации protobuf.
  • Тема обязательна (E408): Тема обязательна для подписчиков.
  • Повторное объявление темы (E311): Темы подписчиков не следует повторно объявлять в одном и том же пакете услуг.

RPC-сервер

В этом разделе объясняется тип сообщения RPC-сервера.

EBNF грамматика

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

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

Прото-определение

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

Пример использования

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

Объяснение

Сообщение Server определяет RPC-сервер, предоставляемый ServiceBundle . В этом сообщении указывается служба, которую реализует сервер, и RPC-канал.

RPC-сервер предоставляет набор методов, которые клиенты могут вызывать удаленно. Поле service указывает имя RPC-сервиса, который реализует сервер. Этот сервис определяется в proto-файле и реализуется в пользовательском коде Rust. RPC-сервисы могут включать унарные методы, методы потоковой передачи данных клиентом и методы потоковой передачи данных сервером, как определено в определении сервиса protobuf. Поле channel определяет конечную точку связи и является обязательным (E409).

Ограничения

  • Определение службы (E603): RPC-сервер должен указать значение service , соответствующее существующему значению service RPC protobuf.
  • Ограничение на количество серверов на одну службу (E100): В рамках одного пакета служб конкретная service RPC может обслуживаться не более чем одним определением сервера.
  • Именование каналов (E20E): RPC-каналы должны быть написаны строчными буквами с дефисом.
  • Обязательный канал (E409): Канал RPC обязателен.
  • Уникальность канала (E40B): RPC-канал должен использоваться только одной службой.

RPC-клиент

В этом разделе объясняется тип сообщения RPC-клиента.

EBNF грамматика

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

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

Прото-определение

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

Пример использования

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

Объяснение

client определяет RPC-клиент, который использует ServiceBundle . client указывает сервис, с которым взаимодействует клиент, и канал для подключения. В зависимости от определения сервиса клиент может взаимодействовать с помощью унарных методов, методов клиент-потоковой передачи и методов сервер-потоковой передачи.

Ограничения

  • Определение сервиса (E60A): RPC-клиент должен указать service , соответствующий существующему определению service protobuf.
  • Уникальный источник службы (E60B): Определение service protobuf, на которое ссылается service RPC-клиента, должно быть однозначно определено (не определено несколько раз) во всех файлах protobuf.
  • Обязательный канал (E409): Канал RPC обязателен.

Конфигурация сборки

В этом разделе объясняется тип сообщения конфигурации сборки.

EBNF грамматика

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

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

Прото-определение

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

Пример использования

build_cfg {
  target_name: "my_custom_target_name"
  skip_codegen: false
}

Объяснение

BuildConfiguration configures nonstandard parameters of ServiceBundle for code generation. All build configurations are optional.

  • target_name (необязательная string ): Указывает имя целевого объекта сборки в файлах Android.bp . Используйте это для задания более коротких имен целевых объектов, чем те, которые выбираются автоматически.
  • skip_codegen (необязательный bool ): указывает, следует ли пропускать генерацию кода для данного пакета сервисов. Если установлено значение true , код для данного пакета сервисов не генерируется. Это может быть полезно для пакетов сервисов, реализованных вручную. По умолчанию установлено значение false .

Ограничения

  • Формат имени цели (E205, E206, E207, E208): Если указано пользовательское имя цели сборки ( build_cfg.target_name ), оно должно строго соответствовать формату snake case:
    • Она должна содержать только строчные буквы ( a до z ), цифры ( 0 до 9 ) и символы подчеркивания ( _ ).
    • В нем не должно быть последовательных символов подчеркивания ( __ ).
    • Оно не должно начинаться с нижнего подчеркивания.
    • Оно не должно заканчиваться нижним подчеркиванием.
  • Уникальность имени цели (E301): заданное пользователем имя build_cfg.target_name должно быть уникальным в системе сборки и не должно конфликтовать с автоматически сгенерированными именами целей, полученными из определений других пакетов служб.