‫AIDL برای HAL

‫Android 11 امکان استفاده از AIDL برای HAL در Android را معرفی می‌کند و به این ترتیب می‌توان بخش‌هایی از Android را بدون HIDL پیاده‌سازی کرد. انتقال HALها برای استفاده انحصاری از AIDL درصورت امکان (وقتی HALهای بالادستی از HIDL استفاده می‌کنند، باید از HIDL استفاده شود).

«لایه‌های انتزاعی سخت‌افزار» (HAL) که از AIDL برای ارتباط بین عناصر چارچوب، مانند عناصر موجود در system.img، و عناصر سخت‌افزار، مانند عناصر موجود در vendor.img، استفاده می‌کنند باید از AIDL پایدار استفاده کنند. بااین‌حال، برای برقراری ارتباط در یک پارتیشن، مثلاً از یک HAL به HAL دیگر، هیچ محدودیتی برای استفاده از سازوکار IPC وجود ندارد.

انگیزه

‫AIDL مدت بیشتری از HIDL وجود داشته است و در بسیاری از مکان‌های دیگر، مانند بین عناصر چارچوب Android یا در برنامه‌ها، استفاده می‌شود. اکنون که AIDL از پایداری پشتیبانی می‌کند، می‌توان کل پشته را با یک زمان اجرای IPC پیاده‌سازی کرد. ‫AIDL همچنین سیستم نسخه‌بندی بهتری نسبت به HIDL دارد. در اینجا برخی‌از مزایای AIDL آورده شده است:

  • استفاده از یک زبان IPC به این معنی است که فقط یک چیز برای یادگیری، اشکال‌زدایی، بهینه‌سازی، و ایمن‌سازی وجود دارد.
  • ‫AIDL از نسخه‌بندی درجا برای مالکان میانای پشتیبانی می‌کند:
    • مالکان می‌توانند روش‌هایی را به انتهای میان‌ها، یا فیلدهایی را به بسته‌های داده اضافه کنند. این یعنی نسخه‌بندی کد درطول سال‌ها آسان‌تر است و همچنین هزینه سال‌به‌سال کمتر است (انواع را می‌توان در محل اصلاح کرد و نیازی به کتابخانه‌های اضافی برای هر نسخه رابط نیست).
    • رابط‌های افزونه را می‌توان در زمان اجرا به‌جای سیستم نوع متصل کرد، بنابراین نیازی به بازپایه کردن افزونه‌های پایین‌دست به نسخه‌های جدیدتر رابط‌ها نیست.
  • وقتی مالک یک میانای AIDL موجود تصمیم می‌گیرد آن را پایدار کند، می‌توان مستقیماً از آن استفاده کرد. قبلاً، کل نسخه واسط باید در HIDL ایجاد می‌شد.

ساختن دربرابر زمان اجرای AIDL

‫AIDL سه زیرینه مختلف دارد: Java،‏ NDK، و CPP. برای استفاده از AIDL پایدار، همیشه از نسخه سیستم libbinder در system/lib*/libbinder.so استفاده کنید و در /dev/binder صحبت کنید. برای کد موجود در تصویر vendor، این یعنی libbinder (از VNDK) نمی‌تواند استفاده شود: این کتابخانه دارای API ناپایدار C++ و بخش‌های داخلی ناپایدار است. درعوض، کد فروشنده بومی باید از زیرینه NDK در AIDL استفاده کند، با libbinder_ndk پیوند دهد (که با سیستم libbinder.so پشتیبانی می‌شود)، و با کتابخانه‌های NDK که توسط ورودی‌های aidl_interface ایجاد شده‌اند پیوند دهد. برای نام‌های دقیق واحد، قوانین نام‌گذاری واحد را ببینید.

نوشتن میانای AIDL HAL

برای اینکه میانای AIDL بین سیستم و فروشنده استفاده شود، میانای موردنظر به دو تغییر نیاز دارد:

  • هر تعریف نوع باید با @VintfStability حاشیه‌نویسی شود.
  • اظهارنامه aidl_interface باید شامل stability: "vintf", باشد.

