Client-side use

You can refactor conditionally compiled code to read values dynamically from the HAL interface. For example:

#ifdef TARGET_FORCE_HWC_FOR_VIRTUAL_DISPLAYS
// some code fragment
#endif

Framework code can then call an appropriate utility function defined in <configstore/Utils.h> depending on its type.

ConfigStore example

This example shows reading TARGET_FORCE_HWC_FOR_VIRTUAL_DISPLAYS, defined in ConfigStore HAL as forceHwcForVirtualDisplays() with return type OptionalBool:

#include <configstore/Utils.h>
using namespace android::hardware::configstore;
using namespace android::hardware::configstore::V1_0;

static bool vsyncPhaseOffsetNs = getBool<ISurfaceFlingerConfigs,
        ISurfaceFlingerConfigs::forceHwcForVirtualDisplays>(false);

The utility function (getBool in the example above) contacts the configstore service to get the handle for the proxy of the interface function, then retrieves the value by invoking the handle via HIDL/hwbinder.

Utility functions

<configstore/Utils.h> (configstore/1.0/include/configstore/Utils.h) provides utility functions for each primitive return type, including Optional[Bool|String|Int32|UInt32|Int64|UInt64], as listed below:

Type Function (template parameters omitted)
OptionalBool bool getBool(const bool defValue)
OptionalInt32 int32_t getInt32(const int32_t defValue)
OptionalUInt32 uint32_t getUInt32(const uint32_t defValue)
OptionalInt64 int64_t getInt64(const int64_t defValue)
OptionalUInt64 uint64_t getUInt64(const uint64_t defValue)
OptionalString std::string getString(const std::string &defValue)

defValue is a default value returned when the HAL implementation doesn't specify a value for the configuration item. Each function takes two template parameters:

  • I is the interface class name.
  • Func is the member function pointer for getting the configuration item.

Because the configuration value is read-only and doesn't change, the utility function internally caches the configuration value. Subsequent calls are serviced more efficiently using the cached value in the same linking unit.

Use configstore-utils

The ConfigStore HAL is designed to be forward compatible for minor version upgrades, meaning that when the HAL is revised and some framework code uses the newly introduced items, the ConfigStore service with an older minor version in /vendor can still be used.

For forward compatibility, ensure that your implementation adheres to the following guidelines:

  1. New items use the default value when only the old version's service is available. Example:
    service = V1_1::IConfig::getService(); // null if V1_0 is installed
    value = DEFAULT_VALUE;
      if(service) {
        value = service->v1_1API(DEFAULT_VALUE);
      }
    
  2. The client uses the first interface that included the ConfigStore item. Example:
    V1_1::IConfig::getService()->v1_0API(); // NOT ALLOWED
    
    V1_0::IConfig::getService()->v1_0API(); // OK
    
  3. The new version's service can be retrieved for old version's interface. In the following example, if the installed version is v1_1, the v1_1 service must be returned for getService():
    V1_0::IConfig::getService()->v1_0API();
    

When the access functions in the configstore-utils library are used for accessing the ConfigStore item, #1 is guaranteed by the implementation and #2 is guaranteed by compiler errors. For these reasons, we strongly recommend using configstore-utils wherever possible.