#!/usr/bin/env bash # Phase 0 — Grundinstallation in Termux. # # Richtet Termux-X11, den GPU-Pfad und ein Debian-13-Rootfs ein, damit die Beweise # S1 bis S4 danach laufen können. Idempotent: mehrfaches Ausführen ist unschädlich. # # Ausführen IN TERMUX auf dem Telefon: bash spike/00-bootstrap-termux.sh set -uo pipefail source "$(dirname "$0")/lib.sh" require_termux DISTRO=debian BIND_ROOT="$REPO_ROOT" log "HPOS Phase 0 — Bootstrap" log "Protokoll: $LOG" geraete_steckbrief # ── Repositories ───────────────────────────────────────────────────────────── # x11-repo bringt Termux-X11 und virglrenderer, tur-repo die Mesa-/Turnip-Pakete. section "Paketquellen" try pkg update -y try pkg install -y x11-repo tur-repo try pkg update -y # Vollupgrade vor allen Einzelinstallationen. Termux verträgt keine Teilupgrades: # die Pakete werden gegeneinander gebaut, und ein einzeln nachinstalliertes trifft # sonst auf veraltete Abhängigkeiten. Genau daran ist proot-distro gescheitert. # init-phone.sh macht das schon; wer direkt hier einsteigt, bekommt es hier. section "Termux auf einen Stand bringen" if [ "${HPOS_OHNE_UPGRADE:-0}" = 1 ]; then warn "Übersprungen (HPOS_OHNE_UPGRADE=1)" else export DEBIAN_FRONTEND=noninteractive # --force-confold: vorhandene Konfiguration behalten, statt mitten im Lauf # eine Rückfrage zu stellen, die niemand beantwortet. if try pkg upgrade -y -o Dpkg::Options::=--force-confold; then ok "Termux ist aktuell" else warn "Upgrade brach ab — versuche zu reparieren." # Dateikonflikt gezielt behandeln: entsteht, wenn ein Paket aufgeteilt # wurde und beide Teile kurzzeitig dieselbe Datei mitbringen — bei Termux # etwa libmagic, herausgelöst aus file. --force-overwrite wird bewusst nur # dann gesetzt, wenn der Konflikt im Protokoll nachgewiesen ist; pauschal # hieße es, jede künftige Dateikollision stillschweigend zu übergehen. if grep -q 'which is also in package' "$LOG" 2>/dev/null; then warn "Dateikonflikt zwischen zwei Paketen erkannt:" grep 'trying to overwrite' "$LOG" | tail -3 | sed 's/^/ /' | tee -a "$LOG" hint "Typisch bei einer Paketaufteilung. Wiederhole mit --force-overwrite." try pkg upgrade -y -o Dpkg::Options::=--force-confold \ -o Dpkg::Options::=--force-overwrite fi # Meist scheitert ein einzelnes Paket beim Auspacken, danach steckt dpkg # halb fertig fest und blockiert jede weitere Installation. try dpkg --configure -a try apt-get -f install -y if try pkg upgrade -y -o Dpkg::Options::=--force-confold \ -o Dpkg::Options::=--force-overwrite; then ok "Nach der Reparatur durchgelaufen" else warn "Bleibt unvollständig." hint "Speicherplatz: df -h \$PREFIX" hint "Freier Platz unter etwa 1 GB ist die häufigste Ursache." hint "Fehler ohne Rauschen: pkg upgrade -y 2>&1 | grep -viE 'unable to delete' | tail -20" hint "Die vielen 'unable to delete old directory' sind Warnungen, keine Fehler." fi fi # Platz prüfen, solange es noch nicht weh tut: das Debian-Rootfs samt Plasma # Mobile braucht mehrere GB, und ein Abbruch mitten im Entpacken ist ärgerlicher # als eine Warnung vorher. FREI_KB=$(df -Pk "$PREFIX" 2>/dev/null | awk 'NR==2 {print $4}') if [ -n "$FREI_KB" ]; then log " Freier Speicher: $((FREI_KB / 1024)) MB" [ "$FREI_KB" -lt 2000000 ] && warn "Unter 2 GB frei — für Debian plus Plasma Mobile knapp." fi fi # ── Basispakete ────────────────────────────────────────────────────────────── # Einzeln installiert und einzeln protokolliert: Paketnamen wandern in Termux # gelegentlich, und wir wollen wissen, WELCHES Paket fehlt, statt nur dass etwas fehlt. section "Basispakete" BASIS=(termux-x11-nightly pulseaudio proot-distro termux-api git python openssl termux-tools) for p in "${BASIS[@]}"; do if try pkg install -y "$p"; then ok "$p"; else fail "$p — fehlt, betroffene Beweise siehe unten"; fi done # ── GPU-Pfad ───────────────────────────────────────────────────────────────── # Adreno 6xx/7xx → Turnip greift direkt auf KGSL zu, das ist der schnellste Weg. # Mali und alles andere → virgl/ANGLE. Wir installieren beides und entscheiden # zur Laufzeit; das Ergebnis landet im GPU-Profil. section "GPU-Pakete" GPU_PKGS=(virglrenderer-android vulkan-loader-android vulkan-tools angle-android mesa-zink virglrenderer-mesa-zink) for p in "${GPU_PKGS[@]}"; do if try pkg install -y "$p"; then ok "$p"; else warn "$p nicht verfügbar — kein Beinbruch"; fi done # Der Vulkan-Treiber ist der einzige GPU-Teil, der wirklich zählt: ohne ihn bleibt # nur Software-Rendering. Die Paketnamen haben sich in Termux mehrfach geändert, # deshalb werden mehrere Kandidaten probiert, bis einer greift. section "Vulkan-Treiber (Turnip)" ICD_KANDIDATEN=(mesa-vulkan-icd-freedreno mesa-vulkan-icd-wrapper mesa-vulkan-icd-wrapper-android mesa-vulkan-icd-swrast) ICD_GEFUNDEN="" for p in "${ICD_KANDIDATEN[@]}"; do if pkg install -y "$p" >>"$LOG" 2>&1; then ICD_GEFUNDEN="$p" ok "$p installiert" break fi hint "$p — nicht verfügbar" done if [ -z "$ICD_GEFUNDEN" ]; then warn "Kein Vulkan-Treiber installierbar." hint "Ohne ihn läuft der Desktop im Software-Rendering — S1 wird träge," hint "sagt aber trotzdem etwas über die Machbarkeit aus." hint "Verfügbare Kandidaten prüfen: pkg search mesa-vulkan" fi section "GPU erkennen" PLATFORM="$(getprop ro.board.platform 2>/dev/null)" HARDWARE="$(getprop ro.hardware 2>/dev/null)" GPU_PROFIL="virgl" # konservative Vorgabe if have vulkaninfo; then vulkaninfo --summary >>"$LOG" 2>&1 || true GPU_NAME="$(vulkaninfo --summary 2>/dev/null | grep -m1 -i 'deviceName' | cut -d= -f2- | xargs)" else GPU_NAME="" fi log " Plattform = ${PLATFORM:-?}" log " Hardware = ${HARDWARE:-?}" log " GPU = ${GPU_NAME:-unbekannt}" case "${GPU_NAME}${PLATFORM}" in *[Aa]dreno*|*qcom*|*sm[0-9]*|*msm*) GPU_PROFIL="turnip" ok "Adreno erkannt → Turnip-Profil (direkter KGSL-Zugriff, schnellster Weg)" ;; *[Mm]ali*) GPU_PROFIL="virgl" warn "Mali erkannt → virgl/ANGLE-Profil. Spürbar langsamer als Turnip." ;; *) warn "GPU nicht eindeutig erkannt → virgl als Vorgabe." hint "Bitte im Spike-Protokoll vermerken, welcher Pfad tatsächlich getragen hat." ;; esac # Das Profil ist eine Datei, kein Sonderfall im Code — so bleibt es später # erweiterbar, ohne dass jemand Skripte anfassen muss. mkdir -p "$REPO_ROOT/rootfs/profiles" PROFIL_DATEI="$OUT_DIR/gpu-profil.env" { echo "# Automatisch erkannt von 00-bootstrap-termux.sh" echo "HPOS_GPU_PROFIL=$GPU_PROFIL" echo "HPOS_GPU_NAME=\"${GPU_NAME:-unbekannt}\"" echo "HPOS_PLATFORM=\"${PLATFORM:-unbekannt}\"" } >"$PROFIL_DATEI" ok "GPU-Profil geschrieben: $PROFIL_DATEI ($GPU_PROFIL)" # ── Termux-Eigenschaften ───────────────────────────────────────────────────── # allow-external-apps ist die Voraussetzung dafür, dass die Bridge-APK später # Kommandos in Termux anstoßen darf. Hier gesetzt, damit Phase 2 es vorfindet. section "Termux-Eigenschaften" TP="$HOME/.termux/termux.properties" mkdir -p "$(dirname "$TP")" touch "$TP" if grep -q '^allow-external-apps' "$TP" 2>/dev/null; then ok "allow-external-apps bereits gesetzt" else echo 'allow-external-apps = true' >>"$TP" ok "allow-external-apps = true gesetzt" hint "Wird erst nach 'termux-reload-settings' oder Neustart von Termux wirksam." fi try termux-reload-settings section "Speicherzugriff" if [ -d "$HOME/storage" ]; then ok "Speicherzugriff bereits eingerichtet" else warn "termux-setup-storage wird gleich einen Berechtigungsdialog zeigen — bitte erlauben." try termux-setup-storage sleep 2 [ -d "$HOME/storage" ] && ok "Speicherzugriff eingerichtet" || fail "Speicherzugriff fehlt — Backup nach /sdcard geht später nicht" fi # ── Wachhalten ─────────────────────────────────────────────────────────────── # Ohne Wake-Lock schläft der Stack weg, sobald der Bildschirm aus geht. # Die herstellerseitigen Maßnahmen kommen zusätzlich, siehe provision/. section "Wake-Lock" try termux-wake-lock && ok "Wake-Lock aktiv" || warn "Wake-Lock nicht gesetzt" # ── Debian-Rootfs ──────────────────────────────────────────────────────────── section "Debian-Rootfs" # Erst prüfen, ob proot-distro überhaupt LÄUFT. Ein installiertes Paket, dessen # Shebang-Interpreter fehlt, meldet sich mit "cannot execute: required file not # found" — eine Meldung, die aussieht als fehle das Programm, obwohl es da ist. if ! proot-distro list >/dev/null 2>&1; then fail "proot-distro ist installiert, lässt sich aber nicht ausführen" PD="$(command -v proot-distro)" SHEBANG="$(head -1 "$PD" 2>/dev/null)" INTERPRETER="$(printf '%s' "$SHEBANG" | sed 's|^#!||; s| .*||')" log " Datei: $PD" log " Shebang: $SHEBANG" log " Interpreter: ${INTERPRETER:-(keiner)}" if [ -n "$INTERPRETER" ] && [ ! -x "$INTERPRETER" ]; then fail "Der Interpreter fehlt — nicht proot-distro selbst." log "" log " Das ist der klassische Termux-Teilupgrade-Fehler: das Paket wurde gegen" log " eine Fassung gebaut, installiert ist eine andere. Termux verträgt keine" log " Teilupgrades — hier hilft nur, alles auf denselben Stand zu bringen." # Schritt 1: fehlendes Paket nachziehen. Bei python3.x heißt es schlicht python. case "$(basename "$INTERPRETER")" in python3*|python) try pkg install -y python ;; bash) try pkg install -y bash ;; *) try pkg install -y "$(basename "$INTERPRETER")" ;; esac # Schritt 2: Vollupgrade. Das ist die eigentliche Reparatur. if [ ! -x "$INTERPRETER" ]; then log "" warn "Reicht nicht — jetzt das Vollupgrade. Das dauert und lädt einiges." try pkg update -y try pkg upgrade -y try pkg install -y proot proot-distro fi # Schritt 3: Notnagel. Nur für Python, und nur weil proot-distro reines # Python ohne kompilierte Erweiterungen ist — sonst wäre eine Version # überzustülpen grob fahrlässig. if [ ! -x "$INTERPRETER" ]; then case "$(basename "$INTERPRETER")" in python3.*) VORHANDEN="$(ls "$PREFIX/bin"/python3.* 2>/dev/null | grep -v config | head -1)" if [ -n "$VORHANDEN" ]; then log "" warn "Notnagel: verweise $(basename "$INTERPRETER") auf $(basename "$VORHANDEN")" hint "Vertretbar, weil proot-distro reines Python ist." hint "Sauber wird es erst mit einem vollständigen 'pkg upgrade'." ln -sf "$VORHANDEN" "$INTERPRETER" && ok "Verweis angelegt" fi ;; esac fi else try pkg install -y bash coreutils proot proot-distro fi if ! proot-distro list >/dev/null 2>&1; then fail "Bleibt defekt — ohne proot-distro geht es nicht weiter." log "" log " Von Hand versuchen, in dieser Reihenfolge:" log " pkg update && pkg upgrade -y # Vollupgrade, keine Teilschritte" log " pkg install -y python proot proot-distro" log " termux-change-repo # falls der Spiegel unstimmig ist" exit 1 fi ok "proot-distro läuft wieder" fi if proot-distro list --installed 2>/dev/null | grep -q "^$DISTRO\b" \ || [ -d "$PREFIX/var/lib/proot-distro/installed-rootfs/$DISTRO" ]; then ok "$DISTRO bereits installiert" else log " Installiere $DISTRO — das dauert einige Minuten." need proot-distro install "$DISTRO" ok "$DISTRO installiert" fi section "Debian-Grundausstattung" # Der Bind macht das Repo im Rootfs unter /hpos sichtbar, damit die inneren # Skripte dieselben Dateien benutzen und Ergebnisse am selben Ort landen. proot-distro login "$DISTRO" --bind "$BIND_ROOT:/hpos" -- bash -lc ' set -uo pipefail export DEBIAN_FRONTEND=noninteractive apt-get update -qq apt-get install -y --no-install-recommends \ ca-certificates locales dbus-x11 sudo nano less procps \ mesa-utils vulkan-tools pulseaudio-utils # Deutsche und englische Locale, sonst meckert die halbe Desktop-Software. sed -i "s/^# *\(de_DE.UTF-8\|en_US.UTF-8\)/\1/" /etc/locale.gen locale-gen >/dev/null 2>&1 echo "--- Debian-Version ---"; cat /etc/debian_version ' 2>&1 | tee -a "$LOG" # ── Abschluss ──────────────────────────────────────────────────────────────── section "Bereit" log "GPU-Profil : $GPU_PROFIL" log "Rootfs : $DISTRO" log "Repo im Rootfs sichtbar unter /hpos" log "" log "Nächste Schritte, in dieser Reihenfolge:" log " bash spike/01-s1-plasma-mobile.sh # der wackligste Beweis, deshalb zuerst" log " bash spike/02-s2-mikrofon.sh" log " bash spike/03-s3-pipewire-kamera.sh" log " bash spike/04-s4-intent-handoff.sh" log "" log "Vor dem Übernacht-Test bitte provision/provision.sh vom PC laufen lassen" log "und die herstellerseitigen Handgriffe aus docs/machbarkeit.md erledigen."