The-Powder-Toy/android/debug.sh

192 lines
4.7 KiB
Bash
Raw Normal View History

#!/usr/bin/env bash
# mainly based on https://www.sh-zam.com/2019/05/debugging-krita-on-android.html
set -euo pipefail
IFS=$'\n\t'
# customize
default_app_id=uk.co.powdertoy.tpt
if which jq >/dev/null && [[ -f meson-info/intro-buildoptions.json ]]; then
default_app_id=$(jq -r '.[] | select(.name == "app_id") | .value' < meson-info/intro-buildoptions.json)
fi
app_id=${APP_ID:-$default_app_id}
lldb_server=${LLDB_SERVER:-/opt/android-ndk/toolchains/llvm/prebuilt/linux-x86_64/lib/clang/17/lib/linux/aarch64/lldb-server}
lldb_server_port=${LLDB_SERVER_PORT:-9998}
jdb_port=${JDB_PORT:-13456}
lldb_client=${LLDB_CLIENT:-/opt/android-ndk/toolchains/llvm/prebuilt/linux-x86_64/bin/lldb.sh}
adb=${ADB:-adb}
jdb=${JDB:-jdb}
# don't customize unless necessary
app_activity=${APP_ACTIVITY:-PowderActivity}
lldb_server_staging=${LLDB_SERVER_STAGING:-/data/local/tmp/lldb-server}
lldb_server_remote=${LLDB_SERVER_REMOTE:-lldb-server}
pidof_retry_count=${PIDOF_RETRY_COUNT:-20}
pidof_retry_delay=${PIDOF_RETRY_DELAY:-0.1}
function check_which() {
if ! which $1; then
>&2 echo "[-] can't run $1"
return 1
fi
}
function check_env() {
if ! [[ -f $lldb_server ]]; then
>&2 echo "[-] $lldb_server doesn't exist"
return 1
fi
check_which $lldb_client
check_which $adb
check_which $jdb
}
function check_adb() {
$adb shell whoami >/dev/null
}
function check_debuggable() {
$adb shell run-as $app_id whoami >/dev/null
}
function find_lldb_server() {
$adb shell run-as $app_id pgrep $lldb_server_remote >/dev/null
}
function kill_lldb_server() {
if ! $adb shell run-as $app_id pkill $lldb_server_remote; then
>&2 echo "[-] failed"
return 1
fi
}
function adb_forward() {
>&2 echo "[+] adb forwarding tcp:$jdb_port jdwp:$pid"
if ! ($adb forward tcp:$jdb_port jdwp:$pid | grep $jdb_port >/dev/null); then
>&2 echo "[+] failed"
return 1
fi
}
function adb_unforward() {
$adb forward --remove tcp:$jdb_port
}
function undo_current_adb_forward() {
>&2 echo "[+] adb un-forwarding orphaned tcp:$jdb_port"
adb_unforward
}
function maybe_undo_previous_adb_forward() {
if $adb forward --list | grep tcp:$jdb_port; then
>&2 echo "[+] adb un-forwarding orphaned tcp:$jdb_port"
adb_unforward
fi
}
function maybe_kill_previous_lldb_server() {
if find_lldb_server; then
>&2 echo "[+] killing orphaned $lldb_server_remote"
kill_lldb_server
fi
}
function kill_current_lldb_server() {
>&2 echo "[+] killing $lldb_server_remote"
kill_lldb_server
}
function start_app() {
>&2 echo "[+] starting $app_id/.$app_activity"
set +e
$adb shell am start -D -n "$app_id/.$app_activity" >/dev/null
set -e
local i
local maybe_pid
local pidof_result
for ((i = 0; i <= $pidof_retry_count; i++)); do
set +e
maybe_pid=$($adb shell pidof $app_id)
pidof_result=$?
set -e
if [[ $pidof_result == 0 ]]; then
pid=$maybe_pid
break
fi
sleep $pidof_retry_delay
done
if [[ -z ${pid-} ]]; then
>&2 echo "[-] failed"
return 1
fi
echo $pid
}
function jdb_attach() {
>&2 echo "[+] attaching jdb in the background"
$jdb -attach localhost:$jdb_port >/dev/null 2>/dev/null &
disown $!
# at some point jdb exits because it doesn't have an stdin... fine by me
}
function maybe_deploy_lldb_server() {
if ! $adb shell [[ -f $lldb_server_staging ]]; then
>&2 echo "[+] $lldb_server_remote not present on host, deploying"
if ! ($adb push $lldb_server $lldb_server_staging && $adb shell chmod +x $lldb_server_staging); then
>&2 echo "[-] failed"
fi
fi
}
function start_lldb_server() {
if ! $adb shell run-as $app_id pgrep $lldb_server_remote >/dev/null; then
>&2 echo "[+] $lldb_server_remote not running on host, starting"
$adb shell run-as $app_id cp $lldb_server_staging /data/data/$app_id/$lldb_server_remote
$adb shell run-as $app_id ./$lldb_server_remote platform --server --listen "*:$lldb_server_port" >/dev/null 2>/dev/null &
disown $!
if ! $adb shell run-as $app_id pgrep $lldb_server_remote >/dev/null; then
>&2 echo "[-] failed"
return 1
fi
fi
}
function start_lldb() {
local pid=$1
>&2 echo "[+] starting $lldb_client"
local lldb_init=$(mktemp)
cat - << LLDB_INIT > $lldb_init
platform select remote-android
platform connect connect://localhost:$lldb_server_port
attach $pid
continue
LLDB_INIT
local lldb_status
set +e
$lldb_client --source $lldb_init
lldb_status=$?
set -e
>&2 echo "[+] $lldb_client exited with status $lldb_status"
rm $lldb_init
}
check_env
check_adb
check_debuggable
maybe_kill_previous_lldb_server
maybe_undo_previous_adb_forward
if [[ ${1-} == clean ]]; then
>&2 echo "[+] done"
exit 0
fi
maybe_deploy_lldb_server
start_lldb_server
pid=$(start_app)
adb_forward
jdb_attach
start_lldb $pid
kill_current_lldb_server
undo_current_adb_forward
>&2 echo "[+] done"