لغة AIDL لـ HALs

يقدّم نظام التشغيل Android 11 إمكانية استخدام AIDL مع واجهات HAL في Android. يتيح ذلك تنفيذ أجزاء من Android بدون HIDL. نقل واجهات برمجة التطبيقات لمستوى الحِزم الأساسية (HAL) لاستخدام AIDL حصريًا حيثما أمكن (يجب استخدام HIDL عندما تستخدم واجهات برمجة التطبيقات لمستوى الحِزم الأساسية في المصدر HIDL).

يجب أن تستخدم واجهات HAL التي تستخدم AIDL للتواصل بين مكوّنات إطار العمل، مثل تلك الواردة في system.img، ومكوّنات الأجهزة، مثل تلك الواردة في vendor.img، مكتبة IDE للبرمجة لنظام التشغيل Android (AIDL) الثابتة. ومع ذلك، للتواصل داخل قسم معيّن، على سبيل المثال، من معالج معالجة حدود المستوى (HAL) إلى آخر، لا يوجد أي قيود على آلية IPC التي يمكن استخدامها.

الحافز

تم استخدام لغة تعريف واجهة نظام Android لفترة أطول من لغة HIDL، ويتم استخدامها في العديد من الأماكن الأخرى، مثل بين مكونات إطار عمل Android أو في التطبيقات. والآن بعد أن أصبح تنسيق AIDL مستقرًا، أصبح من الممكن تنفيذ حِزمة كاملة باستخدام وقت تشغيل واحد لبروتوكول I/O بين العمليات. يحتوي AIDL أيضًا على نظام إصدار أفضل من HIDL.

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

إنشاء التطبيق باستخدام وقت تشغيل AIDL

يحتوي AIDL على ثلاث خلفيات مختلفة: Java وNDK وCPP. لاستخدام حزمة AIDL الثابتة، يجب استخدام نسخة النظام من libbinder في system/lib*/libbinder.so والتحدث عن /dev/binder في جميع الأوقات. بالنسبة إلى الرمز البرمجي في صورة المورّد، يعني ذلك أنّه لا يمكن استخدام libbinder (من حزمة VNDK)، لأنّ هذه المكتبة تتضمّن واجهة برمجة تطبيقات C++ غير مستقرة و مكونات داخلية غير مستقرة. بدلاً من ذلك، يجب أن يستخدم رمز المورّد الأصلي الخلفية لـ NDK في AIDL، وأن يرتبط بـ libbinder_ndk (الذي يستند إلى نظام libbinder.so)، ويرتبط بمكتبات NDK التي تم إنشاؤها بواسطة إدخالات aidl_interface. للاطّلاع على أسماء الوحدات الدقيقة، يُرجى الاطّلاع على قواعد تسمية الوحدات.

كتابة واجهة HAL لـ AIDL

لاستخدام واجهة AIDL بين النظام والمورّد، تحتاج الواجهة إلى تغييرَين:

  • يجب إضافة تعليق توضيحي باستخدام @VintfStability إلى كل تعريف نوع.
  • يجب أن يتضمّن نموذج بيان aidl_interface ما يلي: stability: "vintf",.

لا يمكن لأحد غير مالك الواجهة إجراء هذه التغييرات.

عند إجراء هذه التغييرات، يجب أن تكون الواجهة في بيان VINTF لكي تعمل. اختبِر ذلك (والمتطلبات المرتبطة به، مثل التحقّق من تجميد الواجهات التي تم إصدارها) باستخدام اختبار VTS vts_treble_vintf_vendor_test. يمكنك استخدام واجهة @VintfStability بدون هذه المتطلبات من خلال استدعاء إما AIBinder_forceDowngradeToLocalStability في الخلفية في NDK أو android::Stability::forceDowngradeToLocalStability في الخلفية في C++ أو android.os.Binder#forceDowngradeToSystemStability في الخلفية في Java على عنصر ربط قبل إرساله إلى عملية أخرى. لا تتيح Java تقليل إصدار الخدمة إلى إصدار مستقر من المورّد لأنّ جميع التطبيقات تعمل في سياق النظام.