فقط مالک میان‌گیری می‌تواند این تغییرات را انجام دهد.

وقتی این تغییرات را انجام می‌دهید، واسط باید در مانیفست VINTF باشد تا کار کند. این مورد (و الزامات مرتبط، مثل تأیید اینکه میاناهای منتشرشده ثابت هستند) را بااستفاده از آزمایش Vendor Test Suite (VTS) vts_treble_vintf_vendor_test آزمایش کنید. با فراخوانی AIBinder_forceDowngradeToLocalStability در زیرینه NDK،‏ android::Stability::forceDowngradeToLocalStability در زیرینه C++‎، یا android.os.Binder#forceDowngradeToSystemStability در زیرینه Java در یک شیء پیونددهنده قبل‌از ارسال آن به فرایندی دیگر، می‌توانید از میانای @VintfStability بدون این الزامات استفاده کنید.

علاوه‌براین، برای حداکثر قابلیت حمل کد و جلوگیری از مشکلات احتمالی مانند کتابخانه‌های اضافی غیرضروری، پسوند CPP را غیرفعال کنید.

کد نحوه غیرفعال کردن CPP backend را نشان می‌دهد:

    aidl_interface: {
        ...
        backend: {
            cpp: {
                enabled: false,
            },
        },
    }

پیدا کردن میاناهای AIDL HAL

میاناهای AIDL پایدار AOSP برای HALS در پوشه‌های aidl در همان دایرکتوری‌های پایه میاناهای HIDL قرار دارند:

  • hardware/interfaces برای میانگین‌هایی است که معمولاً سخت‌افزار ارائه می‌دهد.
  • frameworks/hardware/interfaces برای رابط‌های سطح بالا است که برای سخت‌افزار ارائه شده است.
  • ‫system/hardware/interfaces برای میاناهای سطح پایین ارائه‌شده به سخت‌افزار است.

میاناهای افزونه را در زیرفهرست‌های راهنمای دیگر hardware/interfaces در vendor یا hardware قرار دهید.

میاناهای افزونه

‫Android در هر نسخه مجموعه‌ای از میاناهای رسمی AOSP دارد. وقتی شرکای Android می‌خواهند قابلیت‌هایی به این میاناهای کاربری اضافه کنند، نباید آن‌ها را مستقیماً تغییر دهند زیرا این کار باعث می‌شود زمان اجرای Android آن‌ها با زمان اجرای Android در «پروژه منبع باز Android» ناسازگار شود. از تغییر دادن این میاناهای GSI اجتناب کنید تا تصویر GSI بتواند به کار خود ادامه دهد.

افزونه‌ها می‌توانند به دو روش مختلف ثبت شوند:

هرچند افزونه‌ای ثبت شده است، وقتی مؤلفه‌های مختص فروشنده (یعنی بخشی از AOSP بالادستی نیستند) از میانای استفاده می‌کنند، تداخل‌های ادغام ممکن نیست اما وقتی اصلاحات پایین‌دستی در مؤلفه‌های AOSP بالادستی انجام می‌شود، تداخل‌های ادغام ممکن است رخ دهد و راهبردهای زیر توصیه می‌شود:

  • در نسخه پخش بعدی، موارد اضافه‌شده به میانای بالادستی را به AOSP اضافه کنید.
  • افزودن میانای بالادستی که در نسخه بعدی انعطاف‌پذیری بیشتری (بدون تداخل ادغام) فراهم می‌کند.

ParcelableHolder: Extension parcelables

‫ParcelableHolder نمونه‌ای از میانای Parcelable است که می‌تواند نمونه دیگری از Parcelable را دربر بگیرد.

مورد استفاده اصلی ParcelableHolder این است که Parcelable را توسعه‌پذیر کند. برای مثال، تصویر کنید که پیاده‌سازان دستگاه انتظار دارند بتوانند Parcelable و AospDefinedParcelable تعریف‌شده در AOSP را گسترش دهند تا ویژگی‌های ارزش‌افزوده خود را در آن بگنجانند.

