إنشاء واجهة HAL

يجب استخدام HIDL لوصف جميع علامات الإصدار المستخدمة في تجميع إطار العمل بشكل مشروط. ويجب تجميع علامات الإصدار ذات الصلة وتضمينها في ملف .hal واحد. يتضمن استخدام HIDL لتحديد عناصر الإعداد المزايا التالية:

  • الإصدارات (لإضافة عناصر إعداد جديدة، على المورّدين/المصنّعين الأصليين للأجهزة توسيع HAL بشكلٍ صريح)
  • موثَّق بالكامل
  • التحكم في الوصول باستخدام SELinux
  • التحقق من سلامة عناصر الإعداد من خلال مجموعة اختبار البائعين (التحقق من النطاق والتحقق من الاعتمادية بين العناصر وما إلى ذلك)
  • واجهات برمجة التطبيقات التي تم إنشاؤها تلقائيًا في كل من C++ وJava

تحديد علامات الإصدار التي يستخدمها إطار العمل

ابدأ بتحديد تهيئات الإصدار المستخدمة لتجميع إطار العمل بشكل مشروط، ثم التخلي عن الإعدادات القديمة لتصغير المجموعة. على سبيل المثال، يتم تحديد المجموعة التالية من علامات الإصدار الخاصة بـ surfaceflinger:

  • TARGET_USES_HWC2
  • TARGET_BOARD_PLATFORM
  • TARGET_DISABLE_TRIPLE_BUFFERING
  • TARGET_FORCE_HWC_FOR_VIRTUAL_DISPLAYS
  • NUM_FRAMEBUFFER_SURFACE_BUFFERS
  • TARGET_RUNNING_WITHOUT_SYNC_FRAMEWORK
  • VSYNC_EVENT_PHASE_OFFSET_NS
  • SF_VSYNC_EVENT_PHASE_OFFSET_NS
  • PRESENT_TIME_OFFSET_FROM_VSYNC_NS
  • MAX_VIRTUAL_DISPLAY_DIMENSION

إنشاء واجهة HAL

يتم الوصول إلى إعدادات إنشاء النظام الفرعي من خلال واجهة HAL، بينما يتم تجميع الواجهات لتوفير قيم الضبط في حزمة HAL android.hardware.configstore (في الإصدار 1.0 حاليًا). على سبيل المثال، لإنشاء ملف واجهة HAL في surfaceflinger، في hardware/interfaces/configstore/1.0/ISurfaceFlingerConfigs.hal:

package android.hardware.configstore@1.0;

interface ISurfaceFlingerConfigs {
    // TO-BE-FILLED-BELOW
};

بعد إنشاء ملف .hal، شغِّل hardware/interfaces/update-makefiles.sh لإضافة ملف .hal الجديد إلى ملفَي Android.bp وAndroid.mk.

إضافة دوال لعلامات الإصدار

أضِف دالة جديدة إلى الواجهة لكل علامة إصدار. على سبيل المثال، في hardware/interfaces/configstore/1.0/ISurfaceFlingerConfigs.hal:

interface ISurfaceFlingerConfigs {
    disableTripleBuffering() generates(OptionalBool ret);
    forceHwcForVirtualDisplays() generates(OptionalBool ret);
    enum NumBuffers: uint8_t {
        USE_DEFAULT = 0,
        TWO = 2,
        THREE = 3,
    };
    numFramebufferSurfaceBuffers() generates(NumBuffers ret);
    runWithoutSyncFramework() generates(OptionalBool ret);
    vsyncEventPhaseOffsetNs generates (OptionalUInt64 ret);
    presentTimeOffsetFromSyncNs generates (OptionalUInt64 ret);
    maxVirtualDisplayDimension() generates(OptionalInt32 ret);
};

عند إضافة دالة:

  • استخدام الأسماء المختصرة: تجنَّب تحويل أسماء متغيّرات makefile إلى أسماء دوال وتذكَّر أنّ البادئتين TARGET_ وBOARD_ لم تعُد ضرورية.
  • إضافة تعليقات ساعِد المطوّرين على فهم الغرض من عنصر الضبط وكيف يغيّر سلوك إطار العمل والقيم الصالحة والمعلومات الأخرى ذات الصلة.

ويمكن أن تكون أنواع إرجاع الدوال Optional[Bool|String|Int32|UInt32|Int64|UInt64]. يتم تحديد الأنواع في types.hal في الدليل نفسه، مع إحاطة القيم الأساسية بحقل يشير إلى ما إذا كانت القيمة محددة بواسطة HAL، وفي حال عدم تحديدها، يتم استخدام القيمة التلقائية.

struct OptionalString {
    bool specified;
    string value;
};

حدِّد التعداد الذي يمثّل نوع عنصر الضبط على أفضل وجه إذا كان ذلك مناسبًا واستخدِم هذا التعداد كنوع الإرجاع. في المثال أعلاه، يتم تعريف تعداد NumBuffers للحدّ من عدد القيم الصالحة. عند تحديد أنواع البيانات المخصّصة هذه، أضِف حقلاً أو قيمة تعداد (على سبيل المثال، USE_DEFAULT) للإشارة إلى ما إذا كانت القيمة محدّدة في HAL أم لا.

وليس إلزاميًا أن تصبح علامة إصدار واحدة دالة واحدة في HIDL. ويمكن لمالكي الوحدات بدلاً من ذلك تجميع علامات الإصدار ذات الصلة الوثيقة في بنية وتكون لها وظيفة تعرض هذا الهيكل (يمكن أن يؤدي ذلك إلى تقليل عدد استدعاءات الدوال).

على سبيل المثال، أحد الخيارات المتاحة لتجميع علامتَي إنشاء في بنية واحدة في hardware/interfaces/configstore/1.0/ISurfaceFlingerConfigs.hal هو:

 interface ISurfaceFlingerConfigs {
    // other functions here
    struct SyncConfigs {
        OptionalInt64 vsyncEventPhaseoffsetNs;
        OptionalInt64 presentTimeoffsetFromSyncNs;
    };
    getSyncConfigs() generates (SyncConfigs ret);
    // other functions here
};

بدائل لدالة HAL واحدة

كبديل لاستخدام دالة HAL واحدة لجميع علامات الإصدار، توفّر واجهة HAL أيضًا دوال بسيطة مثل getBoolean(string key) وgetInteger(string key). يتم تخزين أزواج key=value الفعلية في ملفات منفصلة وتوفر خدمة HAL القيم من خلال قراءة/تحليل هذه الملفات.

على الرغم من أنّ هذا الأسلوب سهل التعريف، فهو لا يتضمّن المزايا التي تقدّمها "شهادة HIDL" (أي الإصدارات الإلزامية، وسهولة التوثيق، والتحكّم في الوصول)، وبالتالي لا ننصح به.

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

يقدم تصميم واجهة HAL لعناصر التهيئة خيارين:

  • واجهة واحدة تشمل جميع عناصر الضبط
  • واجهات متعددة، يغطي كل منها مجموعة من عناصر الضبط ذات الصلة

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

بسبب هذه المشاكل، يستخدم Android واجهات متعددة مع واجهة HAL واحدة لمجموعة من عناصر الإعداد ذات الصلة. على سبيل المثال، ISurfaceflingerConfigs لعناصر الضبط المتعلقة بـ surfaceflinger، وIBluetoothConfigs لعناصر الضبط المتعلقة بالبلوتوث.