الواجهات والحِزم

تم إنشاء HIDL حول الواجهات، وهي نوع تجريدي يستخدم في اللغات كائنية التوجيه لتحديد السلوكيات. كل واجهة هي جزء من حزمة.

إدارة الحِزم

يمكن أن تحتوي أسماء الحِزم على مستويات فرعية، مثل package.subpackage. ملف تعريف الدليل الجذر لحِزم HIDL المنشورة هو hardware/interfaces أو vendor/vendorName (على سبيل المثال، vendor/google لأجهزة Pixel ). يشكّل اسم الحزمة دليلاً فرعيًا واحدًا أو أكثر ضمن الدليل العميق، وتكون جميع الملفات التي تحدّد الحزمة في الدليل نفسه. على سبيل المثال، يمكن العثور على package android.hardware.example.extension.light@2.0 ضمن hardware/interfaces/example/extension/light/2.0.

يسرد الجدول التالي بادئات الحِزم ومواقعها الجغرافية:

بادئة الحزمة الموقع الجغرافي أنواع الواجهات
android.hardware.* hardware/interfaces/* HAL
android.frameworks.* frameworks/hardware/interfaces/* أُطر عمل/ ذات صلة
android.system.* system/hardware/interfaces/* نظام/ ذات صلة
android.hidl.* system/libhidl/transport/* الأساسية

يحتوي دليل الحزمة على ملفات ذات امتداد .hal. يجب أن يحتوي كل ملف على بيان package يحدِّد الحزمة والإصدار اللذين يمثّل الملف جزءًا منهما. لا يحدِّد الملف types.hal، في حال توفّره، واجهة، بل يحدِّد بدلاً من ذلك أنواع البيانات التي يمكن لكل واجهة في الحزمة الوصول إليها.

تعريف الواجهة

باستثناء types.hal، يحدّد كل ملف .hal آخر واجهة. يتم تعريف الواجهة عادةً على النحو التالي:

interface IBar extends IFoo { // IFoo is another interface
    // embedded types
    struct MyStruct {/*...*/};

    // interface methods
    create(int32_t id) generates (MyStruct s);
    close();
};

تمتد الواجهة بشكل ضمني من android.hidl.base@1.0::IBase (على غرار java.lang.Object في Java) إذا لم يتم تضمين بيان extends صريح لها. واجهة IBase التي يتم استيرادها بشكل ضمني تعلن عن عدة طرق محجوزة لا يجب ولا يمكن إعادة إعلانها في الواجهات التي يحدّدها المستخدم أو استخدامها بأي شكل آخر. وتشمل هذه الطرق ما يلي:

  • ping
  • interfaceChain
  • interfaceDescriptor
  • notifySyspropsChanged
  • linkToDeath
  • unlinkToDeath
  • setHALInstrumentation
  • getDebugInfo
  • debug
  • getHashChain

عملية الاستيراد

عبارة import هي آلية HIDL للوصول إلى واجهة الحزمة وأنواعها في حزمة أخرى. تتناول عبارة import كيانَين:

  • عنصر الاستيراد، الذي يمكن أن يكون حزمة أو واجهة
  • الكيانالمستورَد، والذي يمكن أن يكون حزمة أو واجهة

يتم تحديد الكيان المستورِد حسب موضع بيان import. عندما يكون البيان داخل types.hal الحزمة، يكون ما يتم استيراده مرئيًا للحزمة بأكملها، ويُعدّ ذلك استيرادًا على مستوى الحزمة. عندما يكون البيان داخل ملف واجهة، يكون الكيان المستورِد هو الواجهة نفسها، وهذا هو استيراد على مستوى الواجهة.

