يتطلب HIDL إصدار كل واجهة مكتوبة بلغة HIDL. بعد نشر واجهة HAL ، يتم تجميدها ويجب إجراء أي تغييرات أخرى على إصدار جديد من تلك الواجهة. بينما قد لا يتم تعديل واجهة منشورة معينة ، يمكن توسيعها بواجهة أخرى.
هيكل كود HIDL
يتم تنظيم كود HIDL في أنواع وواجهات وحزم معرّفة من قبل المستخدم:
- الأنواع المعرفة من قبل المستخدم (UDTs) . يوفر HIDL الوصول إلى مجموعة من أنواع البيانات البدائية التي يمكن استخدامها لتكوين أنواع أكثر تعقيدًا عبر الهياكل والنقابات والتعداد. يتم تمرير UDTs إلى طرق الواجهات ، ويمكن تعريفها على مستوى الحزمة (المشتركة لجميع الواجهات) أو محليًا إلى واجهة.
- واجهات . ككتلة بناء أساسية لـ HIDL ، تتكون الواجهة من UDT وإعلانات الطريقة. يمكن أن ترث الواجهات أيضًا من واجهة أخرى.
- الحزم . ينظم واجهات HIDL ذات الصلة وأنواع البيانات التي تعمل عليها. يتم تحديد الحزمة بواسطة اسم وإصدار وتتضمن ما يلي:
- يسمى ملف تعريف نوع البيانات
types.hal
. - لا توجد واجهات أو أكثر ، كل منها في ملف
.hal
الخاص بها.
- يسمى ملف تعريف نوع البيانات
يحتوي ملف تعريف نوع البيانات types.hal
على UDTs فقط (يتم الاحتفاظ بجميع UDTs على مستوى الحزمة في ملف واحد). التمثيلات في اللغة الهدف متاحة لجميع الواجهات في الحزمة.
فلسفة الإصدار
تعد حزمة HIDL (مثل android.hardware.nfc
) ، بعد نشرها لإصدار معين (مثل 1.0
) ، غير قابلة للتغيير ؛ لا يمكن تغييره. يمكن إجراء تعديلات على الواجهات في الحزمة أو أي تغييرات على UDTs الخاصة بها في حزمة أخرى فقط.
في HIDL ، يتم تطبيق الإصدار على مستوى الحزمة ، وليس على مستوى الواجهة ، وجميع الواجهات و UDTs في الحزمة تشترك في نفس الإصدار. تتبع إصدارات الحزمة الإصدارات الدلالية بدون مستوى التصحيح ومكونات البيانات الأولية للبناء. ضمن حزمة معينة ، يشير نتوء الإصدار الثانوي إلى أن الإصدار الجديد من الحزمة متوافق مع الإصدارات السابقة مع الحزمة القديمة ، بينما يشير الإصدار الرئيسي bump إلى أن الإصدار الجديد من الحزمة غير متوافق مع الحزمة القديمة.
من الناحية المفاهيمية ، يمكن أن ترتبط الحزمة بحزمة أخرى بإحدى الطرق المتعددة:
- لا إطلاقا .
- قابلية التمدد المتوافقة مع الإصدارات السابقة على مستوى الحزمة . يحدث هذا من أجل uprevs إصدار ثانوي جديد (المراجعة المتزايدة التالية) للحزمة ؛ الحزمة الجديدة لها نفس الاسم والإصدار الرئيسي مثل الحزمة القديمة ، ولكن إصدار ثانوي أعلى. من الناحية الوظيفية ، الحزمة الجديدة هي مجموعة شاملة من الحزمة القديمة ، مما يعني:
- توجد واجهات المستوى الأعلى للحزمة الرئيسية في الحزمة الجديدة ، على الرغم من أن الواجهات قد تحتوي على طرق جديدة ، UDTs جديدة للواجهة المحلية (ملحق مستوى الواجهة الموصوف أدناه) ، و UDTs جديدة في
types.hal
. - يمكن أيضًا إضافة واجهات جديدة إلى الحزمة الجديدة.
- جميع أنواع البيانات للحزمة الرئيسية موجودة في الحزمة الجديدة ويمكن معالجتها بالطرق (التي ربما أعيد تنفيذها) من الحزمة القديمة.
- يمكن أيضًا إضافة أنواع بيانات جديدة للاستخدام إما عن طريق الأساليب الجديدة للواجهات الحالية المحدثة ، أو بواجهات جديدة.
- توجد واجهات المستوى الأعلى للحزمة الرئيسية في الحزمة الجديدة ، على الرغم من أن الواجهات قد تحتوي على طرق جديدة ، UDTs جديدة للواجهة المحلية (ملحق مستوى الواجهة الموصوف أدناه) ، و UDTs جديدة في
- قابلية التوسعة المتوافقة مع الإصدارات السابقة على مستوى الواجهة . يمكن للحزمة الجديدة أيضًا توسيع الحزمة الأصلية من خلال تكوين واجهات منفصلة منطقيًا توفر ببساطة وظائف إضافية ، وليس الأساسية. لهذا الغرض ، قد يكون من المرغوب فيه ما يلي:
- تحتاج الواجهات في الحزمة الجديدة إلى الرجوع إلى أنواع بيانات الحزمة القديمة.
- قد تعمل الواجهات في الحزمة الجديدة على توسيع واجهات حزمة قديمة واحدة أو أكثر.
- تمديد عدم التوافق الأصلي مع الإصدارات السابقة . هذه نسخة رئيسية من الحزمة وليس هناك حاجة إلى أي ارتباط بين الاثنين. إلى الحد المتاح ، يمكن التعبير عنها بمجموعة من الأنواع من الإصدار الأقدم من الحزمة ، ووراثة مجموعة فرعية من واجهات الحزمة القديمة.
واجهات هيكلة
بالنسبة للواجهة جيدة التنظيم ، فإن إضافة أنواع جديدة من الوظائف التي ليست جزءًا من التصميم الأصلي يجب أن تتطلب تعديلاً على واجهة HIDL. على العكس من ذلك ، إذا كان بإمكانك أو تتوقع إجراء تغيير على جانبي الواجهة يقدم وظائف جديدة دون تغيير الواجهة نفسها ، فإن الواجهة غير منظمة.
يدعم Treble مكونات النظام والمورد التي تم تجميعها بشكل منفصل والتي يمكن فيها تجميع vendor.img
على الجهاز و system.img
بشكل منفصل. يجب تحديد جميع التفاعلات بين vendor.img
و system.img
بوضوح ودقة حتى يتمكنوا من الاستمرار في العمل لسنوات عديدة. يتضمن هذا العديد من أسطح API ، ولكن السطح الرئيسي هو آلية IPC التي يستخدمها HIDL للاتصال بين العمليات على حدود system.img
/ vendor.img
.
متطلبات
يجب تحديد جميع البيانات التي تم تمريرها عبر HIDL بشكل صريح. لضمان استمرار التنفيذ والعميل في العمل معًا حتى عند تجميعها بشكل منفصل أو تطويرها بشكل مستقل ، يجب أن تلتزم البيانات بالمتطلبات التالية:
- يمكن وصفها في HIDL مباشرة (باستخدام تعداد الهياكل ، وما إلى ذلك) مع الأسماء الدلالية والمعنى.
- يمكن وصفه بمعيار عام مثل ISO / IEC 7816.
- يمكن وصفها بمعيار الأجهزة أو التخطيط المادي للأجهزة.
- يمكن أن تكون بيانات غير شفافة (مثل المفاتيح العامة والمعرفات وما إلى ذلك) إذا لزم الأمر.
في حالة استخدام البيانات غير الشفافة ، يجب قراءتها من جانب واحد فقط من واجهة HIDL. على سبيل المثال ، إذا أعطت التعليمات البرمجية vendor.img
مكونًا على system.img
رسالة سلسلة أو بيانات vec<uint8_t>
، فلا يمكن تحليل هذه البيانات بواسطة system.img
نفسه ؛ يمكن فقط إعادته إلى vendor.img
لتفسيره. عند تمرير قيمة من vendor.img
إلى رمز البائع على system.img
أو إلى جهاز آخر ، يجب وصف تنسيق البيانات وكيفية تفسيرها بدقة ولا يزال جزءًا من الواجهة .
القواعد الارشادية
يجب أن تكون قادرًا على كتابة تطبيق أو عميل لـ HAL باستخدام ملفات .hal فقط (على سبيل المثال ، لن تحتاج إلى إلقاء نظرة على مصدر Android أو المعايير العامة). نوصي بتحديد السلوك المطلوب بدقة. عبارات مثل "التنفيذ قد يفعل أ أو ب" تشجع عمليات التنفيذ لتصبح متشابكة مع العملاء التي تم تطويرها معهم.
تخطيط كود HIDL
يتضمن HIDL الحزم الأساسية وحزم البائع.
واجهات HIDL الأساسية هي تلك المحددة بواسطة Google. تبدأ الحزم التي ينتمون إليها بـ android.hardware.
ويتم تسميتها حسب النظام الفرعي ، مع احتمال وجود مستويات متداخلة من التسمية. على سبيل المثال ، تُسمى حزمة NFC android.hardware.nfc
وحزمة الكاميرا هي android.hardware.camera
. بشكل عام ، تحمل الحزمة الأساسية اسم android.hardware.
[ name1
]. [ name2
]…. حزم HIDL لها إصدار بالإضافة إلى أسمائها. على سبيل المثال ، قد تكون الحزمة android.hardware.camera
في الإصدار 3.4
؛ هذا مهم ، لأن إصدار الحزمة يؤثر على وضعها في شجرة المصدر.
يتم وضع جميع الحزم الأساسية تحت hardware/interfaces/
في نظام البناء. الحزمة android.hardware.
[ name1
]. [ name2
] ... في الإصدار $m.$n
تحت hardware/interfaces/name1/name2/
… /$m.$n/
؛ الحزمة android.hardware.camera
الإصدار 3.4
موجودة في دليل hardware/interfaces/camera/3.4/.
يوجد مخطط ثابت بين بادئة الحزمة android.hardware.
hardware/interfaces/
.
الحزم غير الأساسية (البائع) هي تلك التي ينتجها بائع SoC أو ODM. بادئة الحزم غير الأساسية هي vendor.$(VENDOR).hardware.
حيث يشير $(VENDOR)
إلى بائع SoC أو OEM / ODM. هذا التعيين إلى vendor/$(VENDOR)/interfaces
في الشجرة (هذا التعيين أيضًا مشفر بشكل ثابت).
أسماء النوع المعرّف من قبل المستخدم المؤهلة بالكامل
في HIDL ، يكون لكل UDT اسم مؤهل بالكامل يتكون من اسم UDT واسم الحزمة حيث يتم تعريف UDT وإصدار الحزمة. يتم استخدام الاسم المؤهل بالكامل فقط عندما يتم التصريح عن مثيلات من النوع وليس عند تحديد النوع نفسه. على سبيل المثال ، افترض أن الحزمة android.hardware.nfc,
الإصدار 1.0
يعرف بنية تسمى NfcData
. في موقع الإعلان (سواء في types.hal
أو ضمن إعلان الواجهة) ، ينص الإعلان ببساطة على ما يلي:
struct NfcData { vec<uint8_t> data; };
عند الإعلان عن مثيل من هذا النوع (سواء داخل بنية بيانات أو كمعامل أسلوب) ، استخدم اسم النوع المؤهل بالكامل:
android.hardware.nfc@1.0::NfcData
الصيغة العامة هي PACKAGE @ VERSION :: UDT
، حيث:
-
PACKAGE
هو الاسم المفصول بالنقاط لحزمة HIDL (على سبيل المثال ،android.hardware.nfc
). -
VERSION
هو تنسيق main.minor للحزمة مفصول بنقاط (على سبيل المثال ،1.0
). -
UDT
هو الاسم المفصول بالنقاط لـ HIDL UDT. نظرًا لأن HIDL يدعم UDTs المتداخلة ويمكن أن تحتوي واجهات HIDL على UDT (نوع من التصريح المتداخل) ، يتم استخدام النقاط للوصول إلى الأسماء.
على سبيل المثال ، إذا تم تعريف التصريح المتداخل التالي في ملف الأنواع الشائعة في الحزمة android.hardware.example
، الإصدار 1.0
:
// types.hal package android.hardware.example@1.0; struct Foo { struct Bar { // … }; Bar cheers; };
الاسم المؤهل بالكامل لـ Bar
هو android.hardware.example@1.0::Foo.Bar
. إذا كان الإعلان المتداخل ، بالإضافة إلى كونه في الحزمة أعلاه ، موجودًا في واجهة تسمى IQuux
:
// IQuux.hal package android.hardware.example@1.0; interface IQuux { struct Foo { struct Bar { // … }; Bar cheers; }; doSomething(Foo f) generates (Foo.Bar fb); };
الاسم المؤهل بالكامل لـ Bar
هو android.hardware.example@1.0::IQuux.Foo.Bar
.
في كلتا الحالتين ، يمكن الإشارة إلى Bar
على أنه Bar
فقط ضمن نطاق إعلان Foo
. على مستوى الحزمة أو الواجهة ، يجب أن تشير إلى Bar
via Foo
: Foo.Bar
، كما هو الحال في إعلان الطريقة doSomething
أعلاه. بدلاً من ذلك ، يمكنك التصريح عن الطريقة بشكل أكثر تفصيلاً على النحو التالي:
// IQuux.hal doSomething(android.hardware.example@1.0::IQuux.Foo f) generates (android.hardware.example@1.0::IQuux.Foo.Bar fb);
قيم تعداد مؤهلة بالكامل
إذا كان UDT من نوع التعداد ، فإن كل قيمة من نوع التعداد لها اسم مؤهل بالكامل يبدأ بالاسم المؤهل بالكامل لنوع التعداد ، متبوعًا بنقطتين ، ثم متبوعًا باسم قيمة التعداد. على سبيل المثال ، افترض أن الحزمة android.hardware.nfc,
الإصدار 1.0
يعرف نوع التعداد NfcStatus
:
enum NfcStatus { STATUS_OK, STATUS_FAILED };
عند الإشارة إلى STATUS_OK
، فإن الاسم المؤهل بالكامل هو:
android.hardware.nfc@1.0::NfcStatus:STATUS_OK
الصيغة العامة هي PACKAGE @ VERSION :: UDT : VALUE
، حيث:
-
PACKAGE @ VERSION :: UDT
هو نفس الاسم المؤهل بالكامل لنوع التعداد. -
VALUE
هو اسم القيمة.
قواعد الاستدلال التلقائي
لا يلزم تحديد اسم UDT مؤهل بالكامل. يمكن لاسم UDT حذف ما يلي بأمان:
- الحزمة ، على سبيل المثال
@1.0::IFoo.Type
- كل من الحزمة والإصدار ، على سبيل المثال
IFoo.Type
يحاول HIDL إكمال الاسم باستخدام قواعد التداخل التلقائي (يعني رقم القاعدة الأقل أولوية أعلى).
المادة 1
إذا لم يتم توفير حزمة وإصدار ، فستتم محاولة البحث عن الاسم المحلي. مثال:
interface Nfc { typedef string NfcErrorMessage; send(NfcData d) generates (@1.0::NfcStatus s, NfcErrorMessage m); };
يتم البحث عن NfcErrorMessage
محليًا ، ويتم العثور على نوع typedef
أعلاه. يتم أيضًا البحث عن NfcData
محليًا ، ولكن نظرًا لأنه لم يتم تعريفه محليًا ، يتم استخدام القاعدتين 2 و 3. @1.0::NfcStatus
إصدارًا ، لذلك لا تنطبق القاعدة 1.
القاعدة 2
إذا فشلت القاعدة 1 وفقد أحد مكونات الاسم المؤهل بالكامل (الحزمة أو الإصدار أو الحزمة والإصدار) ، فسيتم تعبئة المكون تلقائيًا بمعلومات من الحزمة الحالية. ثم يبحث مترجم HIDL في الملف الحالي (وجميع الواردات) للعثور على الاسم المؤهل بالكامل المعبأ تلقائيًا. باستخدام المثال أعلاه ، افترض أن إعلان ExtendedNfcData
تم إجراؤه في نفس الحزمة ( android.hardware.nfc
) في نفس الإصدار ( 1.0
) مثل NfcData
، على النحو التالي:
struct ExtendedNfcData { NfcData base; // … additional members };
يملأ مترجم HIDL اسم الحزمة واسم الإصدار من الحزمة الحالية لإنتاج اسم UDT المؤهل بالكامل android.hardware.nfc@1.0::NfcData
. نظرًا لوجود الاسم في الحزمة الحالية (بافتراض أنه تم استيرادها بشكل صحيح) ، يتم استخدامه للتصريح.
لا يتم استيراد اسم في الحزمة الحالية إلا إذا تحقق أي مما يلي:
- يتم استيراده بشكل صريح مع بيان
import
. - يتم تعريفه في
types.hal
في الحزمة الحالية
يتم اتباع نفس العملية إذا تم تأهيل NfcData
برقم الإصدار فقط:
struct ExtendedNfcData { // autofill the current package name (android.hardware.nfc) @1.0::NfcData base; // … additional members };
القاعدة 3
إذا فشلت القاعدة 2 في إنتاج تطابق (لم يتم تعريف UDT في الحزمة الحالية) ، يقوم مترجم HIDL بالمسح بحثًا عن تطابق داخل جميع الحزم المستوردة. باستخدام المثال أعلاه ، افترض أن ExtendedNfcData
معلن في الإصدار 1.1
من الحزمة android.hardware.nfc
، 1.1
يستورد 1.0
كما ينبغي (انظر ملحقات مستوى الحزمة ) ، ويحدد التعريف اسم UDT فقط:
struct ExtendedNfcData { NfcData base; // … additional members };
يبحث المترجم عن أي UDT يسمى NfcData
ويجد واحدًا في android.hardware.nfc
في الإصدار 1.0
، مما ينتج عنه UDT مؤهل بالكامل لـ android.hardware.nfc@1.0::NfcData
. إذا تم العثور على أكثر من تطابق واحد لـ UDT مؤهل جزئيًا ، فسيقوم مترجم HIDL بإلقاء خطأ.
مثال
باستخدام القاعدة 2 ، يُفضل النوع المستورد المحدد في الحزمة الحالية على النوع المستورد من حزمة أخرى:
// hardware/interfaces/foo/1.0/types.hal package android.hardware.foo@1.0; struct S {}; // hardware/interfaces/foo/1.0/IFooCallback.hal package android.hardware.foo@1.0; interface IFooCallback {}; // hardware/interfaces/bar/1.0/types.hal package android.hardware.bar@1.0; typedef string S; // hardware/interfaces/bar/1.0/IFooCallback.hal package android.hardware.bar@1.0; interface IFooCallback {}; // hardware/interfaces/bar/1.0/IBar.hal package android.hardware.bar@1.0; import android.hardware.foo@1.0; interface IBar { baz1(S s); // android.hardware.bar@1.0::S baz2(IFooCallback s); // android.hardware.foo@1.0::IFooCallback };
- تم إقحام
S
كـandroid.hardware.bar@1.0::S
، وموجود فيbar/1.0/types.hal
(لأنtypes.hal
يتم استيراده تلقائيًا). - يتم إقحام
IFooCallback
كـandroid.hardware.bar@1.0::IFooCallback
باستخدام القاعدة 2 ، ولكن لا يمكن العثور عليه لأنbar/1.0/IFooCallback.hal
لا يتم استيراده تلقائيًا (كما هوtypes.hal
). وبالتالي ، فإن القاعدة 3 تحلها إلىandroid.hardware.foo@1.0::IFooCallback
بدلاً من ذلك ، والتي يتم استيرادها عبرimport android.hardware.foo@1.0;
).
أنواع
تحتوي كل حزمة HIDL على ملف types.hal
يحتوي على UDTs التي يتم مشاركتها بين جميع الواجهات المشاركة في تلك الحزمة. تكون أنواع HIDL عامة دائمًا ؛ بغض النظر عما إذا كان UDT قد تم الإعلان عنه في types.hal
أو ضمن إعلان واجهة ، فإن هذه الأنواع يمكن الوصول إليها خارج النطاق الذي تم تعريفها فيه. لا يُقصد من types.hal
وصف واجهة برمجة التطبيقات العامة للحزمة ، بل يهدف إلى استضافة UDTs التي تستخدمها جميع الواجهات داخل الحزمة. نظرًا لطبيعة HIDL ، تعد جميع UDTs جزءًا من الواجهة.
يتكون types.hal
من UDTs وبيانات import
. نظرًا types.hal
لكل واجهة من واجهة الحزمة (وهو استيراد ضمني) ، فإن عبارات import
هذه تكون على مستوى الحزمة حسب التعريف. قد تتضمن UDTs في types.hal
أيضًا UDTs والواجهات التي يتم استيرادها.
على سبيل المثال ، بالنسبة إلى IFoo.hal
:
package android.hardware.foo@1.0; // whole package import import android.hardware.bar@1.0; // types only import import android.hardware.baz@1.0::types; // partial imports import android.hardware.qux@1.0::IQux.Quux; // partial imports import android.hardware.quuz@1.0::Quuz;
يتم استيراد ما يلي:
-
android.hidl.base@1.0::IBase
(ضمنيًا) -
android.hardware.foo@1.0::types
(ضمنيًا) - كل شيء في
android.hardware.bar@1.0
(بما في ذلك جميع الواجهاتtypes.hal
. -
types.hal
منandroid.hardware.baz@1.0::types
(لم يتم استيراد واجهات فيandroid.hardware.baz@1.0
) -
IQux.hal
وtypes.hal
منandroid.hardware.qux@1.0
-
Quuz
منandroid.hardware.quuz@1.0
(بافتراض أنQuuz
مُعرَّفة فيtypes.hal
، يتم تحليل ملفtypes.hal
بأكمله ، ولكن لا يتم استيراد الأنواع الأخرى غيرQuuz
).
إصدار على مستوى الواجهة
كل واجهة داخل الحزمة موجودة في ملفها الخاص. يتم التصريح عن الحزمة التي تنتمي إليها الواجهة أعلى الواجهة باستخدام بيان package
. بعد إعلان الحزمة ، قد يتم إدراج صفر أو أكثر من الواردات على مستوى الواجهة (الحزمة الكاملة أو الجزئية). فمثلا:
package android.hardware.nfc@1.0;
في HIDL ، يمكن للواجهات أن ترث من واجهات أخرى باستخدام الكلمة الأساسية extends
. لكي تقوم الواجهة بتوسيع واجهة أخرى ، يجب أن يكون لها حق الوصول إليها عبر بيان import
. يتبع اسم الواجهة التي يتم توسيعها (الواجهة الأساسية) قواعد تأهيل اسم النوع الموضحة أعلاه. قد ترث الواجهة من واجهة واحدة فقط ؛ HIDL لا يدعم الوراثة المتعددة.
تستخدم أمثلة إصدار uprev أدناه الحزمة التالية:
// types.hal package android.hardware.example@1.0 struct Foo { struct Bar { vec<uint32_t> val; }; }; // IQuux.hal package android.hardware.example@1.0 interface IQuux { fromFooToBar(Foo f) generates (Foo.Bar b); }
قواعد Uprev
لتحديد حزمة package@major.minor
، يجب أن يكون كل من A أو B صحيحًا:
القاعدة أ | "هو إصدار ثانوي لبدء التشغيل": يجب عدم تحديد كافة الإصدارات الثانوية السابقة ، package@major.0 ، package@major.1 ،… ، package@major.(minor-1) . |
---|
القاعدة ب | كل ما يلي صحيح:
|
---|
بسبب القاعدة أ:
- يمكن أن تبدأ الحزمة بأي رقم إصدار ثانوي (على سبيل المثال ،
android.hardware.biometrics.fingerprint
يبدأ من@2.1
.) - الشرط "
android.hardware.foo@1.0
غير محدد" يعني أنhardware/interfaces/foo/1.0
يجب ألا تكون موجودة حتى.
ومع ذلك ، لا تؤثر القاعدة A على حزمة تحمل نفس اسم الحزمة ولكن على إصدار رئيسي مختلف (على سبيل المثال ، android.hardware.camera.device
له تعريف @1.0
و @3.2
؛ @3.2
لا يحتاج إلى التفاعل مع @1.0
.) ومن ثم ، @3.2::IExtFoo
يمكن أن يمتد @1.0::IFoo
.
بشرط أن يكون اسم الحزمة مختلفًا ، قد يمتد package@major.minor::IBar
من واجهة باسم مختلف (على سبيل المثال ، android.hardware.bar@1.0::IBar
أن يمتد android.hardware.baz@2.2::IBaz
). إذا لم تعلن الواجهة صراحةً عن نوع super مع الكلمة الأساسية الموسعة ، extend
android.hidl.base@1.0::IBase
(باستثناء IBase
نفسه).
يجب اتباع B.2 و B.3 في نفس الوقت. على سبيل المثال ، حتى إذا android.hardware.foo@1.1::IFoo
بتوسيع android.hardware.foo@1.0::IFoo
لتمرير القاعدة B.2 ، إذا كان android.hardware.foo@1.1::IExtBar
يوسع android.hardware.foo@1.0::IBar
، هذا لا يزال غير صالح uprev.
واجهات رفع
لتحديث android.hardware.example@1.0
(المحدد أعلاه) إلى @1.1
:
// types.hal package android.hardware.example@1.1; import android.hardware.example@1.0; // IQuux.hal package android.hardware.example@1.1 interface IQuux extends @1.0::IQuux { fromBarToFoo(Foo.Bar b) generates (Foo f); }
هذا import
على مستوى الحزمة للإصدار 1.0
من android.hardware.example
في types.hal
. بينما لم تتم إضافة UDTs جديدة في الإصدار 1.1
من الحزمة ، لا تزال هناك حاجة إلى مراجع UDTs في الإصدار 1.0
، ومن ثم استيراد مستوى الحزمة في types.hal
. (كان من الممكن تحقيق نفس التأثير من خلال استيراد على مستوى الواجهة في IQuux.hal
.)
في extends @1.0::IQuux
في إعلان IQuux
، حددنا إصدار IQuux
الموروث (مطلوب توضيح لأن IQuux
يُستخدم للإعلان عن واجهة والوراثة من واجهة). نظرًا لأن الإعلانات هي ببساطة أسماء ترث جميع سمات الحزمة والإصدار في موقع الإعلان ، يجب أن يكون توضيح الغموض باسم الواجهة الأساسية ؛ كان بإمكاننا استخدام UDT المؤهل بالكامل أيضًا ، لكن هذا كان زائداً عن الحاجة.
الواجهة الجديدة IQuux
لا تعيد التصريح عن الطريقة من fromFooToBar()
التي ترثها من @1.0::IQuux
؛ إنه يسرد ببساطة الطريقة الجديدة التي يضيفها fromBarToFoo()
. في HIDL ، قد لا يتم الإعلان عن الأساليب الموروثة مرة أخرى في واجهات الطفل ، لذلك لا يمكن لواجهة IQuux
أن تعلن عن طريقة fromFooToBar()
بشكل صريح.
اتفاقيات Uprev
في بعض الأحيان ، يجب أن تعيد أسماء الواجهة تسمية الواجهة الموسعة. نوصي بأن يكون لملحقات التعداد والبنى والنقابات نفس الاسم الذي يمتد إليه ما لم تكن مختلفة بما يكفي لتبرير اسم جديد. أمثلة:
// in parent hal file enum Brightness : uint32_t { NONE, WHITE }; // in child hal file extending the existing set with additional similar values enum Brightness : @1.0::Brightness { AUTOMATIC }; // extending the existing set with values that require a new, more descriptive name: enum Color : @1.0::Brightness { HW_GREEN, RAINBOW };
إذا كان من الممكن أن يكون للطريقة اسم دلالي جديد (على سبيل المثال fooWithLocation
) ، فهذا هو المفضل. خلاف ذلك ، يجب أن يتم تسميته بشكل مشابه لما يتم توسيعه. على سبيل المثال ، قد تحل الطريقة foo_1_1
في @1.1::IFoo
محل وظيفة التابع foo
في @1.0::IFoo
إذا لم يكن هناك اسم بديل أفضل.
الإصدار على مستوى الحزمة
يحدث إصدار HIDL على مستوى الحزمة ؛ بعد نشر الحزمة ، تصبح غير قابلة للتغيير (لا يمكن تغيير مجموعة الواجهات و UDT). يمكن أن ترتبط الحزم ببعضها البعض بعدة طرق ، وكلها قابلة للتعبير عن طريق مزيج من الميراث على مستوى الواجهة وبناء UDTs عن طريق التكوين.
ومع ذلك ، يتم تحديد نوع واحد من العلاقات بشكل صارم ويجب فرضه: مستوى الحزمة المتوافق مع الإصدارات السابقة . في هذا السيناريو ، تكون الحزمة الأصلية هي الحزمة الموروثة منها والحزمة الفرعية هي الحزمة التي تمد الأصل . قواعد الميراث المتوافقة مع الإصدارات السابقة على مستوى الحزمة هي كما يلي:
- يتم توريث جميع واجهات المستوى الأعلى للحزمة الأصلية من خلال واجهات في الحزمة الفرعية.
- يمكن أيضًا إضافة واجهات جديدة إلى الحزمة الجديدة (لا توجد قيود على العلاقات مع الواجهات الأخرى في الحزم الأخرى).
- يمكن أيضًا إضافة أنواع بيانات جديدة للاستخدام إما عن طريق الأساليب الجديدة للواجهات الحالية المحدثة ، أو بواجهات جديدة.
يمكن تنفيذ هذه القواعد باستخدام الوراثة على مستوى واجهة HIDL وتكوين UDT ، ولكنها تتطلب معرفة على مستوى التعريف لمعرفة أن هذه العلاقات تشكل امتداد حزمة متوافق مع الإصدارات السابقة. يتم الاستدلال على هذه المعرفة على النحو التالي:
إذا كانت الحزمة تفي بهذا المطلب ، hidl-gen
يفرض قواعد التوافق العكسي.