Implementing the Service

To prepare for the HAL implementation, you can generate basic configstore interface code then modify it to meet your needs.

Generating interface code

To generate boilerplate code for the interface, run hidl-gen. For example, to generate code for surfaceflinger:

hidl-gen -o hardware/interfaces/configstore/1.0/default \
    -Lc++-impl \
    -randroid.hardware:hardware/interfaces \
    -randroid.hidl:system/libhidl/transport \
    android.hardware.config@1.0::ISurfaceFlingerConfigs

Note: Don't run hidl-gen with -Landroidbp-impl as this generates Android.bp. The module must be built with Android.mk to access build flags.

Modifying Android.mk

Next, modify Android.mk file to add implementation file (<modulename>Configs.cpp) to LOCAL_SRC_FILES and to map build flags into macro definitions. For example, you can modify surfaceflinger in hardware/interface/configstore/1.0/default/Android.mk:

LOCAL_SRC_FILES += SurfaceFlingerConfigs.cpp
ifneq ($(NUM_FRAMEBUFFER_SURFACE_BUFFERS),)
    LOCAL_CFLAGS += -DNUM_FRAMEBUFFER_SURFACE_BUFFERS=$(NUM_FRAMEBUFFER_SURFACE_BUFFERS)
endif

ifeq ($(TARGET_RUNNING_WITHOUT_SYNC_FRAMEWORK),true)
    LOCAL_CFLAGS += -DRUNNING_WITHOUT_SYNC_FRAMEWORK
endif

If Android.mk includes several ifeq-endif blocks, consider moving your code into a new file (i.e., surfaceflinger.mk) then include that file from Android.mk.

Implementing functions

To fill the functions to implement the HAL, call back the _hidl_cb function with different values (conditioned on build flags). For example, you can fill the functions for surfaceflinger in hardware/interfaces/configstore/1.0/default/SurfaceFlingerConfigs.cpp:

Return<void> SurfaceFlingerConfigs::numFramebufferSurfaceBuffers(
        numFramebufferSurfaceBuffers_cb _hidl_cb) {
    #if NUM_FRAMEBUFFER_SURFACE_BUFFERS 2
    _hidl_cb(NumBuffers.TWO);
    #else if NUM_FRAMEBUFFER_SURFACE_BUFFERS 3
    _hidl_cb(NumBuffers.THREE);
    #else
    _hidl_cb(NumBuffers.USE_DEFAULT);
    #endif
}

Return<void> SurfaceFlingerConfigs::runWithoutSyncFramework(
        runWithoutSyncFramework_cb _hidl_cb) {
    #ifdef RUNNING_WITHOUT_SYNC_FRAMEWORK
    _hidl_cb({true /* specified */, true /* value */});
    #else
    // when macro not defined, we can give any value to the second argument.
    // It will simply be ignored in the framework side.
    _hidl_cb({false /* specified */, false /* value */});
    #endif
}

Ensure the implementation does not contain a function named HIDL_FETCH_<interface name> (e.g., HIDL_FETCH_ISurfaceFlingerConfigs). This function is needed for HIDL passthrough mode, which is unused (and prohibited) by configstore. ConfigStore must always run in binderized mode.

Registering as a service

Finally, register all interface implementations to the configstore service. For example, you can register surfaceflinger implementations in hardware/interfaces/configstore/1.0/default/service.cpp:

configureRpcThreadpool(maxThreads, true);
sp<ISurfaceFlingerConfigs> surfaceFlingerConfigs = new SurfaceFlingerConfigs;
status_t status = surfaceFlingerConfigs->registerAsService();

sp<IBluetoothConfigs> bluetoothConfigs = new BluetoothConfigs;
status = bluetoothConfigs->registerAsService();

// register more interfaces here
joinRpcThreadpool();

Ensuring early access

To ensure a framework module can get early access the HAL service, the config HAL service should start as early as possible, just after hwservicemanager is ready. As the config HAL service does not read external files, it is expected to be ready quickly after it is launched.