ב-Android 11 נוספה האפשרות להשתמש ב-AIDL עבור HAL ב-Android, וכך אפשר להטמיע חלקים ב-Android בלי HIDL. מעבר לשימוש ב-AIDL באופן בלעדי ב-HALs, כשזה אפשרי (אם ה-HALs במעלה הזרם משתמשים ב-HIDL, צריך להשתמש ב-HIDL).
ממשקי HAL שמשתמשים ב-AIDL כדי לתקשר בין רכיבי framework, כמו אלה שב-system.img, לבין רכיבי חומרה, כמו אלה שב-vendor.img, חייבים להשתמש ב-AIDL יציב. עם זאת, כדי לתקשר בתוך מחיצה, למשל מ-HAL אחד ל-HAL אחר, אין הגבלה על מנגנון ה-IPC שבו משתמשים.
מוטיבציה
AIDL קיימת כבר הרבה זמן, יותר מ-HIDL, והיא נמצאת בשימוש במקומות רבים אחרים, כמו בין רכיבי Android framework או באפליקציות. עכשיו, כש-AIDL תומך ביציבות, אפשר להטמיע מחסנית שלמה עם זמן ריצה יחיד של IPC. בנוסף, מערכת ניהול הגרסאות של AIDL טובה יותר מזו של HIDL. אלה כמה מהיתרונות של AIDL:
- שימוש בשפה אחת של IPC מאפשר ללמוד, לנפות באגים, לבצע אופטימיזציה ולאבטח רק דבר אחד.
 - AIDL תומכת בניהול גרסאות במקום לבעלים של ממשק:
- בעלים יכולים להוסיף שיטות לסוף של ממשקים, או שדות לאובייקטים מסוג Parcelable. המשמעות היא שקל יותר ליצור גרסאות של קוד לאורך השנים, וגם העלות השנתית קטנה יותר (אפשר לשנות את הסוגים במקום, ואין צורך בספריות נוספות לכל גרסת ממשק).
 - אפשר לצרף ממשקי תוספים בזמן הריצה ולא במערכת הסוגים, כך שאין צורך לבצע rebase לתוספים במורד הזרם לגרסאות חדשות יותר של ממשקים.
 
 - אפשר להשתמש ישירות בממשק 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. אפשר להשתמש בממשק @VintfStability בלי הדרישות האלה על ידי קריאה ל-AIBinder_forceDowngradeToLocalStability בעורף של NDK, ל-android::Stability::forceDowngradeToLocalStability בעורף של C++ או ל-android.os.Binder#forceDowngradeToSystemStability בעורף של Java באובייקט binder לפני שהוא נשלח לתהליך אחר.
בנוסף, כדי להשיג ניידות מקסימלית של הקוד ולמנוע בעיות פוטנציאליות כמו ספריות נוספות מיותרות, צריך להשבית את קצה העורפי של CPP.
בדוגמה הבאה אפשר לראות איך משביתים את קצה העורפי של CPP:
    aidl_interface: {
        ...
        backend: {
            cpp: {
                enabled: false,
            },
        },
    }
חיפוש ממשקי AIDL HAL
ממשקי AIDL יציבים של AOSP ל-HAL נמצאים בתיקיות aidl באותן ספריות בסיס כמו ממשקי HIDL:
- 
hardware/interfacesהוא ממשקים שמסופקים בדרך כלל על ידי חומרה. - 
frameworks/hardware/interfacesמיועד לממשקים ברמה גבוהה שמועברים לחומרה. - 
system/hardware/interfacesמיועד לממשקים ברמה נמוכה שמועברים לחומרה. 
ממשקי תוספים צריכים להיות בספריות משנה אחרות של hardware/interfaces ב-vendor או ב-hardware.
ממשקי תוספים
בכל גרסה של Android יש קבוצה של ממשקי AOSP רשמיים. כששותפים של Android רוצים להוסיף יכולות לממשקים האלה, הם לא צריכים לשנות אותם ישירות, כי זה גורם לכך שסביבת זמן הריצה של Android לא תהיה תואמת לסביבת זמן הריצה של AOSP Android. כדי שתמונת ה-GSI תמשיך לפעול, אל תשנו את הממשקים האלה.
יש שתי דרכים שבהן תוספים יכולים להירשם:
- בזמן הריצה. אפשר לעיין בממשקי התוספים המצורפים
 - כאפליקציה עצמאית, רשומה בכל העולם וב-VINTF
 