از رابط ParcelableHolder برای گسترش Parcelable با ویژگی‌های ارزش‌افزوده خود استفاده کنید. میانای ParcelableHolder حاوی نمونه‌ای از Parcelable است. اگر بخواهید فیلدها را مستقیماً به Parcelable اضافه کنید، خطا رخ می‌دهد:

parcelable AospDefinedParcelable {
  int a;
  String b;
  String x; // ERROR: added by a device implementer
  int[] y; // added by a device implementer
}

همان‌طور که در کد قبلی دیده می‌شود، این رویه نادرست است زیرا فیلدهای اضافه‌شده توسط پیاده‌ساز دستگاه ممکن است هنگام اصلاح Parcelable در نسخه‌های بعدی Android با مشکل مواجه شوند.

بااستفاده از ParcelableHolder، مالک یک دارایی قابل‌انتقال می‌تواند نقطه افزونه‌ای را در نمونه‌ای از Parcelable تعریف کند:

parcelable AospDefinedParcelable {
  int a;
  String b;
  ParcelableHolder extension;
}

سپس پیاده‌سازان دستگاه می‌توانند نمونه Parcelable خودشان را برای افزونه‌شان تعریف کنند:

parcelable OemDefinedParcelable {
  String x;
  int[] y;
}

نمونه جدید Parcelable را می‌توان با فیلد ParcelableHolder به Parcelable اصلی پیوست کرد:


// Java
AospDefinedParcelable ap = ...;
OemDefinedParcelable op = new OemDefinedParcelable();
op.x = ...;
op.y = ...;

ap.extension.setParcelable(op);

...

OemDefinedParcelable op = ap.extension.getParcelable(OemDefinedParcelable.class);

// C++
AospDefinedParcelable ap;
OemDefinedParcelable op;
std::shared_ptr<OemDefinedParcelable> op_ptr = make_shared<OemDefinedParcelable>();

ap.extension.setParcelable(op);
ap.extension.setParcelable(op_ptr);

...

std::shared_ptr<OemDefinedParcelable> op_ptr;

ap.extension.getParcelable(&op_ptr);

// NDK
AospDefinedParcelable ap;
OemDefinedParcelable op;
ap.extension.setParcelable(op);

...

std::optional<OemDefinedParcelable> op;
ap.extension.getParcelable(&op);

// Rust
let mut ap = AospDefinedParcelable { .. };
let op = Rc::new(OemDefinedParcelable { .. });

ap.extension.set_parcelable(Rc::clone(&op));

...

let op = ap.extension.get_parcelable::<OemDefinedParcelable>();

نام‌های نمونه سرور AIDL HAL

طبق قرارداد، سرویس‌های AIDL HAL نام نمونه‌ای با قالب $package.$type/$instance دارند. برای مثال، نمونه‌ای از HAL لرزاننده به‌عنوان android.hardware.vibrator.IVibrator/default ثبت شده است.

نوشتن سرور AIDL HAL

@VintfStability سرورهای AIDL باید در مانیفست VINTF اعلام شوند، برای مثال:

    <hal format="aidl">
        <name>android.hardware.vibrator</name>
        <version>1</version>
        <fqname>IVibrator/default</fqname>
    </hal>

درغیراین‌صورت، باید سرویس AIDL را به‌طور معمول ثبت کنند. هنگام اجرای آزمایش‌های VTS، انتظار می‌رود که همه AIDL HALهای اعلام‌شده دردسترس باشند.

نوشتن کارخواه AIDL

مشتریان AIDL باید خود را در ماتریس سازگاری اعلام کنند، برای مثال:

    <hal format="aidl" optional="true">
        <name>android.hardware.vibrator</name>
        <version>1-2</version>
        <interface>
            <name>IVibrator</name>
            <instance>default</instance>
        </interface>
    </hal>

تبدیل HAL موجود از HIDL به AIDL

از ابزار hidl2aidl برای تبدیل میانای HIDL به AIDL استفاده کنید.

