Zygote
Builder tracknerd

N04 — A toy HAL

An AIDL HAL in the modern shape: an interface with VINTF stability, a service that implements it, a manifest fragment that declares it, and a client that finds it. The vendor boundary, built by hand.

6 minAPI 26–37 · 17verified 2026-10-27

A HAL is where the platform stops trusting the vendor and starts negotiating with it. The interface is a contract; the manifest is the declaration of what a device actually implements; the service is one process talking to another over Binder. Build one small one and the Treble split stops being an org chart and becomes a directory layout.1

Hardware note: this needs a platform build and a boot, plus ideally a vendor image you control. The build sequence itself is the one from N01, which follows the AOSP build documentation.2

TL;DR#

  • HALs are AIDL now. HIDL is deprecated as of Android 13; new HALs use AIDL.3
  • The interface is an .aidl file annotated @VintfStability, with an aidl_interface module that sets stability: "vintf".
  • The service is a process that registers its binder with the service manager.
  • The VINTF manifest declares it, so the framework knows the device provides it.
  • The boundary is enforced at runtime: a HAL not in the manifest is not supposed to be used.

What you are building#

One interface with one method, implemented by one service, declared in one manifest fragment, and called by a client that looks the service up by instance name. The feature is a string; the lesson is the four artefacts and how they must agree.

The four artefacts#

ArtefactLives inFails if wrong
The interfacean .aidl file in a hardware/interfaces-style packagethe client and server disagree on the transaction
The build declarationAndroid.bp with aidl_interfacethe interface is not compiled for vendor, or not stable
The servicea binary that implements the interface and registers itthe client cannot find it
The VINTF fragmentan XML manifest fragmentthe platform does not believe the device has the HAL

Each of the four is checked separately, and each failure has a different symptom. That is the reason to build one.

Steps#

  1. Choose the interface package

    Stable AIDL interfaces for HALs live in aidl folders in the same base directories as the old HIDL interfaces; hardware/interfaces is the one for interfaces typically provided by hardware, and frameworks/hardware/interfaces and system/hardware/interfaces exist for the other cases.

    4

    The package name follows the usual AIDL rules. Pick a package under your own namespace, for example android.hardware.toy, so you are not claiming a Google-owned package.

    You should seeA directory under a hardware interfaces root.
  2. Write the interface

    Declare one method returning a string. Every type definition must be annotated @VintfStability, and the aidl_interface declaration must include stability: "vintf" — both requirements come from the AIDL-for-HALs page.4

    The annotation is the promise that this interface will not change incompatibly. It is what makes the interface usable across the vendor boundary.

    You should seeA compilable .aidl file.
  3. Declare the interface in Android.bp

    The following is illustrative, modelled on AOSP's vibrator HAL definition:

    aidl_interface {
        name: "android.hardware.toy",
        vendor_available: true,
        stability: "vintf",
        srcs: [
            "android/hardware/toy/*.aidl",
        ],
        backend: {
            cpp: {
                enabled: true,
            },
        },
    }

    The real android.hardware.vibrator module sets vendor_available: true and stability: "vintf", and it enables the backends it needs while disabling the ones it does not. vendor_available is what makes the interface usable from vendor code.

    4
    You should seeThe build generates the stubs and the stability metadata.
  4. Implement the service

    Implement the generated interface in the server language you enabled in the backend, and register the binder. AIDL HAL services conventionally use an instance name of the form $package.$type/$instance — the vibrator HAL, for example, is declared as android.hardware.vibrator.IVibrator/default.4

    If the interface is @VintfStability, the service must be declared in the VINTF manifest; an ordinary AIDL service registers normally and does not need one. You are building the first kind.

    You should seeA binary that registers a binder under the right instance name.
  5. Add the VINTF manifest fragment

    A HAL entry in a device manifest has this shape, quoted from the AIDL-for-HALs page:

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

    fqname is the interface name and the instance, and name is the package. The device manifest itself is read from locations such as /vendor/etc/vintf/manifest.xml and /odm/etc/vintf/manifest.xml.5

    The fragment you ship usually lives in the device or vendor tree and is installed into one of those locations or merged into the manifest at build time. Check the VINTF manifest page for the merge mechanism your release uses rather than assuming a single file.

    You should seeThe manifest parses and names your HAL.
  6. Start it at boot

    A HAL is a service like any other: it needs an init service block, a user/group, a seclabel, and a start trigger. Everything from N03 applies.

    You should seeThe service process exists.
  7. Allow the client to find it

    Two SELinux questions, not one: is the client allowed to find the service by name in the service manager, and is the HAL domain allowed to add it? A missing rule appears as avc: denied with the service_manager class.6

    Policy lives under your device's sepolicy directory and is wired in with BOARD_SEPOLICY_DIRS.

    You should seeNo avc denial when the client calls.
  8. Build, boot and call it

    Build and boot your target, then check that the service is registered and the manifest lists it. The exact build and boot commands are those of N01.

    You should seeThe client gets the string back.
Look for the HAL from the host
adb shell service list | grep toy
adb shell dumpsys -l | grep toy
adb shell dmesg | grep avc
Example output
Illustrative — names and output differ.

The first command lists registered binder services. dumpsys -l lists the service names dumpsys knows about; a HAL only appears there if it implements dumping, so an empty result is not a failure. The third is the one that finds policy problems.

The files you touched#

  • stable AIDL HAL interfaces live in aidl folders here, alongside the HIDL ones
  • Android.bpa real aidl_interface with vendor_available and stability: vintf
  • the base policy; read it, do not edit it
  • where the service_manager rules for your HAL go

Verification#

Three checks that fail independently:

  1. adb shell service list shows the instance — the service started and registered.
  2. The device manifest on the device lists the HAL — the VINTF fragment was installed.
  3. The client's call returns — the interface version, the manifest and the client agree.

If 1 passes and 2 fails, the framework will refuse to use the HAL even though it is running. That gap is the whole point of VINTF: a running service is not a supported device.

What can go wrong#

  • The interface is not stable. Missing stability: "vintf" or a missing @VintfStability annotation makes the HAL unusable across the boundary.
  • vendor_available is missing. Framework code can see the interface; vendor code cannot, and the build fails or the service cannot be built into the vendor image.
  • The manifest does not match the interface. A version or fqname mismatch means the device advertises something the service does not implement.
  • The fragment is in the wrong place. Manifests are read from specific paths; a fragment that is not merged or installed is invisible.
  • SELinux denies the lookup. The client cannot find the service, so it looks like the service is not running.
  • You copied a HIDL example. HIDL is deprecated and its .hal files, hidl_interface modules and hwservicemanager registration are a different mechanism. New HALs use AIDL.
  • The package name collides. Using android.hardware.<something> that Google owns will conflict with the interfaces already in the tree.

Sources#

Sources

Every version number, API level, class name and date on this page is traced to one of these. Pages are re-verified against them; last_verified above says when.

  1. docsHardware abstraction layers (HALs)source.android.comaccessed 2026-10-27↩
  2. docsBuild Androidsource.android.comaccessed 2026-10-27↩
  3. docsHAL typessource.android.comaccessed 2026-10-27↩
  4. docsAIDL for HALssource.android.comaccessed 2026-10-27↩
  5. docsVendor interface objects (VINTF)source.android.comaccessed 2026-10-27↩
  6. docsSELinuxsource.android.comaccessed 2026-10-27↩