بالإضافة إلى ذلك، لتحقيق أقصى قدر من إمكانية نقل الرموز البرمجية وتجنُّب المشاكل المحتملة، مثل المكتبات الإضافية غير الضرورية، يمكنك إيقاف الخلفية في لغة C++.

يُرجى العِلم أنّ استخدام backends في مثال الرمز البرمجي أدناه صحيح، لأنّه تتوفّر ثلاث خلفيات (Java وNDK وCPP). يوضّح الرمز البرمجي أدناه كيفية اختيار واجهة برمجة التطبيقات CPP الخلفية على وجه التحديد لإيقافها.

    aidl_interface: {
        ...
        backends: {
            cpp: {
                enabled: false,
            },
        },
    }

العثور على واجهات AIDL HAL

واجهات AIDL الثابتة في AOSP لواجهة HAL متوفّرة في الدلائل الأساسية نفسها التي تتوفّر فيها واجهات HIDL، في مجلدات aidl.

  • hardware/interfaces: للواجهات التي يوفّرها الجهاز عادةً
  • frameworks/hardware/interfaces: للواجهات العالية المستوى المقدَّمة للأجهزة
  • system/hardware/interfaces: للواجهات ذات المستوى المنخفض المقدَّمة للأجهزة

يجب وضع واجهات الإضافات في أدلة فرعية أخرى hardware/interfaces في vendor أو hardware.

واجهات الإضافات

يتضمّن Android مجموعة من واجهات AOSP الرسمية مع كل إصدار. عندما يريد شركاء Android إضافة وظائف إلى هذه الواجهات، يجب ألا يغيّروا هذه الواجهات مباشرةً لأنّ ذلك يعني أنّ وقت تشغيل Android غير متوافق مع وقت تشغيل Android من AOSP. بالنسبة إلى أجهزة GMS، يضمن أيضًا تجنُّب تغيير هذه الواجهات استمرار عمل صورة GSI.

يمكن تسجيل الإضافات بطريقتَين مختلفتَين:

  • في وقت التشغيل، اطّلِع على الإضافات المرفقة.
  • مستقلة ومسجَّلة على مستوى العالم وفي VINTF

بغض النظر عن كيفية تسجيل الإضافة، لا يمكن أن يحدث تعارض في دمج المكونات الخاصة بالمورّد (أي غير المضمّنة في الإصدار العلني من AOSP) عند استخدامها للواجهة. ومع ذلك، عند إجراء تعديلات على الإصدارات اللاحقة لمكوّنات AOSP في الإصدارات السابقة، يمكن أن يؤدي ذلك إلى حدوث تعارضات في الدمج، لذا ننصحك باتّباع الاستراتيجيات التالية:

  • يمكن نقل إضافات الواجهة إلى AOSP في الإصدار التالي.
  • إضافات الواجهة التي تسمح بمزيد من المرونة بدون تعارضات الدمج، يمكن نقلها إلى الإصدار التالي

عناصر الحزمة الإضافية: ParcelableHolder

ParcelableHolder هو Parcelable يمكن أن يحتوي على Parcelable آخر. تتمثل حالة الاستخدام الرئيسية ParcelableHolder في جعل Parcelable قابلاً للتوسيع. على سبيل المثال، الصورة التي يتوقّع منتشِرو الأجهزة أن يتمكّنوا من توسيع نطاق Parcelable أو AospDefinedParcelable المحدّدَين في AOSP لتشمل ميزات قيّمة.

في السابق، بدون ParcelableHolder، لم يكن بإمكان جهات تنفيذ الأجهزة تعديل واجهة AIDL ثابتة محدّدة في AOSP لأنّه سيحدث خطأ عند إضافة المزيد من الحقول:

parcelable AospDefinedParcelable {
  int a;
  String b;
  String x; // ERROR: added by a device implementer
  int[] y; // added by a device implementer
}

كما هو موضّح في الرمز البرمجي السابق، لا يمكن تنفيذ هذه الممارسة لأنّ الحقول التيأضافها مطوّر الجهاز قد تتعارض مع الحقول في Parcelable عند تعديلها في الإصدارات التالية من Android.