يتم تحديد الكيان المستورَد من خلال القيمة التي تأتي بعد الكلمة الرئيسية import. ولا يلزم أن تكون القيمة اسمًا مؤهَّلاً بالكامل. وفي حال حذف أحد المكوّنات، يتم ملؤه تلقائيًا بمعلومات من الحزمة الحالية. بالنسبة إلى القيم المؤهَّلة بالكامل، تكون حالات الاستيراد التالية متاحة:

  • عمليات استيراد الحِزم بأكملها: إذا كانت القيمة هي اسم حزمة و إصدار (البنية النحوية الموضّحة أدناه)، يتم استيراد الحزمة بأكملها إلى العنصر المستورِد.
  • عمليات الاستيراد الجزئية: إذا كانت القيمة:
    • يتم استيراد واجهة وtypes.hal الحزمة وتلك الواجهة إلى الكيان المستورِد.
    • عنصر بيانات مستخدم محدّد في types.hal، ثم يتم استيراد عنصر البيانات المستخدَم هذا فقط إلى العنصر المستورِد (لا يتم استيراد الأنواع الأخرى في types.hal).
  • عمليات الاستيراد التي تتضمّن الأنواع فقط: إذا كانت القيمة تستخدِم بنية العبارة الخاصة بالاستيراد الجزئي الموضّحة أعلاه، ولكن باستخدام الكلمة الرئيسية types بدلاً من اسم واجهة، لا يتم استيراد سوى أنواع البيانات الوصفية في types.hal من الحزمة المخصّصة.

يحصل الكيان المستورِد على مجموعة من:

  • وحدات البيانات الوصفية الشائعة للحزمة المستورَدة والمُحدَّدة في types.hal
  • واجهات الحزمة المستورَدة (عند استيراد حزمة كاملة) أو الواجهة المحدّدة (عند استيراد جزء من الحزمة) لأغراض استدعائها و/أو تمرير الأسماء المعرِّفة إليها و/أو اكتساب السمات منها

تستخدِم عبارة الاستيراد بنية اسم النوع المؤهَّل بالكامل لتوفير اسم الحزمة أو الواجهة التي يتم استيرادها وإصدارها:

import android.hardware.nfc@1.0;            // import a whole package
import android.hardware.example@1.0::IQuux; // import an interface and types.hal
import android.hardware.example@1.0::types; // import just types.hal

اكتساب الأذونات من الواجهات

يمكن أن تكون الواجهة امتدادًا لواجهة محدّدة مسبقًا. يمكن أن تكون الإضافات من أحد الأنواع الثلاثة التالية:

  • يمكن أن تضيف الواجهة وظيفة إلى واجهة أخرى، مع دمج واجهة برمجة التطبيقات بدون تغيير.
  • يمكن أن تضيف الحزمة وظيفة إلى حزمة أخرى، مع دمج واجهة برمجة التطبيقات بدون تغيير.
  • يمكن للواجهة استيراد الأنواع من حزمة أو من واجهة معيّنة.

يمكن للواجهة أن تمتد إلى واجهة أخرى واحدة فقط (لا يمكن اكتساب سمات متعددة). يجب أن تُنشئ كل واجهة في حزمة ذات رقم إصدار ثانوي غير صفري واجهة في الإصدار السابق من الحزمة. على سبيل المثال، إذا كانت الواجهة IBar في الإصدار 4.0 من الحزمة derivative تستند إلى (توسّع) واجهة IFoo في الإصدار 1.2 من الحزمة original، وتم إنشاء الإصدار 1.3 من الحزمة original، لا يمكن للإصدار 4.1 من IBar توسيع الإصدار 1.3 من IFoo. بدلاً من ذلك، يجب أن يمتد إصدار IBar 4.1 IBar الإصدار 4.0، والذي يرتبط بالإصدار 1.2 من IFoo. يمكن أن يمدِّد الإصدار 5.0 من IBar الإصدار 1.3 من IFoo، إذا كان ذلك مطلوبًا.

لا تشير إضافات الواجهات إلى الاعتماد على المكتبة أو تضمين HAL على مستوى مختلف في الرمز الذي تم إنشاؤه، بل تستورد ببساطة بنية البيانات وتعريفات الأسلوب على مستوى HIDL. يجب تنفيذ كل طريقة في HAL في ملف HAL هذا.

إضافات المورّدين

في بعض الحالات، يتم تنفيذ إضافات المورّدين كصنف فرعي من العنصر الأساسي الذي يمثّل الواجهة الأساسية التي تضيف إليها ميزات. يتم تسجيل العنصر نفسه باستخدام اسم HAL الأساسي وإصداره، واسم HAL (للمورّد) وإصداره في الإضافة.

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

