Android--hw_get_module解析

7979 ワード

Googleがハードウェアメーカーの情報を保護するためにAndroidに1階、つまり有名なHAL階を追加したことを知っています.
HALの書き方を見ていると、モジュール全体に入り口がないようです.一般的にモジュールには入り口がありますが、
アプリケーションにmain関数がある場合は、ローダをロードして実行できます.dllファイルにはdllmainがあり、私たち自身が書いた動的な
リンクライブラリ.ライブラリからエクスポートされた記号を呼び出すことができます.質問ですが、AndroidのHALは比較的汎用性があり、上位の関数がロード呼び出しを行う必要があります.Androidの
HALローダは、異なるHardware Moduleに対して汎用的な呼び出しをどのように実現しているのでしょうか.この疑問を持ってAndroidのソースコードを見ると、AndroidでHALが呼び出されるのはhw_get_moduleが実現しました.
int hw_get_module(const char *id, const struct hw_module_t **module); 

これは関数のプロトタイプで、idはHardwareのidを指定します.これは文字列です.例えば、私たちがよく知っているledのidは
#define SENSORS_HARDWARE_MODULE_ID「led」、対応するhw_が見つかったらmodule_t構造体、
ポインタは*moduleに挿入されます.その実現を見てみましょう.
124 int hw_get_module(const char *id, const struct hw_module_t **module)
125 {
126     int status;
127     int i;                                                                                      
128     const struct hw_module_t *hmi = NULL;
129     char prop[PATH_MAX];
130     char path[PATH_MAX];
131 
132     /*
133      * Here we rely on the fact that calling dlopen multiple times on
134      * the same .so will simply increment a refcount (and not load
135      * a new copy of the library).
136      * We also assume that dlopen() is thread-safe.
137      */
138 
139     /* Loop through the configuration variants looking for a module */
140     for (i=0 ; ivariant_keys     

143                 continue;
144             }
145             snprintf(path, sizeof(path), "%s/%s.%s.so",
146                     HAL_LIBRARY_PATH, id, prop);//       fs100,     system/lib/hw/led.fs100.so
147         } else {  snprintf(path, sizeof(path), "%s/%s.default.so",
149                     HAL_LIBRARY_PATH, id);//      system/lib/hw/led.default.so
150         }
151         if (access(path, R_OK)) {
152             continue;
153         }
154         /* we found a library matching this id/variant */
155         break;
156     }
157 
158     status = -ENOENT;
159     if (i < HAL_VARIANT_KEYS_COUNT+1) {
160         /* load the module, if this fails, we're doomed, and we should not try
161          * to load a different variant. */
162         status = load(id, path, module);//load     ,  load         
163     }
164 
165     return status;
166 } 