باستخدام ParcelableHolder، يمكن لمالك قطعة أرض تحديد نقطة بدء التمديد في Parcelable.

parcelable AospDefinedParcelable {
  int a;
  String b;
  ParcelableHolder extension;
}

بعد ذلك، يمكن لمنفّذِي الأجهزة تحديد Parcelable الخاص بهم لإضافة.

parcelable OemDefinedParcelable {
  String x;
  int[] y;
}

أخيرًا، يمكن إرفاق Parcelable الجديد بـ Parcelable الأصلي باستخدام الحقل ParcelableHolder.


// Java
AospDefinedParcelable ap = ...;
OemDefinedParcelable op = new OemDefinedParcelable();
op.x = ...;
op.y = ...;

ap.extension.setParcelable(op);

...

OemDefinedParcelable op = ap.extension.getParcelable(OemDefinedParcelable.class);

// C++
AospDefinedParcelable ap;
OemDefinedParcelable op;
std::shared_ptr<OemDefinedParcelable> op_ptr = make_shared<OemDefinedParcelable>();

ap.extension.setParcelable(op);
ap.extension.setParcelable(op_ptr);

...

std::shared_ptr<OemDefinedParcelable> op_ptr;

ap.extension.getParcelable(&op_ptr);

// NDK
AospDefinedParcelable ap;
OemDefinedParcelable op;
ap.extension.setParcelable(op);

...

std::optional<OemDefinedParcelable> op;
ap.extension.getParcelable(&op);

// Rust
let mut ap = AospDefinedParcelable { .. };
let op = Rc::new(OemDefinedParcelable { .. });

ap.extension.set_parcelable(Rc::clone(&op));

...

let op = ap.extension.get_parcelable::<OemDefinedParcelable>();

أسماء نُسخ خادم HAL في AIDL

وفقًا للاتفاقية، تتضمّن خدمات HAL في AIDL اسم مثيل بالشكل $package.$type/$instance. على سبيل المثال، يتم تسجيل مثيل HAL الخاص بالهزّاز على أنّه android.hardware.vibrator.IVibrator/default.

كتابة خادم HAL لواجهة برمجة التطبيقات AIDL

@VintfStability يجب الإعلان عن خوادم AIDL في بيان VINTF، على سبيل المثال:

    <hal format="aidl">
        <name>android.hardware.vibrator</name>
        <version>1</version>
        <fqname>IVibrator/default</fqname>
    </hal>

بخلاف ذلك، يجب تسجيل خدمة AIDL بشكلٍ طبيعي. عند إجراء اختبارات VTS، من المتوقّع أن تكون جميع واجهات برمجة التطبيقات لHAL في AIDL مُعلَن عنها ومتوفرة.

كتابة برنامج AIDL

يجب أن يعلن عملاء AIDL عن أنفسهم في مصفوفة التوافق، على سبيل المثال، على النحو التالي:

    <hal format="aidl" optional="true">
        <name>android.hardware.vibrator</name>
        <version>1-2</version>
        <interface>
            <name>IVibrator</name>
            <instance>default</instance>
        </interface>
    </hal>

تحويل HAL حالي من HIDL إلى AIDL

استخدِم أداة hidl2aidl لتحويل واجهة HIDL إلى AIDL.

ميزات hidl2aidl:

  • إنشاء ملفات .aidl استنادًا إلى ملفات .hal للحزمة المحدّدة
  • أنشئ قواعد إنشاء لحزمة AIDL التي تم إنشاؤها حديثًا مع تفعيل جميع الخلفيات
  • أنشئ طرق ترجمة في الخلفيات Java وCPP وNDK لترجمة من أنواع HIDL إلى أنواع AIDL
  • إنشاء قواعد إنشاء لمكتبات الترجمة التي تتضمّن التبعيات المطلوبة
  • أنشئ تأكيدات ثابتة لضمان أنّ أدوات سرد HIDL وAIDL تتضمّن القيم نفسها في الخلفيات CPP وNDK.

