HIDL

لغة تعريف واجهة 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 و 1 1L << 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