1. 程式人生 > 其它 >Android R CtsJniTestCases android.jni.cts.JniStaticTest#test_dlopenPublicLibraries fail

Android R CtsJniTestCases android.jni.cts.JniStaticTest#test_dlopenPublicLibraries fail

技術標籤:gmsandroidcts

測試結果中有多個庫檔案出現如下報錯:
junit.framework.AssertionFailedError: dlopen failed: library “xxxxx.so” not found

一、

test_dlopenPublicLibraries的原始碼在JniStaticTest.java檔案中(舊版本的Android原始碼中搜索不到這個測試項)
沒有過多內容直接呼叫了"LinkerNamespacesHelper.runDlopenPublicLibraries()";

"runDlopenPublicLibraries"方法將多個預先定義的public so list中配置的庫名組裝到一個命名為publicLibs的List變數裡面。

其中比較關鍵的一句是:

publicLibs.addAll(readPublicLibrariesFile(new File(VENDOR_CONFIG_FILE)));

其中VENDOR_CONFIG_FILE的定義:

private final static String VENDOR_CONFIG_FILE = "/vendor/etc/public.libraries.txt"

"/vendor/etc/public.libraries.txt"這個檔案是adb連線手機後,進入對應目錄下可以直接看到的。
也可以直接adb pull 出來,修改後push覆蓋原來的檔案,重啟後修改即可生效。

"runDlopenPublicLibraries"方法將多個list組裝,開始遍歷組裝好的publicLibs,並使用tryDlopen嘗試開啟庫檔案。——dlopen就是公共介面了,一般情況下出問題的可能性較小,所以回過頭來確認下配置的庫。

二、

通過adb直接在機器中"/vendor/lib"目錄下搜尋報錯中提到的所有庫檔案,發現有如下三種情況:

  1. 機器中沒有這個庫
    —— 修改方案: 直接在"public.libraries.txt"中去掉庫名即可解決報錯提示。
  2. 這個庫只存在於"/vendor/lib64" 目錄下,而"/vendor/lib"目錄下是沒有的。
    對應的報錯也只出現在"armeabi-v7a"測試項中,"arm64-v8a"測試項沒有相關報錯
  3. 庫檔案存在於"/vendor/lib/guess(目錄模糊處理)" 目錄下,"armeabi-v7a"與 "arm64-v8a"均報錯

三、

針對於第二種情況,考慮有兩種可能可行的對策
5. 讓測試項不去在"/vendor/lib/“目錄下找這個庫
6. 在”/vendor/lib/"目錄下新增這個庫

看起來第一種對策比較環保,先去找組裝 publicLibs 這個List的邏輯
閱讀"readPublicLibrariesFile"方法的原始碼: 解析txt時分行讀取檔案,並在每一行中以" "作為分隔符,將一行字串分割成多個字串。
然後從後往遍歷,查詢有沒有 “32” 或 "64"這兩個字串,用於給bitness變數置位:

bitness = tokens[i].equals("32") ? Bitness.ONLY_32 : Bitness.ONLY_64;

處理完一行以後,如果bitness 與is64Bit狀態不匹配,則continue,不執行add動作。
看到這裡解決方案就已經出來了,在"public.libraries.txt"檔案中對應庫名後新增 64 標識即可。
修改方案:

- xxxxx.so
+ xxxxx.so 64

四、

針對第三種情況,比較懷疑是dlopen時不會到這個目錄下搜尋庫。這部分的原始碼在linker.cpp這支檔案中。
檢視原始碼可得,開啟log的命令如下:
setprop debug.ld.all dlerror,dlopen,dlsym
如需修改程式碼新增Log,本地驗證:編譯 system/bin/bootstrap/linker(64)?, 然後push到/system/bin/後生效。

通過新增log確認到,dlopen過程中的確沒有到"/vendor/lib/guess/" 進行查詢。
以往的版本中,可以通過在 “ld.config.txt” 中新增 “namespace.xxx.search.paths = /vendor/lib/guess” 來配置查詢路徑。
但在最新的程式碼中,開啟"ld.config.txt"檔案可以看到提示:“This file is no longer in use… You can find the code from /system/linkerconfig”
於是進入程式碼 "android/system/linkerconfig"目錄,找到對應namespace的原始碼檔案,新增:

ns.AddSearchPatch("/vendor/${LIB}/guess", AsanPath::NONE)

“android/system/linkerconfig"目錄下有一個Android.bp檔案。其中配置的out仍然為"ld.config.txt”。最終在手機的"/linkerconfig/"目錄下找到"ld.config.txt"檔案。

編譯"/system/bin/linkerconfig" 並push驗證。
手機重啟後檢查"/linkerconfig/ld.config.txt "檔案,確認修改生效。

五、

新增search patch後重新跑測試項,仍然報錯not found。
通過新增的log確認到,dlopen時已經遍歷到了正確的路徑,但在verifyElfHeader時e_machine這一變量出現匹配異常
e_machine的期待值為40–EM_ARM,標識機器型別。
出錯的庫檔案中e_machine值為164–EM_HEXAGON /* QUALCOMM Hexagon */
——高通DSP相關的庫檔案,只在CP側呼叫,不會有使用dlopen載入的情況。

**修改方案:**在"public.libraries.txt"檔案中去除對應庫名
附:庫檔案的ELF Header資訊也可以在linux環境下用如下命令讀取:

readelf -h <elffile>