اتّبِع الخطوات التالية لتحويل حِزمة من ملفات ‎ .hal إلى ملفات ‎ .aidl:

  1. أنشئ الأداة في system/tools/hidl/hidl2aidl.

    يقدّم إنشاء هذه الأداة من أحدث مصدر أفضل تجربة كاملة. يمكنك استخدام أحدث إصدار لتحويل الواجهات في الإصدارات السابقة من الفروع القديمة.

    m hidl2aidl
  2. يمكنك تنفيذ الأداة مع دليل إخراج متبوع بالحزمة التي تريد تحويلها.

    يمكنك اختياريًا استخدام الوسيطة -l لإضافة محتوى ملف ترخيص جديد إلى أعلى جميع الملفات التي تم إنشاؤها. تأكَّد من استخدام الترخيص والتاريخ الصحيحَين.

    hidl2aidl -o <output directory> -l <file with license> <package>

    مثلاً:

    hidl2aidl -o . -l my_license.txt android.hardware.nfc@1.2
  3. اطّلِع على الملفات التي تم إنشاؤها وأصلِح أي مشاكل في عملية التحويل.

    • يحتوي conversion.log على أي مشاكل لم يتم حلّها ويجب حلّها أولاً.
    • قد تحتوي ملفات .aidl التي تم إنشاؤها على تحذيرات واقتراحات قد تحتاج إلى اتخاذ إجراء. تبدأ هذه التعليقات بالرمز //.
    • يمكنك تنظيف الحزمة وإجراء تحسينات عليها.
    • اطّلِع على التعليق التوضيحي @JavaDerive للاطّلاع على الميزات التي قد تكون مطلوبة، مثل toString أو equals.
  4. أنشئ الاستهدافات التي تحتاج إليها فقط.

    • أوقِف الخلفيات التي لن يتم استخدامها. استخدِم الخلفية في NDK بدلاً من الخلفية في لغة برمجة C++، اطّلِع على اختيار وقت التشغيل.
    • أزِل مكتبات الترجمة أو أيّ من الرموز التي تم إنشاؤها ولن يتم استخدامها.
  5. اطّلِع على الاختلافات الرئيسية بين AIDL وHIDL.

    • يؤدي استخدام Status والاستثناءات المضمّنة في AIDL إلى تحسين الواجهة عادةً وإزالة الحاجة إلى نوع حالة آخر خاص بالواجهة.
    • لا تكون وسيطات واجهة AIDL في الطرق @nullable تلقائيًا كما كانت في HIDL.

سياسة SEPolicy لحِزم HAL لـ AIDL

يجب أن يتضمّن نوع خدمة AIDL الذي يظهر لرمز المورّد سمة hal_service_type. بخلاف ذلك، تكون إعدادات سياسة الأمان مماثلة لأي خدمة أخرى من خدمات AIDL (على الرغم من توفُّر سمات خاصة لواجهة HAL). في ما يلي مثال على تعريف سياق خدمة HAL:

    type hal_foo_service, service_manager_type, hal_service_type;

بالنسبة إلى معظم الخدمات التي تحدّدها المنصة، سبق أن تمت إضافة سياق الخدمة بنوع الصحيح (على سبيل المثال، سبق أن تم وضع علامة على android.hardware.foo.IFoo/default بصفتها hal_foo_service). ومع ذلك، إذا كان أحد عملاء إطار العمل يتيح أسماء نُسخ متعددة، يجب إضافة أسماء نُسخ إضافية فيملفّات service_contexts الخاصة بالجهاز.

    android.hardware.foo.IFoo/custom_instance u:object_r:hal_foo_service:s0

