For Android hardware calls, Google recommends calling using Hal. For the andriod Hal writing method, refer to the templates of several modules under the hardware directory in the android source code.
When you look at Hal's compiling method, you will find that the entire module does not seem to have a portal. Generally, a module has an entry. For example, an application has a main function, which can be loaded and executed for the loader. The DLL file has a dllmain, and for the dynamic link library we write ourselves, we can call any exported symbols in the library.
The problem is that Hal in Android is quite universal and requires upper-layer functions to load and call it, how does the Hal loader of Android implement universal calls to different hardware modules?
Check the android source code with this question and you will find that Hal is called in Android through hw_get_module.
Int hw_get_module (const char * ID, const struct hw_module_t ** module );
This is the prototype of the function. The ID specifies the hardware ID, which is a string. For example, the sensor ID is
# Define sensors_hardware_module_id "sensors". If the corresponding hw_module_t struct is found, the pointer is placed into * module. Let's take a look at its implementation ....
/* Loop through the configuration variants looking for a module */<br/> for (I = 0; I <pal_variant_keys_count + 1; I ++) {<br/> if (I <pal_variant_keys_count) {<br/> // obtain Ro. hardware/Ro. product. board/Ro. board. platform/Ro. arch and other key values. <Br/> If (property_get (variant_keys [I], prop, null) = 0) {<br/> continue; <br/>}< br/> snprintf (path, sizeof (PATH), "% S/% S. % S. so ", <br/> hal_library_path, ID, Prop); <br/> // If the Development Board is called mmdroid, the path here is system/lib/HW/sensor. mmdroid. so <br/>} else {<br/> snprintf (path, sizeof (PATH), "% S/% S. default. so ", <br/> hal_library_path, ID); // The/system/lib/HW/sensor will be loaded by default. default. so <br/>}< br/> If (access (path, r_ OK) {<br/> continue; <br/>}< br/>/* we found a library matching this ID/variant */<br/> break; <br/>}< br/> Status =-enoent; <br/> if (I <pal_variant_keys_count + 1) {<br/>/* load the module, if this fails, we're doomed, And We shocould not try <br/> * to load a different variant. */<br/> Status = load (ID, path, module); // call the load function to open the dynamic link library <br/>}< br/>
After obtaining the path of the Dynamic Link Library, the load function will be called to open it. Next, it will be opened.
Mystery in Load
Static int load (const char * ID, <br/> const char * path, <br/> const struct hw_module_t ** phmi) <br/>{< br/> int status; <br/> void * handle; <br/> struct hw_module_t * HMI; <br/>/* <br/> * load the symbols resolving undefined symbols before <br/> * dlopen returns. since rtld_global is not or 'd in with <br/> * rtld_now the external symbols will not be global <br/> */<br/> handle = dlopen (path, rtld _ Now); // open the dynamic library <br/> If (handle = NULL) {<br/> char const * err_str = dlerror (); <br/> LogE ("load: module = % s/n % s", path, err_str? Err_str: "unknown"); <br/> Status =-einval; <br/> goto done; <br/>}< br/>/* get the address of the struct hal_module_info. */<br/> const char * sym = hal_module_info_sym_as_str; // It is defined as "HMI" <br/> HMI = (struct hw_module_t *) dlsym (handle, sym ); // search for the "HMI" Export symbol and obtain its address <br/> If (HMI = NULL) {<br/> LogE ("load: couldn't find symbol % s ", sym); <br/> Status =-einval; <br/> goto done; <br/>}< br/>/* C Heck that the ID matches */<br/> // The hw_module_t structure is found !!! <Br/> If (strcmp (ID, HMI-> ID )! = 0) {<br/> LogE ("load: Id = % s! = HMI-> id = % s ", ID, HMI-> ID); <br/> Status =-einval; <br/> goto done; <br/>}< br/> HMI-> DSO = handle; <br/>/* success */<br/> Status = 0; <br/> done: <br/> If (status! = 0) {<br/> HMI = NULL; <br/> If (handle! = NULL) {<br/> dlclose (handle); <br/> handle = NULL; <br/>}< br/>}else {<br/> logv ("loaded Hal id = % s Path = % s HMI = % P handle = % P ", <br/> ID, path, * phmi, handle); <br/>}< br/> // returns to the arc of victory <br/> * phmi = HMI; <br/> return status; <br/>}< br/>
From the code above, we will find a very strange macro hal_module_info_sym_as_str, which is directly defined as # define hal_module_info_sym_as_str "HMI ", why can we find the hw_module_t struct in the dynamic link library based on it? Let's take a look at the so corresponding to the hal we use. In Linux, we can use readelf XX. So-s to view it.
Symbol table '. dynsym 'ins ins 28 entries: <br/> num: value size type bind vis ndx name <br/> 0: 00000000 0 notype local default und <br/> 1: 00000594 0 section local default 7 <br/> 2: 00001104 0 section local default 13 <br/> 3: 00000000 0 func global default und IOCTL <br/> 4: 00000000 0 func global default und strerror <br/> 5: 00000b84 0 notype global default ABS _ exidx_end <br/> 6: 00000000 0 object global default und _ stack_chk_guard <br/> 7: 00000000 0 func global default und _ aeabi_unwind_cpp_pr0 <br/> 8: 00000000 0 func global default und _ errno <br/> 9: 00001188 0 notype global default ABS _ bss_end __< br/> 10: 00000000 0 func global default und malloc <br/> 11: 00001188 0 notype global default ABS _ bss_start __< br/> 12: 00000000 0 func global default und _ android_log_print <br/> 13: 00000b3a 0 notype global default ABS _ exidx_start <br/> 14: 00000000 0 func global default und _ stack_chk_fail <br/> 15: 00001188 0 notype global default ABS _ bss_end __< br/> 16: 00001188 0 notype global default ABS _ bss_start <br/> 17: 00000000 0 func global default und memset <br/> 18: 00000000 0 func global default und _ aeabi_uidiv <br/> 19: 00001188 0 notype global default ABS _ end __< br/> 20: 00001188 0 notype global default ABS _ edata <br/> 21: 00001188 0 notype global default ABS _ end <br/> 22: 00000000 0 func global default und open <br/> 23: 00080000 0 notype global default ABS _ stack <br/> 24: 00001104 128 object global default 13 HMI <br/> 25: 00001104 0 notype global default 13 _ data_start <br/> 26: 00000000 0 func global default und close <br/> 27: 00000000 0 func global default und free
From the above, there are 24th symbols named "HMI", corresponding to the hw_module_t struct. Then compare the Hal code.
/* <Br/> * The copybit module <br/> */<br/> struct copybit_module_t hal_module_info_sym = {<br/> common :{< br/> tag: hardware_module_tag, <br/> version_major: 1, <br/> version_minor: 0, <br/> ID: copybit_hardware_module_id, <br/> name: "qct msm7k copybit module ", <br/> author: "Google, Inc. ", <br/> Methods: bit_module_methods <br/>}< br/> };
A copybit_module_t struct named hal_module_info_sym is defined here. The common member is of the hw_module_t type. Note that the hal_module_info_sym variable must be named, so that the compiler will change the exported symbol of this struct to "HMI" so that this struct can be found by the dlsym function!
In summary, we know that the andriod Hal module also has a common entry address, which is the hal_module_info_sym variable, we can access all methods in the Hal module that require external access.