We all know that Android is based on Linux kernel. Android can run on Intel, Qualcomm, Nvidia and other hardware platforms. But it involves some GPU, graphics card and some device drive problem, because these drivers are not open source, Google bit compatible with these device manufacturer's driver source code, proposed the hardware abstraction Layer HAL concept. The HAL layer pair provides a unified API interface for the framework and native development, providing a unified calling interface for lower-level driver code. This article mainly explains how HAL is implemented.
Data structure of 1.HAL
There are two important structures in Hal's general notation:
1.1 hw_module_t Hardware Module structure
typedef struct HW_MODULE_T {/** tag must is 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'll is removed in the next version. * All clients must convert to the new version format. *//** * The API version of the HAL module interface. This was 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 in 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 $ bytes, reserved for future use */uint32_t reserved[32-7];} hw_module_t;
The structure represents an abstract hardware module that contains some basic information about the hardware module. There is a built-in
typedef struct HW_MODULE_METHODS_T {/** Open a specific device */INT (*open) (const struct hw_module_t* module, con St char* ID, struct hw_device_t** device);} hw_module_methods_t;
The structural body of the module method, the Open function pointer, is 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 is 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;
Represents a hardware abstraction device. This is a generic structure, and developers can inherit the structure to add the interfaces they need.
1.3 Getting a hw_model_t module
The HAL layer provides a way for the user to obtain a model, which in turn opens the device with 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={...};
Used to get the global variable when hw_get_modules by parsing so.
2. Loading of the Hardware module library in the parsing
Loading and parsing has hw_get_module completed, it will be in accordance with certain rules to find so library, and then parse out the global variable name, the open function of the hardware device, and finally through the parameters to return a device pointer to the caller.
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 is a set of variant filename for modules. The form of the filename * is "<module_id>.variant.so" so for the LED MODULE the Dream variants * of base "RO.PR Oduct.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 it can Pick up a different file on the emulator. */ "Ro.product.board", "Ro.board.platform", "Ro.arch"};
The search rule is based on the instructions above.
2.2 Process of function load parsing
(1) Call Hw_get_module by passing him a module_id string such as "camera" and so on. Call Hw_get_module_by_class (ID, NULL, module);
(2) search for the corresponding so and call load to parse so
int Hw_get_module_by_class (const char *class_id, const char *inst, const struct hw_module_t **mo Dule) {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 would simply increment a Refcoun T (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) The Load function parses so to get hw_module_t's hw_device_t function pointer./** * 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 =-einva L void *handle = NULL; struct hw_module_t *hmi = NULL; /* * Load the symbols resolving undefined symbols before * Dlopen returns. Since Rtld_global is no or ' d in with * Rtld_now the external symbols would not be GLOBAL */handle = Dlopen (pat h, 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;}