在分析Jelly Bean Audio Subsystem的時候,發現HAL層的庫audio_policy.xxx.so與其依賴的靜態庫libaudiopolicy_legacy.a都有audio_policy_hal.cpp這個源文件而且兩者都定義了一個HMI。當調用者引用HMI的時候,調用的究竟是哪個呢?
首先看audio_policy.xxx.so的Android.mk文件,在定義編譯audio_policy.xxx.so的段落裏面有這麼一句:
LOCAL_STATIC_LIBRARIES := \
libaudiohw_legacy \
libmedia_helper \
libaudiopolicy_legacy
說明libaudiopolicy_legacy是以靜態庫的形式爲audio_policy.xxx.so所用,而在通用的audio_policy庫(也可以說是谷歌提供給廠商參考用的policy庫)audio_policy.default.so的庫裏面是這麼用的:
LOCAL_WHOLE_STATIC_LIBRARIES := \
libaudiopolicy_legacy
而audio_policy.default.so的源碼裏面就沒有audio_policy_hal.cpp這個源文件,所以玄機應該就在LOCAL_WHOLE_STATIC_LIBRARIES和LOCAL_STATIC_LIBRARIES這兩個宏的差異上面。先看下谷歌在build/core/build-system.html裏面是怎麼說的:
LOCAL_STATIC_LIBRARIES
These are the static libraries that you want to include in your module. Mostly, we use shared libraries, but there are a couple of places, like executables in sbin and host executables where we use static libraries instead.
LOCAL_WHOLE_STATIC_LIBRARIES
These are the static libraries that you want to include in your module without allowing the linker to remove dead code from them. This is mostly useful if you want to add a static library to a shared library and have the static library's content exposed from the shared library.
總的來說LOCAL_WHOLE_STATIC_LIBRARIES在連接靜態連接庫的時候不會移除"daed code",何謂dead code呢,就是調用者模塊永遠都不會用到的代碼段和變量,下面用幾個小源碼來說明。
Android.mk如下
- LOCAL_PATH := $(call my-dir)
- include $(CLEAR_VARS)
- LOCAL_SRC_FILES := \
- libstone_1.cpp
- LOCAL_MODULE := libstone_1
- LOCAL_MODULE_TAGS := optional
- include $(BUILD_STATIC_LIBRARY)
- # =========================================
- include $(CLEAR_VARS)
- LOCAL_SRC_FILES := \
- libstone_2.cpp
- LOCAL_STATIC_LIBRARIES := libstone_1
- #<span style="color:#ff0000;"> LOCAL_WHOLE_STATIC_LIBRARIES := libstone_1</span>
- LOCAL_MODULE := libstone_2
- LOCAL_MODULE_TAGS := optional
- include $(BUILD_SHARED_LIBRARY)
靜態庫源文件(libstone_1.cpp):
- char hello[] = "this is a string in libstone_1";
- char str_2[] = "non static string 1";
- char str_3[] = "non static string 2";
- void func_1(){hello[0]+=1;}
調用者源文件(libstone_2.cpp):
- char hello[] = "this is a string in libstone_2";
case 1,按照上述的代碼make之後,libstone_1的所有東西都沒有被連接到動態庫libstone_2裏面:
readelf -Ws system/lib/libstone_2.so
Symbol table '.dynsym' contains 11 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 00000000 0 NOTYPE LOCAL DEFAULT UND
1: 00002000 31 OBJECT GLOBAL DEFAULT 13 hello2
2: 000002e8 12 FUNC GLOBAL DEFAULT 7 __on_dlclose
3: 00000000 0 FUNC GLOBAL DEFAULT UND __cxa_finalize
4: 00000000 0 FUNC GLOBAL DEFAULT UND __aeabi_unwind_cpp_pr0
5: 00002020 0 NOTYPE GLOBAL DEFAULT 14 __dso_handle
6: 00001ee4 0 NOTYPE GLOBAL DEFAULT 9 __INIT_ARRAY__
7: 00001eec 0 NOTYPE GLOBAL DEFAULT 10 __FINI_ARRAY__
8: 0000201f 0 NOTYPE GLOBAL DEFAULT ABS _edata
9: 0000201f 0 NOTYPE GLOBAL DEFAULT ABS __bss_start
10: 00002030 0 NOTYPE GLOBAL DEFAULT ABS _end
case 2,修改Android.mk使用LOCAL_WHOLE_STATIC_LIBRARIES 宏,這個時候libstone_2.cpp中的hello要改成hello2,因爲libstone_1裏面的東西全部鏈接進來了:
readelf -Ws system/lib/libstone_2.so
Symbol table '.dynsym' contains 16 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 00000000 0 NOTYPE LOCAL DEFAULT UND
1: 0000037d 20 FUNC GLOBAL DEFAULT 7 _Z6func_3v
2: 0000201f 31 OBJECT GLOBAL DEFAULT 13 hello
3: 00000000 0 FUNC GLOBAL DEFAULT UND __aeabi_unwind_cpp_pr0
4: 00002000 31 OBJECT GLOBAL DEFAULT 13 hello2
5: 00000390 12 FUNC GLOBAL DEFAULT 7 __on_dlclose
6: 00000000 0 FUNC GLOBAL DEFAULT UND __cxa_finalize
7: 00002070 0 NOTYPE GLOBAL DEFAULT 14 __dso_handle
8: 00001ee0 0 NOTYPE GLOBAL DEFAULT 9 __INIT_ARRAY__
9: 00001ee8 0 NOTYPE GLOBAL DEFAULT 10 __FINI_ARRAY__
10: 000003a1 16 FUNC GLOBAL DEFAULT 7 _Z6func_1v
11: 00002052 20 OBJECT GLOBAL DEFAULT 13 str_3
12: 0000203e 20 OBJECT GLOBAL DEFAULT 13 str_2
13: 00002066 0 NOTYPE GLOBAL DEFAULT ABS _edata
14: 00002066 0 NOTYPE GLOBAL DEFAULT ABS __bss_start
15: 00002080 0 NOTYPE GLOBAL DEFAULT ABS _end
case 2,仍使用LOCAL_STATIC_LIBRARIES宏,libstone_2.cpp的代碼修改爲:
- char hello2[] = "this is a string in libstone_2";
- extern char str_2[];
- void func_3(){str_2[0]+=1;}
readelf -Ws system/lib/libstone_2.so
Symbol table '.dynsym' contains 16 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 00000000 0 NOTYPE LOCAL DEFAULT UND
1: 0000037d 20 FUNC GLOBAL DEFAULT 7 _Z6func_3v
2: 0000201f 31 OBJECT GLOBAL DEFAULT 13 hello
3: 00000000 0 FUNC GLOBAL DEFAULT UND __aeabi_unwind_cpp_pr0
4: 00002000 31 OBJECT GLOBAL DEFAULT 13 hello2
5: 00000390 12 FUNC GLOBAL DEFAULT 7 __on_dlclose
6: 00000000 0 FUNC GLOBAL DEFAULT UND __cxa_finalize
7: 00002070 0 NOTYPE GLOBAL DEFAULT 14 __dso_handle
8: 00001ee0 0 NOTYPE GLOBAL DEFAULT 9 __INIT_ARRAY__
9: 00001ee8 0 NOTYPE GLOBAL DEFAULT 10 __FINI_ARRAY__
10: 000003a1 16 FUNC GLOBAL DEFAULT 7 _Z6func_1v
11: 00002052 20 OBJECT GLOBAL DEFAULT 13 str_3
12: 0000203e 20 OBJECT GLOBAL DEFAULT 13 str_2
13: 00002066 0 NOTYPE GLOBAL DEFAULT ABS _edata
14: 00002066 0 NOTYPE GLOBAL DEFAULT ABS __bss_start
15: 00002080 0 NOTYPE GLOBAL DEFAULT ABS _end
可以看到,不僅僅是被引用到的str_2,所有在libstone_1中的global變量都被鏈接到libstone_2中。
所以可以得到如下的結論:
是否鏈接到調用者模塊 | 使用了靜態庫的global變量 | 不使用 |
LOCAL_STATIC_LIBRARIES | Y | N |
LOCAL_WHOLE_STATIC_LIBRARIES | Y | Y |
至於android的編譯系統是怎麼處理這兩個宏的,在./build目錄發現其實使用了gcc的參數來區分(in core/definitions.mk ):
1161 -Wl,--whole-archive \
1162 $(call normalize-host-libraries,$(PRIVATE_ALL_WHOLE_STATIC_LIBRARIES)) \
1163 -Wl,--no-whole-archive \
1164 $(if $(PRIVATE_GROUP_STATIC_LIBRARIES),-Wl$(comma)--start-group) \
綜上所述,audio_policy.xxx.so這個policy庫使用的是自己的audio_policy_hal.cpp源文件。