#!/data/data/com.termux/files/usr/bin/bash set -euo pipefail # 0_termux-setupv2.sh # - Termux bootstrap (packages, wakelock) # - proot-distro + Debian bootstrap # - ADB wireless pair/connect via Termux:API notifications (no Shizuku) # - Optional PPK / phantom-process tweaks (best-effort) RED="\033[31m"; YEL="\033[33m"; GRN="\033[32m"; BLU="\033[34m"; RST="\033[0m"; BOLD="\033[1m" log() { printf "${BLU}[iiab]${RST} %s\n" "$*"; } ok() { printf "${GRN}[iiab]${RST} %s\n" "$*"; } warn() { printf "${YEL}[iiab] WARNING:${RST} %s\n" "$*" >&2; } warn_red() { printf "${RED}${BOLD}[iiab] WARNING:${RST} %s\n" "$*" >&2; } have() { command -v "$1" >/dev/null 2>&1; } need() { have "$1" || return 1; } die() { echo "[!] $*" >&2; exit 1; } # ------------------------- # Logging # ------------------------- LOG_ENABLED=1 LOG_FILE="" # if empty, auto-generate under $LOG_DIR LOG_KEEP=20 # keep last N logs rotate_logs() { [[ -d "${LOG_DIR:-}" ]] || return 0 local n=$((LOG_KEEP + 1)) while IFS= read -r f; do [[ -n "${f:-}" ]] || continue [[ -n "${LOG_FILE:-}" && "$f" == "$LOG_FILE" ]] && continue rm -f -- "$f" 2>/dev/null || true done < <(ls -1t "$LOG_DIR"/*.log 2>/dev/null | tail -n +"$n" || true) } setup_logging() { # If logging is disabled, still allow --debug to trace to console. if [[ "${LOG_ENABLED:-1}" -ne 1 ]]; then if [[ "${DEBUG:-0}" -eq 1 ]]; then set -x ok "Debug trace enabled (bash -x) -> console (logging disabled)" fi return 0 fi # Save original console fds so interactive tools still work after we redirect stdout/stderr. exec 3>&1 4>&2 mkdir -p "$LOG_DIR" 2>/dev/null || true if [[ -z "${LOG_FILE:-}" ]]; then LOG_FILE="${LOG_DIR}/0_termux-setupv2.$(date +%Y%m%d-%H%M%S).log" else # Best-effort: ensure parent dir exists mkdir -p "$(dirname -- "$LOG_FILE")" 2>/dev/null || true fi # Header (best-effort) { echo "=== iiab termux setup v2 log ===" echo "Started: $(date -Is)" echo "Script: $0" echo "Args: ${*:-}" echo "Android SDK=${ANDROID_SDK:-?} Release=${ANDROID_REL:-?}" echo "PWD: $(pwd 2>/dev/null || true)" echo "================================" } >>"$LOG_FILE" 2>/dev/null || true # Best-effort: restrict log readability (may include debug/xtrace) chmod 600 "$LOG_FILE" 2>/dev/null || true rotate_logs # Duplicate stdout/stderr to console + log (strip ANSI in log) exec \ > >(tee >(sed -E 's/\x1B\[[0-9;]*[ -/]*[@-~]//g' >>"$LOG_FILE")) \ 2> >(tee >(sed -E 's/\x1B\[[0-9;]*[ -/]*[@-~]//g' >>"$LOG_FILE") >&2) ok "Logging to: $LOG_FILE" # If --debug, send xtrace only to log if [[ "${DEBUG:-0}" -eq 1 ]]; then exec 9>>"$LOG_FILE" export BASH_XTRACEFD=9 export PS4='+(${BASH_SOURCE}:${LINENO}): ${FUNCNAME[0]:+${FUNCNAME[0]}(): }' set -x ok "Debug trace enabled (bash -x) -> log only" fi } # ------------------------- # 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" HOST="127.0.0.1" CONNECT_PORT="" TIMEOUT_SECS=180 NOTIF_BASE_ID=9400 NOTIF_SEQ=0 LAST_NOTIF_ID="" CLEANUP_OFFLINE=1 DEBUG=0 RESET_DEBIAN=0 ONLY_CONNECT=0 CHECK_NO_ADB=0 CHECK_SDK="" CHECK_MON="" CHECK_PPK="" # Modes are mutually exclusive (baseline is default) MODE="baseline" # baseline|with-adb|adb-only|connect-only|ppk-only|check|all MODE_SET=0 # Termux apt options (avoid conffile prompts) TERMUX_APT_OPTS=( "-y" "-o" "Dpkg::Options::=--force-confdef" "-o" "Dpkg::Options::=--force-confold" ) termux_apt() { apt-get "${TERMUX_APT_OPTS[@]}" "$@"; } usage() { cat <<'EOF' Usage: ./0_termux-setupv2.sh -> Termux baseline + Debian bootstrap (idempotent). No ADB prompts. ./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 -> Only ADB pair/connect if needed (no Debian; skips if already connected). ./0_termux-setupv2.sh --connect-only [CONNECT_PORT] -> Connect-only (no pairing). Use this after the device was already paired before. ./0_termux-setupv2.sh --ppk-only -> Set PPK only: max_phantom_processes=256 (requires ADB already connected). Android 14-16 usually achieve this via "Disable child process restrictions" in Developer Options. ./0_termux-setupv2.sh --check -> Check readiness: developer options flag (if readable), (Android 14+) "Disable child process restrictions" proxy flag, and (Android 12-13) PPK effective value. ./0_termux-setupv2.sh --all -> 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 --timeout 180 Seconds to wait per prompt --reset-debian Reset (reinstall) Debian in proot-distro --no-log Disable logging --log-file /path/file Write logs to a specific file --debug Extra logs Notes: - ADB prompts require: `pkg install termux-api` + Termux:API app installed + notification permission. - Wireless debugging must be enabled. - This script never uses adb root. EOF } # ------------------------- # Android info # ------------------------- get_android_sdk() { getprop ro.build.version.sdk 2>/dev/null || true; } get_android_release() { getprop ro.build.version.release 2>/dev/null || true; } ANDROID_SDK="$(get_android_sdk)" ANDROID_REL="$(get_android_release)" # ------------------------- # Wakelock (Termux:API) # ------------------------- WAKELOCK_HELD=0 acquire_wakelock() { if have termux-wake-lock; then if termux-wake-lock; then WAKELOCK_HELD=1 ok "Wakelock acquired (termux-wake-lock)." else warn "Failed to acquire wakelock (termux-wake-lock)." fi else warn "termux-wake-lock not available. Install: pkg install termux-api + Termux:API app." fi } release_wakelock() { if [[ "$WAKELOCK_HELD" -eq 1 ]] && have termux-wake-unlock; then termux-wake-unlock || true ok "Wakelock released (termux-wake-unlock)." fi } trap 'cleanup_notif >/dev/null 2>&1 || true; release_wakelock >/dev/null 2>&1 || true' EXIT INT TERM # ------------------------- # One-time repo selector # ------------------------- step_termux_repo_select_once() { local stamp="$STATE_DIR/stamp.termux_repo_selected" [[ -f "$stamp" ]] && return 0 if ! have termux-change-repo; then warn "termux-change-repo not found; skipping mirror selection." return 0 fi if [[ -r /dev/tty ]]; then printf "\n${YEL}[iiab] One-time setup:${RST} Select a nearby Termux repository mirror for faster downloads.\n" >&2 local ans="Y" if ! read -r -p "[iiab] Launch termux-change-repo now? [Y/n]: " ans < /dev/tty; then warn "No interactive TTY available; skipping mirror selection (run script directly to be prompted)." return 0 fi ans="${ans:-Y}" if [[ "$ans" =~ ^[Yy]$ ]]; then # Logging redirects stdout/stderr to pipes, which can break the UI. # Run it using /dev/tty and the original console fds (3/4). if [[ -r /dev/tty ]]; then termux-change-repo &3 2>&4 || true else termux-change-repo || true fi ok "Mirror selection completed (or skipped inside the UI)." else warn "Mirror selection skipped by user." fi date > "$stamp" return 0 fi warn "No /dev/tty available; skipping mirror selection." return 0 } # ------------------------- # Baseline packages # ------------------------- step_termux_base() { local stamp="$STATE_DIR/stamp.termux_base" if [[ -f "$stamp" ]]; then ok "Termux baseline already prepared (stamp found)." return 0 fi log "Updating Termux packages (noninteractive) and installing baseline dependencies..." export DEBIAN_FRONTEND=noninteractive termux_apt update || true termux_apt upgrade || true termux_apt install \ ca-certificates \ curl \ coreutils \ grep \ sed \ gawk \ openssh \ proot proot-distro \ android-tools \ termux-api \ || true if have proot-distro && have adb && have termux-notification; then ok "Termux baseline ready." date > "$stamp" else warn_red "Baseline incomplete (missing proot-distro/adb/termux-notification). Not stamping; rerun later." fi } # ------------------------- # Debian bootstrap # ------------------------- debian_exists() { have proot-distro || return 1 proot-distro login debian -- true >/dev/null 2>&1 } ensure_proot_distro() { if have proot-distro; then return 0; fi warn "proot-distro not found; attempting to install..." termux_apt install proot-distro || true have proot-distro } proot_install_debian_safe() { local out rc set +e out="$(proot-distro install debian 2>&1)" rc=$? set -e if [[ $rc -eq 0 ]]; then return 0; fi if echo "$out" | grep -qi "already installed"; then warn "Debian is already installed; continuing." return 0 fi printf "%s\n" "$out" >&2 return $rc } step_debian_bootstrap_default() { if ! ensure_proot_distro; then warn "Unable to ensure proot-distro; skipping Debian bootstrap." return 0 fi if [[ "$RESET_DEBIAN" -eq 1 ]]; then warn "Reset requested: reinstalling Debian (clean environment)..." if proot-distro help 2>/dev/null | grep -qE '\breset\b'; then proot-distro reset debian || true else if debian_exists; then proot-distro remove debian || true; fi proot_install_debian_safe || true fi else if debian_exists; then ok "Debian already present in proot-distro. Not reinstalling." else log "Installing Debian (proot-distro install debian)..." proot_install_debian_safe || true fi fi log "Installing minimal tools inside Debian (noninteractive)..." proot-distro login debian -- bash -lc ' set -e export DEBIAN_FRONTEND=noninteractive apt-get update -y apt-get -y -o Dpkg::Options::=--force-confdef -o Dpkg::Options::=--force-confold \ install ca-certificates curl coreutils ' || true ok "Debian bootstrap complete." } # ------------------------- # Termux:API sanity check (notifications) # ------------------------- termux_api_ready() { have termux-notification || return 1 # Quick probe: some Samsung setups fail until Termux:API app is installed/allowed. # We try a harmless notification and remove it. 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 fi if have termux-notification-remove; then termux-notification-remove "$NOTIF_BASE_ID" >/dev/null 2>&1 || true fi return 0 } sanitize_timeout() { # Ensure TIMEOUT_SECS is a positive integer if ! [[ "${TIMEOUT_SECS:-}" =~ ^[0-9]+$ ]]; then warn "Invalid --timeout='${TIMEOUT_SECS:-}'. Falling back to 180." TIMEOUT_SECS=180 elif (( TIMEOUT_SECS < 5 )); then warn "Very low --timeout=${TIMEOUT_SECS}. Forcing minimum 5 seconds." TIMEOUT_SECS=5 fi } cleanup_notif() { have termux-notification-remove || return 0 termux-notification-remove "$NOTIF_BASE_ID" >/dev/null 2>&1 || true if [[ -n "${LAST_NOTIF_ID:-}" ]]; then termux-notification-remove "$LAST_NOTIF_ID" >/dev/null 2>&1 || true fi } notify_ask_one() { # args: key title content local key="$1" title="$2" content="$3" local out="$ADB_STATE_DIR/$key.txt" rm -f "$out" # Fresh notification each time + sound (use a new ID so Android plays sound each time) local nid nid=$((NOTIF_BASE_ID + 1 + NOTIF_SEQ)) NOTIF_SEQ=$((NOTIF_SEQ + 1)) LAST_NOTIF_ID="$nid" if have termux-notification-remove; then termux-notification-remove "$nid" >/dev/null 2>&1 || true fi termux-notification \ --id "$nid" \ --ongoing \ --priority max \ --title "$title" \ --content "$content" \ --sound \ --button1 "Answer" \ --button1-action "sh -lc 'printf \"%s\" \"\$REPLY\" > \"$out\"'" \ || return 1 local start now start="$(date +%s)" while true; do if [[ -s "$out" ]]; then # Remove the prompt notification as soon as we got the answer if have termux-notification-remove; then termux-notification-remove "$nid" >/dev/null 2>&1 || true fi tr -d '\r\n' < "$out" return 0 fi now="$(date +%s)" if (( now - start >= TIMEOUT_SECS )); then # Remove the prompt notification on timeout too if have termux-notification-remove; then termux-notification-remove "$nid" >/dev/null 2>&1 || true fi return 1 fi sleep 1 done } ask_port_5digits() { # args: key title local key="$1" title="$2" v="" while true; do v="$(notify_ask_one "$key" "$title" "(5 digits)")" || return 1 v="${v//[[:space:]]/}" [[ "$v" =~ ^[0-9]{5}$ ]] || continue echo "$v" return 0 done } ask_code_6digits() { local v="" while true; do v="$(notify_ask_one code "PAIR CODE" "(6 digits)")" || return 1 v="${v//[[:space:]]/}" [[ -n "$v" ]] || continue [[ "$v" =~ ^[0-9]+$ ]] || continue # Normalize to 6 digits (allow missing leading zeros) if ((${#v} < 6)); then v="$(printf "%06d" "$v")" fi [[ "$v" =~ ^[0-9]{6}$ ]] || continue echo "$v" return 0 done } cleanup_offline_loopback() { local keep_serial="$1" # e.g. 127.0.0.1:41313 local serial state rest while read -r serial state rest; do [[ -n "${serial:-}" ]] || continue [[ "$serial" == ${HOST}:* ]] || continue [[ "$state" == "offline" ]] || continue [[ "$serial" == "$keep_serial" ]] && continue adb disconnect "$serial" >/dev/null 2>&1 || true done < <(adb devices 2>/dev/null | tail -n +2 | sed '/^[[:space:]]*$/d') } # ------------------------- # ADB wireless pair/connect wizard # ------------------------- adb_pair_connect() { need adb || die "Missing adb. Install: pkg install android-tools" # Only require Termux:API when we will prompt the user if [[ "$ONLY_CONNECT" != "1" || -z "${CONNECT_PORT:-}" ]]; then termux_api_ready || die "Termux:API not ready." fi echo "[*] adb: $(adb version | head -n 1)" adb start-server >/dev/null 2>&1 || true if [[ "$ONLY_CONNECT" == "1" ]]; then 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'" else echo "[*] Asking CONNECT PORT..." CONNECT_PORT="$(ask_port_5digits connect "CONNECT PORT")" || die "Timeout waiting CONNECT PORT." fi 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." if [[ "$CLEANUP_OFFLINE" == "1" ]]; then cleanup_offline_loopback "$serial" fi echo "[*] Devices:" adb devices -l echo "[*] ADB check (shell):" adb -s "$serial" shell sh -lc 'echo "it worked: adb shell is working"; id' || true cleanup_notif ok "ADB connected (connect-only): $serial" return 0 fi 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'" else echo "[*] Asking CONNECT PORT..." CONNECT_PORT="$(ask_port_5digits connect "CONNECT PORT")" || die "Timeout waiting CONNECT PORT." fi echo "[*] Asking PAIR PORT..." local pair_port pair_port="$(ask_port_5digits pair "PAIR PORT")" || die "Timeout waiting PAIR PORT." echo "[*] Asking PAIR CODE..." local code code="$(ask_code_6digits)" || die "Timeout waiting PAIR CODE." local serial="${HOST}:${CONNECT_PORT}" adb disconnect "$serial" >/dev/null 2>&1 || true echo "[*] adb pair ${HOST}:${pair_port}" 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." if [[ "$CLEANUP_OFFLINE" == "1" ]]; then cleanup_offline_loopback "$serial" fi echo "[*] Devices:" adb devices -l 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 cleanup_notif ok "ADB connected: $serial" } # Return state for an exact serial (e.g. "device", "offline", empty) adb_device_state() { local s="$1" adb devices 2>/dev/null | awk -v s="$s" 'NR>1 && $1==s {print $2; exit}' } # Return first loopback serial in "device" state (e.g. 127.0.0.1:41313) adb_any_loopback_device() { adb devices 2>/dev/null | awk -v h="$HOST" 'NR>1 && $2=="device" && index($1, h":")==1 {print $1; exit}' } # Pick the loopback serial we will operate on: # - If CONNECT_PORT is set, require that exact HOST:PORT to be in "device" state. # - Otherwise, return the first loopback device. adb_pick_loopback_serial() { if [[ -n "${CONNECT_PORT:-}" ]]; then local p="${CONNECT_PORT//[[:space:]]/}" [[ "$p" =~ ^[0-9]{5}$ ]] || return 1 local target="${HOST}:${p}" [[ "$(adb_device_state "$target")" == "device" ]] && { echo "$target"; return 0; } return 1 fi adb_any_loopback_device } # If already connected, avoid re-pairing/re-connecting prompts (useful for --all), # BUT only consider loopback/target connections as "already connected". adb_pair_connect_if_needed() { need adb || die "Missing adb. Install: pkg install android-tools" adb start-server >/dev/null 2>&1 || true local serial="" # If user provided a connect-port, insist on that exact target serial. 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'" local target="${HOST}:${CONNECT_PORT}" if [[ "$(adb_device_state "$target")" == "device" ]]; then ok "ADB already connected to target: $target (skipping pair/connect)." return 0 fi # Try connect-only first (in case it was already paired before) adb connect "$target" >/dev/null 2>&1 || true if [[ "$(adb_device_state "$target")" == "device" ]]; then ok "ADB connected to target: $target (connect-only succeeded; skipping pair)." return 0 fi # Not connected: run full wizard (pair+connect) adb_pair_connect return $? fi # No explicit port: only skip if we already have a loopback device connected. if serial="$(adb_any_loopback_device 2>/dev/null)"; then ok "ADB already connected (loopback): $serial (skipping pair/connect)." return 0 fi adb_pair_connect } require_adb_connected() { need adb || { warn_red "Missing adb. Install: pkg install android-tools"; return 1; } adb start-server >/dev/null 2>&1 || true if ! adb_pick_loopback_serial >/dev/null 2>&1; then warn_red "No ADB device connected." warn "If already paired before: run --connect-only [PORT]." warn "Otherwise: run --adb-only to pair+connect." return 1 fi return 0 } adb_loopback_serial_or_die() { local s s="$(adb_pick_loopback_serial 2>/dev/null)" || return 1 echo "$s" } # ------------------------- # PPK / phantom-process tuning (best-effort) # ------------------------- ppk_fix_via_adb() { need adb || die "Missing adb. Install: pkg install android-tools" local serial if ! serial="$(adb_pick_loopback_serial)"; then CHECK_NO_ADB=1 warn "No ADB loopback device connected (expected ${HOST}:${CONNECT_PORT:-*})." return 1 fi ok "Using ADB device: $serial" log "Setting PPK: max_phantom_processes=256" # Some Android versions may ignore/rename this; we don't hard-fail. adb -s "$serial" shell sh -lc ' set -e # Persist device_config changes if supported if command -v device_config >/dev/null 2>&1; then device_config set_sync_disabled_for_tests persistent >/dev/null 2>&1 || true device_config put activity_manager max_phantom_processes 256 || true echo "dumpsys effective max_phantom_processes:" dumpsys activity settings 2>/dev/null | grep -i "max_phantom_processes=" | head -n 1 || true else echo "device_config not found; skipping." fi ' || true ok "PPK set done (best effort)." return 0 } # Prefer Android 14+ feature-flag override if present: # OFF -> true, ON -> false adb_get_child_restrictions_flag() { local serial="$1" adb -s "$serial" shell getprop persist.sys.fflag.override.settings_enable_monitor_phantom_procs \ 2>/dev/null | tr -d '\r' || true } # ------------------------- # Check readiness (best-effort) # ------------------------- check_readiness() { # Reset exported check signals so final_advice() never sees stale values CHECK_NO_ADB=0 CHECK_SDK="" CHECK_MON="" CHECK_PPK="" need adb || die "Missing adb. Install: pkg install android-tools" adb start-server >/dev/null 2>&1 || true local serial if ! serial="$(adb_pick_loopback_serial)"; then CHECK_NO_ADB=1 # Best-effort: keep local SDK so final_advice can still warn on A12-13. CHECK_SDK="${ANDROID_SDK:-}" warn_red "No ADB device connected. Cannot run checks." warn "If already paired before: run --connect-only [PORT]." warn "Otherwise: run --adb-only to pair+connect." return 1 fi ok "Check using ADB device: $serial" local dev_enabled sdk rel mon mon_fflag ds ppk_eff 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)" dev_enabled="$(adb -s "$serial" shell settings get global development_settings_enabled 2>/dev/null | tr -d '\r' || true)" 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 # Get effective value from dumpsys (device_config get may return 'null' even when an effective value exists) 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)" # Export check signals for the final advice logic CHECK_SDK="${sdk:-}" CHECK_MON="${mon:-}" CHECK_PPK="${ppk_eff:-}" log " Android release=${rel:-?} sdk=${sdk:-?}" if [[ "${dev_enabled:-}" == "1" ]]; then ok " Developer options: enabled (development_settings_enabled=1)" elif [[ -n "${dev_enabled:-}" ]]; then warn " Developer options: unknown/disabled (development_settings_enabled=${dev_enabled})" else warn " Developer options: unreadable (permission/ROM differences)." fi # Android 14+ only: "Disable child process restrictions" proxy flag if [[ "${sdk:-}" =~ ^[0-9]+$ ]] && (( sdk >= 34 )); then if [[ "${mon:-}" == "false" ]]; then ok " Child restrictions: OK (monitor=false)" elif [[ "${mon:-}" == "true" ]]; then warn " Child restrictions: NOT OK (monitor=true)" elif [[ -n "${mon:-}" && "${mon:-}" != "null" ]]; then warn " Child restrictions: unknown (${mon})" else warn " Child restrictions: unreadable/absent" fi fi # Android 12-13 only: PPK matters (use effective value from dumpsys) if [[ "${sdk:-}" =~ ^[0-9]+$ ]] && (( sdk >= 31 && sdk <= 33 )); then 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: run --ppk-only" fi else warn " PPK: unreadable (dumpsys max_phantom_processes='${ppk_eff:-}')." fi fi log " dumpsys (phantom-related):" printf '%s\n' "$ds" | grep -i phantom || true if [[ "${sdk:-}" =~ ^[0-9]+$ ]] && (( sdk >= 34 )); then log " Note: On A14+, max_phantom_processes is informational; rely on Child restrictions." fi if [[ "${sdk:-}" =~ ^[0-9]+$ ]] && (( sdk >= 34 )) && [[ "${mon:-}" == "false" ]]; then log " Child restrictions OK." fi return 0 } # ------------------------- # Self-check # ------------------------- self_check() { log "Self-check summary:" log " Android release=${ANDROID_REL:-?} sdk=${ANDROID_SDK:-?}" if have proot-distro; then log " proot-distro: present" log " proot-distro list:" proot-distro list 2>/dev/null | sed 's/^/ /' || true if debian_exists; then ok " Debian: present"; else warn " Debian: not present"; fi else warn " proot-distro: not present" fi if have adb; then log " adb: present" adb devices -l 2>/dev/null | sed 's/^/ /' || true local serial if serial="$(adb_pick_loopback_serial 2>/dev/null)"; then log " adb shell id (first device):" adb -s "$serial" shell id 2>/dev/null | sed 's/^/ /' || true fi else warn " adb: not present" fi 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 } final_advice() { # 1) Android-related warnings (only meaningful if we attempted checks) local sdk="${CHECK_SDK:-${ANDROID_SDK:-}}" if [[ "${CHECK_NO_ADB:-0}" -eq 1 ]]; then # If we could not check, still warn on A12-13 because PPK is critical there if [[ "$sdk" =~ ^[0-9]+$ ]] && (( sdk >= 31 && sdk <= 33 )); then warn "A12-13: verify PPK=256 before installing IIAB." fi else # A14+ child restrictions proxy (only if readable) if [[ "$sdk" =~ ^[0-9]+$ ]] && (( sdk >= 34 )) && [[ "${CHECK_MON:-}" == "true" ]]; then warn "A14+: disable child process restrictions before installing IIAB." fi # Only warn about PPK on A12-13 (A14+ uses child restrictions) if [[ "$sdk" =~ ^[0-9]+$ ]] && (( sdk >= 31 && sdk <= 33 )); then if [[ "${CHECK_PPK:-}" =~ ^[0-9]+$ ]] && (( CHECK_PPK < 256 )); then warn "PPK is low (${CHECK_PPK}); consider --ppk-only." fi fi fi # 2) Debian “next step” should only be shown for modes that actually bootstrap Debian case "$MODE" in baseline|with-adb|all) if debian_exists; then ok "Next: proot-distro login debian" else warn "Debian not present. Run: proot-distro install debian" fi ;; *) # adb-only/connect-only/ppk-only/check: do not suggest Debian login as a generic ending ;; esac } # ------------------------- # Args # ------------------------- set_mode() { local new="$1" if [[ "$MODE_SET" -eq 1 ]]; then die "Modes are mutually exclusive. Already set: --${MODE}. Tried: --${new}" fi MODE="$new" MODE_SET=1 } while [[ $# -gt 0 ]]; do case "$1" in --with-adb) set_mode "with-adb"; shift ;; --adb-only) set_mode "adb-only"; shift ;; --connect-only) set_mode "connect-only" ONLY_CONNECT=1 # Optional positional port (5 digits) if [[ "${2:-}" =~ ^[0-9]{5}$ ]]; then CONNECT_PORT="$2" shift 2 else shift fi ;; --ppk-only) set_mode "ppk-only"; shift ;; --check) set_mode "check"; shift ;; --all) set_mode "all"; shift ;; --connect-port) CONNECT_PORT="${2:-}"; shift 2 ;; --timeout) TIMEOUT_SECS="${2:-180}"; shift 2 ;; --host) HOST="${2:-127.0.0.1}"; shift 2 ;; --reset-debian|--clean-debian) RESET_DEBIAN=1; shift ;; --no-log) LOG_ENABLED=0; shift ;; --log-file) LOG_FILE="${2:-}"; shift 2 ;; --debug) DEBUG=1; shift ;; -h|--help) usage; exit 0 ;; *) shift ;; esac done # ------------------------- # Main flows # ------------------------- main() { setup_logging "$@" sanitize_timeout acquire_wakelock case "$MODE" in baseline) step_termux_repo_select_once step_termux_base step_debian_bootstrap_default ;; with-adb) step_termux_repo_select_once step_termux_base step_debian_bootstrap_default adb_pair_connect_if_needed ;; adb-only) step_termux_base adb_pair_connect_if_needed ;; connect-only) step_termux_base adb_pair_connect ;; ppk-only) # No baseline, no Debian. Requires adb already available + connected. require_adb_connected || exit 1 ppk_fix_via_adb || true ;; check) step_termux_base check_readiness || true ;; all) step_termux_repo_select_once step_termux_base step_debian_bootstrap_default adb_pair_connect_if_needed # Android 12-13 only (SDK 31-33): apply PPK tuning automatically if [[ "${ANDROID_SDK:-}" =~ ^[0-9]+$ ]] && (( ANDROID_SDK >= 31 && ANDROID_SDK <= 33 )); then log "Android SDK=${ANDROID_SDK} detected -> applying --ppk automatically (12-13 rule)." ppk_fix_via_adb || true else log "Android SDK=${ANDROID_SDK:-?} -> skipping auto-PPK (only for Android 12-13)." fi check_readiness || true ;; *) die "Unknown MODE='$MODE'" ;; esac self_check ok "0_termux-setupv2.sh completed (mode=$MODE)." log "Tip: Connect-only: --connect-only [PORT]" log "Tip: Pair+connect: --adb-only" log "Tip: Check: --check" log "Tip: Apply PPK: --ppk-only" log "Tip: Base+Debian+Pair+connect: --with-adb" log "Tip: Full run: --all" log "Tip: Reset Debian: --reset-debian" final_advice } main "$@"