تحديد اللغة

تحدّد هذه الصفحة لغة تعريف واجهة خدمة المركبات (VSIDL) باستخدام نموذج Extended Backus-Naur Form (EBNF) وفقًا لمعيار ISO/IEC 14977 وبروتوكول protobuf. تركز هذه الصفحة على قواعد اللغة الخالية من السياق ومعنى عناصر اللغة.

المخطّط الهرمي للغات

وفقًا لمرفق كائنات Meta (MOF)، يستخدم برنامج VSIDL المجمّع (VSIDLC) اللغات الموضّحة في الشكل 1:

لغات VSIDLC

الشكل 1: لغات VSIDLC.

تستند VSIDLC بشكل أساسي إلى Protocol Buffers. يتم استخدام 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 }
;

تعريف 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;
}

مثال على الاستخدام

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 filegroup.

حزمة الخدمات

يوضّح هذا القسم نوع رسالة حزمة الخدمة.

قواعد 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
;

تعريف 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;
}

مثال على الاستخدام

service_bundle {
    name: "SeatController"

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

الشرح

تحدّد حزمة الخدمات مجموعة منطقية من الخدمات والنّاشرين والمشتركين وخوادم استدعاء الإجراء عن بُعد وبرامج استدعاء الإجراء عن بُعد. تعمل حزمة الخدمات كحاوية لمجموعة معيّنة من الوظائف وتفاعلاتها.

القيود

  • متطلبات اسم الحزمة (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
;

تعريف 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;
}

مثال على الاستخدام

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

الشرح

يحدّد نوع الرسالة Publisher مصدر بيانات يوفّره ServiceBundle. يحدد نوع الرسالة هذا نوع البيانات التي يتم نشرها والمواضيع المحددة وسعة تلك البيانات.

المواضيع

يحتوي كل مثيل 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): يجب أن يتضمّن نوع رسالة البروتوكول المخزَّن مؤقتًا المشار إليه من قِبل الناشر التعليق التوضيحي SdvPublication.
  • الاستخدام الصحيح للخيارات (E606): إذا حدّد الناشر خيارًا (مثلاً)، يجب أن يتوفّر هذا الخيار ضمن instances_enum المحدّد لنوع المنشور في protobuf.
  • شرط تحديد الصيغة (E607): لا يمكن للناشر تحديد صيغة (مثيل) صريح إلا إذا كان نوع المنشور يحدّد instances_enum في بروتوكول المخزن المؤقت.
  • تسمية المواضيع (E20D وE20F): يجب أن تكون المواضيع بأحرف صغيرة مع استخدام شرطات، وألا تتجاوز 127 حرفًا.
  • تفرّد الموضوع (E314): يجب أن تكون المواضيع فريدة على مستوى العالم لدى جميع الناشرين.
  • متطلبات السعة (E406 وE407): السعة إلزامية ويجب أن تكون عددًا زوجيًا أكبر من أو يساوي 2.

المشتركون

يوضّح هذا القسم نوع رسالة المشترك.

قواعد EBNF

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

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

تعريف 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;
}

مثال على الاستخدام

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

الشرح

تحدّد رسالة Subscriber مستلِمًا للمنشور يوفّره ServiceBundle. تحدّد هذه الرسالة نوع البيانات التي يتم الاشتراك فيها والمواضيع المحدّدة لهذا المنشور. إذا كان هناك عدة ناشرين لموضوع معيّن، سيتلقّى المشترك الرسائل التي ينشرها جميع هؤلاء الناشرين.

القيود

  • وجود الناشر (E504): يجب أن يتوفّر ناشر واحد على الأقل لكل مشترك محدّد ينشر نوع المنشور وخيار المنشور المحدّدَين.
  • نوع الاشتراك صالح (E608): يجب أن يشير المشترك إلى نوع يتوافق مع رسالة protobuf حالية تم تحديدها باستخدام التعليق التوضيحي SdvPublication.
  • اشتراك صالح في خيار منتج (E609): إذا حدّد المشترك خيارًا مختلفًا (مثلاً، حجمًا أو لونًا)، يجب أن تكون قيمة هذا الخيار صالحة ومحدّدة ضمن instances_enum لنوع المنشور المقابل في بروتوكول Buffer.
  • الموضوع إلزامي (E408): يجب إدخال موضوع للمشتركين.
  • إعادة تعريف الموضوع (E311): يجب عدم إعادة تعريف مواضيع المشتركين في حزمة الخدمة نفسها.

