HIDL نیاز دارد که هر رابط نوشته شده در HIDL نسخه شود. پس از انتشار یک رابط HAL، ثابت می شود و هر گونه تغییر بیشتر باید در نسخه جدیدی از آن رابط انجام شود. در حالی که یک رابط منتشر شده را نمی توان تغییر داد، می توان آن را توسط یک رابط دیگر گسترش داد.
ساختار کد HIDL
کد HIDL در انواع، رابط ها و بسته های تعریف شده توسط کاربر سازماندهی شده است :
- انواع تعریف شده توسط کاربر (UDTs) . HIDL دسترسی به مجموعهای از انواع دادههای اولیه را فراهم میکند که میتوان از آنها برای ترکیب انواع پیچیدهتر از طریق ساختارها، اتحادیهها و شمارشها استفاده کرد. UDT ها به روش های واسط منتقل می شوند و می توانند در سطح یک بسته (مشترک برای همه اینترفیس ها) یا به صورت محلی برای یک رابط تعریف شوند.
- رابط ها به عنوان بلوک اصلی HIDL، یک رابط شامل UDT و اعلان های متد است. رابط ها همچنین می توانند از یک رابط دیگر ارث ببرند.
- بسته ها رابط های HIDL مرتبط و انواع داده هایی که بر روی آنها کار می کنند را سازماندهی می کند. یک بسته با یک نام و یک نسخه شناسایی می شود و شامل موارد زیر است:
- فایل تعریف نوع داده به نام
types.hal
. - صفر یا چند اینترفیس، هر کدام در فایل
.hal
مخصوص به خود.
- فایل تعریف نوع داده به نام
فایل تعریف نوع داده types.hal
فقط حاوی UDT است (همه UDT های سطح بسته در یک فایل واحد نگهداری می شوند). نمایش در زبان مقصد برای همه رابط های بسته در دسترس است.
فلسفه نسخه سازی
بسته HIDL (مانند android.hardware.nfc
)، پس از انتشار برای یک نسخه خاص (مانند 1.0
)، تغییر ناپذیر است. نمی توان آن را تغییر داد. تغییرات در رابط های بسته یا هر گونه تغییر در UDT های آن فقط در بسته دیگری انجام می شود.
در HIDL، نسخهسازی در سطح بسته اعمال میشود، نه در سطح رابط، و همه اینترفیسها و UDTها در یک بسته نسخه مشابهی دارند. نسخههای بسته از نسخهسازی معنایی بدون سطح وصله و اجزای ساخت-فراداده پیروی میکنند. در یک بسته معین، یک برآمدگی جزئی نسخه به این معنی است که نسخه جدید بسته با بسته قدیمی سازگار است و یک ضربه نسخه اصلی به این معنی است که نسخه جدید بسته با بسته قدیمی سازگار نیست.
از نظر مفهومی، یک بسته می تواند به یکی از چندین روش به بسته دیگری مرتبط شود:
- نه اصلا .
- توسعه پذیری سازگار با عقب در سطح بسته . این برای نسخه های فرعی جدید (نسخه افزایشی بعدی) یک بسته اتفاق می افتد. بسته جدید همان نام و نسخه اصلی بسته قدیمی است، اما یک نسخه مینور بالاتر. از نظر عملکردی، بسته جدید یک ابر مجموعه از بسته قدیمی است، به این معنی:
- رابط های سطح بالای بسته والد در بسته جدید وجود دارند، اگرچه اینترفیس ها ممکن است دارای روش های جدید، UDT های رابط-محلی جدید (افزونه سطح واسط که در زیر توضیح داده شده است) و UDT های جدید در
types.hal
داشته باشند. - رابط های جدید نیز می توانند به بسته جدید اضافه شوند.
- تمام انواع دادههای بسته والد در بسته جدید وجود دارند و میتوان آنها را با روشهای (احتمالاً پیادهسازیشده) از بسته قدیمی مدیریت کرد.
- انواع دادههای جدید را میتوان برای استفاده با روشهای جدید رابطهای موجود ارتقا یافته یا با رابطهای جدید اضافه کرد.
- رابط های سطح بالای بسته والد در بسته جدید وجود دارند، اگرچه اینترفیس ها ممکن است دارای روش های جدید، UDT های رابط-محلی جدید (افزونه سطح واسط که در زیر توضیح داده شده است) و UDT های جدید در
- توسعه پذیری سازگار با عقب در سطح رابط . بسته جدید همچنین میتواند بسته اصلی را با متشکل از رابطهای منطقی مجزا گسترش دهد که به سادگی عملکردهای اضافی را ارائه میکنند و نه اصلی. برای این منظور، موارد زیر ممکن است مطلوب باشد:
- رابط های موجود در بسته جدید نیاز به توسل به انواع داده های بسته قدیمی دارند.
- رابط های موجود در بسته جدید می توانند رابط های یک یا چند بسته قدیمی را گسترش دهند.
- ناسازگاری اصلی به عقب را گسترش دهید . این یک نسخه اصلی ارتقاء بسته است و نیازی به هیچ ارتباطی بین این دو نیست. تا جایی که وجود دارد، می توان آن را با ترکیبی از انواع نسخه قدیمی بسته و ارث بردن زیرمجموعه ای از واسط های بسته قدیمی بیان کرد.
ساختار رابط
برای یک رابط با ساختار خوب، افزودن انواع جدیدی از عملکردها که بخشی از طراحی اصلی نیستند، باید نیاز به تغییر در رابط HIDL داشته باشد. برعکس، اگر میتوانید یا انتظار داشته باشید که در هر دو طرف رابط تغییری ایجاد کنید که عملکرد جدیدی را بدون تغییر خود اینترفیس معرفی میکند، آنگاه رابط ساختاری ندارد.
Treble از فروشنده و اجزای سیستم که به طور جداگانه کامپایل شده اند پشتیبانی می کند که در آن vendor.img
در یک دستگاه و system.img
می توانند به طور جداگانه کامپایل شوند. تمام تعاملات بین vendor.img
و system.img
باید به طور صریح و کامل تعریف شوند تا بتوانند سال ها به کار خود ادامه دهند. این شامل بسیاری از سطوح API است، اما یک سطح اصلی مکانیسم IPC است که HIDL برای ارتباطات بین فرآیندی در مرز system.img
/ vendor.img
استفاده می کند.
الزامات
تمام داده های ارسال شده از طریق HIDL باید به صراحت تعریف شوند. برای اطمینان از اینکه یک پیاده سازی و کلاینت می تواند به کار با هم ادامه دهد، حتی زمانی که به طور جداگانه کامپایل شده یا به طور مستقل توسعه یافته است، داده ها باید از شرایط زیر پیروی کنند:
- می توان مستقیماً در HIDL (با استفاده از ساختارهای enums و غیره) با نام های معنایی و معنی توصیف کرد.
- می توان با یک استاندارد عمومی مانند ISO/IEC 7816 توصیف کرد.
- می توان با یک استاندارد سخت افزاری یا طرح فیزیکی سخت افزار توصیف کرد.
- در صورت لزوم می تواند داده های مات (مانند کلیدهای عمومی، شناسه ها و غیره) باشد.
اگر از داده های مات استفاده می شود، باید فقط توسط یک طرف رابط HIDL خوانده شود. به عنوان مثال، اگر کد vendor.img
به یک جزء در system.img
یک پیام رشته یا داده vec<uint8_t>
بدهد، آن داده توسط خود system.img
قابل تجزیه نیست. فقط می توان آن را برای تفسیر به vendor.img
بازگرداند. هنگام ارسال یک مقدار از vendor.img
به کد فروشنده در system.img
یا به دستگاه دیگری، قالب داده ها و نحوه تفسیر آن باید دقیقاً توضیح داده شود و همچنان بخشی از رابط است .
رهنمودها
شما باید بتوانید یک پیاده سازی یا کلاینت یک HAL را با استفاده از فایل های .hal بنویسید (یعنی نیازی نیست به منبع Android یا استانداردهای عمومی نگاه کنید). توصیه می کنیم رفتار دقیق مورد نیاز را مشخص کنید. عباراتی مانند "یک پیاده سازی ممکن است A یا B را انجام دهد" پیاده سازی ها را تشویق می کند تا با مشتریانی که با آنها توسعه یافته اند در هم آمیخته شوند.
طرح کد HIDL
HIDL شامل بسته های هسته و فروشنده است.
رابط های اصلی HIDL آنهایی هستند که توسط گوگل مشخص شده اند. بسته هایی که متعلق به آنها هستند با android.hardware.
و توسط زیرسیستم نامگذاری می شوند، به طور بالقوه با سطوح نامگذاری تو در تو. به عنوان مثال، بسته NFC با نام android.hardware.nfc
و بسته دوربین android.hardware.camera
است. به طور کلی، یک بسته اصلی دارای نام android.hardware.
[ name1
].[ name2
]…. بسته های HIDL علاوه بر نام دارای یک نسخه هستند. برای مثال، بسته android.hardware.camera
ممکن است در نسخه 3.4
باشد. این مهم است، زیرا نسخه یک بسته بر قرارگیری آن در درخت منبع تأثیر می گذارد.
تمام بستههای هسته تحت hardware/interfaces/
در سیستم ساخت قرار میگیرند. بسته android.hardware.
[ name1
].[ name2
]… در نسخه $m.$n
در قسمت hardware/interfaces/name1/name2/
… /$m.$n/
قرار دارد. بسته android.hardware.camera
نسخه 3.4
در دایرکتوری hardware/interfaces/camera/3.4/.
یک نقشه سخت کدگذاری شده بین پیشوند بسته android.hardware.
و مسیر hardware/interfaces/
.
بسته های غیر هسته ای (فروشنده) آنهایی هستند که توسط فروشنده SoC یا ODM تولید می شوند. پیشوند بسته های غیر اصلی vendor.$(VENDOR).hardware.
جایی که $(VENDOR)
به یک فروشنده SoC یا OEM/ODM اشاره دارد. این نقشه به vendor/$(VENDOR)/interfaces
موجود در درخت (این نگاشت نیز سخت کدگذاری شده است).
نامهای کاملاً واجد شرایط از نوع تعریف شده توسط کاربر
در HIDL، هر UDT دارای یک نام کاملا واجد شرایط است که شامل نام UDT، نام بسته ای که UDT در آن تعریف شده است و نسخه بسته است. نام کاملاً واجد شرایط فقط زمانی استفاده میشود که نمونههایی از نوع تعریف شده باشند و نه در جایی که خود نوع تعریف شده است. برای مثال، فرض کنید بسته android.hardware.nfc,
نسخه 1.0
ساختاری به نام NfcData
را تعریف می کند. در محل اعلان (چه در types.hal
یا در یک اعلان رابط)، اعلان به سادگی بیان می کند:
struct NfcData { vec<uint8_t> data; };
هنگام اعلام یک نمونه از این نوع (چه در یک ساختار داده یا به عنوان پارامتر روش)، از نام نوع کاملاً واجد شرایط استفاده کنید:
android.hardware.nfc@1.0::NfcData
نحو کلی PACKAGE @ VERSION :: UDT
است، که در آن:
-
PACKAGE
نام یک بسته HIDL است که با نقطه جدا شده است (به عنوان مثال،android.hardware.nfc
). -
VERSION
قالب نسخه اصلی بسته جدا شده با نقطه است (مثلاً1.0
). -
UDT
نام نقطه ای از HIDL UDT است. از آنجایی که HIDL از UDT های تودرتو پشتیبانی می کند و رابط های HIDL می توانند حاوی UDT (نوعی اعلان تودرتو) باشند، برای دسترسی به نام ها از نقاط استفاده می شود.
به عنوان مثال، اگر اعلان تودرتو زیر در فایل انواع رایج در بسته android.hardware.example
نسخه 1.0
تعریف شده باشد:
// types.hal package android.hardware.example@1.0; struct Foo { struct Bar { // … }; Bar cheers; };
نام کاملا واجد شرایط برای Bar
android.hardware.example@1.0::Foo.Bar
است. اگر اعلان تودرتو علاوه بر قرار گرفتن در بسته فوق در رابطی به نام IQuux
باشد:
// IQuux.hal package android.hardware.example@1.0; interface IQuux { struct Foo { struct Bar { // … }; Bar cheers; }; doSomething(Foo f) generates (Foo.Bar fb); };
نام کاملاً واجد شرایط برای Bar
android.hardware.example@1.0::IQuux.Foo.Bar
است.
در هر دو مورد، Bar
فقط در محدوده اعلامیه Foo
می تواند به عنوان Bar
شناخته شود. در سطح بسته یا رابط، باید به Bar
via Foo
مراجعه کنید: Foo.Bar
، همانطور که در بیانیه روش doSomething
در بالا وجود دارد. از طرف دیگر، میتوانید روش را به صورت واضحتر به صورت زیر بیان کنید:
// IQuux.hal doSomething(android.hardware.example@1.0::IQuux.Foo f) generates (android.hardware.example@1.0::IQuux.Foo.Bar fb);
مقادیر شمارش کاملا واجد شرایط
اگر یک UDT یک نوع enum باشد، پس هر مقدار از نوع enum یک نام کاملاً واجد شرایط دارد که با نام کاملاً واجد شرایط نوع enum شروع میشود، سپس یک دونقطه و سپس نام مقدار enum قرار میگیرد. به عنوان مثال، فرض کنید بسته android.hardware.nfc,
نسخه 1.0
یک نوع enum NfcStatus
را تعریف می کند:
enum NfcStatus { STATUS_OK, STATUS_FAILED };
هنگام مراجعه به STATUS_OK
، نام کاملا واجد شرایط این است:
android.hardware.nfc@1.0::NfcStatus:STATUS_OK
نحو کلی PACKAGE @ VERSION :: UDT : VALUE
است، که در آن:
-
PACKAGE @ VERSION :: UDT
دقیقاً همان نام کاملاً واجد شرایط برای نوع enum است. -
VALUE
نام مقدار است.
قوانین استنتاج خودکار
یک نام UDT کاملا واجد شرایط نیازی به ذکر نیست. یک نام UDT می تواند با خیال راحت موارد زیر را حذف کند:
- بسته، به عنوان مثال
@1.0::IFoo.Type
- هم بسته و هم نسخه، به عنوان مثال
IFoo.Type
HIDL سعی می کند نام را با استفاده از قوانین تداخل خودکار تکمیل کند (عدد قانون کمتر به معنای اولویت بالاتر است).
قانون 1
اگر بسته و نسخه ای ارائه نشده باشد، جستجوی نام محلی انجام می شود. مثال:
interface Nfc { typedef string NfcErrorMessage; send(NfcData d) generates (@1.0::NfcStatus s, NfcErrorMessage m); };
NfcErrorMessage
به صورت محلی جستجو می شود و typedef
بالای آن پیدا می شود. NfcData
نیز به صورت محلی جستجو می شود، اما از آنجایی که به صورت محلی تعریف نشده است، از قانون 2 و 3 استفاده می شود. @1.0::NfcStatus
یک نسخه ارائه می کند، بنابراین قانون 1 اعمال نمی شود.
قانون 2
اگر قانون 1 ناموفق باشد و یک مؤلفه از نام کاملاً واجد شرایط (بسته، نسخه یا بسته و نسخه) وجود نداشته باشد، مؤلفه به طور خودکار با اطلاعات بسته فعلی پر می شود. سپس کامپایلر HIDL در فایل فعلی (و همه واردات) جستجو می کند تا نام کاملاً واجد شرایط تکمیل شده خودکار را پیدا کند. با استفاده از مثال بالا، فرض کنید که اعلان ExtendedNfcData
در همان بسته ( android.hardware.nfc
) در همان نسخه ( 1.0
) NfcData
به شرح زیر ساخته شده است:
struct ExtendedNfcData { NfcData base; // … additional members };
کامپایلر HIDL نام بسته و نام نسخه را از بسته فعلی پر می کند تا نام UDT کاملاً واجد شرایط android.hardware.nfc@1.0::NfcData
تولید کند. از آنجایی که نام در بسته فعلی وجود دارد (با فرض اینکه به درستی وارد شده باشد)، برای اظهارنامه استفاده می شود.
یک نام در بسته فعلی تنها در صورتی وارد می شود که یکی از موارد زیر درست باشد:
- به صراحت با یک بیانیه
import
وارد می شود. - در پکیج فعلی در
types.hal
تعریف شده است
اگر NfcData
فقط با شماره نسخه واجد شرایط باشد، همین روند دنبال می شود:
struct ExtendedNfcData { // autofill the current package name (android.hardware.nfc) @1.0::NfcData base; // … additional members };
قانون 3
اگر قانون 2 نتواند مطابقت ایجاد کند (UDT در بسته فعلی تعریف نشده است)، کامپایلر HIDL برای یک تطابق در تمام بسته های وارد شده اسکن می کند. با استفاده از مثال بالا، فرض کنید ExtendedNfcData
در نسخه 1.1
بسته android.hardware.nfc
اعلان شده است، 1.1
1.0
همانطور که باید وارد می کند (به برنامه های افزودنی سطح بسته مراجعه کنید)، و تعریف فقط نام UDT را مشخص می کند:
struct ExtendedNfcData { NfcData base; // … additional members };
کامپایلر به دنبال هر UDT با نام NfcData
میگردد و یکی را در android.hardware.nfc
در نسخه 1.0
پیدا میکند که در نتیجه یک UDT کاملاً واجد شرایط android.hardware.nfc@1.0::NfcData
ایجاد میشود. اگر بیش از یک تطابق برای یک UDT تا حدی واجد شرایط پیدا شود، کامپایلر HIDL یک خطا ایجاد می کند.
مثال
با استفاده از قانون 2، یک نوع وارداتی تعریف شده در بسته فعلی نسبت به نوع وارداتی از بسته دیگر ترجیح داده می شود:
// hardware/interfaces/foo/1.0/types.hal package android.hardware.foo@1.0; struct S {}; // hardware/interfaces/foo/1.0/IFooCallback.hal package android.hardware.foo@1.0; interface IFooCallback {}; // hardware/interfaces/bar/1.0/types.hal package android.hardware.bar@1.0; typedef string S; // hardware/interfaces/bar/1.0/IFooCallback.hal package android.hardware.bar@1.0; interface IFooCallback {}; // hardware/interfaces/bar/1.0/IBar.hal package android.hardware.bar@1.0; import android.hardware.foo@1.0; interface IBar { baz1(S s); // android.hardware.bar@1.0::S baz2(IFooCallback s); // android.hardware.foo@1.0::IFooCallback };
-
S
به عنوانandroid.hardware.bar@1.0::S
درونیابی می شود و درbar/1.0/types.hal
یافت می شود (زیراtypes.hal
به طور خودکار وارد می شود). -
IFooCallback
به عنوانandroid.hardware.bar@1.0::IFooCallback
با استفاده از قانون 2 درون یابی می شود، اما نمی توان آن را پیدا کرد زیراbar/1.0/IFooCallback.hal
به طور خودکار وارد نمی شود (همانطور کهtypes.hal
است). بنابراین، قانون 3 آن را بهandroid.hardware.foo@1.0::IFooCallback
حل می کند که از طریقimport android.hardware.foo@1.0;
).
انواع.حال
هر بسته HIDL حاوی یک فایل types.hal
حاوی UDT است که در بین تمام رابط های شرکت کننده در آن بسته به اشتراک گذاشته شده است. انواع HIDL همیشه عمومی هستند. صرف نظر از اینکه یک UDT در types.hal
یا در یک اعلان رابط اعلان شده باشد، این انواع خارج از محدوده ای که در آن تعریف شده اند قابل دسترسی هستند. types.hal
به معنای توصیف API عمومی یک بسته نیست، بلکه برای میزبانی UDT هایی است که توسط همه اینترفیس های درون بسته استفاده می شود. با توجه به ماهیت HIDL، همه UDT ها بخشی از رابط هستند.
types.hal
از UDT ها و بیانیه های import
تشکیل شده است. از آنجایی که types.hal
برای هر رابط بسته در دسترس است (این یک واردات ضمنی است)، این عبارات import
طبق تعریف در سطح بسته هستند. UDT ها در types.hal
همچنین می توانند UDT ها و رابط های وارد شده را در خود جای دهند.
به عنوان مثال، برای IFoo.hal
:
package android.hardware.foo@1.0; // whole package import import android.hardware.bar@1.0; // types only import import android.hardware.baz@1.0::types; // partial imports import android.hardware.qux@1.0::IQux.Quux; // partial imports import android.hardware.quuz@1.0::Quuz;
موارد زیر وارد می شود:
-
android.hidl.base@1.0::IBase
(به طور ضمنی) -
android.hardware.foo@1.0::types
(به طور ضمنی) - همه چیز در
android.hardware.bar@1.0
(از جمله تمام رابط ها وtypes.hal
آن.hal) -
types.hal
ازandroid.hardware.baz@1.0::types
(رابط موجود درandroid.hardware.baz@1.0
وارد نشده است) -
IQux.hal
وtypes.hal
ازandroid.hardware.qux@1.0
-
Quuz
ازandroid.hardware.quuz@1.0
(با فرض اینکهQuuz
درtypes.hal
تعریف شده باشد، کل فایلtypes.hal
تجزیه می شود، اما انواعی غیر ازQuuz
وارد نمی شوند).
نسخه سازی در سطح رابط
هر اینترفیس درون یک بسته در فایل خودش قرار دارد. بسته ای که اینترفیس به آن تعلق دارد با استفاده از دستور package
در بالای رابط اعلام می شود. پس از اعلام بسته، ممکن است واردات صفر یا بیشتر در سطح رابط (جزئی یا کل بسته) فهرست شود. به عنوان مثال:
package android.hardware.nfc@1.0;
در HIDL، اینترفیس ها می توانند با استفاده از کلمه کلیدی extends
از سایر رابط ها ارث ببرند. برای اینکه یک رابط بتواند رابط دیگری را گسترش دهد، باید از طریق یک عبارت import
به آن دسترسی داشته باشد. نام رابطی که در حال گسترش است (واسط پایه) از قوانین واجد شرایط نام نوع که در بالا توضیح داده شد پیروی می کند. یک رابط فقط می تواند از یک رابط به ارث ببرد. HIDL از وراثت چندگانه پشتیبانی نمی کند.
نمونه های نسخه uprev زیر از بسته زیر استفاده می کنند:
// types.hal package android.hardware.example@1.0 struct Foo { struct Bar { vec<uint32_t> val; }; }; // IQuux.hal package android.hardware.example@1.0 interface IQuux { fromFooToBar(Foo f) generates (Foo.Bar b); }
قوانین Uprev
برای تعریف یک بسته package@major.minor
، A یا تمام B باید درست باشد:
قانون الف | "یک نسخه ابتدایی مینور است": همه نسخه های مینور قبلی، package@major.0 ، package@major.1 ، ...، package@major.(minor-1) نباید تعریف شوند. |
---|
قانون ب | همه موارد زیر درست است:
|
---|
به دلیل قانون A:
- بسته می تواند با هر شماره نسخه جزئی شروع شود (برای مثال،
android.hardware.biometrics.fingerprint
از@2.1
شروع می شود.) - شرط "
android.hardware.foo@1.0
تعریف نشده است" به این معنی است که دایرکتوریhardware/interfaces/foo/1.0
حتی نباید وجود داشته باشد.
با این حال، قانون A روی بستهای با نام بسته مشابه اما نسخه اصلی متفاوتی تأثیر نمیگذارد (برای مثال، android.hardware.camera.device
هر دو @1.0
و @3.2
تعریف شده است؛ @3.2
نیازی به تعامل با @1.0
ندارد. @1.0
.) بنابراین، @3.2::IExtFoo
میتواند @1.0::IFoo
را گسترش دهد.
به شرطی که نام بسته متفاوت باشد، package@major.minor::IBar
می تواند از یک رابط با نام متفاوت گسترش یابد (به عنوان مثال، android.hardware.bar@1.0::IBar
می تواند android.hardware.baz@2.2::IBaz
گسترش دهد. ). اگر یک رابط صریحاً یک super type را با کلمه کلیدی extend
اعلام نکند، android.hidl.base@1.0::IBase
گسترش می دهد (به جز خود IBase
).
B.2 و B.3 باید همزمان رعایت شوند. برای مثال، حتی اگر android.hardware.foo@1.1::IFoo
android.hardware.foo@1.0::IFoo
را برای تصویب قانون B.2 گسترش دهد، اگر android.hardware.foo@1.1::IExtBar
android.hardware.foo@1.0::IBar
، این هنوز یک آپدیت معتبر نیست.
رابط های Uprev
برای بالا بردن android.hardware.example@1.0
(تعریف شده در بالا) به @1.1
:
// types.hal package android.hardware.example@1.1; import android.hardware.example@1.0; // IQuux.hal package android.hardware.example@1.1 interface IQuux extends @1.0::IQuux { fromBarToFoo(Foo.Bar b) generates (Foo f); }
این یک import
در سطح بسته از نسخه 1.0
android.hardware.example
در types.hal
است. در حالی که هیچ UDT جدیدی در نسخه 1.1
بسته اضافه نشده است، ارجاع به UDT ها در نسخه 1.0
همچنان مورد نیاز است، بنابراین وارد کردن در سطح بسته در types.hal
می شود. (همان اثر را میتوان با وارد کردن سطح رابط در IQuux.hal
به دست آورد.)
در extends @1.0::IQuux
در اعلان IQuux
، نسخه IQuux
را مشخص کردیم که در حال به ارث بردن است (ابهامزدایی لازم است زیرا IQuux
برای اعلام یک رابط و برای ارث بردن از یک رابط استفاده میشود). از آنجایی که اعلانها به سادگی نامهایی هستند که تمام ویژگیهای بسته و نسخه را در سایت اعلان به ارث میبرند، ابهامزدایی باید در نام رابط پایه باشد. ما می توانستیم از UDT کاملاً واجد شرایط نیز استفاده کنیم، اما این کار اضافی بود.
رابط جدید IQuux
متد را fromFooToBar()
مجدداً اعلام نمیکند و از @1.0::IQuux
به ارث میبرد. به سادگی متد جدیدی را که fromBarToFoo()
اضافه می کند لیست می کند. در HIDL، متدهای ارثی را نمیتوان دوباره در رابطهای فرزند اعلان کرد، بنابراین رابط IQuux
نمیتواند متد fromFooToBar()
را به صراحت اعلام کند.
کنوانسیون های Uprev
گاهی اوقات نام رابط باید رابط توسعه دهنده را تغییر نام دهد. ما توصیه میکنیم که پسوندها، ساختارها و اتحادیههای enum همان نامی را داشته باشند که گسترش میدهند، مگر اینکه به اندازه کافی متفاوت باشند تا یک نام جدید را تضمین کنند. مثال ها:
// in parent hal file enum Brightness : uint32_t { NONE, WHITE }; // in child hal file extending the existing set with additional similar values enum Brightness : @1.0::Brightness { AUTOMATIC }; // extending the existing set with values that require a new, more descriptive name: enum Color : @1.0::Brightness { HW_GREEN, RAINBOW };
اگر یک متد بتواند نام معنایی جدیدی داشته باشد (مثلا fooWithLocation
)، ترجیح داده می شود. در غیر این صورت، باید به طور مشابه با آنچه که در حال گسترش است نامگذاری شود. به عنوان مثال، اگر نام جایگزین بهتری وجود نداشته باشد، متد foo_1_1
در @1.1::IFoo
میتواند عملکرد متد foo
را در @1.0::IFoo
جایگزین کند.
نسخه سازی در سطح بسته
نسخه HIDL در سطح بسته رخ می دهد. پس از انتشار یک بسته، تغییر ناپذیر است (مجموعه رابط ها و UDT های آن قابل تغییر نیستند). بستهها میتوانند به روشهای مختلفی با یکدیگر مرتبط شوند، که همگی از طریق ترکیبی از وراثت در سطح رابط و ساخت UDTها بر اساس ترکیب قابل بیان هستند.
با این حال، یک نوع رابطه کاملاً تعریف شده است و باید اجرا شود: وراثت سازگار با سطح بسته . در این سناریو، بسته والد بسته ای است که از آن به ارث رسیده است و بسته فرزند همان بسته ای است که والد را گسترش می دهد. قوانین وراثت سازگار با سطح بسته به شرح زیر است:
- تمام واسط های سطح بالای بسته والد توسط رابط های بسته فرزند به ارث برده می شوند.
- اینترفیسهای جدید را نیز میتوان به بسته جدید اضافه کرد (بدون محدودیت در رابطه با رابطهای دیگر در بستههای دیگر).
- انواع دادههای جدید را میتوان برای استفاده با روشهای جدید رابطهای موجود ارتقا یافته یا با رابطهای جدید اضافه کرد.
این قوانین را میتوان با استفاده از وراثت در سطح رابط HIDL و ترکیب UDT پیادهسازی کرد، اما برای دانستن این که این روابط یک پسوند بسته سازگار با عقب را تشکیل میدهند، به دانش فراسطحی نیاز دارد. این دانش به شرح زیر استنباط می شود:
اگر بسته ای این الزام را برآورده کند، hidl-gen
قوانین سازگاری با عقب را اعمال می کند.