HIDL Java

In Android 8.0 the Android OS was re-architected to define clear interfaces between the device-independent Android platform, and device- and vendor-specific code. Android already defined many such interfaces in the form of HAL interfaces, defined as C headers in hardware/libhardware. HIDL replaced these HAL interfaces with stable, versioned interfaces, which can either be in Java (described below) or be client- and server-side HIDL interfaces in C++.

HIDL interfaces are intended to be used primarily from native code, and as a result HIDL is focused on the auto-generation of efficient code in C++. However, HIDL interfaces must also be available for use directly from Java, as some Android subsystems (such as Telephony) have Java HIDL interfaces.

The pages in this section describe the Java frontend for HIDL interfaces, detail how to create, register, and use services, and explain how HALs and HAL clients written in Java interact with the HIDL RPC system.

Being a client

This is an example of a client for an interface IFoo in package android.hardware.foo@1.0 that is registered as service name default and an additional service with the custom service name second_impl.

Adding libraries

You need to add dependencies on the corresponding HIDL stub library if you want to use it. Usually, this is a static library:

// in Android.bp
static_libs: [ "android.hardware.foo-V1.0-java", ],
// in Android.mk
LOCAL_STATIC_JAVA_LIBRARIES += android.hardware.foo-V1.0-java

If you know that you're already pulling in dependencies on these libraries, you can also use shared linkage:

// in Android.bp
libs: [ "android.hardware.foo-V1.0-java", ],
// in Android.mk
LOCAL_JAVA_LIBRARIES += android.hardware.foo-V1.0-java

Additional considerations for adding libraries in Android 10

If you have a system or vendor app that targets Android 10 or higher, you can statically include these libraries. You can also use (only) HIDL classes from custom JARs installed on the device with stable Java APIs made available using the existing uses-library mechanism for system apps. The latter approach saves space on the device. For more details, see Implementing Java SDK Library. For older apps, the old behavior is preserved.

Starting in Android 10, "shallow" versions of these libraries are also available. These include the class in question but don't include any of the dependent classes. For instance, android.hardware.foo-V1.0-java-shallow includes classes in the foo package, but doesn't include classes in android.hidl.base-V1.0-java, which contains the base class of all HIDL interfaces. If you're creating a library that already has the preferred interface's base classes available as a dependency, you can use the following:

// in Android.bp
static_libs: [ "android.hardware.foo-V1.0-java-shallow", ],
// in Android.mk
LOCAL_STATIC_JAVA_LIBRARIES += android.hardware.foo-V1.0-java-shallow

HIDL base and manager libraries are also no longer available on the boot classpath for apps (previously, they were sometimes used as hidden API, due to Android's delegate-first classloader). Instead, they've been moved into a new namespace with jarjar, and apps which use these (necessarily priv apps) must have their own separate copies. Modules on the boot classpath using HIDL must use the shallow variants of these Java libraries and to add jarjar_rules: ":framework-jarjar-rules" to their Android.bp to use the version of these libraries that exists in the boot classpath.

Modifying your Java source

There's only one version (@1.0) of this service, so this code retrieves only that version. See interface extensions for how to handle multiple different versions of the service.

import android.hardware.foo.V1_0.IFoo;
...
// retry to wait until the service starts up if it is in the manifest
IFoo server = IFoo.getService(true /* retry */); // throws NoSuchElementException if not available
IFoo anotherServer = IFoo.getService("second_impl", true /* retry */);
server.doSomething(…);

Providing a service

Framework code in Java might need to serve interfaces to receive asynchronous callbacks from HALs.

For the IFooCallback interface in version 1.0 of the android.hardware.foo package, you can implement your interface in Java using the following steps:

  1. Define your interface in HIDL.
  2. Open /tmp/android/hardware/foo/IFooCallback.java as a reference.
  3. Create a new module for your Java implementation.
  4. Examine the abstract class android.hardware.foo.V1_0.IFooCallback.Stub, then write a new class to extend it and implement the abstract methods.

Viewing auto-generated files

To view the automatically generated files, run:

hidl-gen -o /tmp -Ljava \
  -randroid.hardware:hardware/interfaces \
  -randroid.hidl:system/libhidl/transport android.hardware.foo@1.0

These commands generate the directory /tmp/android/hardware/foo/1.0. For the file hardware/interfaces/foo/1.0/IFooCallback.hal, this generates the file /tmp/android/hardware/foo/1.0/IFooCallback.java, which encapsulates the Java interface, the proxy code, and the stubs (both proxy and stubs conform to the interface).

-Lmakefile generates the rules that run this command at build time and allow you to include android.hardware.foo-V1.0-java and link against the appropriate files. A script that automatically does this for a project full of interfaces can be found at hardware/interfaces/update-makefiles.sh. The paths in this example are relative; hardware/interfaces can be a temporary directory under your code tree to enable you to develop a HAL prior to publishing it.

Running a service

The HAL provides the IFoo interface, which must make asynchronous callbacks to the framework over the IFooCallback interface. The IFooCallback interface isn't registered by name as a discoverable service; instead, IFoo must contain a method such as setFooCallback(IFooCallback x).

To set up IFooCallback from version 1.0 of the android.hardware.foo package, add android.hardware.foo-V1.0-java to Android.mk. The code to run the service is:

import android.hardware.foo.V1_0.IFoo;
import android.hardware.foo.V1_0.IFooCallback.Stub;
....
class FooCallback extends IFooCallback.Stub {
    // implement methods
}
....
// Get the service from which you will be receiving callbacks.
// This also starts the threadpool for your callback service.
IFoo server = IFoo.getService(true /* retry */); // throws NoSuchElementException if not available
....
// This must be a persistent instance variable, not local,
//   to avoid premature garbage collection.
FooCallback mFooCallback = new FooCallback();
....
// Do this once to create the callback service and tell the "foo-bar" service
server.setFooCallback(mFooCallback);

Interface extensions

Assuming a given service implements the IFoo interface across all devices, it's possible that on a particular device the service might provide additional capabilities implemented in the interface extension IBetterFoo, as follows:

interface IFoo {
   ...
};

interface IBetterFoo extends IFoo {
   ...
};

Calling code aware of the extended interface can use the castFrom() Java method to safely cast the base interface to the extended interface:

IFoo baseService = IFoo.getService(true /* retry */); // throws NoSuchElementException if not available
IBetterFoo extendedService = IBetterFoo.castFrom(baseService);
if (extendedService != null) {
  // The service implements the extended interface.
} else {
  // The service implements only the base interface.
}