לא משנה איך התוסף רשום, כשרכיבים ספציפיים לספק (כלומר, לא חלק מ-AOSP במעלה הזרם) משתמשים בממשק, לא יכולים להיווצר קונפליקטים במיזוג. עם זאת, כשמבצעים שינויים במורד הזרם ברכיבי AOSP במעלה הזרם, יכולים להיווצר קונפליקטים במיזוג, ולכן מומלץ להשתמש באסטרטגיות הבאות:
- העברת התוספות לממשק ל-AOSP בגרסה הבאה.
 - תוספות לממשק שמאפשרות גמישות רבה יותר (ללא התנגשויות מיזוג) בגרסה הבאה.
 
אובייקטים מסוג Parcelable של תוספים: ParcelableHolder
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 למקור Parcelable באמצעות השדה ParcelableHolder:
// 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, מצפים שכל מודולי ה-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 החדשה עם כל קצוות העורף המופעלים.
 - יוצרים שיטות תרגום בקצה העורפי של Java, CPP ו-NDK כדי לתרגם מסוגי HIDL לסוגי AIDL.
 - יוצרים כללי בנייה לספריות תרגום עם יחסי התלות הנדרשים.
 - יוצרים הצהרות סטטיות כדי לוודא שלמספרי HIDL ו-AIDL יש את אותם ערכים ב-CPP וב-NDK backends.
 
כדי להמיר חבילה של קובצי HAL לקובצי AIDL:
בניית הכלי שנמצא ב
system/tools/hidl/hidl2aidl.כדי ליהנות מהחוויה הכי מלאה, מומלץ להשתמש בכלי הזה בגרסה העדכנית ביותר. אפשר להשתמש בגרסה העדכנית כדי להמיר ממשקים בענפים ישנים יותר מגרסאות קודמות:
m hidl2aidlמריצים את הכלי עם ספריית פלט ואחריה החבילה שרוצים להמיר.
אפשר להשתמש בארגומנט
-lכדי להוסיף את התוכן של קובץ רישיון חדש לראש כל הקבצים שנוצרו. חשוב להשתמש ברישיון הנכון ובתאריך הנכון:hidl2aidl -o <output directory> -l <file with license> <package>לדוגמה:
hidl2aidl -o . -l my_license.txt android.hardware.nfc@1.2קוראים את הקבצים שנוצרו ופותרים בעיות בהמרה:
conversion.logמכיל בעיות לא מטופלות שצריך לפתור קודם.- יכול להיות שבקובצי ה-AIDL שנוצרו יהיו אזהרות והצעות שצריך לפעול לפיהן. התגובות האלה מתחילות ב-
//. - לנקות את החבילה ולשפר אותה.
 - בודקים את ההערה 
@JavaDeriveכדי לראות אילו תכונות עשויות להידרש, כמוtoStringאוequals. 
יוצרים רק את היעדים שצריכים:
- משביתים את ה-backends שלא ישמשו אתכם. עדיף להשתמש ב-NDK backend במקום ב-CPP backend. מידע נוסף זמין במאמר בנושא Build against the AIDL runtime.
 - מסירים ספריות תרגום או קוד שנוצר מהן ולא יהיה בשימוש.
 
ההבדלים העיקריים בין AIDL ל-HIDL
- שימוש ב-
Statusובחריגים המובנים של AIDL בדרך כלל משפר את הממשק ומבטל את הצורך בסוג סטטוס נוסף שספציפי לממשק. - כברירת מחדל, הארגומנטים של ממשק AIDL בשיטות לא 
@nullableכמו שהם היו ב-HIDL. 
- שימוש ב-
 
