Files
linux-on-android-without-root/provision/adb-wireless.sh
T
StefanandClaude Opus 5 915fe53eeb Mehrere Geräte gleichzeitig unterstützen
Ein bereits verbundenes Gerät war bisher ein Grund auszusteigen, und provision.sh
brach bei mehr als einem sogar ab. Beim Gerätewechsel ist genau das aber der
Normalfall: altes und neues Telefon müssen zusammen erreichbar sein, sonst lässt
sich nichts klonen.

adb-wireless.sh zeigt jetzt die verbundenen Geräte mit Hersteller und Modell und
bietet an, weiterzugehen, ein weiteres Gerät aufzunehmen oder eines zu trennen.
provision.sh fragt bei mehreren, welches eingerichtet werden soll.

Die Auswahl landet in ADB_SERIAL, und die adb-Hülle in lib.sh ergänzt -s
selbsttätig — aber nur bei Unterbefehlen, die sich an ein Gerät richten.
'adb -s X devices' oder 'adb -s X connect' wären Unsinn und würden fehlschlagen.

Dazu eine Korrektur, die beim Hinzufügen sonst falsch angeschlagen hätte: nach
dem Koppeln reicht 'irgendein Gerät verbunden' als Erfolgsnachweis nicht, denn
das erste Telefon ist ja noch da. Gezählt wird jetzt, ob eines DAZUGEKOMMEN ist.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-09 18:12:57 +02:00

290 lines
11 KiB
Bash
Executable File

