最新公司項目須要開發一我的臉融合的demo,C++部分已經由另外團隊開發完成,須要跟Android進行對接。可是在so庫編譯完成以後,發現閃退,logcat看不到任何信息, 只能學習一下如何對so庫進行調試,仍是有點門檻的,再此根據實踐經驗理清一下思路和結果。java
先說一個概念:so庫的調試不是像java代碼同樣使用AS直接在界面裏能夠調試的,咱們使用的gdb調試是須要在終端裏進行操做調試,下面會有詳細解釋。linux
一、Mac+NDKr9+AS+SDK,android5.0的設備android
二、確保 android-sdk/tools 和 android-sdk/platform-tools在Path路徑裏;git
三、確保設備已經鏈接-使用adb shell 看看是否能正常執行;github
四、確保你的app的application加入了android:debugable="true"shell
五、編譯使用的so庫,必須用ndk-build DEBUG=1來生成,纔可進行調試;app
一、新建文件夾,取名Log(這個名字任意,本身方便就行); 二、cd Log; 三、新建文件夾system_lib和vendor_lib,名字最好和這個同樣了,若是自定義的話,後邊的參數自行修改; 四、cd system_lib,adb pull /system/lib,你會發現下拉了好多so庫; 五、cd ../vendor_lib,adb pull /vendor/lib,這時候也會下來好多庫; 六、cd .. 此時應該在Log目錄下了,執行 adb pull /system/bin/app_process; adb pull /system/bin/app_process32; adb pull /system/bin/app_process64; adb pull /system/bin/linker adb pull /system/bin/linker64
OK,如今所須要的庫已經都準備完成了。接下就是安裝gdb;tcp
一、從ndk裏拷貝gdbserver 路徑是:/Users/mu/Downloads/android-ndk-r9/prebuilt/android-arm/gdbserveride
二、拷貝到工程目錄下的 app/src/main/jniLibs的armeabi,armeabi-v7a,x86下邊;並重命名爲gdbserver.so;學習
三、用AS 運行工程,gdbserver就會運行在你的設備裏了。
一、給你須要調試的那行java代碼進行斷點,而後debug到那一步,而後保持這種狀態;
此時你會看到logcat打印處理端口號,它是這樣的:
OK,如今app已經處於調試狀態了,咱們能夠啓動gdb server進行調試了;
一、打開終端
二、查詢PID:
adb shell "ps | grep com.richard.glestutorial"; 其中com.richard.glestutorial是app的包名;
若是app從新調試的話,這個PID是會變的,每次進行attach的時候須要從新查詢一下。
三、端口映射:
adb forward tcp:8100 localfilesystem:/data/data/com.richard.glestutorial/debug-pipe 其中com.richard.glestutorial是app的包名;
四、手機上啓動gdbserver做爲服務端,而後讓它attach到3820這個進程
adb shell run-as com.richard.glestutorial /data/data/com.richard.glestutorial/lib/gdbserver.so +debug-pipe --attach 3820 其中com.richard.glestutorial是app的包名;
執行成功的話你看到的應該是這樣,說明Gdbserver已經在監聽調試了:
接下來咱們要啓動GDB進行調試了
一、打開另一個終端;
二、進入NDK目錄/Users/mu/Downloads/android-ndk-r9/toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64/bin
三、執行./arm-linux-androideabi-gdb /Users/mu/IMYFaceSwap-android/Log/app_process
這裏若是出現"not in executable format: File format not recognized"的話,請執行
./arm-linux-androideabi-gdb /Users/mu/IMYFaceSwap-android/Log/app_process32
或者
./arm-linux-androideabi-gdb /Users/mu/IMYFaceSwap-android/Log/app_process64
成功的話它應該這樣的,這個時候咱們就進入gdb了:
其中這個路徑/Users/mu/IMYFaceSwap-android/Log,是你剛纔新建的Log的路徑;
四、在gdb裏執行target remote:8100,關聯到app的端口,就是咱們剛纔端口映射的那個端口
五、設置linker關聯; set solib-search-path /Users/mu/IMYFaceSwap-android/Log/:/Users/mu/IMYFaceSwap-android/Log/system_lib:/Users/mu/IMYFaceSwap-android/Log/vendor_lib:/Users/mu/IMYFaceSwap-android/Log/vendor_lib/egl:/Users/mu/IMYFaceSwap-android/app/src/main/obj/local/armeabi-v7a
這句話是告訴gdb,若是linker須要load其餘依賴so的時候,gdb須要在哪一個目錄去找對應的文件;
這裏對幾個路徑進行解釋一下:
/Users/mu/IMYFaceSwap-android/Log/ 剛纔新建了Log文件夾位置;
/Users/mu/IMYFaceSwap-android/Log/system_lib 剛纔新建了Log文件夾位置;
/Users/mu/IMYFaceSwap-android/Log/vendor_lib 剛纔新建了Log文件夾位置;
Users/mu/IMYFaceSwap-android/Log/vendor_lib/egl 剛纔新建了Log文件夾位置;
/Users/mu/IMYFaceSwap-android/app/src/main/obj/local/armeabi-v7a;這個是在jni文件下使用ndk-build DEBUG=1編譯後在工程裏生成的文件路徑
六、使用info sharedlibrary 檢測一下是否有找到依賴,確保每一個so庫前邊都是Yes;正常的話是這樣: 確認完了以後,執行quit退出;
七、接下來個cpp文件下斷點;執行
b com_richard_glestutorial_GLRenderer.cpp:88
b com_richard_glestutorial_GLRenderer.cpp:89
b com_richard_glestutorial_GLRenderer.cpp:90
能夠看到下斷點成功; 對應的cpp源碼是這樣:
八、最激動人心的時刻,調試: gdb裏執行c,回車,此時會顯示continue...
而後回到AS,執行 Run -> Resume Program 你就會在終端裏看到執行到了你的斷點的位置了: 而後怎麼進行下一步?直接執行c回車,c回車,便可,直到定位到閃退的那一行:
能夠看到,代碼執行過這行: int code = IMY::FSWrapper::swapFace();以後就閃退了,接下來就叫給C++端吧。搞定!
九、注意事項:
gdb調試忽略SIGPIPE:在gdb裏執行handle SIGPIPE nostop noprint便可;
關於so庫調試,最好開三個終端比較不容易亂;查詢PID一個;開啓gdbserver一個;gdb調試一個;
https://github.com/mapbox/mapbox-gl-native/wiki/Android-debugging-with-remote-GDB
QQ:452825089
mail:452825089@qq.com
wechat:ice3897315