SEPolicy for 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 משויך לשירותי AIDL HAL באמצעות מאקרו hal_attribute_service (ב-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 קיים. כשצריך יכולת חדשה לגמרי, אין צורך במנגנון הזה, ואפשר לרשום ממשק תוסף ישירות במנהל השירותים. הכי הגיוני לצרף ממשקי הרחבות כשהם מצורפים לממשקי משנה, כי ההיררכיות האלה יכולות להיות עמוקות או מרובות מופעים. שימוש בתוסף גלובלי כדי לשקף את היררכיית ממשק ה-binder של שירות אחר דורש ניהול חשבונות נרחב כדי לספק יכולות שוות ערך לתוספים שמצורפים ישירות.
כדי להגדיר תוסף ב-binder, משתמשים בממשקי ה-API הבאים:
- קצה עורפי של NDK: 
AIBinder_setExtension - קצה עורפי של Java:  
android.os.Binder.setExtension - קצה עורפי של CPP: 
android::Binder::setExtension - קצה עורפי של Rust:  
binder::Binder::set_extension 
כדי לקבל תוסף ב-binder, משתמשים בממשקי ה-API הבאים:
- קצה עורפי של NDK: 
AIBinder_getExtension - קצה עורפי של Java:  
android.os.IBinder.getExtension - קצה עורפי של CPP: 
android::IBinder::getExtension - קצה עורפי של Rust:  
binder::Binder::get_extension 
מידע נוסף על ממשקי ה-API האלה מופיע במסמכי העזרה של הפונקציה getExtension בשרת העורפי המתאים. דוגמה לשימוש בתוספים מופיעה במאמר hardware/interfaces/tests/extension/vibrator.
ההבדלים העיקריים בין AIDL לבין HIDL
כשמשתמשים ב-AIDL HALs או בממשקי AIDL HAL, חשוב לשים לב להבדלים ביחס לכתיבת HIDL HALs.
- התחביר של שפת 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 מסתמכת על VTS כדי לאמת הטמעות צפויות של HAL. מערכת VTS עוזרת לוודא שאפשר להשתמש ב-Android בתאימות לאחור עם יישומי ספקים ישנים. להטמעות שלא עוברות את VTS יש בעיות תאימות ידועות שעלולות למנוע את הפעולה שלהן בגרסאות עתידיות של מערכת ההפעלה.
יש שני חלקים עיקריים ב-VTS עבור HAL.
1. אימות של HAL במכשיר מוכר וצפוי על ידי Android
מערכת Android מסתמכת על רשימה סטטית ומדויקת של כל ממשקי 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 שיצאו משימוש. מערכת Android מפסיקה את התמיכה בגרסאות ישנות יותר של ממשקי HAL, כמו שמתואר במחזור החיים של FCM.
 - ה-HAL הנדרשים קיימים במכשיר. חלק מ-HALs נדרשים כדי ש-Android יפעל כראוי.
 
2. אימות ההתנהגות הצפויה של כל HAL
לכל ממשק HAL יש בדיקות VTS משלו כדי לאמת את ההתנהגות הצפויה מהלקוחות שלו. מקרים לבדיקה מופעלים בכל מופע של ממשק HAL מוצהר, ומכתיבים התנהגות ספציפית על סמך גרסת הממשק שהוטמעה.
ב-C++, אפשר לקבל רשימה של כל שכבת ה-HAL שמותקנת במערכת באמצעות הפונקציה android::getAidlHalInstanceNames ב-libaidlvintf_gtest_helper. ב-Rust, משתמשים ב-binder::get_declared_instances.
הבדיקות האלה מנסות לכסות כל היבט של הטמעת ה-HAL שעליו מסתמכת מסגרת Android, או שעשויה להסתמך עליו בעתיד.
הבדיקות האלה כוללות אימות של תמיכה בתכונות, טיפול בשגיאות וכל התנהגות אחרת שלקוח עשוי לצפות מהשירות.
אבני דרך של VTS לפיתוח HAL
כשיוצרים או משנים ממשקי HAL של Android, צריך לעדכן את בדיקות VTS (או כל בדיקה אחרת).
צריך לסיים את הבדיקות של VTS ולהכין אותן לאימות ההטמעות של הספקים לפני שהן קפאות לגרסאות של Android Vendor API. הם צריכים להיות מוכנים לפני שהממשקים קפואים, כדי שהמפתחים יוכלו ליצור את היישומים שלהם, לאמת אותם ולספק משוב למפתחי ממשקי HAL.
בדיקה ב-Cuttlefish
כשאין חומרה זמינה, מערכת Android משתמשת ב-Cuttlefish ככלי פיתוח לממשקי HAL. כך אפשר לבצע בדיקות שילוב של Android בהיקף רחב.
hal_implementation_test בדיקות שכוללות הטמעות של הגרסאות העדכניות של ממשק HAL ב-Cuttlefish, כדי לוודא שמערכת Android מוכנה לטפל בממשקים החדשים, ובדיקות VTS מוכנות לבדוק את ההטמעות החדשות של הספקים ברגע שחומרה ומכשירים חדשים יהיו זמינים.