diff --git a/android/0_termux-setup_v2.sh b/android/0_termux-setup_v2.sh index 0ed8f6a..dd9c5bd 100755 --- a/android/0_termux-setup_v2.sh +++ b/android/0_termux-setup_v2.sh @@ -23,6 +23,21 @@ have() { command -v "$1" >/dev/null 2>&1; } need() { have "$1" || return 1; } die() { echo "[!] $*" >&2; exit 1; } +# ------------------------- +# Global defaults (may be overridden via environment) +# ------------------------- +STATE_DIR="${STATE_DIR:-${HOME}/.iiab-android}" +ADB_STATE_DIR="${ADB_STATE_DIR:-${STATE_DIR}/adbw_pair}" +LOG_DIR="${LOG_DIR:-${STATE_DIR}/logs}" + +HOST="${HOST:-127.0.0.1}" +CONNECT_PORT="${CONNECT_PORT:-}" +TIMEOUT_SECS="${TIMEOUT_SECS:-180}" + +# Defaults used by ADB flows / logging / misc +CLEANUP_OFFLINE="${CLEANUP_OFFLINE:-1}" +DEBUG="${DEBUG:-0}" + # ---- END 00_lib_common.sh ---- @@ -325,10 +340,8 @@ LAST_NOTIF_ID="" # Termux:API sanity check (notifications) termux_api_ready() { have termux-notification || return 1 - have termux-dialog || return 1 - # Quick probe: some Samsung setups fail until Termux:API app is installed/allowed. - # We try a harmless notification and remove it. + # Quick probe: some setups fail until Termux:API app is installed/allowed. local msg="iiab test notification" if ! termux-notification --id "$NOTIF_BASE_ID" --title "iiab" --content "$msg" --priority max --sound >/dev/null 2>&1; then return 1 @@ -361,9 +374,8 @@ cleanup_notif() { notify_ask_one() { # args: key title content local key="$1" title="$2" content="$3" - local out="$ADB_STATE_DIR/$key.txt" + local out="$ADB_STATE_DIR/$key.reply" rm -f "$out" - local action # Fresh notification each time + sound (use a new ID so Android plays sound each time) local nid @@ -375,13 +387,10 @@ notify_ask_one() { termux-notification-remove "$nid" >/dev/null 2>&1 || true fi - # termux-notification does not provide a reply input; use termux-dialog to capture text. - if ! have termux-dialog; then - warn "termux-dialog not available. Install: pkg install termux-api + Termux:API app." - return 1 - fi - - action="sh -lc 'termux-dialog -i -t \"${title}\" -h \"${content}\" | tr -d \"\\n\" | sed -n \"s/.*\\\"text\\\"[[:space:]]*:[[:space:]]*\\\"\\([^\\\"]*\\)\\\".*/\\1/p\" > \"${out}\"'" + # Direct reply: Termux:API injects the user input into $REPLY for the action. + # Write it to a known file, then the main loop reads it. + local action + action="sh -lc 'umask 077; printf \"%s\" \"\$REPLY\" > \"${out}\"'" termux-notification \ --id "$nid" \ @@ -394,16 +403,20 @@ notify_ask_one() { --button1-action "$action" \ || return 1 - local start now + local start now reply start="$(date +%s)" + while true; do if [[ -f "$out" ]]; then + reply="$(tr -d '\r\n' < "$out" 2>/dev/null || true)" + rm -f "$out" >/dev/null 2>&1 || true if have termux-notification-remove; then termux-notification-remove "$nid" >/dev/null 2>&1 || true fi - tr -d '\r\n' < "$out" + printf '%s' "$reply" return 0 fi + now="$(date +%s)" if (( now - start >= TIMEOUT_SECS )); then if have termux-notification-remove; then @@ -454,6 +467,92 @@ ask_code_6digits() { # ------------------------- # ADB wireless pair/connect wizard # ------------------------- + +# Local stamp so we can detect "connect-only" misuse after reinstall/clear-data. +ADB_PAIRED_STAMP="${ADB_STATE_DIR}/stamp.adb_paired" + +adb_hostkey_fingerprint() { + # Returns a stable fingerprint for THIS Termux install's adb host key. + local pub="${HOME}/.android/adbkey.pub" + [[ -r "$pub" ]] || return 1 + if have sha256sum; then + sha256sum "$pub" | awk '{print $1}' + elif have shasum; then + shasum -a 256 "$pub" | awk '{print $1}' + elif have openssl; then + openssl dgst -sha256 "$pub" 2>/dev/null | awk '{print $2}' + elif have md5sum; then + md5sum "$pub" | awk '{print $1}' + else + return 1 + fi +} + +adb_stamp_write() { + # args: mode serial + local mode="$1" serial="$2" fp="" + fp="$(adb_hostkey_fingerprint 2>/dev/null || true)" + { + echo "ts=$(date -Is 2>/dev/null || date || true)" + echo "mode=${mode}" + echo "host=${HOST}" + echo "serial=${serial}" + echo "connect_port=${CONNECT_PORT:-}" + echo "hostkey_fp=${fp}" + } >"$ADB_PAIRED_STAMP" 2>/dev/null || true + chmod 600 "$ADB_PAIRED_STAMP" 2>/dev/null || true +} + +adb_stamp_read_fp() { + [[ -r "$ADB_PAIRED_STAMP" ]] || return 1 + sed -n 's/^hostkey_fp=//p' "$ADB_PAIRED_STAMP" 2>/dev/null | head -n 1 +} + +adb_warn_connect_only_if_suspicious() { + # Called only in connect-only flows. + local cur_fp old_fp + cur_fp="$(adb_hostkey_fingerprint 2>/dev/null || true)" + old_fp="$(adb_stamp_read_fp 2>/dev/null || true)" + + if [[ ! -f "$ADB_PAIRED_STAMP" ]]; then + warn "connect-only assumes THIS Termux install has been paired before." + warn "No local pairing stamp found ($ADB_PAIRED_STAMP)." + warn "If you reinstalled Termux / cleared data / changed user, you must re-pair (run: --adb-only)." + [[ -n "$cur_fp" ]] && warn "Current ADB hostkey fingerprint: ${cur_fp:0:12}..." + return 0 + fi + + if [[ -n "$old_fp" && -n "$cur_fp" && "$old_fp" != "$cur_fp" ]]; then + warn_red "ADB host key changed since last pairing stamp." + warn "Old fingerprint: ${old_fp:0:12}... Current: ${cur_fp:0:12}..." + warn "Android Wireless debugging -> Paired devices: remove the old entry, then run: --adb-only" + fi +} + +adb_connect_verify() { + # args: serial (HOST:PORT) + local serial="$1" out rc start now state + set +e + out="$(adb connect "$serial" 2>&1)" + rc=$? + set -e + + # Always verify via `adb devices` (adb may exit 0 even on failure). + start="$(date +%s)" + while true; do + state="$(adb_device_state "$serial" || true)" + [[ "$state" == "device" ]] && { printf '%s\n' "$out"; return 0; } + now="$(date +%s)" + (( now - start >= 5 )) && break + sleep 1 + done + + warn_red "adb connect did not result in a usable device entry for: $serial (state='${state:-none}')." + warn "adb connect output: ${out:-}" + warn "If you recently reinstalled Termux/cleared data, the phone may show an OLD paired device. Remove it and re-pair." + return 1 +} + cleanup_offline_loopback() { local keep_serial="$1" # e.g. 127.0.0.1:41313 local serial state rest @@ -478,6 +577,7 @@ adb_pair_connect() { adb start-server >/dev/null 2>&1 || true if [[ "$ONLY_CONNECT" == "1" ]]; then + adb_warn_connect_only_if_suspicious if [[ -n "$CONNECT_PORT" ]]; then CONNECT_PORT="${CONNECT_PORT//[[:space:]]/}" [[ "$CONNECT_PORT" =~ ^[0-9]{5}$ ]] || die "Invalid CONNECT PORT (must be 5 digits): '$CONNECT_PORT'" @@ -489,7 +589,7 @@ adb_pair_connect() { local serial="${HOST}:${CONNECT_PORT}" adb disconnect "$serial" >/dev/null 2>&1 || true echo "[*] adb connect $serial" - adb connect "$serial" >/dev/null || die "adb connect failed to $serial. Verify Wireless debugging is enabled and CONNECT PORT is correct." + adb_connect_verify "$serial" >/dev/null || die "adb connect failed to $serial. Verify Wireless debugging is enabled, and pairing exists for THIS Termux install." if [[ "$CLEANUP_OFFLINE" == "1" ]]; then cleanup_offline_loopback "$serial" @@ -500,6 +600,7 @@ adb_pair_connect() { echo "[*] ADB check (shell):" adb -s "$serial" shell sh -lc 'echo "it worked: adb shell is working"; id' || true + adb_stamp_write "connect-only" "$serial" cleanup_notif ok "ADB connected (connect-only): $serial" @@ -529,7 +630,7 @@ adb_pair_connect() { printf '%s\n' "$code" | adb pair "${HOST}:${pair_port}" || die "adb pair failed. Verify PAIR PORT and PAIR CODE (and that the pairing dialog is showing)." echo "[*] adb connect $serial" - adb connect "$serial" >/dev/null || die "adb connect failed after pairing. Re-check CONNECT PORT and Wireless debugging." + adb_connect_verify "$serial" >/dev/null || die "adb connect failed after pairing. Re-check CONNECT PORT and Wireless debugging." if [[ "$CLEANUP_OFFLINE" == "1" ]]; then cleanup_offline_loopback "$serial" @@ -540,6 +641,7 @@ adb_pair_connect() { echo "[*] ADB check (shell):" adb -s "$serial" shell sh -lc 'echo "it worked: adb shell is working"; getprop ro.product.model; getprop ro.build.version.release' || true + adb_stamp_write "paired" "$serial" cleanup_notif ok "ADB connected: $serial" @@ -777,6 +879,55 @@ check_readiness() { return 0 } +self_check_android_flags() { + have adb || return 0 + adb start-server >/dev/null 2>&1 || true + + local serial sdk rel mon mon_fflag ds ppk_eff + serial="$(adb_pick_loopback_serial 2>/dev/null)" || { + warn "ADB: no loopback device connected. Tip: run --adb-only (pair+connect) or --check for more info." + return 0 + } + + sdk="$(adb -s "$serial" shell getprop ro.build.version.sdk 2>/dev/null | tr -d '\r' || true)" + rel="$(adb -s "$serial" shell getprop ro.build.version.release 2>/dev/null | tr -d '\r' || true)" + log " Android flags (quick): release=${rel:-?} sdk=${sdk:-?} serial=$serial" + + if [[ "$sdk" =~ ^[0-9]+$ ]] && (( sdk >= 34 )); then + mon_fflag="$(adb_get_child_restrictions_flag "$serial")" + if [[ "$mon_fflag" == "true" || "$mon_fflag" == "false" ]]; then + mon="$mon_fflag" + else + mon="$(adb -s "$serial" shell settings get global settings_enable_monitor_phantom_procs 2>/dev/null | tr -d '\r' || true)" + fi + + if [[ "$mon" == "false" ]]; then + ok " Child restrictions: OK (monitor=false)" + elif [[ "$mon" == "true" ]]; then + warn " Child restrictions: NOT OK (monitor=true) -> check Developer Options" + else + warn " Child restrictions: unknown/unreadable (monitor='${mon:-}')" + fi + fi + + if [[ "$sdk" =~ ^[0-9]+$ ]] && (( sdk >= 31 && sdk <= 33 )); then + ds="$(adb -s "$serial" shell dumpsys activity settings 2>/dev/null | tr -d '\r' || true)" + ppk_eff="$(printf '%s\n' "$ds" | awk -F= '/max_phantom_processes=/{print $2; exit}' | tr -d '[:space:]' || true)" + + if [[ "$ppk_eff" =~ ^[0-9]+$ ]]; then + if (( ppk_eff >= 256 )); then + ok " PPK: OK (max_phantom_processes=$ppk_eff)" + else + warn " PPK: low (max_phantom_processes=$ppk_eff) -> suggest: --ppk-only" + fi + else + warn " PPK: unreadable (max_phantom_processes='${ppk_eff:-}')" + fi + fi + + log " Tip: run --check for full details." +} + # ---- END 60_mod_ppk_checks.sh ---- @@ -793,16 +944,10 @@ check_readiness() { # ------------------------- # Defaults # ------------------------- -STATE_DIR="${HOME}/.iiab-android" -ADB_STATE_DIR="${STATE_DIR}/adbw_pair" -LOG_DIR="${STATE_DIR}/logs" -mkdir -p "$STATE_DIR" "$ADB_STATE_DIR" +# NOTE: Core defaults live in 00_lib_common.sh to guarantee availability for all modules. -HOST="127.0.0.1" -CONNECT_PORT="" -TIMEOUT_SECS=180 -CLEANUP_OFFLINE=1 -DEBUG=0 +# Ensure state directories exist (safe even if user overrides via environment). +mkdir -p "$STATE_DIR" "$ADB_STATE_DIR" "$LOG_DIR" 2>/dev/null || true RESET_DEBIAN=0 ONLY_CONNECT=0 @@ -825,8 +970,9 @@ Usage: ./0_termux-setupv2.sh --with-adb -> Termux baseline + Debian bootstrap + ADB pair/connect if needed (skips if already connected). - ./0_termux-setupv2.sh --adb-only + ./0_termux-setupv2.sh --adb-only [--connect-port PORT] -> Only ADB pair/connect if needed (no Debian; skips if already connected). + Tip: --connect-port skips the CONNECT PORT prompt (you’ll still be asked for PAIR PORT + PAIR CODE). ./0_termux-setupv2.sh --connect-only [CONNECT_PORT] -> Connect-only (no pairing). Use this after the device was already paired before. @@ -843,7 +989,7 @@ Usage: -> baseline + Debian + ADB pair/connect if needed + (Android 12-13 only) apply --ppk + run --check. Optional: - --connect-port 41313 (5 digits) Skip CONNECT PORT prompt + --connect-port 41313 (5 digits) Skip CONNECT PORT prompt used with --adb-only --timeout 180 Seconds to wait per prompt --reset-debian Reset (reinstall) Debian in proot-distro --no-log Disable logging @@ -888,6 +1034,8 @@ self_check() { else warn " adb: not present" fi + # Quick Android flags check (best-effort; no prompts) + self_check_android_flags || true if have termux-wake-lock; then ok " Termux:API wakelock: available"; else warn " Termux:API wakelock: not available"; fi if have termux-notification; then ok " Termux:API notifications: command present"; else warn " Termux:API notifications: missing"; fi @@ -1101,13 +1249,13 @@ main() { self_check ok "0_termux-setupv2.sh completed (mode=$MODE)." log "---- Mode list ----" - log "Connect-only: --connect-only [PORT]" - log "Pair+connect: --adb-only" - log "Check: --check" - log "Apply PPK: --ppk-only" - log "Base+Debian+Pair+connect: --with-adb" - log "Full run: --all" - log "Reset Debian: --reset-debian" + log "Connect-only --connect-only [PORT]" + log "Pair+connect --adb-only [--connect-port PORT]" + log "Check --check" + log "Apply PPK --ppk-only" + log "Base+Debian+Pair+connect --with-adb" + log "Full run --all" + log "Reset Debian --reset-debian" log "-------------------" final_advice }