يتم إصدار الحِزم، وتحتوي الواجهات على إصدار الحزمة. يتم التعبير عن الإصدارات برقمين صحيحَين، الإصدار الرئيسي.الإصدار الثانوي.

  • لا تتوافق الإصدارات الرئيسية مع الإصدارات القديمة. يؤدي الزيادة في رقم الإصدار الرئيسي إلى إعادة ضبط رقم الإصدار الثانوي على 0.
  • تكون الإصدارات الثانوية متوافقة مع الإصدارات القديمة. تشير الزيادة في الرقم الثانوي إلى أنّ الإصدار الأحدث متوافق تمامًا مع الإصدار السابق. يمكن إضافة هياكل بيانات وطُرق جديدة، ولكن لا يجوز تغيير هياكل البيانات أو توقيعات الطُرق الحالية.

يمكن أن تتوفّر عدة إصدارات رئيسية أو ثانوية من HAL على جهازٍ في الوقت نفسه. ومع ذلك، يجب تفضيل الإصدار الثانوي على الإصدار العميق لأنّ رمز العميل الذي يعمل مع واجهة إصدار ثانوي سابق يعمل أيضًا مع الإصدارات الثانوية اللاحقة من هذه الواجهة نفسها. لمزيد من التفاصيل حول تحديد الإصدارات وإضافات المصنّعين، يُرجى الاطّلاع على تحديد إصدار HIDL.

ملخّص تنسيق الواجهة

يلخِّص هذا القسم كيفية إدارة حزمة واجهة HIDL (مثل hardware/interfaces) ويجمع المعلومات المقدَّمة في قسم HIDL. قبل القراءة، تأكَّد من أنّك على دراية بمفهومَي إصدار HIDL و التجزئة باستخدام hidl-gen، وتفاصيل العمل مع HIDL بشكل عام، والتعريفات التالية:

العبارة التعريف
واجهة التطبيق الثنائية (ABI) واجهة برمجة التطبيقات بالإضافة إلى أي روابط ثنائية مطلوبة
الاسم المؤهَّل بالكامل (fqName) اسم لتمييز نوع hidl مثال: android.hardware.foo@1.0::IFoo
طرد حزمة تحتوي على واجهة HIDL وأنواعها مثال: android.hardware.foo@1.0
جذر الحزمة الحزمة الجذر التي تحتوي على واجهات HIDL مثال: واجهة HIDL android.hardware في جذر الحزمة android.hardware.foo@1.0
مسار جذر الحزمة الموقع في شجرة مصدر Android الذي يتمّ ربط جذر الحزمة به

لمزيد من التعريفات، يُرجى الاطّلاع على HIDL المصطلحات.

يمكن العثور على كل ملف من خلال تعيين جذر الحزمة واسمه المحدَّد بالكامل.

يتم تحديد جذور الحِزم على أنّها hidl-gen كوسيطة -r android.hardware:hardware/interfaces. على سبيل المثال، إذا كان الحزمة هي vendor.awesome.foo@1.0::IFoo وتم إرسال hidl-gen -r vendor.awesome:some/device/independent/path/interfaces، يجب أن يكون ملف الواجهة في $ANDROID_BUILD_TOP/some/device/independent/path/interfaces/foo/1.0/IFoo.hal.

من الناحية العملية، ننصح المورّد أو المصنّع الأصلي للجهاز الذي يحمل الاسم awesome بوضع واجهاته العادية في vendor.awesome. بعد اختيار مسار بستهة، يجب عدم تغييره لأنّه يتم دمجه في ABI للواجهة.

يجب أن يكون تعيين مسار الحزمة فريدًا.

على سبيل المثال، إذا كان لديك -rsome.package:$PATH_A و -rsome.package:$PATH_B، يجب أن يكون $PATH_A مساويًا $PATH_B لإنشاء دليل واجهة متّسق (يسهّل ذلك أيضًا إنشاء واجهات بإصدارات مختلفة).

يجب أن يحتوي جذر الحزمة على ملف تحديد إصدار

إذا أنشأت مسار حزمة مثل -r vendor.awesome:vendor/awesome/interfaces، عليك أيضًا إنشاء الملف $ANDROID_BUILD_TOP/vendor/awesome/interfaces/current.txt، الذي يجب أن يحتوي على تجزئات للواجهات التي تم إنشاؤها باستخدام الخيار -Lhash في hidl-gen (يتم مناقشة هذا الموضوع بشكل مفصّل في مقالة التجزئة باستخدام hidl-gen).

توضع الواجهات في مواضع مستقلة عن الجهاز .

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