خادم RPC

يوضّح هذا القسم نوع رسالة خادم RPC.

قواعد EBNF

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

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

تعريف 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;
}

مثال على الاستخدام

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

الشرح

تحدّد الرسالة Server خادم RPC يوفّره ServiceBundle. تحدّد هذه الرسالة الخدمة التي ينفّذها الخادم وقناة RPC.

يعرض خادم استدعاء الإجراء عن بُعد مجموعة من الطرق التي يمكن للعملاء استدعاؤها عن بُعد. يحدّد الحقل service اسم خدمة RPC التي ينفّذها الخادم. يتم تحديد هذه الخدمة في ملف proto وتنفيذها في رمز Rust مخصّص. يمكن أن تتضمّن خدمات RPC طرقًا أحادية، وطرقًا لبث البيانات من العميل، وطرقًا لبث البيانات من الخادم، وذلك على النحو المحدّد في تعريف خدمة protobuf. يحدّد الحقل channel نقطة نهاية التواصل وهو حقل إلزامي (E409).

القيود

  • تعريف الخدمة (E603): يجب أن يحدّد خادم RPC قيمة service تتطابق مع قيمة service الحالية لاستدعاء الإجراء عن بُعد لمخزن البروتوكولات المؤقت.
  • حدّ الخادم لكل خدمة (E100): ضمن حزمة خدمة واحدة، يمكن أن يتم تقديم service معيّن من خلال تعريف خادم واحد على الأكثر.
  • تسمية القنوات (E20E): يجب أن تكون قنوات RPC بأحرف صغيرة مع استخدام شرطات.
  • القناة إلزامية (E409): قناة RPC إلزامية.
  • تفرد القناة (E40B): يجب أن تستخدم خدمة واحدة فقط قناة RPC.

عميل RPC

يوضّح هذا القسم نوع رسالة عميل RPC.

قواعد EBNF

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

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

تعريف 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;
}

مثال على الاستخدام

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

الشرح

تحدّد client برنامجًا لعميل RPC تستخدمه ServiceBundle. تحدِّد السمة client الخدمة التي يتفاعل معها العميل والقناة التي سيتم الاتصال بها. يمكن للعميل التفاعل مع طرق أحادية الاتجاه وطرق بث من جهة العميل وطرق بث من جهة الخادم، وذلك حسب تعريف الخدمة.

القيود

  • تعريف الخدمة (E60A): يجب أن يحدّد عميل RPC service يتوافق مع تعريف service حالي لمخزن البروتوكولات المؤقتة.
  • مصدر الخدمة الفريد (E60B): يجب أن يكون تعريف service في protobuf الذي يشير إليه service الخاص بأحد برامج RPC محدّدًا بشكل فريد (أي لا يتم تحديده عدة مرات) في جميع ملفات protobuf.
  • القناة إلزامية (E409): قناة RPC إلزامية.

إعدادات التصميم

يوضّح هذا القسم نوع رسالة إعدادات التصميم.

قواعد EBNF

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

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

تعريف 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;
}

مثال على الاستخدام

build_cfg {
  target_name: "my_custom_target_name"
  skip_codegen: false
}

الشرح

تضبط BuildConfiguration المَعلمات غير العادية الخاصة بـ ServiceBundle من أجل إنشاء الرموز. جميع إعدادات الإنشاء اختيارية.

  • 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 المحدّد من قِبل المستخدم فريدًا على مستوى نظام التصميم وألا يتعارض مع أي أسماء أهداف تم إنشاؤها تلقائيًا ومستمدة من تعريفات حِزم الخدمات الأخرى.