HIDL

زبان تعریف رابط HAL یا HIDL (تلفظ "hide-l") یک زبان توصیف رابط (IDL) برای تعیین رابط بین HAL و کاربران آن است. این اجازه می دهد تا انواع و روش فراخوانی ها را که در واسط ها و بسته ها جمع آوری می شوند، مشخص کنید. به طور گسترده تر، HIDL یک سیستم برای برقراری ارتباط بین پایگاه های کد است که ممکن است به طور مستقل کامپایل شود. از اندروید 10، HIDL منسوخ شده است و اندروید برای استفاده از AIDL در همه جا مهاجرت می کند.

HIDL برای ارتباط بین فرآیندی (IPC) در نظر گرفته شده است. ارتباط بین فرآیندها به عنوان Binderized نامیده می شود. برای کتابخانه هایی که باید به یک فرآیند پیوند داده شوند، حالت عبور نیز در دسترس است (در جاوا پشتیبانی نمی شود).

HIDL ساختارهای داده و امضاهای متد را مشخص می‌کند که در واسط‌هایی (شبیه به یک کلاس) سازمان‌دهی شده‌اند که در بسته‌ها جمع‌آوری می‌شوند. سینتکس HIDL برای برنامه نویسان C++ و جاوا آشنا به نظر می رسد، البته با مجموعه ای متفاوت از کلمات کلیدی. HIDL همچنین از حاشیه نویسی به سبک جاوا استفاده می کند.

طراحی HIDL

هدف HIDL این است که چارچوب را می توان بدون نیاز به بازسازی HAL ها جایگزین کرد. HAL‌ها توسط فروشندگان یا سازندگان SOC ساخته می‌شوند و در یک پارتیشن /vendor روی دستگاه قرار می‌گیرند، تا چارچوب، در پارتیشن خودش، بدون کامپایل مجدد 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 در حالت عبور استفاده می‌کند باید thread-safe باشد).

با توجه به یک 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 عبوری را باز می‌کند و خود را به‌عنوان یک سرویس binderized ثبت می‌کند، و امکان استفاده از همان پیاده‌سازی 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

واژه شناسی

این بخش از اصطلاحات مرتبط با HIDL زیر استفاده می کند:

صحافی شده نشان می‌دهد که HIDL برای فراخوانی رویه از راه دور بین فرآیندها استفاده می‌شود، که بر روی یک مکانیسم Binder مانند اجرا می‌شود. گذرگاه را نیز ببینید.
پاسخ به تماس، ناهمزمان رابطی که توسط یک کاربر HAL ارائه می شود، به HAL منتقل می شود (از طریق روش HIDL)، و توسط HAL فراخوانی می شود تا داده ها را در هر زمان برگرداند.
پاسخ به تماس، همزمان داده‌های پیاده‌سازی روش HIDL سرور را به مشتری برمی‌گرداند. برای متدهایی که void یا یک مقدار اولیه را برمی‌گردانند استفاده نمی‌شود.
مشتری فرآیندی که متدهای یک رابط خاص را فراخوانی می کند. یک فرآیند HAL یا چارچوب ممکن است مشتری یک رابط و سرور یک رابط دیگر باشد. گذرگاه را نیز ببینید.
گسترش می یابد رابطی را نشان می‌دهد که روش‌ها و/یا انواع را به واسط دیگر اضافه می‌کند. یک رابط می تواند تنها یک رابط دیگر را گسترش دهد. می تواند برای افزایش نسخه جزئی در همان نام بسته یا برای یک بسته جدید (مثلاً یک پسوند فروشنده) برای ساخت بسته های قدیمی استفاده شود.
ایجاد می کند یک روش رابط را نشان می دهد که مقادیر را به مشتری برمی گرداند. برای برگرداندن یک مقدار غیر ابتدایی یا بیش از یک مقدار، یک تابع تماس همزمان تولید می شود.
رابط مجموعه ای از روش ها و انواع. به یک کلاس در C++ یا جاوا ترجمه شده است. همه متدها در یک اینترفیس در یک جهت فراخوانی می شوند: یک فرآیند مشتری متدهای پیاده سازی شده توسط یک فرآیند سرور را فراخوانی می کند.
یک طرفه هنگامی که به یک روش HIDL اعمال می شود، نشان می دهد که روش هیچ مقداری برمی گرداند و مسدود نمی شود.
بسته بندی مجموعه ای از رابط ها و انواع داده ها که یک نسخه را به اشتراک می گذارند.
عبور حالت dlopen که در آن سرور یک کتابخانه مشترک است که توسط کلاینت ویرایش شده است. در حالت عبور، کلاینت و سرور یک فرآیند هستند اما پایگاه های کد جداگانه هستند. فقط برای وارد کردن پایگاه های کد قدیمی به مدل HIDL استفاده می شود. همچنین به Binderized مراجعه کنید.
سرور فرآیندی که روش های یک رابط را پیاده سازی می کند. گذرگاه را نیز ببینید.
حمل و نقل زیرساخت HIDL که داده ها را بین سرور و کلاینت جابجا می کند.
نسخه نسخه یک بسته از دو عدد صحیح اصلی و کوچک تشکیل شده است. افزایش جزئی نسخه ممکن است انواع و روش ها را اضافه کند (اما تغییر نمی کند).