يجب إضافة سمات HAL عند إنشاء نوع جديد من HAL. قد تكون سمة HAL معيّنة مرتبطة بأنواع خدمات متعددة (قد يكون لكل منها مثيلات متعددة كما ناقشنا للتو). بالنسبة إلى HAL، foo، لدينا hal_attribute(foo). يحدِّد هذا الماكرو السمتَين hal_foo_client و hal_foo_server. بالنسبة إلى نطاق معيّن، تربط الوحدات النمطية hal_client_domain و hal_server_domain نطاقًا بسمة HAL معيّنة. على سبيل المثال، يتوافق خادم النظام الذي يكون عميلًا لواجهة HAL هذه مع السياسة hal_client_domain(system_server, hal_foo). يتضمّن خادم HAL بالمثل hal_server_domain(my_hal_domain, hal_foo). عادةً، بالنسبة إلى سمة HAL معيّنة، ننشئ أيضًا نطاقًا مثل hal_foo_default كمرجع أو كمثال على HAL. ومع ذلك، تستخدم بعض الأجهزة هذه النطاقات لخوادم خاصة بها. لا يهمّ التمييز بين نطاقات الخوادم المتعددة إلا إذا كان لدينا خوادم متعددة تعرِض الواجهة نفسها وتحتاج إلى مجموعة أذونات مختلفة في عمليات التنفيذ. في كل هذه الوحدات النمطية، hal_foo ليس كائنًا لسياسة الأمان. بدلاً من ذلك، تستخدم هذه الوحدات النمطية هذا الرمز المميّز للإشارة إلى مجموعة السمات المرتبطة بزوج من الخادم والعميل.

ومع ذلك، لم نربط حتى الآن hal_foo_service وhal_foo (زوج السمات من hal_attribute(foo)). يتم ربط سمة HAL بخدمات AIDL HAL باستخدام الماكرو hal_attribute_service (تستخدم HIDL HALs الماكرو hal_attribute_hwservice). على سبيل المثال، hal_attribute_service(hal_foo, hal_foo_service). وهذا يعني أنّه يمكن لعمليات hal_foo_client الحصول على HAL، ويمكن لعمليات hal_foo_server تسجيل HAL. ينفِّذ مدير السياق (servicemanager) قواعد التسجيل هذه. يُرجى العِلم أنّ أسماء الخدمات قد لا تتطابق دائمًا مع سمات HAL. على سبيل المثال، قد نرى hal_attribute_service(hal_foo, hal_foo2_service). بشكل عام، بما أنّه يشير ذلك إلى أنّه يتم استخدام الخدمات معًا دائمًا، يمكننا التفكير في إزالة hal_foo2_service واستخدام hal_foo_service في جميع سياقات خدماتنا. إنّ معظم واجهات HAL التي تضبط hal_attribute_service متعددة ترجع إلى أنّ اسم سمة HAL الأصلي ليس عامًا بما يكفي ولا يمكن تغييره.

بعد تجميع كل هذه العناصر معًا، يظهر مثال على HAL على النحو التالي:

    public/attributes:
    // define hal_foo, hal_foo_client, hal_foo_server
    hal_attribute(foo)

    public/service.te
    // define hal_foo_service
    type hal_foo_service, hal_service_type, protected_service, service_manager_type

    public/hal_foo.te:
    // allow binder connection from client to server
    binder_call(hal_foo_client, hal_foo_server)
    // allow client to find the service, allow server to register the service
    hal_attribute_service(hal_foo, hal_foo_service)
    // allow binder communication from server to service_manager
    binder_use(hal_foo_server)

    private/service_contexts:
    // bind an AIDL service name to the selinux type
    android.hardware.foo.IFooXxxx/default u:object_r:hal_foo_service:s0

    private/<some_domain>.te:
    // let this domain use the hal service
    binder_use(some_domain)
    hal_client_domain(some_domain, hal_foo)

    vendor/<some_hal_server_domain>.te
    // let this domain serve the hal service
    hal_server_domain(some_hal_server_domain, hal_foo)

واجهات الإضافات المرفقة

يمكن إرفاق إضافة بأي واجهة ربط، سواء كانت واجهة على مستوى أعلى مسجّلة مباشرةً مع مدير الخدمة أو واجهة فرعية. عند الحصول على إضافة، يجب التأكّد من أنّ نوع الإضافة هو كما هو متوقّع. لا يمكن ضبط الإضافات إلا من العملية التي تقدّم رابطًا.