ویژگی‌های hidl2aidl:

  • فایل‌های AIDL (.aidl) را براساس فایل‌های HAL (.hal) برای بسته داده‌شده ایجاد کن.
  • قوانین ساخت را برای بسته AIDL جدیداً ایجادشده با همه زمینه‌های پشتیبان فعال ایجاد کنید.
  • روش‌های ترجمه را در زیرینه‌های Java،‏ CPP، و NDK برای ترجمه از انواع HIDL به انواع AIDL ایجاد کنید.
  • قوانین ساخت را برای ترجمه کتابخانه‌ها با وابستگی‌های موردنیاز ایجاد کنید.
  • ادعاهای ایستا ایجاد کنید تا مطمئن شوید که شمارنده‌های HIDL و AIDL در پس‌زمینه‌های CPP و NDK مقادیر یکسانی دارند.

برای تبدیل بسته‌ای از فایل‌های HAL به فایل‌های AIDL، این مراحل را دنبال کنید:

  1. ابزار موجود در system/tools/hidl/hidl2aidl را بسازید.

    ساختن این ابزار از جدیدترین منبع، کامل‌ترین تجربه را ارائه می‌دهد. می‌توانید از جدیدترین نسخه برای تبدیل کردن میاناهای شاخه‌های قدیمی‌تر از نسخه‌های قبلی استفاده کنید:

    m hidl2aidl
  2. ابزار را با دایرکتوری خروجی و سپس بسته‌ای که باید تبدیل شود اجرا کنید.

    به‌صورت اختیاری، از آرگومان -l برای افزودن محتوای فایل پروانه جدید به بالای همه فایل‌های تولیدشده استفاده کنید. حتماً از پروانه و تاریخ صحیح استفاده کنید:

    hidl2aidl -o <output directory> -l <file with license> <package>

    برای مثال:

    hidl2aidl -o . -l my_license.txt android.hardware.nfc@1.2
  3. فایل‌های تولیدشده را بخوانید و مشکلات تبدیل را برطرف کنید:

    • ‫conversion.log حاوی مشکلات رسیدگی‌نشده‌ای است که باید ابتدا آن‌ها را برطرف کنید.
    • فایل‌های AIDL تولیدشده ممکن است هشدارها و پیشنهادهایی داشته باشند که نیاز به اقدام دارند. این نظرات با // شروع می‌شود.
    • بسته را پاک‌سازی و بهبود دهید.
    • حاشیه‌نویسی @JavaDerive را برای ویژگی‌هایی که ممکن است لازم باشد، مثل toString یا equals، بررسی کنید.
  4. فقط هدف‌هایی را بسازید که نیاز دارید:

    • پشتیبان‌هایی را که استفاده نخواهند شد غیرفعال کنید. زیرینه NDK را بر زیرینه CPP ترجیح دهید؛ ساختن دربرابر زمان اجرای AIDL را ببینید.
    • کتابخانه‌های ترجمه یا هرکدام از کدهای تولیدشده آن‌ها را که استفاده نخواهد شد بردارید.
  5. تفاوت‌های اصلی AIDL و HIDL را ببینید:

    • استفاده از Status و استثناهای داخلی AIDL معمولاً باعث بهبود میانای کاربر می‌شود و نیاز به نوع وضعیت خاص میانای کاربر دیگری را برطرف می‌کند.
    • متغیرهای مستقل میانای AIDL در روش‌ها به‌طور پیش‌فرض @nullable نیستند، همان‌طور که در HIDL بودند.

‫SEPolicy برای AIDL HALs

نوع سرویس AIDL که برای کد فروشنده قابل‌مشاهده است باید دارای مشخصه hal_service_type باشد. درغیراین‌صورت، پیکربندی sepolicy مانند هر سرویس AIDL دیگری است (اگرچه ویژگی‌های خاصی برای HAL وجود دارد). در اینجا تعریف نمونه‌ای از بافت سرویس HAL آورده شده است:

    type hal_foo_service, service_manager_type, hal_service_type;

