لغة تعريف واجهة HAL أو HIDL هي لغة وصف واجهة (IDL) لتحديد الواجهة بين HAL ومستخدميها. يسمح HIDL بتحديد الأنواع واستدعاءات الطريقة ، التي يتم جمعها في واجهات وحزم. على نطاق أوسع ، HIDL هو نظام للتواصل بين قواعد الرموز التي يمكن تجميعها بشكل مستقل. اعتبارًا من Android 10 ، تم إهمال HIDL وهاجر Android لاستخدام AIDL في كل مكان.
الغرض من HIDL هو استخدامه للاتصال بين العمليات (IPC). يطلق على HALs التي تم إنشاؤها باستخدام HDL اسم HALs المرتبط من حيث أنه يمكنها التواصل مع طبقات البنية الأخرى باستخدام مكالمات الاتصال بين العمليات (IPC). يتم تشغيل HALs Binderized في عملية منفصلة عن العميل الذي يستخدمها. بالنسبة للمكتبات التي يجب أن تكون مرتبطة بعملية ، يتوفر أيضًا وضع العبور (غير مدعوم في Java).
يحدد HIDL هياكل البيانات وتوقيعات الأسلوب ، المنظمة في واجهات (على غرار الفئة) التي يتم جمعها في حزم. يبدو بناء جملة HIDL مألوفًا لمبرمجي C ++ و Java ، ولكن مع مجموعة مختلفة من الكلمات الرئيسية. يستخدم HIDL أيضًا التعليقات التوضيحية بنمط Java.
المصطلح
يستخدم هذا القسم المصطلحات التالية المتعلقة بـ HIDL:
موثق | يشير إلى أنه يتم استخدام HIDL لاستدعاءات الإجراءات عن بُعد بين العمليات ، والتي يتم تنفيذها عبر آلية تشبه Binder. انظر أيضا العبور . |
---|---|
رد الاتصال غير متزامن | واجهة يخدمها مستخدم HAL ، تم تمريرها إلى HAL (باستخدام طريقة HIDL) ، ويتم استدعاؤها بواسطة HAL لإرجاع البيانات في أي وقت. |
رد اتصال متزامن | إرجاع البيانات من تطبيق أسلوب HIDL الخاص بالخادم إلى العميل. غير مستخدمة للطرق التي تُرجع باطلة أو قيمة أولية واحدة. |
عميل | العملية التي تستدعي طرق واجهة معينة. قد تكون عملية إطار عمل HAL أو Android عبارة عن عميل لواجهة واحدة وخادم آخر. انظر أيضا العبور . |
يمتد | يشير إلى واجهة تضيف أساليب و / أو أنواعًا إلى واجهة أخرى. يمكن للواجهة توسيع واجهة واحدة أخرى فقط. يمكن استخدامه لزيادة إصدار ثانوي في نفس اسم الحزمة أو لحزمة جديدة (مثل امتداد البائع) للبناء على حزمة قديمة. |
يولد | يشير إلى طريقة واجهة تقوم بإرجاع القيم إلى العميل. لإرجاع قيمة واحدة غير أولية ، أو أكثر من قيمة واحدة ، يتم إنشاء وظيفة رد اتصال متزامن. |
واجهه المستخدم | مجموعة من الأساليب والأنواع. تُترجم إلى فصل دراسي بلغة C ++ أو Java. يتم استدعاء جميع الطرق في الواجهة في نفس الاتجاه: تستدعي عملية العميل الطرق التي تنفذها عملية الخادم. |
طريقة واحدة | عند تطبيقه على طريقة HIDL ، يشير إلى أن الطريقة لا تُرجع أي قيم ولا تمنع. |
حزمة | مجموعة من الواجهات وأنواع البيانات التي تشترك في إصدار. |
يمر من خلال | وضع dlopen حيث يكون الخادم عبارة عن مكتبة مشتركة ، يتم تحريرها بواسطة العميل. في وضع العبور ، يكون العميل والخادم نفس العملية ولكنهما مصدران منفصلان. تستخدم فقط لإحضار قواعد الرموز القديمة في نموذج HIDL. انظر أيضا Binderized . |
الخادم | العملية التي تنفذ أساليب الواجهة. انظر أيضا العبور . |
المواصلات | البنية التحتية HIDL التي تنقل البيانات بين الخادم والعميل. |
الإصدار | نسخة الحزمة. يتكون من عددين صحيحين ، كبير وثانوي. قد تضيف الزيادات الطفيفة في الإصدارات (ولكن لا تغير) الأنواع والطرق. |
تصميم HIDL
الهدف من HIDL هو أنه يمكن استبدال إطار عمل Android دون الحاجة إلى إعادة إنشاء HALs. سيتم إنشاء HALs بواسطة البائعين أو صانعي SOC ووضعها في قسم /vendor
على الجهاز ، مما يتيح استبدال إطار عمل Android ، في القسم الخاص به ، بـ OTA دون إعادة تجميع HALs.
يوازن تصميم HIDL بين الاهتمامات التالية:
- قابلية التشغيل البيني . قم بإنشاء واجهات قابلة للتشغيل المتبادل بشكل موثوق بين العمليات التي يمكن تجميعها باستخدام العديد من البنى ، وسلاسل الأدوات ، وتكوينات البناء. تم إصدار واجهات HIDL ولا يمكن تغييرها بعد نشرها.
- الكفاءة . يحاول HIDL تقليل عدد عمليات النسخ. يتم تسليم البيانات المعرفة بواسطة HIDL إلى كود C ++ في هياكل بيانات التخطيط القياسي C ++ التي يمكن استخدامها دون تفريغ. يوفر HIDL أيضًا واجهات ذاكرة مشتركة ، وبما أن RPCs بطيئة إلى حد ما ، فإن HIDL يدعم طريقتين لنقل البيانات دون استخدام مكالمة RPC: الذاكرة المشتركة وقائمة انتظار الرسائل السريعة (FMQ).
- حدسي . يتجنب HIDL المشكلات الشائكة المتعلقة بملكية الذاكرة باستخدامه فقط
in
معلمات RPC (انظر لغة تعريف واجهة Android (AIDL) ) ؛ يتم إرجاع القيم التي لا يمكن إرجاعها بكفاءة من الطرق عبر وظائف رد الاتصال. لا يؤدي تمرير البيانات إلى HIDL لنقل أو تلقي البيانات من HIDL إلى تغيير ملكية البيانات - تظل الملكية دائمًا مع وظيفة الاستدعاء. تحتاج البيانات إلى الاستمرار فقط طوال مدة الوظيفة التي تم استدعاؤها ويمكن تدميرها على الفور بعد إرجاع الوظيفة المستدعى.
استخدام وضع العبور
لتحديث الأجهزة التي تعمل بإصدارات سابقة من Android إلى Android O ، يمكنك التفاف كل من HALs التقليدية (والقديمة) في واجهة HIDL جديدة تخدم HAL في وضعي Bindered ونفس العملية (العبور). هذا التغليف شفاف لكل من HAL وإطار عمل Android.
وضع العبور متاح فقط لعملاء C ++ والتطبيقات. الأجهزة التي تعمل بإصدارات سابقة من Android لا تحتوي على HALs مكتوبة بلغة Java ، لذلك فإن Java HALs مرتبطة بطبيعتها.
ملفات رأس العبور
عندما يتم تجميع ملف .hal
، ينتج hidl-gen
ملف رأس مرور إضافي BsFoo.h
بالإضافة إلى الرؤوس المستخدمة لاتصال الموثق ؛ يحدد هذا الرأس الوظائف التي سيتم dlopen
ed. نظرًا لأن HALs العبور تعمل في نفس العملية التي يتم استدعاؤها فيها ، يتم استدعاء طرق المرور في معظم الحالات بواسطة استدعاء دالة مباشر (نفس مؤشر الترابط). تعمل طرق oneway
في مؤشر ترابط خاص بها حيث لا يُقصد منها انتظار HAL لمعالجتها (وهذا يعني أن أي HAL يستخدم طرق oneway
في وضع العبور يجب أن يكون آمنًا للخيط).
بالنظر إلى IFoo.hal
، BsFoo.h
بتغليف طرق HIDL المُنشأة لتوفير ميزات إضافية (مثل إجراء معاملات oneway
في سلسلة محادثات أخرى). يشبه هذا الملف BpFoo.h
، ولكن بدلاً من تمرير مكالمات IPC باستخدام Binder ، يتم استدعاء الوظائف المطلوبة مباشرةً. قد توفر عمليات التنفيذ المستقبلية لـ HALs تطبيقات متعددة ، مثل FooFast HAL و FooAccurate HAL. في مثل هذه الحالات ، سيتم إنشاء ملف لكل عملية تنفيذ إضافية (على سبيل المثال ، PTFooFast.cpp
و PTFooAccurate.cpp
).
ممر تجليد HALs
يمكنك ربط تطبيقات HAL التي تدعم وضع العبور. بالنظر إلى واجهة HAL abcd@MN::IFoo
، يتم إنشاء حزمتين:
-
abcd@MN::IFoo-impl
. يحتوي على تطبيق HAL ويكشف الوظيفةIFoo* HIDL_FETCH_IFoo(const char* name)
. على الأجهزة القديمة ، يتمdlopen
ed هذه الحزمة ويتم إنشاء مثيل للتطبيق باستخدامHIDL_FETCH_IFoo
. يمكنك إنشاء الكود الأساسي باستخدامhidl-gen
و-Lc++-impl
impl و-Landroidbp-impl
. -
abcd@MN::IFoo-service
. يفتح HAL العبور ويسجل نفسه كخدمة مقيدة ، مما يتيح استخدام نفس تطبيق HAL كمرور وربط.
بالنظر إلى النوع IFoo
، يمكنك استدعاء sp<IFoo> IFoo::getService(string name, bool getStub)
للوصول إلى مثيل IFoo
. إذا كان getStub
صحيحًا ، تحاول getService
فتح HAL فقط في وضع العبور. إذا كانت getStub
خاطئة ، تحاول getService
العثور على خدمة مرتبطة ؛ إذا فشل ذلك ، فسيحاول العثور على خدمة العبور. يجب عدم استخدام المعلمة getStub
إلا في defaultPassthroughServiceImplementation
. (الأجهزة التي يتم تشغيلها باستخدام Android O هي أجهزة مقيدة بالكامل ، لذا فإن فتح خدمة في وضع العبور غير مسموح به.)
قواعد HIDL
حسب التصميم ، تشبه لغة HIDL لغة C (ولكنها لا تستخدم المعالج الأولي C). جميع علامات الترقيم غير الموضحة أدناه (بصرف النظر عن الاستخدام الواضح لـ =
و |
) جزء من القواعد.
ملاحظة: للحصول على تفاصيل حول نمط رمز HIDL ، راجع دليل نمط التعليمات البرمجية .
-
/** */
يشير إلى تعليق توثيق. يمكن تطبيق هذه فقط على إعلانات النوع والطريقة والحقل وقيمة التعداد. -
/* */
يشير إلى تعليق متعدد الأسطر. -
//
يشير إلى تعليق في نهاية السطر. بصرف النظر عن//
، فإن الأسطر الجديدة هي نفسها مثل أي مسافة بيضاء أخرى. - في المثال النحوي أدناه ، النص من
//
إلى نهاية السطر ليس جزءًا من القواعد ولكنه بدلاً من ذلك تعليق على القواعد. -
[empty]
يعني أن المصطلح قد يكون فارغًا. -
?
اتباع حرفي أو مصطلح يعني أنه اختياري. -
...
يشير إلى تسلسل يحتوي على صفر أو أكثر من العناصر مع فصل علامات الترقيم كما هو موضح. لا توجد حجج متغيرة في HIDL. - تفصل الفواصل عن عناصر التسلسل.
- تنهي الفاصلة المنقوطة كل عنصر ، بما في ذلك العنصر الأخير.
- الأحرف الكبيرة هي علامة غير نهائية.
-
italics
هو عائلة رمزية مثلinteger
أوidentifier
(قواعد تحليل C القياسية). -
constexpr
هو تعبير ثابت من النمط C (مثل1 + 1
و 11L << 3
). -
import_name
هو اسم حزمة أو واجهة ، مؤهل كما هو موصوف في HIDL Versioning . -
words
الصغيرة هي رموز حرفية.
مثال:
ROOT = PACKAGE IMPORTS PREAMBLE { ITEM ITEM ... } // not for types.hal | PACKAGE IMPORTS ITEM ITEM... // only for types.hal; no method definitions ITEM = ANNOTATIONS? oneway? identifier(FIELD, FIELD ...) GENERATES?; | safe_union identifier { UFIELD; UFIELD; ...}; | struct identifier { SFIELD; SFIELD; ...}; // Note - no forward declarations | union identifier { UFIELD; UFIELD; ...}; | enum identifier: TYPE { ENUM_ENTRY, ENUM_ENTRY ... }; // TYPE = enum or scalar | typedef TYPE identifier; VERSION = integer.integer; PACKAGE = package android.hardware.identifier[.identifier[...]]@VERSION; PREAMBLE = interface identifier EXTENDS EXTENDS = <empty> | extends import_name // must be interface, not package GENERATES = generates (FIELD, FIELD ...) // allows the Binder interface to be used as a type // (similar to typedef'ing the final identifier) IMPORTS = [empty] | IMPORTS import import_name; TYPE = uint8_t | int8_t | uint16_t | int16_t | uint32_t | int32_t | uint64_t | int64_t | float | double | bool | string | identifier // must be defined as a typedef, struct, union, enum or import // including those defined later in the file | memory | pointer | vec<TYPE> | bitfield<TYPE> // TYPE is user-defined enum | fmq_sync<TYPE> | fmq_unsync<TYPE> | TYPE[SIZE] FIELD = TYPE identifier UFIELD = TYPE identifier | safe_union identifier { FIELD; FIELD; ...} identifier; | struct identifier { FIELD; FIELD; ...} identifier; | union identifier { FIELD; FIELD; ...} identifier; SFIELD = TYPE identifier | safe_union identifier { FIELD; FIELD; ...}; | struct identifier { FIELD; FIELD; ...}; | union identifier { FIELD; FIELD; ...}; | safe_union identifier { FIELD; FIELD; ...} identifier; | struct identifier { FIELD; FIELD; ...} identifier; | union identifier { FIELD; FIELD; ...} identifier; SIZE = // Must be greater than zero constexpr ANNOTATIONS = [empty] | ANNOTATIONS ANNOTATION ANNOTATION = | @identifier | @identifier(VALUE) | @identifier(ANNO_ENTRY, ANNO_ENTRY ...) ANNO_ENTRY = identifier=VALUE VALUE = "any text including \" and other escapes" | constexpr | {VALUE, VALUE ...} // only in annotations ENUM_ENTRY = identifier | identifier = constexpr