يجب استخدام الإضافات المرفقة كلما عدّلت إضافة وظيفية HAL حالية. عند الحاجة إلى وظيفة جديدة تمامًا، لا يلزم استخدام هذه الآلية، ويمكن تسجيل واجهة إضافة مع مدير الخدمة مباشرةً. تكون واجهات الإضافات المُرفَقة أكثر منطقية عند إرفاقها بواجهات فرعية، لأنّ هذه الهرميات قد تكون معقدة أو متعددة النُسخ. إنّ استخدام إضافة عالمية لعكس التسلسل الهرمي لواجهة الربط لخدمة أخرى سيتطلب تدقيقًا واسع النطاق لتوفير وظيفة مماثلة للإضافات المرتبطة مباشرةً.

لضبط إضافة على أداة الربط، استخدِم واجهات برمجة التطبيقات التالية:

  • في الخلفية في NDK: AIBinder_setExtension
  • في الخلفية في Java: android.os.Binder.setExtension
  • في الخلفية في صفحة المنتج في خدمة مقارنة الأسعار: android::Binder::setExtension
  • في الخلفية في Rust: binder::Binder::set_extension

للحصول على إضافة في رابط، استخدِم واجهات برمجة التطبيقات التالية:

  • في الخلفية في NDK: AIBinder_getExtension
  • في الخلفية في Java: android.os.IBinder.getExtension
  • في الخلفية في صفحة المنتج في خدمة مقارنة الأسعار: android::IBinder::getExtension
  • في الخلفية في Rust: binder::Binder::get_extension

يمكنك العثور على مزيد من المعلومات عن واجهات برمجة التطبيقات هذه في مستندات دالة getExtension في الخلفية المقابلة. يمكنك العثور على مثال على كيفية استخدام الإضافات في hardware/interfaces/tests/extension/vibrator.

الاختلافات الرئيسية بين AIDL وHIDL

عند استخدام واجهات HAL في AIDL أو استخدام واجهات HAL في AIDL، يجب الانتباه إلى الاختلافات مقارنةً بكتابة واجهات HAL في HIDL.

  • يشبه بناء جملة لغة AIDL لغة Java. يشبه بناء جملة HIDL لغة C++.
  • تحتوي جميع واجهات AIDL على حالات خطأ مضمّنة. بدلاً من إنشاء أنواع حالة مخصّصة، أنشئ أرقامًا صحيحة ثابتة للحالة في ملفات الواجهات واستخدِم EX_SERVICE_SPECIFIC في الخلفيات البرمجية لـ CPP/NDK وServiceSpecificException في الخلفية البرمجية لـ Java. يُرجى الاطّلاع على معالجة الأخطاء.
  • لا يبدأ AIDL مجموعات مؤشرات الترابط تلقائيًا عند إرسال عناصر الربط. ويجب بدء هذه العمليات يدويًا (راجِع إدارة المواضيع).
  • لا تُلغي حزمة AIDL عمليات النقل في حال حدوث أخطاء غير محدَّدة (تُلغي حزمة HIDL Return عمليات النقل في حال حدوث أخطاء غير محدَّدة).
  • يمكن أن تحدِّد لغة AIDL نوعًا واحدًا فقط لكل ملف.
  • يمكن تحديد مَعلمات AIDL على أنّها in/out/inout بالإضافة إلى مَعلمة output (لا تتوفّر "طلبات استدعاء متزامنة").
  • يستخدم AIDL fd كنوع أساسي بدلاً من handle.
  • يستخدم HIDL الإصدارات الرئيسية للتغييرات غير المتوافقة والإصدارات الثانوية للتغييرات المتوافقة. في AIDL، يتم إجراء التغييرات المتوافقة مع الإصدارات القديمة في مكانها. لا يتضمّن تنسيق AIDL مفهومًا صريحًا للإصدارات الرئيسية، بل يتم بدلاً من ذلك دمجه في أسماء الحِزم. على سبيل المثال، قد يستخدم AIDL اسم الحزمة bluetooth2.
  • لا يكتسب AIDL الأولوية في الوقت الفعلي تلقائيًا. يجب استخدام الدالة setInheritRt لكل رابط لتفعيل اكتساب الأولوية في الوقت الفعلي.

اختبارات مجموعة اختبار المورّد (VTS) لواجهة HAL

