We all know that android is based on the linux kernel. Android can run on intel, Qualcomm, nvidia, and other hardware platforms. However, some GPU, video card, and driver problems are involved, because these drivers are not open-source, and google is compatible with the driver source code of these device manufacturers, the Hardware Abstraction Layer HAL is proposed. The HAL layer provides a unified API interface for framework and native development, and provides a unified call interface for the underlying driver code. This article describes how HAL is implemented.
1. HAL Data Structure
There are two important structures in HAL's general syntax:
1.1 hw_module_t hardware module structure
typedef struct hw_module_t { /** tag must be initialized to HARDWARE_MODULE_TAG */ uint32_t tag; uint16_t module_api_version;#define version_major module_api_version /** * version_major/version_minor defines are supplied here for temporary * source code compatibility. They will be removed in the next version. * ALL clients must convert to the new version format. */ /** * The API version of the HAL module interface. This is meant to * version the hw_module_t, hw_module_methods_t, and hw_device_t * structures and definitions. * * The HAL interface owns this field. Module users/implementations * must NOT rely on this value for version information. * * Presently, 0 is the only valid value. */ uint16_t hal_api_version;#define version_minor hal_api_version /** Identifier of module */ const char *id; /** Name of this module */ const char *name; /** Author/owner/implementor of the module */ const char *author; /** Modules methods */ struct hw_module_methods_t* methods; /** module's dso */ void* dso; /** padding to 128 bytes, reserved for future use */ uint32_t reserved[32-7];} hw_module_t;
This struct indicates an abstract hardware module, which contains some basic information about the hardware module. Embedded with
typedef struct hw_module_methods_t { /** Open a specific device */ int (*open)(const struct hw_module_t* module, const char* id, struct hw_device_t** device);} hw_module_methods_t;
The struct of the module method, the open function pointer, used to open a hardware device hw_device_t. Developers need to implement this open function.
1.2 hardware device structure
typedef struct hw_device_t { /** tag must be initialized to HARDWARE_DEVICE_TAG */ uint32_t tag; uint32_t version; /** reference to the module this device belongs to */ struct hw_module_t* module; /** padding reserved for future use */ uint32_t reserved[12]; /** Close this device */ int (*close)(struct hw_device_t* device);} hw_device_t;
Indicates a hardware abstraction device. This is a common struct. developers can inherit this struct to add their own required interfaces.
1.3 obtain an hw_model_t Module
The HAL layer provides a method for the user to obtain a model, and then enable the device through the open method.
/** * Get the module info associated with a module by id. * * @return: 0 == success, <0 == error and *module == NULL */int hw_get_module(const char *id, const struct hw_module_t **module);
Define a global variable
Const struct hw_module_t HAL_MODULE_INFO_SYM = {...};
This global variable is obtained when hw_get_modules parses so.
2. parsing the hardware module library
The hw_get_module is loaded and parsed. It will find the so library according to certain rules, and then parse the global variable name to obtain the open function of the hardware device, finally, a device pointer is returned to the caller through the parameter.
2.1 search for so rules;
/** Base path of the hal modules */#define HAL_LIBRARY_PATH1 "/system/lib/hw"#define HAL_LIBRARY_PATH2 "/vendor/lib/hw"/** * There are a set of variant filename for modules. The form of the filename * is "
.variant.so" so for the led module the Dream variants * of base "ro.product.board", "ro.board.platform" and "ro.arch" would be: * * led.trout.so * led.msm7k.so * led.ARMV6.so * led.default.so */static const char *variant_keys[] = { "ro.hardware", /* This goes first so that it can pick up a different file on the emulator. */ "ro.product.board", "ro.board.platform", "ro.arch"};
The Search rules follow the instructions above.
2.2 function loading and parsing process
(1) Call hw_get_module and pass it a module_id string, for example, "camera. Call hw_get_module_by_class (id, NULL, module );
(2) Search for the corresponding so and call load to parse the so
Int hw_get_module_by_class (const char * class_id, const char * inst, const struct hw_module_t ** module) {int status =-EINVAL; int I = 0; char prop [PATH_MAX] = {0}; char path [PATH_MAX] = {0}; char name [PATH_MAX] = {0}; if (inst) snprintf (name, PATH_MAX, "% s. % s ", class_id, inst); else strlcpy (name, class_id, PATH_MAX);/** Here we rely on the fact that calling dlopen multiple times on * the same. so will simply increment a refcount (and not load * a new copy of the library ). * We also assume that dlopen () is thread-safe. * // * Loop through the configuration variants looking for a module */for (I = 0; I
(3) load function parse so to get the function pointer of hw_device_t of hw_module_t.
/** * Load the file defined by the variant and if successful * return the dlopen handle and the hmi. * @return 0 = success, !0 = failure. */static int load(const char *id, const char *path, const struct hw_module_t **pHmi){ int status = -EINVAL; void *handle = NULL; struct hw_module_t *hmi = NULL; /* * load the symbols resolving undefined symbols before * dlopen returns. Since RTLD_GLOBAL is not or'd in with * RTLD_NOW the external symbols will not be global */ handle = dlopen(path, RTLD_NOW); if (handle == NULL) { char const *err_str = dlerror(); ALOGE("load: module=%s\n%s", path, err_str?err_str:"unknown"); status = -EINVAL; goto done; } /* Get the address of the struct hal_module_info. */ const char *sym = HAL_MODULE_INFO_SYM_AS_STR; hmi = (struct hw_module_t *)dlsym(handle, sym); if (hmi == NULL) { ALOGE("load: couldn't find symbol %s", sym); status = -EINVAL; goto done; } /* Check that the id matches */ if (strcmp(id, hmi->id) != 0) { ALOGE("load: id=%s != hmi->id=%s", id, hmi->id); status = -EINVAL; goto done; } hmi->dso = handle; /* success */ status = 0; done: if (status != 0) { hmi = NULL; if (handle != NULL) { dlclose(handle); handle = NULL; } } else { ALOGV("loaded HAL id=%s path=%s hmi=%p handle=%p", id, path, *pHmi, handle); } *pHmi = hmi; return status;}