#!/usr/bin/env bash
# HPOS — ADB über WLAN verbinden, ohne USB-Kabel.
#
# Android 11 und neuer bringen "Wireless Debugging" mit: einmal per sechsstelligem
# Code koppeln, danach verbindet sich adb über das Netz. Ein Kabel wird nie gebraucht.
#
# Zwei Dinge, die regelmäßig für Verwirrung sorgen und die dieses Skript deshalb
# auseinanderhält:
#
# · Die KOPPLUNG bleibt dauerhaft bestehen. Nur die VERBINDUNG geht verloren,
# und der Port wechselt bei jedem Einschalten. Ein zweiter Kopplungscode wird
# daher nie gebraucht — deshalb wird immer erst ein Verbindungsversuch gemacht.
# · Kopplungsport und Verbindungsport sind VERSCHIEDEN. Der eine steht im
# Kopplungsfenster, der andere auf der Hauptseite von "Drahtloses Debugging".
#
# Aufruf: ./provision/adb-wireless.sh
# Umgebung: HPOS_ADB_MANUELL=1 überspringt die mDNS-Suche und fragt direkt nach
# der Adresse (nützlich, wenn das Netz kein
# Multicast durchlässt)
set -uo pipefail
source "$(dirname "$0")/lib.sh"
# Das Skript lebt von Rückfragen und liest bewusst aus /dev/tty statt von stdin —
# sonst würde eine Pipe die Antworten wegfressen. Ohne Terminal ist das aussichtslos,
# und ein klarer Hinweis ist besser als eine Kette von /dev/tty-Fehlern.
# Umleitungen wertet bash von links nach rechts aus — 2>/dev/null muss deshalb VOR
# dem Schreibversuch stehen, sonst landet der Fehler trotzdem auf dem Bildschirm.
if ! { : 2>/dev/null >/dev/tty; }; then
fehl "Dieses Skript braucht ein Terminal für die Rückfragen."
hinweis "Bitte direkt in einer Shell aufrufen, nicht in einer Pipe oder aus einem Dienst."
exit 1
fi
kopf "Werkzeug"
if adb_einrichten; then
ok "adb $(adb_version "$ADB_BIN") — kann WLAN-Kopplung"
hinweis "$ADB_BIN"
else
fehl "Ohne 'adb pair' ist eine Kopplung über WLAN nicht möglich."
hinweis "Entweder aktuelle platform-tools installieren, oder doch ein Kabel besorgen."
exit 1
fi
adb start-server >/dev/null 2>&1
# ── Hilfsmittel ──────────────────────────────────────────────────────────────
ist_verbunden() { adb devices | grep -qw 'device$'; }
anzahl_geraete() { adb_geraete | wc -l | tr -d ' '; }
# Nach dem Koppeln reicht "irgendein Gerät verbunden" als Erfolgsnachweis nicht:
# beim Hinzufügen eines zweiten Telefons wäre das erste ja noch da. Es zählt nur,
# ob EIN GERÄT DAZUGEKOMMEN ist.
GERAETE_VORHER=0
neues_geraet() { [ "$(anzahl_geraete)" -gt "$GERAETE_VORHER" ]; }
# Sucht einen mDNS-Dienst und gibt HOST:PORT zurück. Der Kopplungsdienst wird nur
# angekündigt, solange der Kopplungsdialog auf dem Telefon offen ist — deshalb wird
# wiederholt gesucht statt einmal.
suche_dienst() {
local typ="$1" versuche="${2:-15}" i zeile
for ((i = 1; i <= versuche; i++)); do
zeile=$(adb mdns services 2>/dev/null | awk -v t="$typ" '$2 == t {print $3; exit}')
if [ -n "$zeile" ]; then printf '%s' "$zeile"; return 0; fi
printf '.' >&2
sleep 1
done
return 1
}
plausibel() {
case "$1" in
*:[0-9]*) return 0 ;;
*) return 1 ;;
esac
}
# Wie die Adresse ermittelt wird — einmal gefragt, dann für beide Schritte gemerkt.
# mDNS ist bequem, scheitert aber in Netzen, die Multicast filtern. Das ist keine
# Seltenheit und kein Fehler des Nutzers, deshalb steht die manuelle Eingabe
# gleichberechtigt daneben statt nur als Notnagel nach einer Wartezeit.
ADRESS_MODUS="${HPOS_ADB_MANUELL:+manuell}"
modus_erfragen() {
[ -n "$ADRESS_MODUS" ] && return 0
{
printf '\n Wie soll die Adresse ermittelt werden?\n\n'
printf ' [m] automatisch per mDNS (bequem, scheitert in manchen Netzen)\n'
printf ' [e] von Hand eingeben (Adresse steht auf dem Telefon)\n\n'
printf ' Auswahl [m] > '
} >&2
local wahl
read -r wahl </dev/tty || wahl=m
case "${wahl:-m}" in
e|E) ADRESS_MODUS=manuell ;;
*) ADRESS_MODUS=mdns ;;
esac
}
# Liefert HOST:PORT auf stdout. Alle Ausgaben für den Menschen gehen nach stderr,
# damit der Rückgabewert nicht verschmutzt wird.
adresse_holen() {
local typ="$1" wo="$2" wartezeit="${3:-15}" ziel
modus_erfragen
while :; do
if [ "$ADRESS_MODUS" = mdns ]; then
printf ' Suche per mDNS ' >&2
if ziel=$(suche_dienst "$typ" "$wartezeit"); then
printf '\n' >&2
ok "gefunden: $ziel" >&2
printf '%s' "$ziel"
return 0
fi
printf '\n' >&2
warn "Per mDNS nichts gefunden." >&2
hinweis "Viele Netze filtern Multicast — dann hilft nur die Eingabe von Hand." >&2
ADRESS_MODUS=manuell
continue
fi
hinweis "$wo" >&2
printf ' Adresse eingeben (IP:PORT), [m] für mDNS, leer für Abbruch > ' >&2
read -r ziel </dev/tty || ziel=""
case "$ziel" in
"") return 1 ;;
m|M) ADRESS_MODUS=mdns; continue ;;
esac
if plausibel "$ziel"; then
printf '%s' "$ziel"
return 0
fi
warn "Das sieht nicht nach IP:PORT aus — der Port gehört dazu." >&2
hinweis "Beispiel: 192.168.178.42:37123" >&2
done
}
weiter_mit_provision() {
adb devices | grep -w 'device$' | sed 's/^/ /'
kopf "Fertig"
cat <<'TEXT'
Weiter mit:
./provision/provision.sh
Für später: die Kopplung bleibt bestehen. Nach einem Neustart oder nach dem
Aus- und Einschalten von "Drahtloses Debugging" ändert sich nur der Port —
dann genügt dieses Skript erneut, ohne neuen Code.
ADB wird in diesem Projekt nur für die Ersteinrichtung gebraucht. Im
Dauerbetrieb kommt HPOS ohne Privilegienkanal aus.
Trennen mit: adb disconnect
TEXT
}
WO_VERBINDUNG="Auf dem Telefon: Drahtloses Debugging → 'IP-Adresse und Port' (Hauptseite)"
WO_KOPPLUNG="Auf dem Telefon: im Fenster 'Mit Kopplungscode koppeln' (ANDERER Port!)"
# ── Schon verbunden? ─────────────────────────────────────────────────────────
# Ein bereits verbundenes Gerät darf kein Grund sein auszusteigen: ein zweites
# Telefon dazuzunehmen ist ein völlig normaler Wunsch, etwa beim Gerätewechsel,
# wenn altes und neues Gerät gleichzeitig erreichbar sein müssen.
kopf "Aktueller Stand"
if ist_verbunden; then
ok "Verbundene Geräte:"
while IFS= read -r S; do
[ -n "$S" ] && printf ' %-24s %s\n' "$S" "$(geraet_beschreiben "$S")"
done < <(adb_geraete)
cat <<'TEXT'
Was möchtest du tun?
[w] weiter zur Einrichtung (provision.sh übernimmt die Auswahl)
[n] ein weiteres Gerät hinzufügen (Kopplung oder Verbindung)
[t] ein verbundenes Gerät trennen
[a] abbrechen
TEXT
printf '\n Auswahl [w] > '
read -r AKTION </dev/tty || AKTION=w
case "${AKTION:-w}" in
n|N) hinweis "Gut — weiter mit dem neuen Gerät." ;;
t|T)
printf ' Welche Adresse trennen? (leer = alle) > '
read -r TRENNEN </dev/tty || TRENNEN=""
if [ -n "$TRENNEN" ]; then adb disconnect "$TRENNEN"; else adb disconnect; fi
ok "Getrennt."
exit 0
;;
a|A) hinweis "Abgebrochen."; exit 0 ;;
*) weiter_mit_provision; exit 0 ;;
esac
fi
# Stand festhalten, BEVOR etwas dazukommt — daran wird der Erfolg gemessen.
GERAETE_VORHER=$(anzahl_geraete)
# ── Erst verbinden, dann erst koppeln ────────────────────────────────────────
# Wer schon einmal gekoppelt hat, braucht keinen neuen Code, sondern nur ein neues
# connect. Ohne diesen Schritt landet man bei jedem Aufruf wieder im Kopplungsdialog.
printf '\n Wurde DIESES Telefon hier schon einmal gekoppelt? [j/N] > '
read -r SCHON_GEKOPPELT </dev/tty || SCHON_GEKOPPELT=n
case "${SCHON_GEKOPPELT:-n}" in
j|J)
kopf "Verbinden"
hinweis "Kopplung besteht bereits — es fehlt nur die Verbindung."
if ZIEL=$(adresse_holen _adb-tls-connect._tcp "$WO_VERBINDUNG" 15); then
adb connect "$ZIEL"
sleep 2
if neues_geraet; then
ok "Verbunden"
weiter_mit_provision
exit 0
fi
warn "Verbindung kam nicht zustande."
adb devices | sed 's/^/ /'
hinweis "Steht dort 'unauthorized', den Dialog auf dem Telefon bestätigen."
hinweis "Sonst war die Kopplung doch nicht mehr gültig — weiter zur Neukopplung."
else
hinweis "Abgebrochen — weiter zur Kopplung."
fi
;;
esac
# ── Kopplung ─────────────────────────────────────────────────────────────────
kopf "Auf dem Telefon"
cat <<'TEXT'
1. Telefon und dieser Rechner müssen im SELBEN WLAN sein.
Gäste-WLAN oder aktive Client-Isolierung verhindern die Verbindung.
2. Einstellungen → System → Entwickleroptionen → "Drahtloses Debugging" EIN
3. Dort auf "Gerät mit Kopplungscode koppeln" tippen.
Es erscheint ein sechsstelliger Code und eine Adresse.
Dieses Fenster BITTE OFFEN LASSEN, bis die Kopplung durch ist —
der Kopplungsdienst verschwindet sonst sofort wieder.
TEXT
printf '\n Wenn das Fenster mit dem Code offen ist, hier Enter drücken > '
read -r _ </dev/tty
kopf "Kopplungsadresse"
if ! PAIR_ZIEL=$(adresse_holen _adb-tls-pairing._tcp "$WO_KOPPLUNG" 20); then
fehl "Ohne Adresse geht es nicht."
exit 1
fi
printf ' Sechsstelligen Kopplungscode eingeben > '
read -r CODE </dev/tty
kopf "Koppeln"
if adb pair "$PAIR_ZIEL" "$CODE"; then
ok "Kopplung erfolgreich"
else
fehl "Kopplung fehlgeschlagen."
hinweis "Häufigste Ursachen: Code abgelaufen (er gilt nur kurz),"
hinweis "Fenster zu früh geschlossen, oder Telefon in einem anderen Netz."
exit 1
fi
# ── Verbinden ────────────────────────────────────────────────────────────────
kopf "Verbinden"
hinweis "Das Kopplungsfenster kann jetzt geschlossen werden."
# Neuere adb-Fassungen verbinden nach dem Koppeln von selbst über mDNS.
sleep 3
if neues_geraet; then
ok "Verbindung stand bereits nach dem Koppeln"
weiter_mit_provision
exit 0
fi
if ! ZIEL=$(adresse_holen _adb-tls-connect._tcp "$WO_VERBINDUNG" 20); then
fehl "Ohne Adresse geht es nicht."
hinweis "Die Kopplung ist aber erfolgt — beim nächsten Aufruf 'j' antworten."
exit 1
fi
adb connect "$ZIEL"
sleep 2
if neues_geraet; then
ok "Verbunden"
weiter_mit_provision
exit 0
fi
fehl "Verbindung kam nicht zustande."
adb devices | sed 's/^/ /'
hinweis "Steht dort 'unauthorized', den Dialog auf dem Telefon bestätigen."
hinweis "Die Kopplung ist erfolgt — beim nächsten Aufruf 'j' antworten."
exit 1