AIDL برای HAL ها

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

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

انگیزه

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

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

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

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

یک رابط AIDL HAL بنویسید

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

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

فقط مالک یک رابط می‌تواند این تغییرات را اعمال کند.

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

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

این کد نحوه غیرفعال کردن 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 قرار دهید.

رابط‌های افزونه

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

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

با این حال، یک افزونه ثبت می‌شود، زمانی که اجزای مختص فروشنده (به این معنی که بخشی از AOSP بالادستی نیستند) از رابط استفاده می‌کنند، تداخل ادغام امکان‌پذیر نیست. با این حال، هنگامی که تغییرات پایین‌دستی در اجزای AOSP بالادستی انجام می‌شود، تداخل ادغام می‌تواند منجر شود و استراتژی‌های زیر توصیه می‌شوند:

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

افزونه‌های قابل بسته‌بندی: ParcelableHolder

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

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

از رابط 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 در نسخه‌های بعدی اندروید، با هم تداخل داشته باشند.

با استفاده از ParcelableHolder ، مالک یک parcelable می‌تواند یک نقطه توسعه در نمونه‌ای از 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 بنویسید

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

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

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

یک کلاینت 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 تازه ایجاد شده با فعال بودن همه بک‌اندها ایجاد کنید.
  • ایجاد متدهای ترجمه در بک‌اندهای جاوا، CPP و NDK برای ترجمه از انواع HIDL به انواع AIDL.
  • ایجاد قوانین ساخت برای کتابخانه‌های ترجمه با وابستگی‌های مورد نیاز.
  • برای اطمینان از اینکه شمارنده‌های HIDL و AIDL در بک‌اندهای CPP و NDK مقادیر یکسانی دارند، از دستورات ایستا (static assertions) استفاده کنید.

برای تبدیل یک بسته از فایل‌های 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. فقط اهدافی را که نیاز دارید بسازید:

    • غیرفعال کردن backendهایی که استفاده نمی‌شوند. backend NDK را به backend CPP ترجیح دهید؛ به بخش Build against the AIDL runtime مراجعه کنید.
    • کتابخانه‌های ترجمه یا هر یک از کدهای تولید شده توسط آنها را که استفاده نخواهند شد، حذف کنید.
  5. تفاوت‌های عمده AIDL و HIDL را ببینید:

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

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

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

  • بک‌اند NDK: AIBinder_setExtension
  • بک‌اند جاوا: android.os.Binder.setExtension
  • بخش مدیریت CPP: android::Binder::setExtension
  • پشت صحنه Rust: binder::Binder::set_extension

برای دریافت یک افزونه روی یک binder، از API های زیر استفاده کنید:

  • باطن NDK: AIBinder_getExtension
  • باطن جاوا: android.os.IBinder.getExtension
  • باطن CPP: android::IBinder::getExtension
  • پشت صحنه Rust: binder::Binder::get_extension

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

تفاوت‌های عمده AIDL و HIDL

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

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

آزمایش‌های HAL

این بخش بهترین شیوه‌ها برای آزمایش HALها را شرح می‌دهد. این شیوه‌ها حتی اگر آزمون ادغام برای HAL شما در VTS نباشد، معتبر هستند.

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

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

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

اندروید به داشتن یک لیست ثابت و دقیق از تمام HAL های نصب شده متکی است. این لیست در مانیفست 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 منسوخ‌شده‌ای روی دستگاه ارائه نمی‌شود. اندروید پشتیبانی از نسخه‌های پایین‌تر رابط‌های HAL را همانطور که در چرخه حیات FCM توضیح داده شده است، متوقف می‌کند.
  • HAL های مورد نیاز در دستگاه موجود هستند. برخی از HAL ها برای عملکرد صحیح اندروید مورد نیاز هستند.

۲. رفتار مورد انتظار هر HAL را تأیید کنید

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

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

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

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

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

انتظار می‌رود تست‌های VTS (یا هر تست دیگری) هنگام ایجاد یا تغییر رابط‌های HAL اندروید به‌روز نگه داشته شوند.

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

آزمایش روی ماهی مرکب

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

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