上記のコードは主にダイナミックリンクライブラリのパスを取得し、指定したパスの下のライブラリファイルを開くためにload関数を呼び出します.load関数が重要です.
では、load関数の神秘的なベールを解きましょう!!!     
 65 static int load(const char *id,
 66         const char *path,
 67         const struct hw_module_t **pHmi)
 68 {
 69     int status;
 70     void *handle;
 71     struct hw_module_t *hmi;
 72 
 73     /*
 74      * load the symbols resolving undefined symbols before
 75      * dlopen returns. Since RTLD_GLOBAL is not or'd in with
 76      * RTLD_NOW the external symbols will not be global
 77      */
 78     handle = dlopen(path, RTLD_NOW);
 79     if (handle == NULL) {
 80         char const *err_str = dlerror();
 81         LOGE("load: module=%s
%s", path, err_str?err_str:"unknown"); 82 status = -EINVAL; 83 goto done; 84 } 85 86 /* Get the address of the struct hal_module_info. */ 87 const char *sym = HAL_MODULE_INFO_SYM_AS_STR; 88 hmi = (struct hw_module_t *)dlsym(handle, sym); 89 if (hmi == NULL) { 90 LOGE("load: couldn't find symbol %s", sym); 91 status = -EINVAL; 92 goto done; 93 } 94 95 /* Check that the id matches */ 96 if (strcmp(id, hmi->id) != 0) { 97 LOGE("load: id=%s != hmi->id=%s", id, hmi->id); 98 status = -EINVAL; 99 goto done; 100 } 101 102 hmi->dso = handle; 103 104 /* success */ 105 status = 0; 106 93 } 94 95 /* Check that the id matches */ 96 if (strcmp(id, hmi->id) != 0) { 97 LOGE("load: id=%s != hmi->id=%s", id, hmi->id); 98 status = -EINVAL; 99 goto done; 100 } 101 102 hmi->dso = handle; 103 104 /* success */ 105 status = 0; 106 107 done: 108 if (status != 0) { 109 hmi = NULL; 110 if (handle != NULL) { 111 dlclose(handle); 112 handle = NULL; 113 } 114 } else { 115 LOGV("loaded HAL id=%s path=%s hmi=%p handle=%p", 116 id, path, *pHmi, handle); 117 } 118 119 *pHmi = hmi; 120 121 return status; 122 }

        
ここにマクロHALがあります.MODULE_INFO_SYM_AS_STRの注意事項:
#define HAL_MODULE_INFO_SYM_AS_STR  "HMI"
hmi=(struct hw_module_t*)dlsym(handle,sym);
ここでは、「HMI」という書き出し記号を検索し、そのアドレスを取得します.
ここで、なぜ「HMI」という導出記号に基づいて、動的リンクライブラリから構造体hw_を見つけることができるのかを問う.module_tは??
ELF=Executable and Linkable Formatは、UNIXシステムラボ(USL)がアプリケーションバイナリインタフェース(ApplicationBinary Interface,ABI)として開発・配布された接続フォーマットであることを知っています.拡張子はelfです.ELFヘッダは、ファイルの開始時にルートマップ(road map)を保存し、ファイルの組織状況を記述する.sectionsはobjectファイルの情報を保存しており,接続の観点から命令,データ,シンボルテーブル,再配置情報などを含む.私たちのled.default.soはelf形式のファイルです.
linux@ubuntu:~/eclair_2.1_farsight/out/target/product/fs100/system/lib/hw$ file led.default.so 
led.default.so: ELF 32-bit LSB shared object, ARM, version 1 (SYSV), dynamically linked, stripped

だから、unixが提供してくれたreadefコマンドを使って、対応するシンボル情報を表示することができます.一目瞭然です.
linux@ubuntu:~/eclair_2.1_farsight/out/target/product/fs100/system/lib/hw$ readelf -s led.default.so 

Symbol table '.dynsym' contains 25 entries:
   Num:    Value  Size Type    Bind   Vis      Ndx Name
     0: 00000000     0 NOTYPE  LOCAL  DEFAULT  UND 
     1: 000004c8     0 SECTION LOCAL  DEFAULT    7 
     2: 00001000     0 SECTION LOCAL  DEFAULT   11 
     3: 00000000     0 FUNC    GLOBAL DEFAULT  UND ioctl
     4: 000006d4     0 NOTYPE  GLOBAL DEFAULT  ABS __exidx_end
     5: 00000000     0 FUNC    GLOBAL DEFAULT  UND __aeabi_unwind_cpp_pr0
     6: 00001178     0 NOTYPE  GLOBAL DEFAULT  ABS _bss_end__
     7: 00000000     0 FUNC    GLOBAL DEFAULT  UND malloc
     8: 00001174     0 NOTYPE  GLOBAL DEFAULT  ABS __bss_start__
     9: 00000000     0 FUNC    GLOBAL DEFAULT  UND __android_log_print
    10: 000006ab     0 NOTYPE  GLOBAL DEFAULT  ABS __exidx_start
    11: 00001174     4 OBJECT  GLOBAL DEFAULT   15 fd
    12: 000005d5    60 FUNC    GLOBAL DEFAULT    7 led_set_off
    13: 00001178     0 NOTYPE  GLOBAL DEFAULT  ABS __bss_end__
    14: 00001174     0 NOTYPE  GLOBAL DEFAULT  ABS __bss_start
    15: 00000000     0 FUNC    GLOBAL DEFAULT  UND memset
    16: 00001178     0 NOTYPE  GLOBAL DEFAULT  ABS __end__
    17: 00001174     0 NOTYPE  GLOBAL DEFAULT  ABS _edata
    18: 00001178     0 NOTYPE  GLOBAL DEFAULT  ABS _end
    19: 00000000     0 FUNC    GLOBAL DEFAULT  UND open
    20: 00080000     0 NOTYPE  GLOBAL DEFAULT  ABS _stack
    21: 00001000   128 OBJECT  GLOBAL DEFAULT   11 HMI
    22: 00001170     0 NOTYPE  GLOBAL DEFAULT   14 __data_start
    23: 00000000     0 FUNC    GLOBAL DEFAULT  UND close
    24: 00000000     0 FUNC    GLOBAL DEFAULT  UND free

21行で発見された名前は「HMI」で、hw_に対応しています.module_t構造体.HALのコードをもう一度照合してみましょう.
const struct led_module_t HAL_MODULE_INFO_SYM = {
    common: {
        tag: HARDWARE_MODULE_TAG,
	    version_major: 1,
	    version_minor: 0,
	    id: LED_HARDWARE_MODULE_ID, 
	    name: "led HAL module",
	    author: "farsight",             
	    methods: &led_module_methods, 
	}, 
	
};

ここではHAL_という名前を定義します.MODULE_INFO_SYMのcopybit_module_tの構造体、commonメンバーはhw_module_tタイプ.ここのHALに注意MODULE_INFO_SYM変数はこの名前でなければなりません.これにより、コンパイラはこの構造体の導出記号を「HMI」に変更し、dlsym関数によってこの構造体を見つけることができます.
以上、andriod HALモジュールにも共通のエントリアドレスがあることがわかりました.このエントリアドレスはHALです.MODULE_INFO_SYM変数は、HALモジュール内の外部アクセスを望むすべての方法にアクセスできます.