Files
linux-on-android-without-root/provision/provision.sh
T
StefanandClaude Opus 5 14f054c8e3 Entwicklerzugang: SSH nach Termux, sshfs, scrcpy
Auf der Bildschirmtastatur eines Telefons lässt sich nicht arbeiten. Zwei Wege,
die sich ergänzen: SSH für alles Textliche, scrcpy für alles, was man sehen muss —
Beweis S1 zeigt sich nur auf dem Bildschirm, die Kamera in S3 prüft man im Browser.

tools/dev-ssh.sh richtet Termux' sshd ein (Port 8022, weil eine gewöhnliche App
keine Ports unter 1024 belegen darf). Schlüssel vor Passwort: ein Passwort auf der
Bildschirmtastatur einzutippen ist mühsam, und wer es sich deshalb kurz wählt, hat
einen offenen Dienst im WLAN. provision.sh legt den öffentlichen Schlüssel des
Rechners deshalb gleich mit ab.

Über sshfs lassen sich die Dateien des Telefons im Editor des Rechners öffnen —
kein Hin- und Herkopieren mehr.

docs/entwicklung.md beschreibt beides samt Richtung der Änderungen: entwickelt
wird auf dem Rechner, das Telefon führt nur aus und holt per git pull. Genau
deshalb kommt per adb auch nur das Startskript aufs Gerät.

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

364 lines
16 KiB
Bash
Executable File