برای اکثر سرویس‌های تعریف‌شده توسط پلاتفرم، زمینه سرویس با نوع صحیح ازقبل اضافه شده است (برای مثال، android.hardware.foo.IFoo/default ازقبل به‌عنوان hal_foo_service علامت‌گذاری شده است). بااین‌حال، اگر مشتری چارچوب از نام‌های نمونه چندگانه پشتیبانی کند، نام‌های نمونه اضافی باید در فایل‌های service_contexts مختص دستگاه اضافه شوند:

    android.hardware.foo.IFoo/custom_instance u:object_r:hal_foo_service:s0

وقتی نوع جدیدی از HAL ایجاد می‌کنید، باید مشخصه‌های HAL را اضافه کنید. یک مشخصه HAL خاص ممکن است با چند نوع سرویس مرتبط باشد (هرکدام از آن‌ها می‌تواند چند نمونه داشته باشد، همان‌طور که قبلاً بحث شد). برای لایه انتزاع سخت‌افزار، foo، hal_attribute(foo) وجود دارد. این کلان‌دستور مشخصه‌های hal_foo_client و hal_foo_server را تعریف می‌کند. برای دامنه معین، ماکروهای hal_client_domain و hal_server_domain دامنه را با مشخصه HAL معینی مرتبط می‌کنند. برای مثال، سرور سیستم که کارخواه این HAL است با خط‌مشی hal_client_domain(system_server, hal_foo) مطابقت دارد. سرور HAL نیز به‌طور مشابه شامل hal_server_domain(my_hal_domain, hal_foo) است.

معمولاً برای یک مشخصه HAL معین، دامنه‌ای مثل hal_foo_default برای مرجع یا نمونه‌های HAL ایجاد کنید. بااین‌حال، برخی‌از دستگاه‌ها از این دامنه‌ها برای سرورهای خودشان استفاده می‌کنند. تمایز بین دامنه‌ها برای چندین سرور فقط زمانی اهمیت دارد که چندین سرور وجود داشته باشند که به یک میانای یکسان خدمات ارائه می‌دهند و در پیاده‌سازی‌هایشان به مجموعه اجازه‌های متفاوتی نیاز دارند. در همه این کلان‌دستورها، hal_foo یک شیء sepolicy نیست. درعوض، این نشان توسط این کلان‌ها برای ارجاع به گروه مشخصه‌های مرتبط با جفت سرور کارخواه استفاده می‌شود.

بااین‌حال، تاکنون hal_foo_service و hal_foo (جفت مشخصه از hal_attribute(foo)) مرتبط نشده‌اند. مشخصه HAL بااستفاده از کلان‌دستور hal_attribute_service با خدمات AIDL HAL مرتبط می‌شود (در HIDL HAL از کلان‌دستور hal_attribute_hwservice استفاده می‌شود)، برای مثال، hal_attribute_service(hal_foo, hal_foo_service). این یعنی hal_foo_client فرایند می‌تواند به HAL دسترسی پیدا کند و hal_foo_server فرایند می‌تواند HAL را ثبت کند. اجرای این قوانین ثبت‌نام توسط مدیر زمینه‌ای (servicemanager) انجام می‌شود.

نام‌های سرویس ممکن است همیشه با مشخصه‌های HAL مطابقت نداشته باشند، برای مثال، hal_attribute_service(hal_foo, hal_foo2_service). به‌طورکلی، چون این امر به این معنی است که سرویس‌ها همیشه با هم استفاده می‌شوند، می‌توانید hal_foo2_service را بردارید و از hal_foo_service برای همه زمینه‌های سرویس استفاده کنید. وقتی HALها چندین نمونه hal_attribute_service تنظیم می‌کنند، دلیلش این است که نام مشخصه HAL اصلی به‌اندازه کافی عمومی نیست و نمی‌توان آن را تغییر داد.

