تحديد الإصدار

يتطلب 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 .
    • يمكن أيضًا إضافة واجهات جديدة إلى الحزمة الجديدة.
    • جميع أنواع البيانات للحزمة الرئيسية موجودة في الحزمة الجديدة ويمكن معالجتها بالطرق (التي ربما أعيد تنفيذها) من الحزمة القديمة.
    • يمكن أيضًا إضافة أنواع بيانات جديدة للاستخدام إما عن طريق الأساليب الجديدة للواجهات الحالية المحدثة ، أو بواجهات جديدة.
  • قابلية التوسعة المتوافقة مع الإصدارات السابقة على مستوى الواجهة . يمكن للحزمة الجديدة أيضًا توسيع الحزمة الأصلية من خلال تكوين واجهات منفصلة منطقيًا توفر ببساطة وظائف إضافية ، وليس الأساسية. لهذا الغرض ، قد يكون من المرغوب فيه ما يلي:
    • تحتاج الواجهات في الحزمة الجديدة إلى الرجوع إلى أنواع بيانات الحزمة القديمة.
    • قد تعمل الواجهات في الحزمة الجديدة على توسيع واجهات حزمة قديمة واحدة أو أكثر.
  • تمديد عدم التوافق الأصلي مع الإصدارات السابقة . هذه نسخة رئيسية من الحزمة وليس هناك حاجة إلى أي ارتباط بين الاثنين. إلى الحد المتاح ، يمكن التعبير عنها بمجموعة من الأنواع من الإصدار الأقدم من الحزمة ، ووراثة مجموعة فرعية من واجهات الحزمة القديمة.

واجهات هيكلة

بالنسبة للواجهة جيدة التنظيم ، فإن إضافة أنواع جديدة من الوظائف التي ليست جزءًا من التصميم الأصلي يجب أن تتطلب تعديلاً على واجهة 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) .
أو
القاعدة ب

كل ما يلي صحيح:

  1. "الإصدار الثانوي السابق صالح": يجب تعريف package @ major. (small package@major.(minor-1) واتباع نفس القاعدة A (لم يتم تحديد أي من package@major.0 عبر package@major.(minor-2) ) أو القاعدة B (إذا كانت uprev من @major.(minor-2) ) ؛

    و

  2. "توارث واجهة واحدة على الأقل بنفس الاسم": توجد واجهة package@major.minor::IFoo توسع package@major.(minor-1)::IFoo (إذا كانت الحزمة السابقة بها واجهة) ؛

    و

  3. "لا توجد واجهة موروثة باسم مختلف": يجب ألا يكون هناك package@major.minor::IBar يمتد package@major.(minor-1)::IBaz ، حيث IBar و IBaz مختلفان. إذا كانت هناك واجهة تحمل نفس الاسم ، فيجب أن package@major.minor::IBar بتوسيع package@major.(minor-k)::IBar بحيث لا يوجد IBar مع k أصغر.

بسبب القاعدة أ:

  • يمكن أن تبدأ الحزمة بأي رقم إصدار ثانوي (على سبيل المثال ، 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 عن طريق التكوين.

ومع ذلك ، يتم تحديد نوع واحد من العلاقات بشكل صارم ويجب فرضه: مستوى الحزمة المتوافق مع الإصدارات السابقة . في هذا السيناريو ، تكون الحزمة الأصلية هي الحزمة الموروثة منها والحزمة الفرعية هي الحزمة التي تمد الأصل . قواعد الميراث المتوافقة مع الإصدارات السابقة على مستوى الحزمة هي كما يلي:

  1. يتم توريث جميع واجهات المستوى الأعلى للحزمة الأصلية من خلال واجهات في الحزمة الفرعية.
  2. يمكن أيضًا إضافة واجهات جديدة إلى الحزمة الجديدة (لا توجد قيود على العلاقات مع الواجهات الأخرى في الحزم الأخرى).
  3. يمكن أيضًا إضافة أنواع بيانات جديدة للاستخدام إما عن طريق الأساليب الجديدة للواجهات الحالية المحدثة ، أو بواجهات جديدة.

يمكن تنفيذ هذه القواعد باستخدام الوراثة على مستوى واجهة HIDL وتكوين UDT ، ولكنها تتطلب معرفة على مستوى التعريف لمعرفة أن هذه العلاقات تشكل امتداد حزمة متوافق مع الإصدارات السابقة. يتم الاستدلال على هذه المعرفة على النحو التالي:

إذا كانت الحزمة تفي بهذا المطلب ، hidl-gen يفرض قواعد التوافق العكسي.