#!/usr/bin/env bash
# HPOS — Ersteinrichtung vom PC aus, per ADB.
#
# ADB wird ausschließlich hier gebraucht, einmalig. Im Dauerbetrieb kommt das
# System mit gewöhnlichen App-Berechtigungen aus — das ist eine harte Regel des
# Projekts, siehe CONTRIBUTING.md.
#
# Voraussetzung: Entwickleroptionen aktiv. Die Verbindung geht per USB-Kabel ODER
# per WLAN (Android 11 und neuer) — das Skript fragt danach, wenn kein Gerät da ist.
#
# Aufruf: ./provision/provision.sh [--dry-run]
set -uo pipefail
TERMUX=com.termux
TROCKEN=0
[ "${1:-}" = "--dry-run" ] && TROCKEN=1
source "$(dirname "$0")/lib.sh"
# Wählt eine adb-Fassung aus, statt sich auf die Reihenfolge in PATH zu verlassen:
# Debians Paket ist Version 29 und kennt kein 'adb pair'. Rückgabewert 2 heißt
# "gefunden, aber zu alt für WLAN" — für USB reicht es trotzdem.
ADB_KANN_WLAN=1
adb_einrichten || ADB_KANN_WLAN=0
# Führt ein adb-Kommando aus und meldet das Ergebnis, ohne bei Fehlschlag
# abzubrechen: Hersteller-ROMs kennen nicht jedes appops-Ziel, und ein fehlendes
# ist kein Grund, die restliche Einrichtung liegen zu lassen.
adbs() {
local beschreibung="$1"; shift
if [ "$TROCKEN" = 1 ]; then
printf '%s ? %s%s (adb shell %s)\n' "$C_DIM" "$beschreibung" "$C_OFF" "$*"
return 0
fi
local aus
if aus=$(adb shell "$@" 2>&1); then
if printf '%s' "$aus" | grep -qiE 'error|exception|denied|unknown'; then
warn "$beschreibung — ROM hat abgelehnt"
hinweis "$(printf '%s' "$aus" | head -1)"
return 1
fi
ok "$beschreibung"
return 0
fi
warn "$beschreibung — fehlgeschlagen"
hinweis "$(printf '%s' "$aus" | head -1)"
return 1
}
# ── Gerät ────────────────────────────────────────────────────────────────────
kopf "Gerät"
hinweis "adb $(adb_version "$ADB_BIN")$ADB_BIN"
HIER="$(cd "$(dirname "$0")" && pwd)"
ANZAHL=$(adb devices | grep -cw 'device$' || true)
# Ohne Gerät nicht einfach abbrechen: der häufigste Fall ist, dass gar kein Kabel
# zur Hand ist. Android 11+ kann Wireless Debugging, das reicht für alles hier.
if [ "$ANZAHL" -eq 0 ]; then
warn "Kein Gerät verbunden."
if [ ! -t 0 ]; then
hinweis "Keine Eingabe möglich — bitte erst ./provision/adb-wireless.sh ausführen."
exit 1
fi
cat <<'TEXT'
Wie soll verbunden werden?
[u] USB-Kabel
Entwickleroptionen und USB-Debugging aktiv, Dialog "Diesem Computer
vertrauen" auf dem Telefon bestätigt.
[w] WLAN, ohne Kabel (Android 11 und neuer)
Einmalige Kopplung per sechsstelligem Code. Danach läuft alles
über das Netz — ein Kabel wird nie gebraucht.
[a] Abbrechen
TEXT
[ "$ADB_KANN_WLAN" = 0 ] && warn "Achtung: das gefundene adb kann kein WLAN — [w] wird scheitern."
printf '\n Auswahl > '
read -r WAHL </dev/tty
case "$WAHL" in
w|W)
if [ ! -x "$HIER/adb-wireless.sh" ]; then
fehl "adb-wireless.sh nicht gefunden neben diesem Skript."
exit 1
fi
"$HIER/adb-wireless.sh" || exit 1
ANZAHL=$(adb devices | grep -cw 'device$' || true)
;;
u|U)
printf ' Kabel anschließen und Enter drücken > '
read -r _ </dev/tty
adb wait-for-device &
WARTE=$!
# Nicht ewig hängen bleiben, falls das Kabel nur lädt und keine Daten überträgt.
( sleep 60; kill "$WARTE" 2>/dev/null ) >/dev/null 2>&1 &
wait "$WARTE" 2>/dev/null
ANZAHL=$(adb devices | grep -cw 'device$' || true)
;;
*)
hinweis "Abgebrochen."
exit 0
;;
esac
if [ "$ANZAHL" -eq 0 ]; then
fehl "Es ist weiterhin kein Gerät verbunden."
adb devices | sed 's/^/ /'
hinweis "Steht dort 'unauthorized', den Dialog auf dem Telefon bestätigen."
exit 1
fi
ok "Gerät verbunden"
fi
# Mehrere Geräte sind kein Fehler, sondern der Normalfall beim Gerätewechsel:
# altes und neues Telefon müssen gleichzeitig erreichbar sein. Statt abzubrechen
# wird gefragt — und die Auswahl gilt danach für ALLE folgenden Befehle, weil die
# adb-Hülle in lib.sh selbsttätig -s ergänzt.
if ! geraet_waehlen; then
fehl "Es ist kein Gerät verbunden."
exit 1
fi
for p in ro.product.manufacturer ro.product.model ro.product.device \
ro.build.version.release ro.board.platform; do
printf ' %-28s %s\n' "$p" "$(adb shell getprop "$p" 2>/dev/null | tr -d '\r')"
done
hinweis "Ziel: ${ADB_SERIAL:-(einziges Gerät)}"
[ "$TROCKEN" = 1 ] && warn "Trockenlauf — es wird nichts verändert."
# ── Termux vorhanden? ────────────────────────────────────────────────────────
kopf "Termux"
if adb shell pm list packages 2>/dev/null | tr -d '\r' | grep -q "^package:$TERMUX$"; then
ok "$TERMUX ist installiert"
else
fehl "$TERMUX ist nicht installiert."
cat <<'TEXT'
Termux muss zuerst aufs Telefon. WICHTIG: nicht aus dem Play Store — die
Fassung dort ist seit Jahren nicht mehr gepflegt und für dieses Projekt
unbrauchbar. Alle Bestandteile müssen aus derselben Quelle stammen, sonst
passen die Signaturen nicht zusammen und die Zusatz-Apps verweigern den Dienst.
Empfohlen — F-Droid:
Termux https://f-droid.org/packages/com.termux/
Termux:API https://f-droid.org/packages/com.termux.api/
Termux:Boot https://f-droid.org/packages/com.termux.boot/
Oder direkt von GitHub:
Termux https://github.com/termux/termux-app/releases/latest
Termux:API https://github.com/termux/termux-api/releases/latest
Termux:Boot https://github.com/termux/termux-boot/releases/latest
Termux:X11 gibt es nur bei GitHub (Nightly, app-universal-debug.apk):
https://github.com/termux/termux-x11/releases
Auf dem Telefon einfach im Browser öffnen und die APK installieren.
"Installation aus unbekannten Quellen" muss für den Browser erlaubt sein.
TEXT
if [ "$TROCKEN" != 1 ] && [ -x "$HIER/install-termux.sh" ]; then
cat <<'TEXT'
Das muss aber niemand von Hand machen: install-termux.sh lädt alle vier
Apps von GitHub und installiert sie über die bestehende adb-Verbindung —
per WLAN genauso wie per Kabel.
TEXT
printf '\n Jetzt automatisch installieren? [J/n] > '
read -r AUTOINSTALL </dev/tty || AUTOINSTALL=n
case "${AUTOINSTALL:-j}" in
j|J|"")
if ADB_SERIAL="$ADB_SERIAL" "$HIER/install-termux.sh"; then
ok "Termux ist installiert — weiter mit der Einrichtung."
hinweis "Bitte Termux einmal öffnen, damit es sein Dateisystem anlegt."
printf ' Wenn das erledigt ist, Enter drücken > '
read -r _ </dev/tty
else
fehl "Automatische Installation fehlgeschlagen."
exit 1
fi
;;
*)
hinweis "Dann von Hand — danach dieses Skript erneut aufrufen."
exit 1
;;
esac
else
printf '\n'
hinweis "Danach dieses Skript erneut aufrufen."
exit 1
fi
fi
# ── Hintergrundbetrieb, Android-Standardebene ────────────────────────────────
# Der Punkt, an dem das Konzept in der Praxis scheitern kann. Diese Maßnahmen
# überleben Neustarts. Die Entwickleroptionen helfen hier NICHT — sie betreffen
# nur gecachte Prozesse, nicht Vordergrunddienste.
kopf "Hintergrundbetrieb (Android-Standardebene)"
adbs "Aus der Doze-Beschränkung ausgenommen" dumpsys deviceidle whitelist "+$TERMUX"
adbs "RUN_IN_BACKGROUND erlaubt" cmd appops set "$TERMUX" RUN_IN_BACKGROUND allow
adbs "RUN_ANY_IN_BACKGROUND erlaubt" cmd appops set "$TERMUX" RUN_ANY_IN_BACKGROUND allow
adbs "Standby-Bucket auf 'never' gesetzt" am set-standby-bucket "$TERMUX" never
adbs "Adaptive Akkunutzung abgeschaltet" settings put global adaptive_battery_management_enabled 0
adbs "Akku-Optimierung ignoriert" cmd appops set "$TERMUX" REQUEST_IGNORE_BATTERY_OPTIMIZATIONS allow
# Die Zusatz-APKs, sofern schon installiert. Fehlen sie, ist das hier kein Problem.
for extra in com.termux.api com.termux.x11 com.termux.boot; do
if adb shell pm list packages 2>/dev/null | tr -d '\r' | grep -q "^package:$extra$"; then
adbs " $extra aus der Doze-Beschränkung" dumpsys deviceidle whitelist "+$extra"
adbs " $extra darf im Hintergrund laufen" cmd appops set "$extra" RUN_ANY_IN_BACKGROUND allow
fi
done
# ── Berechtigungen ───────────────────────────────────────────────────────────
kopf "Berechtigungen"
# Termux selbst braucht RECORD_AUDIO und Speicherzugriff — nicht nur Termux:API.
# PulseAudio läuft IM Termux-Prozess und öffnet das Mikrofon über OpenSL ES von
# dort aus. Eine Berechtigung, die nur Termux:API hat, nützt ihm nichts: das
# Modul lädt dann zwar, liefert aber keinen brauchbaren Ton.
for perm in \
android.permission.RECORD_AUDIO \
android.permission.READ_EXTERNAL_STORAGE \
android.permission.WRITE_EXTERNAL_STORAGE
do
adbs "${perm##*.} für Termux" pm grant "$TERMUX" "$perm" 2>/dev/null || true
done
# Termux:API bedient Kamera, Sensoren, Standort und Taschenlampe.
for perm in \
android.permission.RECORD_AUDIO \
android.permission.CAMERA \
android.permission.ACCESS_FINE_LOCATION \
android.permission.READ_EXTERNAL_STORAGE \
android.permission.WRITE_EXTERNAL_STORAGE
do
adbs "${perm##*.} für Termux:API" pm grant com.termux.api "$perm" 2>/dev/null || true
done
hinweis "Fehlschläge sind normal, solange Termux:API noch nicht installiert ist."
hinweis "Eine App, die eine Berechtigung gar nicht anmeldet, lässt sich nicht beschenken."
# ── Was ADB nicht kann ───────────────────────────────────────────────────────
kopf "Von Hand zu erledigen"
HERSTELLER=$(adb shell getprop ro.product.manufacturer 2>/dev/null | tr -d '\r')
cat <<TEXT
Die folgenden Punkte liegen unterhalb der Android-Mechanismen und sind per
ADB nicht zuverlässig erreichbar. Ohne sie beendet das ROM den Stack über Nacht.
1. Einstellungen → Apps → Termux → Akku → "Nicht optimieren"
2. Einstellungen → Akku → "Sleep Standby Optimization" ausschalten
3. Einstellungen → Akku → adaptive Akkunutzung ausschalten
4. Termux im Task-Manager anpinnen (Schloss-Symbol)
5. Für Overlay-Begleit-Apps: "Über anderen Apps anzeigen" erlauben
TEXT
case "$HERSTELLER" in
[Oo]ne[Pp]lus|OPPO|oppo|realme)
printf '\n%s Zu deinem Gerät:%s\n' "$C_WARN" "$C_OFF"
hinweis "OxygenOS/ColorOS friert Apps besonders aggressiv ein."
hinweis "Zusätzlich unter Einstellungen → Akku → Akkuoptimierung die"
hinweis "erweiterte bzw. 'intelligente' Optimierung für Termux abschalten."
;;
[Xx]iaomi|[Rr]edmi|[Pp]oco|samsung|Samsung)
printf '\n%s Zu deinem Gerät:%s\n' "$C_WARN" "$C_OFF"
hinweis "Dieser Hersteller ist für aggressives Beenden bekannt."
hinweis "Zusätzlich Autostart erlauben und die App von der Speicherbereinigung ausnehmen."
;;
esac
# ── Startskript aufs Telefon ─────────────────────────────────────────────────
# Bewusst NUR dieses eine Skript, nicht das ganze Repo. Es installiert git und
# klont die Quellen — danach ist auf dem Telefon eine Arbeitskopie, keine Kopie.
# Aktualisieren heißt dann 'git pull' statt jedes Mal wieder den PC anzuwerfen.
kopf "Startskript aufs Telefon"
REPO_ROOT="$(cd "$HIER/.." && pwd)"
REPO_URL="$(git -C "$REPO_ROOT" remote get-url origin 2>/dev/null || true)"
ZIEL=/sdcard/hpos-init.sh
if [ -z "$REPO_URL" ]; then
warn "Keine Repo-Adresse gefunden (kein origin-Remote gesetzt)."
hinweis "Ohne sie kann das Telefon die Quellen nicht holen."
printf ' Adresse von Hand eingeben (leer = überspringen) > '
read -r REPO_URL </dev/tty || REPO_URL=""
fi
# Benutzernamen entfernen: das Telefon liest nur, und Lesen geht anonym. Bliebe
# der Name in der Adresse, fragte git dort nach einem Passwort — auf einer
# Bildschirmtastatur eine unnötige Quälerei.
if [ -n "$REPO_URL" ]; then
REPO_URL_ROH="$REPO_URL"
REPO_URL=$(printf '%s' "$REPO_URL" | sed -E 's#^(https?://)[^/@]+@#\1#')
[ "$REPO_URL" != "$REPO_URL_ROH" ] && hinweis "Benutzername für das Telefon entfernt (Lesen geht anonym)"
fi
if [ "$TROCKEN" = 1 ]; then
warn "Trockenlauf — es wird nichts übertragen."
elif [ -z "$REPO_URL" ]; then
hinweis "Übersprungen."
else
hinweis "Repo: $REPO_URL"
printf ' Startskript nach %s übertragen? [J/n] > ' "$ZIEL"
read -r UEBERTRAGEN </dev/tty || UEBERTRAGEN=n
case "${UEBERTRAGEN:-j}" in
j|J|"")
# Adresse fest ins Skript schreiben, damit auf dem Telefon nichts
# abgetippt werden muss. sed mit | als Trenner, weil URLs Schrägstriche
# enthalten.
TMP=$(mktemp)
sed "s|@@REPO_URL@@|$REPO_URL|" "$HIER/init-phone.sh" >"$TMP"
if adb push "$TMP" "$ZIEL" >/dev/null 2>&1; then
ok "Übertragen nach $ZIEL"
else
warn "Übertragung fehlgeschlagen."
fi
rm -f "$TMP"
;;
*) hinweis "Übersprungen." ;;
esac
fi
# ── Entwicklerzugang ─────────────────────────────────────────────────────────
# Öffentlichen Schlüssel gleich mitschicken, damit später kein Passwort auf der
# Bildschirmtastatur eingetippt werden muss.
if [ "$TROCKEN" != 1 ]; then
PUBKEY=""
for k in ~/.ssh/id_ed25519.pub ~/.ssh/id_rsa.pub; do
[ -r "$k" ] && { PUBKEY="$k"; break; }
done
if [ -n "$PUBKEY" ]; then
kopf "Entwicklerzugang"
hinweis "Für SSH nach Termux — echte Tastatur statt Bildschirmtastatur."
printf ' Öffentlichen Schlüssel (%s) aufs Telefon legen? [J/n] > ' "$(basename "$PUBKEY")"
read -r SCHLUESSEL </dev/tty || SCHLUESSEL=n
case "${SCHLUESSEL:-j}" in
j|J|"")
if adb push "$PUBKEY" /sdcard/hpos-id.pub >/dev/null 2>&1; then
ok "Schlüssel abgelegt unter /sdcard/hpos-id.pub"
hinweis "Auf dem Telefon einrichten: bash ~/hpos/tools/dev-ssh.sh"
else
warn "Übertragung fehlgeschlagen"
fi
;;
esac
fi
fi
kopf "Fertig"
cat <<TEXT
Nächste Schritte auf dem Telefon, in Termux:
bash /sdcard/hpos-init.sh # installiert git und klont das Repo
cd ~/hpos
bash spike/00-bootstrap-termux.sh
Ab dann genügt zum Aktualisieren:
cd ~/hpos && git pull
Danach die Beweise der Reihe nach — S1 zuerst, weil er der wackligste ist.
Ergebnisse gehören nach docs/spike-protokoll.md.
Nicht vergessen: die oben genannten Handgriffe von Hand erledigen.
Ohne sie beendet das ROM den Stack über Nacht.
TEXT