با کنار هم قرار دادن همه این‌ها، یک HAL نمونه به این شکل است:

    public/attributes:
    // define hal_foo, hal_foo_client, hal_foo_server
    hal_attribute(foo)

    public/service.te
    // define hal_foo_service
    type hal_foo_service, hal_service_type, protected_service, service_manager_type

    public/hal_foo.te:
    // allow binder connection from client to server
    binder_call(hal_foo_client, hal_foo_server)
    // allow client to find the service, allow server to register the service
    hal_attribute_service(hal_foo, hal_foo_service)
    // allow binder communication from server to service_manager
    binder_use(hal_foo_server)

    private/service_contexts:
    // bind an AIDL service name to the selinux type
    android.hardware.foo.IFooXxxx/default u:object_r:hal_foo_service:s0

    private/<some_domain>.te:
    // let this domain use the hal service
    binder_use(some_domain)
    hal_client_domain(some_domain, hal_foo)

    vendor/<some_hal_server_domain>.te
    // let this domain serve the hal service
    hal_server_domain(some_hal_server_domain, hal_foo)

میاناهای افزونه پیوست‌شده

افزونه می‌تواند به هر رابط چسباننده‌ای پیوست شود، چه رابط سطح بالایی باشد که مستقیماً در مدیر سرویس ثبت شده است یا رابط فرعی باشد. هنگام دریافت افزونه، باید تأیید کنید که نوع افزونه همان چیزی است که انتظار می‌رود. فقط از فرایندی که پوشه را ارائه می‌کند می‌توانید افزونه‌ها را تنظیم کنید.

هرگاه افزونه‌ای عملکرد یک HAL موجود را تغییر می‌دهد، از افزونه‌های پیوست‌شده استفاده کنید. وقتی به قابلیت کاملاً جدیدی نیاز است، این سازوکار ضروری نیست و می‌توانید میانای افزونه را مستقیماً در مدیر سرویس ثبت کنید. رابط‌های افزونه پیوست‌شده وقتی به زیررابط‌ها پیوست می‌شوند منطقی‌تر هستند، زیرا این سلسله مراتب می‌تواند عمیق یا چند نمونه‌ای باشد. استفاده از افزونه سراسری برای بازتاب دادن سلسله‌مراتب میانای متصل‌کننده سرویس دیگر نیازمند دفترداری گسترده‌ای است تا قابلیت‌های معادل را برای افزونه‌های مستقیماً متصل‌شده ارائه دهد.

برای تنظیم افزونه در پوشه، از APIهای زیر استفاده کنید:

  • انتهای NDK: ‏ AIBinder_setExtension
  • پشت‌صحنه Java: android.os.Binder.setExtension
  • ‫CPP backend: ‏ android::Binder::setExtension
  • پشتیبان Rust: binder::Binder::set_extension

برای دریافت افزونه در پوشه، از میاناهای برنامه‌سازی کاربردی زیر استفاده کنید:

  • بخش پشتی NDK: ‏ AIBinder_getExtension
  • پشت‌صحنه Java: android.os.IBinder.getExtension
  • بک‌اند CPP: ‏ android::IBinder::getExtension
  • بخش پشتی Rust: binder::Binder::get_extension

می‌توانید اطلاعات بیشتری درباره این میاناهای برنامه‌سازی کاربردی در اسناد تابع getExtension در پسای مربوطه پیدا کنید. نمونه‌ای از نحوه استفاده از افزونه‌ها در hardware/interfaces/tests/extension/vibrator آمده است.

تفاوت‌های اصلی AIDL و HIDL

