HIDL

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

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، در پارتیشن خودش، با یک OTA بدون کامپایل مجدد HAL‌ها جایگزین شود.

طراحی HIDL نگرانی های زیر را متعادل می کند:

  • قابلیت همکاری . ایجاد رابط های قابل اعتماد قابل اعتماد بین فرآیندها که ممکن است با معماری های مختلف، زنجیره های ابزار و پیکربندی های ساخت کامپایل شوند. رابط‌های HIDL نسخه‌بندی شده‌اند و پس از انتشار قابل تغییر نیستند.
  • بهره وری . HIDL سعی می کند تعداد عملیات کپی را به حداقل برساند. داده‌های تعریف‌شده توسط HIDL به کد C++ در ساختارهای داده طرح‌بندی استاندارد C++ تحویل داده می‌شوند که می‌توانند بدون باز کردن بسته‌بندی استفاده شوند. HIDL همچنین رابط های حافظه مشترک را فراهم می کند و از آنجایی که RPC ها ذاتاً تا حدودی کند هستند، HIDL از دو روش برای انتقال داده ها بدون استفاده از تماس RPC پشتیبانی می کند: حافظه مشترک و صف پیام سریع (FMQ).
  • شهودی HIDL تنها با استفاده in پارامترهای RPC از مسائل دشوار مالکیت حافظه جلوگیری می کند (به زبان تعریف رابط اندروید (AIDL) مراجعه کنید). مقادیری که نمی توانند به طور موثر از متدها برگردانده شوند، از طریق توابع برگشت به تماس برگردانده می شوند. نه انتقال داده به HIDL برای انتقال و نه دریافت داده از HIDL مالکیت داده ها را تغییر نمی دهد - مالکیت همیشه در تابع فراخوان باقی می ماند. داده ها باید فقط برای مدت زمان تابع فراخوانی شده باقی بمانند و ممکن است بلافاصله پس از بازگشت تابع فراخوانی شده از بین بروند.

با استفاده از حالت عبور

برای به‌روزرسانی دستگاه‌هایی که نسخه‌های قبلی Android را اجرا می‌کنند به Android O، می‌توانید HAL‌های معمولی (و قدیمی) را در یک رابط HIDL جدید بپیچید که HAL را در حالت‌های بایندر شده و یک فرآیند (عبور) ارائه می‌کند. این بسته بندی برای هر دو چارچوب 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