إنشاء واجهة 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);
};

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

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

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

struct OptionalString {
    bool specified;
    string value;
};

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

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

على سبيل المثال، أحد الخيارات المتاحة لتجميع علامتَي إنشاء في بنية واحدة في 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 لعناصر الضبط المتعلقةsurfaceflinger.