هنگام استفاده از AIDL HAL یا استفاده از میاناهای AIDL HAL، از تفاوت‌های آن در مقایسه با نوشتن HIDL HAL آگاه باشید.

  • نحو زبان AIDL به Java نزدیک‌تر است. نحو HIDL مشابه C++ است.
  • همه میاناهای AIDL وضعیت‌های خطای داخلی دارند. به‌جای ایجاد انواع وضعیت سفارشی، اعداد صحیح وضعیت ثابت را در فایل‌های میانای ایجاد کنید و از EX_SERVICE_SPECIFIC در زیرینه‌های CPP و NDK و ServiceSpecificException در زیرینه Java استفاده کنید. رسیدگی به خطا را ببینید.
  • AIDL هنگام ارسال اشیاء binder، استخرهای رشته را به‌طور خودکار راه‌اندازی نمی‌کند. باید آن‌ها را به‌صورت دستی شروع کنید (مدیریت رشته را ببینید).
  • ‫AIDL درصورت بروز خطاهای انتقال بررسی‌نشده لغو نمی‌شود (HIDL Return درصورت بروز خطاهای بررسی‌نشده لغو می‌شود).
  • ‫AIDL می‌تواند فقط یک نوع در هر فایل تعریف کند.
  • آرگومان‌های AIDL را می‌توان علاوه‌بر پارامتر خروجی، به‌صورت in، out، یا inout مشخص کرد (فراخوان‌های برگشتی همگام وجود ندارد).
  • ‫AIDL از fd به‌عنوان نوع اولیه به‌جای handle استفاده می‌کند.
  • ‫HIDL از نسخه‌های اصلی برای تغییرات ناسازگار و از نسخه‌های فرعی برای تغییرات سازگار استفاده می‌کند. در AIDL، تغییرات سازگار با نسخه قدیمی در همان مکان انجام می‌شود. ‫AIDL مفهوم صریحی از نسخه‌های اصلی ندارد؛ درعوض، این مفهوم در نام بسته‌ها گنجانده شده است. برای مثال، AIDL ممکن است از نام بسته bluetooth2 استفاده کند.
  • ‫AIDL به‌طور پیش‌فرض اولویت هم‌زمان را به‌ارث نمی‌برد. تابع setInheritRt باید برای هر بایندر استفاده شود تا وراثت اولویت هم‌زمان فعال شود.

آزمایش‌های HAL

این بخش روال‌های مطلوب برای آزمایش «لایه انتزاع سخت‌افزار» را شرح می‌دهد. این روال‌های مطلوب حتی اگر آزمون یکپارچه‌سازی برای HAL شما در VTS نباشد معتبر است.

‫Android برای درستی‌سنجی پیاده‌سازی‌های موردانتظار HAL به VTS متکی است. «مجموعه آزمون فروشنده» کمک می‌کند مطمئن شویم Android با پیاده‌سازی‌های قدیمی فروشنده سازگار است. پیاده‌سازی‌هایی که در VTS ناموفق بوده‌اند مشکلات سازگاری شناخته‌شده‌ای دارند که می‌تواند مانع از کار کردن آن‌ها با نسخه‌های آینده سیستم‌عامل شود.

دو بخش اصلی VTS برای HAL وجود دارد.

۱. درستی‌سنجی HALها در دستگاه توسط Android شناخته شده و موردانتظار است

‫Android برای داشتن فهرستی ثابت و دقیق از همه «لایه انتزاع سخت‌افزار» نصب‌شده به آن متکی است. این فهرست در مانیفست VINTF بیان شده است. آزمایش‌های ویژه در سراسر پلاتفرم تمامیت لایه‌های HAL را در کل سیستم باهم تأیید می‌کنند. قبل‌از نوشتن هرگونه آزمایش مختص HAL، باید این آزمایش‌ها را نیز اجرا کنید، زیرا این آزمایش‌ها می‌توانند نشان دهند که آیا HAL پیکربندی‌های VINTF ناسازگار دارد یا نه.

این مجموعه آزمایش‌ها را می‌توانید در test/vts-testcase/hal/treble/vintf پیدا کنید. اگر روی پیاده‌سازی HAL فروشنده کار می‌کنید، از vts_treble_vintf_vendor_test برای درستی‌سنجی آن استفاده کنید. می‌توانید این آزمایش را با فرمان atest vts_treble_vintf_vendor_test اجرا کنید.

