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が実現しました.
これは関数のプロトタイプで、idはHardwareのidを指定します.これは文字列です.例えば、私たちがよく知っているledのidは
#define SENSORS_HARDWARE_MODULE_ID「led」、対応するhw_が見つかったらmodule_t構造体、
ポインタは*moduleに挿入されます.その実現を見てみましょう.
上記のコードは主にダイナミックリンクライブラリのパスを取得し、指定したパスの下のライブラリファイルを開くためにload関数を呼び出します.load関数が重要です.
では、load関数の神秘的なベールを解きましょう!!!
ここにマクロHALがあります.MODULE_INFO_SYM_AS_STRの注意事項:
ここでは、「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形式のファイルです.
だから、unixが提供してくれたreadefコマンドを使って、対応するシンボル情報を表示することができます.一目瞭然です.
21行で発見された名前は「HMI」で、hw_に対応しています.module_t構造体.HALのコードをもう一度照合してみましょう.
ここではHAL_という名前を定義します.MODULE_INFO_SYMのcopybit_module_tの構造体、commonメンバーはhw_module_tタイプ.ここのHALに注意MODULE_INFO_SYM変数はこの名前でなければなりません.これにより、コンパイラはこの構造体の導出記号を「HMI」に変更し、dlsym関数によってこの構造体を見つけることができます.
以上、andriod HALモジュールにも共通のエントリアドレスがあることがわかりました.このエントリアドレスはHALです.MODULE_INFO_SYM変数は、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モジュール内の外部アクセスを望むすべての方法にアクセスできます.