يعتمد Android على مجموعة اختبار المورّدين (VTS) للتحقّق من صحة عمليات تنفيذ HAL المتوقّعة. تساعد ميزة "التحقّق من صحة النقل" في ضمان توافق Android مع عمليات التنفيذ القديمة للمورّدين. إنّ عمليات التنفيذ التي لا تجتاز اختبار VTS تواجه مشاكل توافق معروفة قد تمنع عملها مع الإصدارات القادمة من نظام التشغيل.

هناك جزءان رئيسيان من نظام التحكّم في الرؤية (VTS) لأجهزة HAL.

1. تأكَّد من أنّ واجهات HAL على الجهاز معروفة ومتوقّعة من قِبل Android.

يمكن العثور على هذه المجموعة من الاختبارات في test/vts-testcase/hal/treble/vintf. وتتحمّل هذه الجهات مسؤولية التحقّق مما يلي:

  • يتم تجميد كل واجهة @VintfStability يتم الإعلان عنها في بيان VIRTF عند إصدار معروف. يضمن ذلك توافق كلا جانبَي الواجهة على التعريف الدقيق لهذا الإصدار من الواجهة. هذا الإجراء ضروري للتشغيل الأساسي.
  • تتوفّر جميع واجهات HAL التي تم الإعلان عنها في بيان VINTF على هذا الجهاز. يجب أن يتمكّن أيّ مستخدم لديه أذونات كافية لاستخدام خدمة HAL مُعلَن عنها من الحصول على هذه الخدمات واستخدامها في أيّ وقت.
  • إنّ جميع واجهات HAL التي تم الإعلان عنها في ملف بيان VINTF تعرِض إصدار الواجهة الذي تم الإعلان عنه في البيان.
  • لا يتم عرض أي واجهات HAL متوقّفة نهائيًا على الجهاز. سيتوقف نظام Android عن إتاحة استخدام الإصدارات الأقدم من واجهات HAL كما هو موضّح في دورة حياة FCM.
  • توفّر واجهات HAL المطلوبة على الجهاز تكون بعض واجهات HAL مطلوبة لكي يعمل Android بشكل صحيح.

‫2- التحقّق من السلوك المتوقّع لكل HAL

تحتوي كل واجهة HAL على اختبارات VTS الخاصة بها للتحقّق من السلوك المتوقّع من العميل. يتم تشغيل حالات الاختبار على كل مثيل لواجهة HAL معلَن عنها وفرض سلوك معيّن استنادًا إلى إصدار الواجهة الذي يتم تنفيذه.

تحاول هذه الاختبارات تغطية كل جانب من جوانب تنفيذ HAL الذي يعتمد عليه إطار عمل Android أو قد يعتمد عليه في المستقبل.

وتشمل هذه الاختبارات التحقّق من توفّر الميزات، ومعالجة الأخطاء، وأي سلوك آخر قد يتوقّعه العميل من الخدمة.

محطات VTS المهمة لتطوير HAL

من المتوقّع أن يتم تعديل اختبارات VTS عند إنشاء واجهة HAL أو تعديلها في Android.

يجب أن تكون اختبارات VTS قد اكتملت وجاهزة للتحقّق من عمليات تنفيذ المورّدين قبل تجميدها لإصدارات Android Vendor API. ويجب أن تكون جاهزة قبل تجميد الواجهات حتى يتمكّن المطوّرون من إنشاء عمليات التنفيذ الخاصة بهم والتحقق منها وتقديم ملاحظاتهم إلى مطوّري واجهة HAL.

ميزة "التتبّع في الوقت الفعلي" على Cuttlefish

عندما لا يتوفّر الجهاز، يستخدم Android Cuttlefish كأداة تطوير لواجهات HAL. يتيح ذلك إجراء اختبارات VTS واختبارات الدمج تضاعفًا لنظام Android. يُجري hal_implementation_test اختبارات للتأكّد من أنّ Cuttlefish يتضمّن أحدث إصدارات واجهة HAL للتأكّد من أنّ نظام Android جاهز للتعامل مع الواجهات الجديدة ومن أنّ اختبارات VTS جاهزة لاختبار عمليات التنفيذ الجديدة لمورّدي الأجهزة فور توفّر الأجهزة الجديدة.