如要對使用原生程式碼的應用程式進行偵錯及剖析,建議您使用原生程式碼 需要在程序啟動時啟用的偵錯工具。這需要 請在新程序中執行應用程式,而不是從 zygote 複製。 例如:
- 使用 strace 追蹤系統呼叫。
- 使用 malloc debug 或 Address Sanitizer (ASan) 找出記憶體錯誤。
- 使用 Simpleperf 進行分析。
使用包裝殼層指令碼
wrap.sh
使用起來很簡單:
- 編譯可進行偵錯的自訂 APK,其中包含以下內容:
- 一個名為
wrap.sh
的殼層指令碼。詳情請參閱建立包裝殼層指令碼和套件 wrap.sh。 - 殼層指令碼所需的其他任何工具 (例如您自己的
strace
二進位檔)。
- 一個名為
- 在裝置上安裝可進行偵錯的 APK。
- 啟動應用程式。
建立包裝殼層指令碼
當您啟動包含 wrap.sh
的可進行偵錯 APK 時,系統會執行該指令碼,並傳遞做為引數的啟動應用程式指令。這個指令碼負責啟動應用程式,但也可以變更任何環境或引數。此外,這個指令碼應遵循 MirBSD Korn shell (mksh) 語法。
下列程式碼片段示範如何編寫僅用於啟動應用程式的簡單 wrap.sh
檔案:
#!/system/bin/sh exec "$@"
Malloc debug
如要透過 wrap.sh
使用 malloc debug,請加入以下這行:
#!/system/bin/sh LIBC_DEBUG_MALLOC_OPTIONS=backtrace logwrapper "$@"
ASan
以下範例說明如何對 ASan 執行這項操作 ASan 說明文件。
wrap.sh 套件
為充分運用 wrap.sh
,您的 APK 必須可進行偵錯。請確認
android:debuggable="true"
相關設定位於
<application>
,或者您使用的是 Android Studio
您已經在
build.gradle
檔案。
此外,您必須設定 useLegacyPackaging
新增至應用程式的 build.gradle
檔案中true
。在大多數情況下
預設為 false
,因此建議您明確設為 true
避免任何意外發生
您必須將 wrap.sh
指令碼與應用程式的原生資料庫封裝在一起。如果
您的應用程式不含原生資料庫,請手動將 lib 目錄新增到
。針對您的應用程式支援的每個架構,您必須在該原生資料庫目錄下提供包裝殼層指令碼的副本。
以下範例展示同時支援 ARMv8 和 x86-64 架構的檔案版面配置:
# App Directory |- AndroidManifest.xml |- … |- lib |- arm64-v8a |- ... |- wrap.sh |- x86_64 |- ... |- wrap.sh
Android Studio 只會封裝 lib/
目錄中的 .so
檔案,因此
如果您是 Android Studio 使用者,請將 wrap.sh
檔案放在
src/main/resources/lib/*
目錄,如此一來,這些目錄就會封裝
正確。
請注意,resources/lib/x86
在 UI 中會顯示為
lib.x86
,但它實際上應該是子目錄:
在使用 wrap.sh 時進行偵錯
如要在使用 wrap.sh
時附加偵錯工具,您必須為殼層指令碼手動啟用偵錯功能。執行這項操作的方式因版本而異,因此以下範例示範如何為所有支援 wrap.sh
的版本新增適當的選項:
#!/system/bin/sh
cmd=$1
shift
os_version=$(getprop ro.build.version.sdk)
if [ "$os_version" -eq "27" ]; then
cmd="$cmd -Xrunjdwp:transport=dt_android_adb,suspend=n,server=y -Xcompiler-option --debuggable $@"
elif [ "$os_version" -eq "28" ]; then
cmd="$cmd -XjdwpProvider:adbconnection -XjdwpOptions:suspend=n,server=y -Xcompiler-option --debuggable $@"
else
cmd="$cmd -XjdwpProvider:adbconnection -XjdwpOptions:suspend=n,server=y $@"
fi
exec $cmd