زبان تعریف رابط HAL یا HIDL یک زبان توصیف رابط (IDL) برای تعیین رابط بین HAL و کاربران آن است. HIDL اجازه می دهد تا انواع و روش فراخوانی ها را که در واسط ها و بسته ها جمع آوری شده اند، مشخص کنید. به طور گسترده تر، HIDL یک سیستم برای برقراری ارتباط بین پایگاه های کد است که ممکن است به طور مستقل کامپایل شود.
HIDL برای ارتباط بین فرآیندی (IPC) در نظر گرفته شده است. HAL هایی که با HDL ایجاد می شوند، HAL های binderized نامیده می شوند زیرا می توانند با دیگر لایه های معماری با استفاده از فراخوانی ارتباط بین فرآیندی (IPC) بایندر ارتباط برقرار کنند. HAL های Binderized در یک فرآیند مجزا از کلاینتی که از آنها استفاده می کند اجرا می شوند. برای کتابخانه هایی که باید به یک فرآیند پیوند داده شوند، حالت عبور نیز در دسترس است (در جاوا پشتیبانی نمی شود).
HIDL ساختارهای داده و امضاهای متد را مشخص میکند که در واسطهایی (شبیه به یک کلاس) سازماندهی شدهاند که در بستهها جمعآوری میشوند. سینتکس HIDL برای برنامه نویسان C++ و جاوا آشنا به نظر می رسد، اما با مجموعه ای متفاوت از کلمات کلیدی. HIDL همچنین از حاشیه نویسی به سبک جاوا استفاده می کند.
اصطلاحات
این بخش از اصطلاحات مرتبط با HIDL زیر استفاده می کند:
صحافی شده | نشان میدهد که HIDL برای فراخوانی رویههای راه دور بین فرآیندها استفاده میشود، که بر روی یک مکانیسم Binder مانند اجرا میشود. گذرگاه را نیز ببینید. |
---|---|
پاسخ به تماس، ناهمزمان | رابطی که توسط یک کاربر HAL ارائه میشود، به HAL ارسال میشود (با استفاده از روش HIDL)، و توسط HAL فراخوانی میشود تا دادهها را در هر زمان برگرداند. |
پاسخ به تماس، همزمان | دادههای پیادهسازی روش HIDL سرور را به مشتری برمیگرداند. برای متدهایی که void یا یک مقدار اولیه را برمیگردانند استفاده نمیشود. |
مشتری | فرآیندی که متدهای یک رابط خاص را فراخوانی می کند. یک فرآیند فریمورک HAL یا Android ممکن است مشتری یک رابط و سرور یک رابط دیگر باشد. گذرگاه را نیز ببینید. |
گسترش می یابد | رابطی را نشان می دهد که روش ها و/یا انواعی را به واسط دیگر اضافه می کند. یک رابط می تواند تنها یک رابط دیگر را گسترش دهد. می تواند برای افزایش نسخه جزئی در همان نام بسته یا برای یک بسته جدید (مثلاً یک پسوند فروشنده) برای ساخت بسته های قدیمی استفاده شود. |
ایجاد می کند | یک روش رابط را نشان می دهد که مقادیر را به مشتری برمی گرداند. برای برگرداندن یک مقدار غیر اولیه یا بیش از یک مقدار، یک تابع تماس همزمان تولید می شود. |
رابط | مجموعه ای از روش ها و انواع. به یک کلاس در C++ یا جاوا ترجمه شده است. همه متدها در یک اینترفیس در یک جهت فراخوانی میشوند: یک فرآیند مشتری متدهایی را فراخوانی میکند که توسط یک فرآیند سرور پیادهسازی شدهاند. |
یک طرفه | هنگامی که به روش HIDL اعمال می شود، نشان می دهد که روش هیچ مقداری برمی گرداند و مسدود نمی شود. |
بسته بندی | مجموعه ای از رابط ها و انواع داده ها که یک نسخه را به اشتراک می گذارند. |
عبور | حالت HIDL که در آن سرور یک کتابخانه مشترک است که توسط کلاینت dlopen شده است. در حالت عبور، کلاینت و سرور فرآیند یکسانی هستند اما پایگاه های کد مجزا هستند. فقط برای وارد کردن پایگاه های کد قدیمی به مدل HIDL استفاده می شود. Binderized را نیز ببینید. |
سرور | فرآیندی که روش های یک رابط را پیاده سازی می کند. گذرگاه را نیز ببینید. |
حمل و نقل | زیرساخت HIDL که داده ها را بین سرور و کلاینت جابجا می کند. |
نسخه | نسخه یک بسته از دو عدد صحیح اصلی و کوچک تشکیل شده است. افزایش جزئی نسخه ممکن است انواع و روش ها را اضافه کند (اما تغییر نمی کند). |
طراحی HIDL
هدف HIDL این است که فریم ورک اندروید را می توان بدون نیاز به بازسازی HAL ها جایگزین کرد. HALها توسط فروشندگان یا سازندگان SOC ساخته میشوند و در یک پارتیشن /vendor
در دستگاه قرار میگیرند، تا چارچوب Android در پارتیشن خودش، بدون کامپایل مجدد HALها با یک OTA جایگزین شود.
طراحی HIDL نگرانی های زیر را متعادل می کند:
- قابلیت همکاری . ایجاد رابط های قابل اعتماد قابل اعتماد بین فرآیندها که ممکن است با معماری های مختلف، زنجیره های ابزار و پیکربندی های ساخت کامپایل شوند. رابطهای HIDL نسخهبندی شدهاند و پس از انتشار قابل تغییر نیستند.
- کارایی . HIDL سعی می کند تعداد عملیات کپی را به حداقل برساند. دادههای تعریفشده توسط HIDL به کد C++ در ساختارهای داده طرحبندی استاندارد C++ تحویل داده میشوند که میتوانند بدون باز کردن بستهبندی استفاده شوند. HIDL همچنین رابط های حافظه مشترک را فراهم می کند و از آنجایی که RPC ها ذاتاً تا حدودی کند هستند، HIDL از دو روش برای انتقال داده ها بدون استفاده از تماس RPC پشتیبانی می کند: حافظه مشترک و صف پیام سریع (FMQ).
- شهودی HIDL تنها با استفاده
in
پارامترهای RPC از مسائل دشوار مالکیت حافظه جلوگیری می کند (به زبان تعریف رابط اندروید (AIDL) مراجعه کنید). مقادیری که نمی توانند به طور موثر از متدها برگردانده شوند، از طریق توابع برگشت به تماس برگردانده می شوند. نه انتقال داده به HIDL برای انتقال و نه دریافت داده از HIDL مالکیت داده ها را تغییر نمی دهد - مالکیت همیشه در تابع فراخوان باقی می ماند. داده ها باید فقط برای مدت زمان تابع فراخوانی شده باقی بمانند و ممکن است بلافاصله پس از بازگشت تابع فراخوانی شده از بین بروند.
از حالت عبور استفاده کنید
برای بهروزرسانی دستگاههایی که نسخههای قبلی Android را اجرا میکنند به Android O، میتوانید HALهای معمولی (و قدیمی) را در یک رابط HIDL جدید بپیچید که HAL را در حالتهای binderized و همان فرآیند (عبور) ارائه میکند. این بسته بندی برای هر دو چارچوب HAL و Android شفاف است.
حالت عبور فقط برای کلاینتها و پیادهسازیهای C++ در دسترس است. دستگاههایی که نسخههای قبلی اندروید را اجرا میکنند، HALهای نوشته شده در جاوا ندارند، بنابراین HALهای جاوا ذاتاً بایندر شده هستند.
فایل های هدر عبور
هنگامی که یک فایل .hal
کامپایل می شود، hidl-gen
یک فایل هدر عبوری اضافی BsFoo.h
علاوه بر هدرهای مورد استفاده برای ارتباط بایندر تولید می کند. این هدر توابعی را تعریف می کند که باید dlopen
شوند. از آنجایی که HAL های عبوری در همان فرآیندی اجرا می شوند که در آن فراخوانی می شوند، در بیشتر موارد روش های عبور از طریق فراخوانی تابع مستقیم (همان رشته) فراخوانی می شوند. متدهای oneway
در thread خود اجرا میشوند، زیرا قرار نیست منتظر بمانند تا HAL آنها را پردازش کند (این بدان معنی است که هر HAL که از روشهای oneway
در حالت عبور استفاده میکند باید از نظر موضوعی مطمئن باشد).
با توجه به یک IFoo.hal
، BsFoo.h
روش های تولید شده توسط HIDL را برای ارائه ویژگی های اضافی (مانند اجرای تراکنش های oneway
در یک رشته دیگر) می بندد. این فایل مشابه BpFoo.h
است، اما به جای انتقال تماس IPC با استفاده از Binder، توابع مورد نظر مستقیماً فراخوانی می شوند. پیاده سازی های آینده HAL ها ممکن است چندین پیاده سازی مانند FooFast HAL و FooAccurate HAL را ارائه دهند . در چنین مواردی، یک فایل برای هر پیاده سازی اضافی ایجاد می شود (به عنوان مثال، PTFooFast.cpp
و PTFooAccurate.cpp
).
HAL های عبوری بایندر کننده
میتوانید پیادهسازیهای HAL را که از حالت عبور پشتیبانی میکنند، بایندر کنید. با توجه به یک رابط HAL abcd@MN::IFoo
، دو بسته ایجاد می شود:
-
abcd@MN::IFoo-impl
. شامل اجرای HAL است و تابعIFoo* HIDL_FETCH_IFoo(const char* name)
را نمایش می دهد. در دستگاههای قدیمی، این بستهdlopen
میشود و پیادهسازی با استفاده ازHIDL_FETCH_IFoo
نمونهسازی میشود. می توانید کد پایه را با استفاده ازhidl-gen
و-Lc++-impl
و-Landroidbp-impl
تولید کنید. -
abcd@MN::IFoo-service
. HAL عبوری را باز میکند و خود را بهعنوان یک سرویس بایندر شده ثبت میکند و امکان استفاده از همان پیادهسازی HAL را بهعنوان گذرگاه و بایندر میدهد.
با توجه به نوع IFoo
، می توانید sp<IFoo> IFoo::getService(string name, bool getStub)
برای دسترسی به نمونه ای از IFoo
فراخوانی کنید. اگر getStub
درست باشد، getService
تلاش می کند HAL را فقط در حالت عبور باز کند. اگر getStub
نادرست باشد، getService
تلاش می کند تا یک سرویس binderized را پیدا کند. اگر شکست خورد، سپس سعی می کند سرویس عبور را پیدا کند. پارامتر getStub
هرگز نباید به جز در defaultPassthroughServiceImplementation
استفاده شود. (دستگاههایی که با Android O راهاندازی میشوند، دستگاههایی کاملاً بایندر هستند، بنابراین باز کردن سرویس در حالت عبور مجاز نیست.)
دستور زبان HIDL
از نظر طراحی، زبان HIDL شبیه به C است (اما از پیش پردازنده C استفاده نمی کند). تمام علائم نگارشی که در زیر توضیح داده نشده اند (به غیر از استفاده آشکار از =
و |
) بخشی از دستور زبان هستند.
توجه: برای جزئیات بیشتر در مورد سبک کد HIDL، به راهنمای سبک کد مراجعه کنید.
-
/** */
یک نظر مستند را نشان می دهد. اینها را می توان فقط برای نوع، روش، فیلد، و اعلان مقدار enum اعمال کرد. -
/* */
یک نظر چند خطی را نشان می دهد. -
//
یک نظر تا انتهای خط را نشان می دهد. به غیر از//
، خطوط جدید مانند هر فضای سفید دیگری است. - در گرامر مثال زیر، متن از
//
به انتهای خط بخشی از گرامر نیست، بلکه یک نظر در گرامر است. -
[empty]
به این معنی است که ممکن است اصطلاح خالی باشد. -
?
دنبال کردن یک کلمه یا اصطلاح به معنای اختیاری است. -
...
دنباله ای حاوی صفر یا بیشتر را با علائم نگارشی جداکننده همانطور که نشان می دهد نشان می دهد. هیچ آرگومان متغیری در HIDL وجود ندارد. - کاما عناصر دنباله را از هم جدا می کند.
- نقطه ویرگول به هر عنصر از جمله آخرین عنصر پایان می دهد.
- UPPERCASE یک غیر ترمینال است.
-
italics
یک خانواده نشانه مانندinteger
یاidentifier
(قوانین تجزیه استاندارد C) است. -
constexpr
یک عبارت ثابت سبک C است (مانند1 + 1
و1L << 3
). -
import_name
یک نام بسته یا رابط است که مطابق با نسخه HIDL شرح داده شده است. -
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