این آزمایش‌ها مسئول درستی‌سنجی موارد زیر هستند:

  • هر میانای @VintfStability که در مانیفست VINTF اعلام شده است در نسخه منتشرشده شناخته‌شده‌ای ثابت می‌شود. این کار تأیید می‌کند که هر دو طرف میانای کاربری بر سر تعریف دقیق آن نسخه از میانای کاربری توافق دارند. این کار برای عملکرد پایه ضروری است.
  • همه HALهایی که در مانیفست VINTF اعلام شده‌اند در آن دستگاه دردسترس هستند. هر کارخواهی که اجازه‌های کافی برای استفاده از سرویس HAL اعلام‌شده را داشته باشد باید بتواند در هر زمانی آن سرویس‌ها را دریافت و از آن‌ها استفاده کند.
  • همه HALهایی که در مانیفست VINTF اعلام شده‌اند نسخه میانایی را ارائه می‌دهند که در مانیفست اعلام کرده‌اند.
  • هیچ HAL منسوخی در دستگاه ارائه نمی‌شود. همان‌طور که در دوره حیات FCM توضیح داده شده است، Android پشتیبانی از نسخه‌های پایین‌تر میاناهای HAL را متوقف می‌کند.
  • «لایه انتزاعی سخت‌افزار» موردنیاز در دستگاه وجود دارد. برخی‌از HALها برای عملکرد صحیح Android ضروری هستند.

۲. رفتار موردانتظار هر «لایه انتزاع سخت‌افزار» را درستی‌سنجی کنید

هر میانای HAL آزمون‌های VTS خود را دارد تا رفتار موردانتظار از کاربرانش را درستی‌سنجی کند. موارد آزمایشی دربرابر هر نمونه از میانای HAL اعلام‌شده اجرا می‌شود و رفتار خاصی را براساس نسخه میانای پیاده‌سازی‌شده اعمال می‌کند.

در C++‎، می‌توانید بااستفاده از تابع android::getAidlHalInstanceNames در libaidlvintf_gtest_helper، فهرستی از همه HALهای نصب‌شده در سیستم دریافت کنید. در Rust، از binder::get_declared_instances استفاده کنید.

این آزمایش‌ها تلاش می‌کنند تا هر جنبه‌ای از پیاده‌سازی HAL را که چارچوب Android به آن متکی است یا ممکن است در آینده به آن متکی باشد، پوشش دهند.

این آزمایش‌ها شامل تأیید پشتیبانی از ویژگی‌ها، مدیریت خطا، و هر رفتار دیگری است که مشتری ممکن است از سرویس انتظار داشته باشد.

نقاط عطف VTS برای توسعه HAL

انتظار می‌رود آزمایش‌های VTS (یا هر آزمایشی) هنگام ایجاد یا اصلاح کردن میاناهای HAL در Android به‌روز نگه داشته شوند.

آزمایش‌های VTS باید قبل‌از اینکه برای نسخه‌های Android Vendor API ثابت شوند، تکمیل و آماده درستی‌سنجی پیاده‌سازی‌های فروشنده باشند. این پیاده‌سازی‌ها باید قبل‌از ثابت شدن میاناها آماده باشند تا توسعه‌دهندگان بتوانند پیاده‌سازی‌های خود را ایجاد کنند، آن‌ها را درستی‌سنجی کنند، و به توسعه‌دهندگان میانای HAL بازخورد ارائه دهند.

آزمایش در Cuttlefish

وقتی سخت‌افزار دردسترس نباشد، Android از Cuttlefish به‌عنوان وسیله توسعه برای میاناهای HAL استفاده می‌کند. این کار امکان آزمایش یکپارچگی مقیاس‌پذیر Android را فراهم می‌کند.

‫hal_implementation_test آزمایش که Cuttlefish پیاده‌سازی‌های جدیدترین نسخه‌های میانای HAL را دارد تا مطمئن شود Android آماده کار با میاناهای جدید است و آزمایش‌های VTS آماده‌اند تا پیاده‌سازی‌های جدید فروشنده را به‌محض دردسترس قرار گرفتن سخت‌افزار و دستگاه‌های جدید آزمایش کنند.