Compare commits
24
Commits
a58754dbfc
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ab847cc46f | ||
|
|
a3a6d7216b | ||
|
|
1caaeedef1 | ||
|
|
f3ef48fd10 | ||
|
|
c2b602dcb4 | ||
|
|
d4a6b59f81 | ||
|
|
3643cbd5cb | ||
|
|
ec76b785b3 | ||
|
|
985f48177d | ||
|
|
bafa2f3dd1 | ||
|
|
0e301f2455 | ||
|
|
95de7b6614 | ||
|
|
f20ad44e25 | ||
|
|
10851df46a | ||
|
|
ab4432cf84 | ||
|
|
7d0063278c | ||
|
|
488851101e | ||
|
|
603ad38fc3 | ||
|
|
3c41623e52 | ||
|
|
14f054c8e3 | ||
|
|
2d3c2fbc6d | ||
|
|
69802cde6b | ||
|
|
1cea1df9e7 | ||
|
|
c7221e18ad |
@@ -0,0 +1,61 @@
|
|||||||
|
---
|
||||||
|
name: Gerät melden
|
||||||
|
about: Ergebnis der Phase-0-Beweise auf deinem Telefon — Erfolg wie Fehlschlag
|
||||||
|
title: "[Gerät] Hersteller Modell (Android X)"
|
||||||
|
labels: geraet
|
||||||
|
---
|
||||||
|
|
||||||
|
**Ein Fehlschlag ist genauso wertvoll wie ein Erfolg.** Sauber dokumentiert zeigt er,
|
||||||
|
wo die Grenze verläuft — und das ist für andere oft nützlicher als eine weitere
|
||||||
|
Erfolgsmeldung. Bitte nichts beschönigen und nichts weglassen.
|
||||||
|
|
||||||
|
## Gerät
|
||||||
|
|
||||||
|
| | |
|
||||||
|
|---|---|
|
||||||
|
| Hersteller und Modell | |
|
||||||
|
| Codename (`getprop ro.product.device`) | |
|
||||||
|
| SoC / GPU | |
|
||||||
|
| Android-Version und ROM | |
|
||||||
|
| RAM / freier Speicher | |
|
||||||
|
|
||||||
|
## Ergebnisse
|
||||||
|
|
||||||
|
| Beweis | Ergebnis | Anmerkung |
|
||||||
|
|---|---|---|
|
||||||
|
| **S1** Plasma Mobile in proot | ⬜ bestanden / ⬜ gescheitert / ⬜ teilweise | |
|
||||||
|
| **S2** Mikrofon im Linux | ⬜ bestanden / ⬜ gescheitert / ⬜ teilweise | |
|
||||||
|
| **S3** Virtuelle PipeWire-Kamera | ⬜ bestanden / ⬜ gescheitert / ⬜ teilweise | |
|
||||||
|
| **S4** Intent-Handoff | ⬜ bestanden / ⬜ gescheitert / ⬜ teilweise | |
|
||||||
|
| **Übernacht-Test** | ⬜ bestanden / ⬜ gescheitert | |
|
||||||
|
|
||||||
|
## Leistung
|
||||||
|
|
||||||
|
| | |
|
||||||
|
|---|---|
|
||||||
|
| GPU-Pfad (Turnip / Zink / virgl / Software) | |
|
||||||
|
| `glmark2` | |
|
||||||
|
| Virtuelle Auflösung | |
|
||||||
|
| Akkuverbrauch im Leerlauf mit laufendem Stack | |
|
||||||
|
|
||||||
|
## Hintergrundbetrieb
|
||||||
|
|
||||||
|
Manche ROMs beenden Hintergrundprozesse deutlich aggressiver als andere. Das entscheidet
|
||||||
|
über die Alltagstauglichkeit, deshalb bitte ausfüllen:
|
||||||
|
|
||||||
|
- Welche Handgriffe waren nötig, damit der Stack eine Nacht überlebt?
|
||||||
|
- Was hat das ROM trotzdem beendet?
|
||||||
|
|
||||||
|
## Was schiefging
|
||||||
|
|
||||||
|
Bitte die Protokolle aus `spike/out/*.log` anhängen oder die entscheidenden Zeilen
|
||||||
|
einfügen. Interessant ist vor allem, **woran** etwas gescheitert ist — nicht nur, dass.
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>Protokoll</summary>
|
||||||
|
|
||||||
|
```
|
||||||
|
hier einfügen
|
||||||
|
```
|
||||||
|
|
||||||
|
</details>
|
||||||
@@ -41,24 +41,85 @@ Ergebnisse landen in [`docs/spike-protokoll.md`](docs/spike-protokoll.md).
|
|||||||
|
|
||||||
Getestet wird auf einem **OnePlus 7 Pro (Snapdragon 855, Adreno 640) mit Stock OxygenOS 12**.
|
Getestet wird auf einem **OnePlus 7 Pro (Snapdragon 855, Adreno 640) mit Stock OxygenOS 12**.
|
||||||
|
|
||||||
|
Voraussetzung ist nur, dass die Entwickleroptionen aktiv sind. **Ein USB-Kabel wird
|
||||||
|
nicht gebraucht** — ab Android 11 läuft die Ersteinrichtung über WLAN.
|
||||||
|
|
||||||
|
### Auf dem PC
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# 1. Auf dem PC. Verbindet per USB oder WLAN — das Skript fragt danach.
|
./provision/adb-wireless.sh # Verbindung per WLAN (oder Kabel anstecken)
|
||||||
# Ein Kabel wird nicht gebraucht: Android 11+ kann Wireless Debugging.
|
./provision/install-termux.sh # lädt Termux + 3 Zusatz-Apps, installiert sie,
|
||||||
# Fehlt Termux, bietet es an, alle vier Apps herunterzuladen und
|
# erteilt die nötigen Berechtigungen
|
||||||
# fernzuinstallieren (oder direkt: ./provision/install-termux.sh).
|
./provision/provision.sh # Akku- und Hintergrundeinstellungen,
|
||||||
./provision/provision.sh
|
# legt das Startskript aufs Telefon
|
||||||
|
```
|
||||||
|
|
||||||
|
`provision.sh` allein genügt auch — es ruft die anderen bei Bedarf selbst auf.
|
||||||
|
|
||||||
|
### Auf dem Telefon, in Termux
|
||||||
|
|
||||||
|
```bash
|
||||||
|
bash /sdcard/hpos-init.sh # installiert git, klont das Repo nach ~/hpos
|
||||||
|
cd ~/hpos
|
||||||
|
|
||||||
# 2. Auf dem Telefon in Termux:
|
|
||||||
bash spike/00-bootstrap-termux.sh
|
bash spike/00-bootstrap-termux.sh
|
||||||
|
|
||||||
# 3. Beweise der Reihe nach:
|
bash spike/01-s1-plasma-mobile.sh # S1 zuerst — der wackligste Beweis
|
||||||
bash spike/01-s1-plasma-mobile.sh
|
|
||||||
bash spike/02-s2-mikrofon.sh
|
bash spike/02-s2-mikrofon.sh
|
||||||
bash spike/03-s3-pipewire-kamera.sh
|
bash spike/03-s3-pipewire-kamera.sh
|
||||||
bash spike/04-s4-intent-handoff.sh
|
bash spike/04-s4-intent-handoff.sh
|
||||||
```
|
```
|
||||||
|
|
||||||
Details und Voraussetzungen: [`spike/README.md`](spike/README.md).
|
### Aktualisieren
|
||||||
|
|
||||||
|
Per adb kommt bewusst **nur das Startskript** aufs Telefon, nicht das Repo selbst.
|
||||||
|
Dadurch liegt dort eine echte Arbeitskopie — spätere Änderungen brauchen keinen PC:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd ~/hpos && git pull
|
||||||
|
```
|
||||||
|
|
||||||
|
**Wenn `git pull` scheitert:**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
rm -rf ~/hpos && bash /sdcard/hpos-init.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
Das Startskript versucht zuerst wieder einen Klon und weicht, falls der Server keine
|
||||||
|
Pakete ausliefert, auf den Archiv-Endpunkt aus (`/archive/main.tar.gz`). Der geht
|
||||||
|
nicht über `git upload-pack` und funktioniert deshalb auch dann noch.
|
||||||
|
|
||||||
|
Das Ergebnis ist dann allerdings **ein Abzug, keine Arbeitskopie** — `git pull` geht
|
||||||
|
damit nicht mehr, jede Aktualisierung braucht denselben Befehl erneut. Sobald der
|
||||||
|
Server wieder Pakete liefert, stellt genau dieser Befehl auch die Arbeitskopie
|
||||||
|
wieder her.
|
||||||
|
|
||||||
|
Typische Meldung, wenn es so weit ist:
|
||||||
|
|
||||||
|
```
|
||||||
|
fatal: early EOF
|
||||||
|
fatal: fetch-pack: invalid index-pack output
|
||||||
|
```
|
||||||
|
|
||||||
|
Das ist ein serverseitiges Problem — `upload-pack` stirbt beim Schnüren des Pakets,
|
||||||
|
während die Objekte selbst heil sind. Erkennbar daran, dass sich ein Archiv weiterhin
|
||||||
|
erzeugen lässt.
|
||||||
|
|
||||||
|
Details, Stellschrauben und was bei Fehlschlägen zu tun ist:
|
||||||
|
[`spike/README.md`](spike/README.md).
|
||||||
|
|
||||||
|
### Warum Termux nicht aus dem Play Store
|
||||||
|
|
||||||
|
Termux und seine Plugins teilen sich eine Android-UID. Android verlangt für Apps mit
|
||||||
|
gemeinsamer UID **denselben Signaturschlüssel** — mischt man F-Droid und GitHub,
|
||||||
|
scheitert die Installation mit `INSTALL_FAILED_SHARED_USER_INCOMPATIBLE`, ohne dass
|
||||||
|
die Meldung den Grund nennt. `install-termux.sh` nimmt deshalb durchgängig GitHub und
|
||||||
|
räumt vorhandene Installationen aus fremder Quelle auf Nachfrage weg.
|
||||||
|
|
||||||
|
Nebeneffekt der Entscheidung: Termux:X11 gibt es dort in einer sharedUid-Variante, die
|
||||||
|
in Termux' Prozessgruppe läuft und dessen Akku-Ausnahmen erbt. Bei ROMs, die
|
||||||
|
Hintergrund-Apps aggressiv beenden, ist das der Unterschied zwischen „läuft über Nacht"
|
||||||
|
und „war morgens weg".
|
||||||
|
|
||||||
## Dokumentation
|
## Dokumentation
|
||||||
|
|
||||||
@@ -67,6 +128,8 @@ Details und Voraussetzungen: [`spike/README.md`](spike/README.md).
|
|||||||
- [Verworfene Entscheidungen](docs/verworfene-entscheidungen.md) — sieben Wege, die
|
- [Verworfene Entscheidungen](docs/verworfene-entscheidungen.md) — sieben Wege, die
|
||||||
geprüft und begründet verworfen wurden. **Vor jedem "warum eigentlich nicht …" lesen.**
|
geprüft und begründet verworfen wurden. **Vor jedem "warum eigentlich nicht …" lesen.**
|
||||||
- [Spike-Protokoll](docs/spike-protokoll.md) — Messergebnisse von Phase 0
|
- [Spike-Protokoll](docs/spike-protokoll.md) — Messergebnisse von Phase 0
|
||||||
|
- [Am Projekt arbeiten](docs/entwicklung.md) — SSH nach Termux, scrcpy, sshfs.
|
||||||
|
**Nicht auf der Bildschirmtastatur entwickeln.**
|
||||||
|
|
||||||
## Geräte
|
## Geräte
|
||||||
|
|
||||||
@@ -78,8 +141,12 @@ Läuft es bei dir? [Geräte-Meldung eröffnen](.github/ISSUE_TEMPLATE/geraet-mel
|
|||||||
|
|
||||||
## Lizenz
|
## Lizenz
|
||||||
|
|
||||||
GPLv3 — siehe [LICENSE](LICENSE). Das Projekt verteilt Termux (GPLv3) mit;
|
GPLv3 — siehe [LICENSE](LICENSE).
|
||||||
die einheitliche Lizenz erfüllt die Quellen-Angebotspflicht.
|
|
||||||
|
Termux wird **nicht mitverteilt**: `install-termux.sh` lädt die APKs zur Laufzeit von
|
||||||
|
den offiziellen GitHub-Releases. Eine Quellen-Angebotspflicht entsteht dadurch nicht.
|
||||||
|
Sollte die Installer-APK in Phase 2 Termux als Asset mitbringen, ändert sich das —
|
||||||
|
die einheitliche GPLv3 deckt es dann ab.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -95,4 +162,23 @@ Currently in **Phase 0** — proving four load-bearing assumptions (S1–S4 abov
|
|||||||
any infrastructure gets built. See [`spike/`](spike/) and
|
any infrastructure gets built. See [`spike/`](spike/) and
|
||||||
[`docs/spike-protokoll.md`](docs/spike-protokoll.md).
|
[`docs/spike-protokoll.md`](docs/spike-protokoll.md).
|
||||||
|
|
||||||
|
## Quick start
|
||||||
|
|
||||||
|
No USB cable needed — Android 11+ pairs over WLAN.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# On the PC
|
||||||
|
./provision/adb-wireless.sh # pair and connect over WLAN
|
||||||
|
./provision/install-termux.sh # download and remote-install Termux + addons
|
||||||
|
./provision/provision.sh # battery/background settings, push init script
|
||||||
|
|
||||||
|
# On the phone, in Termux
|
||||||
|
bash /sdcard/hpos-init.sh # installs git, clones this repo to ~/hpos
|
||||||
|
cd ~/hpos && bash spike/00-bootstrap-termux.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
Updating later needs no PC: `cd ~/hpos && git pull`.
|
||||||
|
|
||||||
Documentation is currently German-first; English will follow once Phase 0 concludes.
|
Documentation is currently German-first; English will follow once Phase 0 concludes.
|
||||||
|
Device reports are welcome in either language — a well-documented failure is as
|
||||||
|
valuable as a success.
|
||||||
|
|||||||
@@ -0,0 +1,102 @@
|
|||||||
|
# Am Projekt arbeiten
|
||||||
|
|
||||||
|
Die Bildschirmtastatur eines Telefons ist zum Entwickeln unbrauchbar. Zwei Werkzeuge
|
||||||
|
lösen das, und sie ergänzen sich: **SSH** für alles Textliche, **scrcpy** für alles,
|
||||||
|
was man sehen muss.
|
||||||
|
|
||||||
|
## SSH nach Termux — für Terminalarbeit
|
||||||
|
|
||||||
|
Der wichtigere der beiden Wege. Echte Tastatur, Zwischenablage, Verlauf, Rollbalken.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Einmalig auf dem PC (provision.sh bietet es von selbst an)
|
||||||
|
adb push ~/.ssh/id_ed25519.pub /sdcard/hpos-id.pub
|
||||||
|
|
||||||
|
# Auf dem Telefon
|
||||||
|
bash ~/hpos/tools/dev-ssh.sh
|
||||||
|
|
||||||
|
# Danach vom PC
|
||||||
|
ssh -p 8022 <benutzer>@<telefon-ip>
|
||||||
|
```
|
||||||
|
|
||||||
|
Port 8022 statt 22, weil eine gewöhnliche App keine Ports unter 1024 belegen darf.
|
||||||
|
|
||||||
|
**Dateien im Editor des Rechners bearbeiten** — kein Hin- und Herkopieren:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
mkdir -p ~/telefon
|
||||||
|
sshfs -p 8022 <benutzer>@<ip>:/data/data/com.termux/files/home ~/telefon
|
||||||
|
# lösen mit: fusermount3 -u ~/telefon
|
||||||
|
```
|
||||||
|
|
||||||
|
`sshd` überlebt keinen Neustart von Termux. Danach genügt `sshd` in Termux.
|
||||||
|
In fremden Netzen abschalten: `pkill sshd` — der Dienst ist im ganzen WLAN erreichbar.
|
||||||
|
|
||||||
|
## scrcpy — Bildschirm und Zwischenablage
|
||||||
|
|
||||||
|
Für alles Grafische unverzichtbar: Beweis S1 zeigt sich nur auf dem Bildschirm, und
|
||||||
|
die Kamera in S3 prüft man in einem Browserfenster.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./tools/install-scrcpy.sh # holt das offizielle Linux-Paket nach ~/.local
|
||||||
|
scrcpy # nutzt die bestehende adb-Verbindung, auch über WLAN
|
||||||
|
```
|
||||||
|
|
||||||
|
**`apt install scrcpy` funktioniert auf Debian 12 nicht** — dort ist das Paket gar
|
||||||
|
nicht enthalten, und ab trixie-backports liegt es in `contrib` statt `main`. Das
|
||||||
|
Projekt liefert aber ein eigenständiges Linux-Paket ohne Systemabhängigkeiten, und
|
||||||
|
genau das holt das Skript. Kein root, alles unter `~/.local`, Rückbau mit
|
||||||
|
`--deinstallieren`.
|
||||||
|
|
||||||
|
Das Skript legt dabei einen Starter an, der scrcpy **dasselbe adb unterschiebt**, das
|
||||||
|
auch die Provisioning-Skripte benutzen. Das ist kein Schönheitsfehler: das Paket
|
||||||
|
bringt eine eigene, oft neuere adb-Fassung mit, und ein abweichendes adb beendet einen
|
||||||
|
laufenden Server — was mitten in der Arbeit die WLAN-Verbindung zum Telefon kappen
|
||||||
|
würde.
|
||||||
|
|
||||||
|
Was es mitbringt, ohne weitere Einrichtung:
|
||||||
|
|
||||||
|
- **Zwischenablage in beide Richtungen.** Auf dem Telefon kopieren, auf dem PC
|
||||||
|
einfügen und umgekehrt.
|
||||||
|
- **Tastatur und Maus des Rechners** wirken direkt im Telefon — auch in Termux.
|
||||||
|
- Läuft über dieselbe WLAN-Verbindung, die schon steht.
|
||||||
|
|
||||||
|
Nützliche Schalter:
|
||||||
|
|
||||||
|
| Schalter | Wofür |
|
||||||
|
|---|---|
|
||||||
|
| `--max-size 1024` | weniger Bandbreite, flüssiger über WLAN |
|
||||||
|
| `--stay-awake` | Bildschirm bleibt an, solange gespiegelt wird |
|
||||||
|
| `--turn-screen-off` | Telefonbildschirm aus, spart Akku beim langen Arbeiten |
|
||||||
|
| `--no-audio` | falls die Tonübertragung stört |
|
||||||
|
|
||||||
|
`scrcpy --new-display` kann eine App in ein eigenes virtuelles Display legen. Als
|
||||||
|
Entwicklerwerkzeug ist das nützlich — als Produktbestandteil wurde es
|
||||||
|
[verworfen](verworfene-entscheidungen.md#v6--host-apps-als-fenster-im-linux-desktop),
|
||||||
|
weil es dauerhaft Shell-Rechte bräuchte.
|
||||||
|
|
||||||
|
## Der Weg der Änderungen
|
||||||
|
|
||||||
|
```
|
||||||
|
PC (Arbeitskopie) --git push--> Forge --git pull--> Telefon (~/hpos)
|
||||||
|
```
|
||||||
|
|
||||||
|
Auf dem Telefon wird nicht entwickelt, dort wird ausgeführt. Änderungen entstehen auf
|
||||||
|
dem Rechner, werden gepusht und mit `cd ~/hpos && git pull` geholt. Deshalb kommt per
|
||||||
|
adb auch nur das Startskript aufs Gerät und nicht das Repo — sonst wäre es eine Kopie
|
||||||
|
statt einer Arbeitskopie.
|
||||||
|
|
||||||
|
Ergebnisse laufen in die Gegenrichtung: `spike/out/` bleibt lokal auf dem Telefon
|
||||||
|
(bewusst nicht im Repo), die Auswertung wandert von Hand nach
|
||||||
|
[`spike-protokoll.md`](spike-protokoll.md).
|
||||||
|
|
||||||
|
## Kleinigkeiten, die Zeit sparen
|
||||||
|
|
||||||
|
- **Protokolle direkt vom Telefon holen**, ohne SSH:
|
||||||
|
`adb shell run-as com.termux cat …` scheitert meist an fehlender Debuggability.
|
||||||
|
Einfacher ist der Umweg über die gemeinsame Ablage:
|
||||||
|
`cp ~/hpos/spike/out/*.log /sdcard/` und dann `adb pull /sdcard/…`
|
||||||
|
- **Termux offen halten**: Ein Wisch aus den zuletzt verwendeten Apps beendet den
|
||||||
|
gesamten Stack. Im Task-Manager anpinnen.
|
||||||
|
- **Mehrere Sitzungen** in Termux mit `Ctrl+Alt+C` — praktisch, um neben einem
|
||||||
|
laufenden Desktop noch ein Terminal zu haben.
|
||||||
+20
-5
@@ -10,14 +10,29 @@ Fehlschlag ist wertvoller als ein geschöntes Ergebnis.
|
|||||||
|
|
||||||
| | |
|
| | |
|
||||||
|---|---|
|
|---|---|
|
||||||
| Modell | OnePlus 7 Pro (`guacamole`) |
|
| Modell | OnePlus 7 Pro — `GM1913` / `OnePlus7Pro` |
|
||||||
| SoC / GPU | Snapdragon 855 / Adreno 640 |
|
| SoC | Snapdragon 855 (`SM8150`, Plattform `msmnile`) |
|
||||||
| RAM / Speicher | _(ausfüllen)_ |
|
| GPU | Adreno 640 — **Turnip aktiv**, laut `vulkaninfo`: `Turnip Adreno (TM) 640` |
|
||||||
| ROM | Stock OxygenOS 12 (Android 12) |
|
| RAM | 11 GiB |
|
||||||
|
| Freier Speicher | ~19,9 GB unter `$PREFIX` |
|
||||||
|
| ROM | Stock OxygenOS 12 (Android 12, SDK 31) |
|
||||||
|
| Kernel | 4.14.180-perf+ |
|
||||||
|
| Rootfs | Debian 13.3 (Trixie) über proot-distro |
|
||||||
| Display | 3120 × 1440, virtuelle Auflösung im Test: _(ausfüllen)_ |
|
| Display | 3120 × 1440, virtuelle Auflösung im Test: _(ausfüllen)_ |
|
||||||
| Akku | 4000 mAh, Baujahr 2019 — getauscht? _(ausfüllen)_ |
|
| Akku | 4000 mAh, Baujahr 2019 — getauscht? _(ausfüllen)_ |
|
||||||
| Datum des Tests | _(ausfüllen)_ |
|
| Datum des Tests | _(ausfüllen)_ |
|
||||||
|
|
||||||
|
**Bootstrap: bestanden.** Zwei Stolpersteine unterwegs, beide gelöst und im Skript
|
||||||
|
abgefangen:
|
||||||
|
|
||||||
|
- `libmagic` gegen `file 5.47`: Dateikonflikt aus einer Paketaufteilung, aufgelöst
|
||||||
|
mit `--force-overwrite`.
|
||||||
|
- `proot-distro` verlangt `python3.13`, installiert ist `python3.14`. Weder
|
||||||
|
Nachinstallieren noch Vollupgrade haben das behoben — die Paketquelle liefert
|
||||||
|
hier einen unstimmigen Satz. Behelf: Verweis `python3.13 → python3.14`.
|
||||||
|
**Vertretbar, weil proot-distro reines Python ist, aber nicht sauber** — beim
|
||||||
|
nächsten Update von proot-distro kann es erneut auftreten.
|
||||||
|
|
||||||
## Zusammenfassung
|
## Zusammenfassung
|
||||||
|
|
||||||
| Beweis | Ergebnis | Konsequenz |
|
| Beweis | Ergebnis | Konsequenz |
|
||||||
@@ -132,7 +147,7 @@ basiert auf ColorOS mit aggressiver App-Einfrierung unterhalb der Android-Mechan
|
|||||||
|---|---|
|
|---|---|
|
||||||
| `vkcube` läuft | |
|
| `vkcube` läuft | |
|
||||||
| `glmark2` Score | |
|
| `glmark2` Score | |
|
||||||
| GPU-Treiberpfad (Turnip / Zink / virgl / Software) | |
|
| GPU-Treiberpfad (Turnip / Zink / virgl / Software) | **Turnip** — bestätigt im Bootstrap |
|
||||||
| Virtuelle Auflösung | |
|
| Virtuelle Auflösung | |
|
||||||
| Akku: Leerlauf mit laufendem Stack | |
|
| Akku: Leerlauf mit laufendem Stack | |
|
||||||
| Akku: Desktop aktiv | |
|
| Akku: Desktop aktiv | |
|
||||||
|
|||||||
+131
-21
@@ -35,39 +35,134 @@ case "$REPO" in
|
|||||||
exit 1 ;;
|
exit 1 ;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
|
# Benutzernamen aus der Adresse entfernen. Lesen geht anonym; steht ein Name in
|
||||||
|
# der URL, fragt git trotzdem nach einem Passwort — auf einer Bildschirmtastatur
|
||||||
|
# eine unnötige Quälerei. Zum Schreiben braucht man ihn ohnehin nur auf dem PC.
|
||||||
|
REPO_ROH="$REPO"
|
||||||
|
REPO=$(printf '%s' "$REPO" | sed -E 's#^(https?://)[^/@]+@#\1#')
|
||||||
|
[ "$REPO" != "$REPO_ROH" ] && ANONYM=1 || ANONYM=0
|
||||||
|
|
||||||
kopf "HPOS — Ersteinrichtung auf dem Telefon"
|
kopf "HPOS — Ersteinrichtung auf dem Telefon"
|
||||||
hinweis "Repo: $REPO"
|
hinweis "Repo: $REPO"
|
||||||
|
[ "$ANONYM" = 1 ] && hinweis "(Benutzername entfernt — gelesen wird anonym)"
|
||||||
|
|
||||||
|
# ── Vollupgrade ──────────────────────────────────────────────────────────────
|
||||||
|
# Muss VOR jedem anderen Paket laufen. 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 —
|
||||||
|
# es trug die Shebang-Zeile python3.13, während eine andere Fassung installiert war.
|
||||||
|
#
|
||||||
|
# Überspringbar mit HPOS_OHNE_UPGRADE=1, etwa bei knappem Datenvolumen.
|
||||||
|
kopf "Termux auf einen Stand bringen"
|
||||||
|
if [ "${HPOS_OHNE_UPGRADE:-0}" = 1 ]; then
|
||||||
|
warn "Übersprungen (HPOS_OHNE_UPGRADE=1)"
|
||||||
|
hinweis "Bei Problemen mit proot-distro ist das die erste Stelle zum Nachsehen."
|
||||||
|
else
|
||||||
|
hinweis "Das dauert und lädt einiges. Es erspart aber genau die Fehler,"
|
||||||
|
hinweis "die sonst erst Stunden später als kaputtes proot-distro auffallen."
|
||||||
|
export DEBIAN_FRONTEND=noninteractive
|
||||||
|
|
||||||
|
# Beim Wechsel der Python-Version wirft dpkg dutzende Zeilen
|
||||||
|
# "unable to delete old directory ... Directory not empty". Das sind
|
||||||
|
# Warnungen, keine Fehler: in site-packages liegen noch .pyc-Dateien oder
|
||||||
|
# selbst installierte Module. Sie herauszufiltern ist kein Verstecken —
|
||||||
|
# sie verdecken sonst die eine Zeile, auf die es ankommt.
|
||||||
|
rauschfilter() { grep -viE 'unable to delete old directory|^(Unpacking|Preparing|Selecting) '; }
|
||||||
|
|
||||||
|
# --force-confold: vorhandene Konfiguration behalten, statt mitten im Lauf
|
||||||
|
# eine Rückfrage zu stellen, die niemand beantwortet.
|
||||||
|
AUSGABE=$(mktemp)
|
||||||
|
pkg update -y >"$AUSGABE" 2>&1; rauschfilter <"$AUSGABE"
|
||||||
|
|
||||||
|
upgrade_lauf() {
|
||||||
|
pkg upgrade -y -o Dpkg::Options::=--force-confold "$@" >"$AUSGABE" 2>&1
|
||||||
|
local rc=$?
|
||||||
|
rauschfilter <"$AUSGABE"
|
||||||
|
return $rc
|
||||||
|
}
|
||||||
|
|
||||||
|
if upgrade_lauf; then
|
||||||
|
ok "Termux ist aktuell"
|
||||||
|
else
|
||||||
|
# Dateikonflikt gezielt behandeln. Er entsteht, wenn ein Paket aufgeteilt
|
||||||
|
# wurde und beide Teile kurzzeitig dieselbe Datei mitbringen — bei Termux
|
||||||
|
# etwa libmagic, herausgelöst aus file. dpkg verweigert dann grundsätzlich.
|
||||||
|
#
|
||||||
|
# --force-overwrite wird bewusst NUR hier gesetzt, nachdem der Konflikt in
|
||||||
|
# der Ausgabe nachgewiesen ist. Pauschal mitzugeben hieße, jede künftige
|
||||||
|
# Dateikollision stillschweigend zu übergehen.
|
||||||
|
if grep -q 'which is also in package' "$AUSGABE"; then
|
||||||
|
warn "Dateikonflikt zwischen zwei Paketen — typisch bei einer Paketaufteilung."
|
||||||
|
grep 'trying to overwrite' "$AUSGABE" | head -3 | sed 's/^/ /'
|
||||||
|
hinweis "Wiederhole gezielt mit --force-overwrite."
|
||||||
|
if upgrade_lauf -o Dpkg::Options::=--force-overwrite; then
|
||||||
|
ok "Konflikt aufgelöst, Upgrade durchgelaufen"
|
||||||
|
rm -f "$AUSGABE"
|
||||||
|
AUSGABE=""
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -n "$AUSGABE" ] && ! upgrade_lauf; then
|
||||||
|
warn "Upgrade weiterhin unvollständig — versuche dpkg zu entwirren."
|
||||||
|
# Nach einem Abbruch steckt dpkg halb fertig fest und blockiert alles.
|
||||||
|
dpkg --configure -a >>"$AUSGABE" 2>&1
|
||||||
|
apt-get -f install -y >>"$AUSGABE" 2>&1
|
||||||
|
if upgrade_lauf -o Dpkg::Options::=--force-overwrite; then
|
||||||
|
ok "Nach der Reparatur durchgelaufen"
|
||||||
|
else
|
||||||
|
warn "Bleibt unvollständig."
|
||||||
|
hinweis "Speicherplatz prüfen: df -h \$PREFIX (nicht / — das ist die Systempartition)"
|
||||||
|
hinweis "Fehler ohne Rauschen: pkg upgrade -y 2>&1 | grep -viE 'unable to delete' | tail -20"
|
||||||
|
hinweis "Weiter geht es trotzdem — aber hier ansetzen, falls später etwas klemmt."
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
rm -f "$AUSGABE" 2>/dev/null || true
|
||||||
|
fi
|
||||||
|
|
||||||
# ── git ──────────────────────────────────────────────────────────────────────
|
# ── git ──────────────────────────────────────────────────────────────────────
|
||||||
kopf "git"
|
kopf "git"
|
||||||
if command -v git >/dev/null 2>&1; then
|
if command -v git >/dev/null 2>&1; then
|
||||||
ok "bereits vorhanden ($(git --version))"
|
ok "bereits vorhanden ($(git --version))"
|
||||||
else
|
else
|
||||||
pkg update -y >/dev/null 2>&1
|
|
||||||
if pkg install -y git; then ok "installiert"
|
if pkg install -y git; then ok "installiert"
|
||||||
else fehl "Installation von git fehlgeschlagen"; exit 1; fi
|
else fehl "Installation von git fehlgeschlagen"; exit 1; fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# ── Zugangsdaten ─────────────────────────────────────────────────────────────
|
# Das Telefon liest nur. Es soll nie versehentlich versuchen zurückzuschreiben —
|
||||||
# Bei einem privaten Repo fragt git bei jedem Zugriff nach dem Passwort. Auf einer
|
# ein Push von hier wäre weder gewollt noch möglich.
|
||||||
# Bildschirmtastatur ist das eine Zumutung, deshalb wird der Speicher angeboten.
|
git config --global credential.helper "" 2>/dev/null || true
|
||||||
# Er legt die Zugangsdaten im Klartext unter ~/.git-credentials ab — das gehört
|
|
||||||
# gesagt, damit die Entscheidung bewusst fällt.
|
# ── Rückfallebene: Archiv statt Klon ─────────────────────────────────────────
|
||||||
case "$REPO" in
|
# Gitea, Forgejo und GitHub bieten den Baum zusätzlich als Tarball an. Der Weg
|
||||||
https://*@*)
|
# dorthin geht nicht über upload-pack und funktioniert deshalb auch dann noch,
|
||||||
if [ ! -f "$HOME/.git-credentials" ]; then
|
# wenn der Klon am Server scheitert. Das Ergebnis ist aber nur ein Abzug: kein
|
||||||
kopf "Zugangsdaten"
|
# .git, kein 'git pull'. Es ist eine Notlösung, keine Alternative.
|
||||||
hinweis "Das Repo verlangt vermutlich ein Passwort."
|
archiv_holen() {
|
||||||
printf ' Nach der Eingabe dauerhaft merken? (Klartext in ~/.git-credentials) [j/N] > '
|
local basis zweig="${HPOS_ZWEIG:-main}" url tmp
|
||||||
read -r MERKEN
|
basis="${REPO%.git}"
|
||||||
case "${MERKEN:-n}" in
|
|
||||||
j|J) git config --global credential.helper store
|
command -v curl >/dev/null 2>&1 || pkg install -y curl >/dev/null 2>&1
|
||||||
ok "Passwort wird nach der ersten Eingabe gespeichert" ;;
|
command -v tar >/dev/null 2>&1 || pkg install -y tar >/dev/null 2>&1
|
||||||
*) hinweis "Dann fragt git bei jedem Zugriff erneut." ;;
|
|
||||||
esac
|
tmp=$(mktemp -d)
|
||||||
|
for url in "$basis/archive/$zweig.tar.gz" \
|
||||||
|
"$basis/archive/refs/heads/$zweig.tar.gz"; do
|
||||||
|
hinweis "Versuche Archiv: $url"
|
||||||
|
if curl -sfL -o "$tmp/a.tar.gz" "$url" && tar tzf "$tmp/a.tar.gz" >/dev/null 2>&1; then
|
||||||
|
mkdir -p "$ZIEL"
|
||||||
|
# --strip-components=1: die Archive enthalten alles unter einem
|
||||||
|
# Wurzelverzeichnis, das wir nicht mit übernehmen wollen.
|
||||||
|
if tar xzf "$tmp/a.tar.gz" -C "$ZIEL" --strip-components=1; then
|
||||||
|
rm -rf "$tmp"
|
||||||
|
ok "Archiv entpackt nach $ZIEL"
|
||||||
|
return 0
|
||||||
fi
|
fi
|
||||||
;;
|
fi
|
||||||
esac
|
done
|
||||||
|
rm -rf "$tmp"
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
# ── Holen oder aktualisieren ─────────────────────────────────────────────────
|
# ── Holen oder aktualisieren ─────────────────────────────────────────────────
|
||||||
kopf "Repo"
|
kopf "Repo"
|
||||||
@@ -81,14 +176,29 @@ if [ -d "$ZIEL/.git" ]; then
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
|
# --depth reicht nicht: für 'git pull' später brauchen wir eine vollwertige
|
||||||
|
# Arbeitskopie, kein abgeschnittenes Archiv.
|
||||||
if git clone "$REPO" "$ZIEL"; then
|
if git clone "$REPO" "$ZIEL"; then
|
||||||
ok "geklont nach $ZIEL"
|
ok "geklont nach $ZIEL"
|
||||||
else
|
else
|
||||||
fehl "git clone fehlgeschlagen."
|
fehl "git clone fehlgeschlagen."
|
||||||
hinweis "Bei privaten Repos: Benutzername und Passwort prüfen."
|
|
||||||
hinweis "Adresse war: $REPO"
|
hinweis "Adresse war: $REPO"
|
||||||
|
echo
|
||||||
|
# Ein scheiternder Klon bei erreichbarem Repo hat fast immer eine
|
||||||
|
# serverseitige Ursache: upload-pack stirbt beim Schnüren des Pakets,
|
||||||
|
# während die Objekte selbst heil sind. Erkennbar daran, dass sich ein
|
||||||
|
# Archiv weiterhin erzeugen lässt — und genau das ist die Rückfallebene.
|
||||||
|
if archiv_holen; then
|
||||||
|
warn "Über ein Archiv geholt, NICHT als Arbeitskopie."
|
||||||
|
hinweis "'git pull' funktioniert damit nicht. Sobald der Server wieder"
|
||||||
|
hinweis "Pakete ausliefert: rm -rf ~/hpos && bash /sdcard/hpos-init.sh"
|
||||||
|
else
|
||||||
|
fehl "Auch die Rückfallebene über das Archiv hat nicht geklappt."
|
||||||
|
hinweis "Ist das Repo öffentlich lesbar? Ohne das braucht es Zugangsdaten,"
|
||||||
|
hinweis "und die gehören nicht aufs Telefon."
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
chmod +x "$ZIEL"/spike/*.sh "$ZIEL"/spike/inner/*.sh 2>/dev/null || true
|
chmod +x "$ZIEL"/spike/*.sh "$ZIEL"/spike/inner/*.sh 2>/dev/null || true
|
||||||
|
|||||||
@@ -282,6 +282,15 @@ if [ -z "$REPO_URL" ]; then
|
|||||||
read -r REPO_URL </dev/tty || REPO_URL=""
|
read -r REPO_URL </dev/tty || REPO_URL=""
|
||||||
fi
|
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
|
if [ "$TROCKEN" = 1 ]; then
|
||||||
warn "Trockenlauf — es wird nichts übertragen."
|
warn "Trockenlauf — es wird nichts übertragen."
|
||||||
elif [ -z "$REPO_URL" ]; then
|
elif [ -z "$REPO_URL" ]; then
|
||||||
@@ -308,6 +317,32 @@ else
|
|||||||
esac
|
esac
|
||||||
fi
|
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"
|
kopf "Fertig"
|
||||||
cat <<TEXT
|
cat <<TEXT
|
||||||
Nächste Schritte auf dem Telefon, in Termux:
|
Nächste Schritte auf dem Telefon, in Termux:
|
||||||
|
|||||||
@@ -23,6 +23,58 @@ try pkg update -y
|
|||||||
try pkg install -y x11-repo tur-repo
|
try pkg install -y x11-repo tur-repo
|
||||||
try pkg update -y
|
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 ──────────────────────────────────────────────────────────────
|
# ── Basispakete ──────────────────────────────────────────────────────────────
|
||||||
# Einzeln installiert und einzeln protokolliert: Paketnamen wandern in Termux
|
# Einzeln installiert und einzeln protokolliert: Paketnamen wandern in Termux
|
||||||
# gelegentlich, und wir wollen wissen, WELCHES Paket fehlt, statt nur dass etwas fehlt.
|
# gelegentlich, und wir wollen wissen, WELCHES Paket fehlt, statt nur dass etwas fehlt.
|
||||||
@@ -38,11 +90,33 @@ done
|
|||||||
# zur Laufzeit; das Ergebnis landet im GPU-Profil.
|
# zur Laufzeit; das Ergebnis landet im GPU-Profil.
|
||||||
section "GPU-Pakete"
|
section "GPU-Pakete"
|
||||||
GPU_PKGS=(virglrenderer-android vulkan-loader-android vulkan-tools angle-android
|
GPU_PKGS=(virglrenderer-android vulkan-loader-android vulkan-tools angle-android
|
||||||
mesa-vulkan-icd-wrapper mesa-zink virglrenderer-mesa-zink)
|
mesa-zink virglrenderer-mesa-zink)
|
||||||
for p in "${GPU_PKGS[@]}"; do
|
for p in "${GPU_PKGS[@]}"; do
|
||||||
if try pkg install -y "$p"; then ok "$p"; else warn "$p nicht verfügbar — kein Beinbruch"; fi
|
if try pkg install -y "$p"; then ok "$p"; else warn "$p nicht verfügbar — kein Beinbruch"; fi
|
||||||
done
|
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"
|
section "GPU erkennen"
|
||||||
PLATFORM="$(getprop ro.board.platform 2>/dev/null)"
|
PLATFORM="$(getprop ro.board.platform 2>/dev/null)"
|
||||||
HARDWARE="$(getprop ro.hardware 2>/dev/null)"
|
HARDWARE="$(getprop ro.hardware 2>/dev/null)"
|
||||||
@@ -118,13 +192,111 @@ try termux-wake-lock && ok "Wake-Lock aktiv" || warn "Wake-Lock nicht gesetzt"
|
|||||||
|
|
||||||
# ── Debian-Rootfs ────────────────────────────────────────────────────────────
|
# ── Debian-Rootfs ────────────────────────────────────────────────────────────
|
||||||
section "Debian-Rootfs"
|
section "Debian-Rootfs"
|
||||||
if proot-distro list --installed 2>/dev/null | grep -q "^$DISTRO\b" \
|
# Erst prüfen, ob proot-distro überhaupt LÄUFT. Ein installiertes Paket, dessen
|
||||||
|| [ -d "$PREFIX/var/lib/proot-distro/installed-rootfs/$DISTRO" ]; then
|
# Shebang-Interpreter fehlt, meldet sich mit "cannot execute: required file not
|
||||||
ok "$DISTRO bereits installiert"
|
# 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
|
||||||
|
|
||||||
|
# Ob ein Rootfs da ist, wird nicht mehr an Pfaden oder Ausgabeformaten festgemacht:
|
||||||
|
# proot-distro hat sein Ablageformat gewechselt (erkennbar an der Meldung
|
||||||
|
# "Migrating legacy container"), und danach lag das Rootfs woanders als erwartet.
|
||||||
|
# Ein Anmeldeversuch ist die einzige Prüfung, die das nicht betrifft — sie fragt
|
||||||
|
# nicht, wo etwas liegt, sondern ob es funktioniert.
|
||||||
|
rootfs_laeuft() { proot-distro login "$DISTRO" -- true >/dev/null 2>&1; }
|
||||||
|
|
||||||
|
if rootfs_laeuft; then
|
||||||
|
ok "$DISTRO bereits installiert und lauffähig"
|
||||||
else
|
else
|
||||||
log " Installiere $DISTRO — das dauert einige Minuten."
|
log " Installiere $DISTRO — das dauert einige Minuten."
|
||||||
need proot-distro install "$DISTRO"
|
if proot-distro install "$DISTRO" >>"$LOG" 2>&1; then
|
||||||
ok "$DISTRO installiert"
|
ok "$DISTRO installiert"
|
||||||
|
else
|
||||||
|
# 'already exists' bzw. 'already installed' ist kein Fehler, sondern ein
|
||||||
|
# Wettlauf zwischen meiner Prüfung und der Wirklichkeit. Die Wortwahl hat
|
||||||
|
# sich über die Fassungen geändert (5.5.0 spricht von Containern), deshalb
|
||||||
|
# werden beide Formulierungen abgedeckt. Entscheidend ist ohnehin allein,
|
||||||
|
# ob sich danach anmelden lässt.
|
||||||
|
if grep -qiE 'already (installed|exists)' "$LOG"; then
|
||||||
|
warn "proot-distro meldet: gibt es bereits"
|
||||||
|
else
|
||||||
|
warn "Installation meldete einen Fehler:"
|
||||||
|
tail -n 12 "$LOG" | sed 's/^/ /'
|
||||||
|
fi
|
||||||
|
if rootfs_laeuft; then
|
||||||
|
ok "Anmeldung funktioniert trotzdem — weiter."
|
||||||
|
else
|
||||||
|
fail "Kein lauffähiges $DISTRO-Rootfs."
|
||||||
|
log ""
|
||||||
|
log " Von Hand versuchen:"
|
||||||
|
log " proot-distro list # was ist da?"
|
||||||
|
log " proot-distro reset $DISTRO # neu aufsetzen, Daten weg"
|
||||||
|
log " proot-distro remove $DISTRO && proot-distro install $DISTRO"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
section "Debian-Grundausstattung"
|
section "Debian-Grundausstattung"
|
||||||
|
|||||||
+117
-15
@@ -27,11 +27,54 @@ log "HPOS Phase 0 · S1 — Plasma Mobile in proot"
|
|||||||
log "Auflösung: ${BREITE}x${HOEHE} GPU-Profil: $GPU_PROFIL"
|
log "Auflösung: ${BREITE}x${HOEHE} GPU-Profil: $GPU_PROFIL"
|
||||||
log "Protokoll: $LOG"
|
log "Protokoll: $LOG"
|
||||||
|
|
||||||
|
voraussetzungen_pruefen "$DISTRO" || {
|
||||||
|
log ""
|
||||||
|
fail "Abbruch: die Grundlage steht nicht. S1 wäre nicht aussagekräftig."
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
# ── Alte Reste einsammeln ────────────────────────────────────────────────────
|
# ── Alte Reste einsammeln ────────────────────────────────────────────────────
|
||||||
|
# Läufe hinterlassen Prozesse, die den nächsten stören: ein zweiter KWin findet
|
||||||
|
# den Wayland-Socket belegt, ein alter virgl-Server hält seinen Socket, und
|
||||||
|
# plasmashell hängt sich an die falsche Sitzung. Die proot-Prozesse liegen im
|
||||||
|
# selben PID-Raum wie Termux und sind von hier aus erreichbar.
|
||||||
|
#
|
||||||
|
# Bewusst NICHT mit 'pkill -f': das durchsucht die gesamte Kommandozeile und
|
||||||
|
# trifft dabei auch den eigenen Aufruf, wenn das Muster darin vorkommt. Beim
|
||||||
|
# Entwickeln dieses Blocks hat sich der Test genau so selbst abgeschossen.
|
||||||
|
# Deshalb über pgrep, mit eigener PID und Elternprozess ausgenommen.
|
||||||
section "Aufräumen"
|
section "Aufräumen"
|
||||||
pkill -f termux-x11 2>/dev/null && ok "alten X-Server beendet" || hint "kein alter X-Server"
|
|
||||||
pkill -f virgl_test_server 2>/dev/null && ok "alten virgl-Server beendet" || true
|
# Die eigene Ahnenkette. Nicht nur $$ und $PPID: wird das Skript aus einer Shell
|
||||||
sleep 1
|
# gestartet, deren Kommandozeile eines der Muster enthält, trifft pgrep diese
|
||||||
|
# Shell — und das Skript beendet seinen eigenen Großelternprozess. Genau das ist
|
||||||
|
# beim Entwickeln dieses Blocks passiert.
|
||||||
|
AHNEN=" "
|
||||||
|
_p=$$
|
||||||
|
while [ -n "$_p" ] && [ "$_p" != "0" ] && [ "$_p" != "1" ]; do
|
||||||
|
AHNEN="$AHNEN$_p "
|
||||||
|
_p=$(awk '{print $4}' "/proc/$_p/stat" 2>/dev/null)
|
||||||
|
done
|
||||||
|
|
||||||
|
beenden() {
|
||||||
|
local muster="$1" pid anzahl=0
|
||||||
|
for pid in $(pgrep -f "$muster" 2>/dev/null); do
|
||||||
|
case "$AHNEN" in *" $pid "*) continue ;; esac
|
||||||
|
kill "$pid" 2>/dev/null && anzahl=$((anzahl + 1))
|
||||||
|
done
|
||||||
|
if [ "$anzahl" -gt 0 ]; then ok "beendet: $muster ($anzahl)"
|
||||||
|
else hint "nichts zu beenden: $muster"; fi
|
||||||
|
}
|
||||||
|
|
||||||
|
for muster in kwin_wayland plasmashell xdg-desktop-portal \
|
||||||
|
termux-x11 virgl_test_server; do
|
||||||
|
beenden "$muster"
|
||||||
|
done
|
||||||
|
|
||||||
|
# Verwaiste Wayland-Sockets aus abgebrochenen Läufen. Bleiben sie liegen, startet
|
||||||
|
# KWin auf wayland-1 statt wayland-0 — und plasmashell sucht auf wayland-0.
|
||||||
|
rm -f /tmp/hpos-runtime/wayland-* 2>/dev/null || true
|
||||||
|
sleep 2
|
||||||
|
|
||||||
# ── X-Server ─────────────────────────────────────────────────────────────────
|
# ── X-Server ─────────────────────────────────────────────────────────────────
|
||||||
section "Termux-X11 starten"
|
section "Termux-X11 starten"
|
||||||
@@ -39,6 +82,24 @@ if ! have termux-x11; then
|
|||||||
fail "termux-x11 fehlt. Bitte 00-bootstrap-termux.sh laufen lassen."
|
fail "termux-x11 fehlt. Bitte 00-bootstrap-termux.sh laufen lassen."
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Das Termux-Paket und die Termux:X11-APP sind zwei verschiedene Dinge. Fehlt die
|
||||||
|
# App, startet der X-Server anstandslos — nur sieht man nichts.
|
||||||
|
#
|
||||||
|
# Zuverlässig prüfen lässt sich das aber nicht: seit Android 11 sieht eine App
|
||||||
|
# nur noch die Pakete, die sie in ihrem Manifest anmeldet oder die ihre UID teilen.
|
||||||
|
# 'pm list packages' liefert aus Termux heraus also eine gefilterte Liste, und ein
|
||||||
|
# Nichtfinden beweist gar nichts. Deshalb nur ein Hinweis, kein Abbruch — ein
|
||||||
|
# falscher Abbruch wäre schlimmer als ein überflüssiger Hinweis.
|
||||||
|
if pm list packages 2>/dev/null | tr -d '\r' | grep -q '^package:com\.termux\.x11$'; then
|
||||||
|
ok "Termux:X11-App gefunden"
|
||||||
|
else
|
||||||
|
warn "Termux:X11-App nicht in der Paketliste — sagt wenig aus."
|
||||||
|
hint "Android filtert diese Liste seit Version 11; die App kann trotzdem da sein."
|
||||||
|
hint "Bleibt der Bildschirm später leer, hier ansetzen:"
|
||||||
|
hint " Vom Rechner: ./provision/install-termux.sh"
|
||||||
|
hint " Von Hand: https://github.com/termux/termux-x11/releases"
|
||||||
|
fi
|
||||||
termux-x11 :0 >>"$LOG" 2>&1 &
|
termux-x11 :0 >>"$LOG" 2>&1 &
|
||||||
X11_PID=$!
|
X11_PID=$!
|
||||||
sleep 3
|
sleep 3
|
||||||
@@ -50,22 +111,53 @@ else
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# Die App muss im Vordergrund sein, sonst sieht man nichts und Android drosselt.
|
# Die App muss im Vordergrund sein, sonst sieht man nichts und Android drosselt.
|
||||||
|
# Hier zeigt sich auch, ob sie überhaupt existiert: 'am start' meldet einen
|
||||||
|
# Fehler, wenn es die Aktivität nicht gibt — das ist die verlässliche Prüfung,
|
||||||
|
# anders als die gefilterte Paketliste weiter oben.
|
||||||
log " Hole die Termux:X11-App in den Vordergrund …"
|
log " Hole die Termux:X11-App in den Vordergrund …"
|
||||||
try am start --user 0 -n com.termux.x11/com.termux.x11.MainActivity
|
if am start --user 0 -n com.termux.x11/com.termux.x11.MainActivity >>"$LOG" 2>&1; then
|
||||||
|
ok "Termux:X11-App gestartet"
|
||||||
|
else
|
||||||
|
fail "Termux:X11-App ließ sich nicht starten — sie fehlt vermutlich."
|
||||||
|
tail -n 5 "$LOG" | sed 's/^/ /'
|
||||||
|
hint "Installieren: ./provision/install-termux.sh (vom Rechner)"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
sleep 2
|
sleep 2
|
||||||
|
log " In der App sollte jetzt nicht mehr 'not connected' stehen."
|
||||||
|
hint "Steht es weiterhin dort, hat der X-Server keine Verbindung bekommen."
|
||||||
|
|
||||||
# ── GPU-Server ───────────────────────────────────────────────────────────────
|
# ── GPU-Server ───────────────────────────────────────────────────────────────
|
||||||
section "GPU-Pfad vorbereiten ($GPU_PROFIL)"
|
section "GPU-Pfad vorbereiten ($GPU_PROFIL)"
|
||||||
if [ "$GPU_PROFIL" = "virgl" ] && have virgl_test_server_android; then
|
# Wichtige Korrektur gegenüber der ersten Fassung: Turnip lebt in Termux'
|
||||||
virgl_test_server_android >>"$LOG" 2>&1 &
|
# Verzeichnis, nicht im Debian-Rootfs. Im Container GALLIUM_DRIVER=zink zu setzen
|
||||||
sleep 1
|
# geht deshalb ins Leere — Zink bräuchte dort einen Vulkan-Treiber, und da ist
|
||||||
ok "virgl-Server gestartet"
|
# keiner. Ergebnis war gar kein OpenGL, und ohne das kann QtQuick nichts zeichnen.
|
||||||
elif [ "$GPU_PROFIL" = "turnip" ]; then
|
#
|
||||||
ok "Turnip greift direkt auf KGSL zu — kein Proxy nötig"
|
# Der tragfähige Weg führt über virgl: der Server läuft in TERMUX und nutzt dort
|
||||||
else
|
# den schnellen Pfad (Zink auf Turnip), der Container spricht nur virpipe mit ihm.
|
||||||
warn "Kein GPU-Server aktiv, Software-Rendering wahrscheinlich"
|
# Turnip bleibt also im Spiel — nur eine Ebene tiefer als gedacht.
|
||||||
|
if ! have virgl_test_server_android; then
|
||||||
|
fail "virgl_test_server_android fehlt — ohne ihn gibt es im Container kein OpenGL."
|
||||||
|
hint "Nachinstallieren: pkg install -y virglrenderer-android"
|
||||||
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
pkill -f virgl_test_server 2>/dev/null; sleep 1
|
||||||
|
if [ "$GPU_PROFIL" = "turnip" ]; then
|
||||||
|
# Der Server selbst rendert über Zink auf Turnip — dort ist der Treiber ja.
|
||||||
|
GALLIUM_DRIVER=zink MESA_LOADER_DRIVER_OVERRIDE=zink \
|
||||||
|
virgl_test_server_android >>"$LOG" 2>&1 &
|
||||||
|
ok "virgl-Server gestartet, rendert über Zink auf Turnip"
|
||||||
|
else
|
||||||
|
virgl_test_server_android >>"$LOG" 2>&1 &
|
||||||
|
ok "virgl-Server gestartet"
|
||||||
|
fi
|
||||||
|
VIRGL_PID=$!
|
||||||
|
sleep 2
|
||||||
|
kill -0 "$VIRGL_PID" 2>/dev/null && ok "läuft (PID $VIRGL_PID)" \
|
||||||
|
|| warn "virgl-Server sofort beendet — siehe Protokoll"
|
||||||
|
|
||||||
# ── Audio, damit der Desktop nicht schon daran scheitert ─────────────────────
|
# ── Audio, damit der Desktop nicht schon daran scheitert ─────────────────────
|
||||||
section "PulseAudio"
|
section "PulseAudio"
|
||||||
pulseaudio --kill 2>/dev/null || true
|
pulseaudio --kill 2>/dev/null || true
|
||||||
@@ -83,7 +175,17 @@ HPOS_GPU_PROFIL="$GPU_PROFIL" HPOS_BREITE="$BREITE" HPOS_HOEHE="$HOEHE" \
|
|||||||
proot-distro login "$DISTRO" --shared-tmp --bind "$REPO_ROOT:/hpos" -- \
|
proot-distro login "$DISTRO" --shared-tmp --bind "$REPO_ROOT:/hpos" -- \
|
||||||
bash /hpos/spike/inner/s1-plasma.sh 2>&1 | tee -a "$LOG"
|
bash /hpos/spike/inner/s1-plasma.sh 2>&1 | tee -a "$LOG"
|
||||||
|
|
||||||
verdict "S1" "Zeigt die Termux:X11-App eine bedienbare Plasma-Mobile-Oberfläche?
|
verdict "S1" "Was zeigt die Termux:X11-App?
|
||||||
Prüfe: reagiert Touch, erscheint die Maliit-Tastatur beim Tippen in ein Feld?"
|
|
||||||
|
|
||||||
log "Aufräumen: pkill -f termux-x11 ; pkill -f virgl_test_server"
|
[n] Nichts, oder nur 'not connected' — der X-Server kam nicht durch.
|
||||||
|
[t] Schwarze Fläche mit kleinem X-Cursor oben links.
|
||||||
|
Das heißt: X11 ist verbunden und der Server läuft, aber es zeichnet
|
||||||
|
nichts darauf. KWin oder die Plasma-Shell fehlen — halber Erfolg.
|
||||||
|
[j] Eine Plasma-Mobile-Oberfläche mit Hintergrund und Bedienelementen.
|
||||||
|
|
||||||
|
Nur bei [j] weiter prüfen: reagiert Touch auf Wischen und Tippen?
|
||||||
|
Die Bildschirmtastatur erst dort testen, wo es ein Eingabefeld gibt —
|
||||||
|
etwa in den Plasma-Einstellungen. Vorher gibt es nichts zu tippen."
|
||||||
|
|
||||||
|
log "Alles beenden: pkill -f 'kwin_wayland|plasmashell|termux-x11|virgl_test_server'"
|
||||||
|
log "(Das Skript macht das beim nächsten Start ohnehin von selbst.)"
|
||||||
|
|||||||
+14
-2
@@ -24,20 +24,32 @@ WAV="$OUT_DIR/$WAV_NAME"
|
|||||||
log "HPOS Phase 0 · S2 — Mikrofon im Linux"
|
log "HPOS Phase 0 · S2 — Mikrofon im Linux"
|
||||||
log "Protokoll: $LOG"
|
log "Protokoll: $LOG"
|
||||||
|
|
||||||
|
voraussetzungen_pruefen "$DISTRO" || {
|
||||||
|
log ""
|
||||||
|
fail "Abbruch: die Grundlage steht nicht. S2 wäre nicht aussagekräftig."
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
# ── Berechtigung ─────────────────────────────────────────────────────────────
|
# ── Berechtigung ─────────────────────────────────────────────────────────────
|
||||||
# Der häufigste Grund für eine formal korrekte, aber stumme Aufnahme: PulseAudio
|
# Der häufigste Grund für eine formal korrekte, aber stumme Aufnahme: PulseAudio
|
||||||
# läuft IM Termux-Prozess und öffnet das Mikrofon über OpenSL ES von dort aus.
|
# 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 deshalb nichts.
|
# Eine Berechtigung, die nur Termux:API hat, nützt ihm deshalb nichts.
|
||||||
section "Mikrofonberechtigung von Termux"
|
section "Mikrofonberechtigung von Termux"
|
||||||
BERECHTIGT="unbekannt"
|
BERECHTIGT="unbekannt"
|
||||||
if RECHTE=$(dumpsys package com.termux 2>/dev/null | grep -i 'RECORD_AUDIO'); then
|
RECHTE=$(dumpsys package com.termux 2>/dev/null | grep -i 'RECORD_AUDIO' || true)
|
||||||
|
if [ -n "$RECHTE" ]; then
|
||||||
log "$(printf '%s' "$RECHTE" | sed 's/^/ /')"
|
log "$(printf '%s' "$RECHTE" | sed 's/^/ /')"
|
||||||
case "$RECHTE" in
|
case "$RECHTE" in
|
||||||
*granted=true*) BERECHTIGT=ja; ok "com.termux darf aufnehmen" ;;
|
*granted=true*) BERECHTIGT=ja; ok "com.termux darf aufnehmen" ;;
|
||||||
*granted=false*) BERECHTIGT=nein; fail "com.termux darf NICHT aufnehmen" ;;
|
*granted=false*) BERECHTIGT=nein; fail "com.termux darf NICHT aufnehmen" ;;
|
||||||
esac
|
esac
|
||||||
else
|
else
|
||||||
warn "Konnte den Berechtigungsstatus nicht auslesen"
|
# Erwartbar: dumpsys verlangt die DUMP-Berechtigung, die eine gewöhnliche App
|
||||||
|
# nicht hat. Kein Grund zur Sorge, aber der Status bleibt hier eben offen.
|
||||||
|
warn "Status von hier aus nicht auslesbar (dumpsys ist Apps verwehrt)"
|
||||||
|
hint "Vom PC prüfen: adb shell dumpsys package com.termux | grep RECORD_AUDIO"
|
||||||
|
hint "Setzen: adb shell pm grant com.termux android.permission.RECORD_AUDIO"
|
||||||
|
hint "Oder am Gerät: Einstellungen → Apps → Termux → Berechtigungen → Mikrofon"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ "$BERECHTIGT" = nein ]; then
|
if [ "$BERECHTIGT" = nein ]; then
|
||||||
|
|||||||
@@ -17,6 +17,12 @@ DISTRO=debian
|
|||||||
|
|
||||||
log "HPOS Phase 0 · S3 — Virtuelle PipeWire-Kamera"
|
log "HPOS Phase 0 · S3 — Virtuelle PipeWire-Kamera"
|
||||||
log "Protokoll: $LOG"
|
log "Protokoll: $LOG"
|
||||||
|
|
||||||
|
voraussetzungen_pruefen "$DISTRO" || {
|
||||||
|
log ""
|
||||||
|
fail "Abbruch: die Grundlage steht nicht. S3 wäre nicht aussagekräftig."
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
log ""
|
log ""
|
||||||
log "Voraussetzung: ein laufender X-Server aus S1."
|
log "Voraussetzung: ein laufender X-Server aus S1."
|
||||||
log "Falls nicht, in einer zweiten Sitzung: termux-x11 :0 &"
|
log "Falls nicht, in einer zweiten Sitzung: termux-x11 :0 &"
|
||||||
|
|||||||
@@ -94,11 +94,19 @@ bash spike/04-s4-intent-handoff.sh
|
|||||||
|
|
||||||
```bash
|
```bash
|
||||||
cd ~/hpos && git pull
|
cd ~/hpos && git pull
|
||||||
|
|
||||||
|
# Falls das scheitert (Server liefert keine Pakete aus):
|
||||||
|
rm -rf ~/hpos && bash /sdcard/hpos-init.sh
|
||||||
```
|
```
|
||||||
|
|
||||||
Per adb kommt bewusst nur das Startskript aufs Telefon, nicht das Repo selbst.
|
Per adb kommt bewusst nur das Startskript aufs Telefon, nicht das Repo selbst.
|
||||||
Dadurch liegt dort eine echte Arbeitskopie statt einer Kopie.
|
Dadurch liegt dort eine echte Arbeitskopie statt einer Kopie.
|
||||||
|
|
||||||
|
Der zweite Befehl weicht auf den Archiv-Endpunkt aus, wenn `git clone` am Server
|
||||||
|
scheitert. Das Ergebnis ist dann ein Abzug ohne `.git` — `git pull` geht damit nicht
|
||||||
|
mehr, und jede Aktualisierung braucht denselben Befehl erneut. Sobald der Server
|
||||||
|
wieder Pakete liefert, stellt er auch die Arbeitskopie wieder her.
|
||||||
|
|
||||||
Jedes Skript fragt am Ende nach deiner Beurteilung und schreibt sie nach
|
Jedes Skript fragt am Ende nach deiner Beurteilung und schreibt sie nach
|
||||||
`spike/out/ergebnisse.tsv`. Rohprotokolle liegen daneben in `spike/out/*.log`.
|
`spike/out/ergebnisse.tsv`. Rohprotokolle liegen daneben in `spike/out/*.log`.
|
||||||
|
|
||||||
|
|||||||
+204
-28
@@ -22,21 +22,19 @@ export QT_QPA_PLATFORM=wayland
|
|||||||
export QT_QUICK_CONTROLS_MOBILE=1
|
export QT_QUICK_CONTROLS_MOBILE=1
|
||||||
export PLASMA_PLATFORM=phone
|
export PLASMA_PLATFORM=phone
|
||||||
export KDE_FULL_SESSION=true
|
export KDE_FULL_SESSION=true
|
||||||
|
# Ohne gesetztes Cursor-Thema meldet KWin 'Failed to load cursor theme "default"'
|
||||||
|
# und zeichnet gar keinen Mauszeiger.
|
||||||
|
export XCURSOR_THEME=breeze_cursors
|
||||||
|
export XCURSOR_SIZE=24
|
||||||
|
|
||||||
case "$GPU_PROFIL" in
|
# Im Container immer virpipe, unabhängig vom Profil. Der Vulkan-Treiber liegt in
|
||||||
turnip)
|
# Termux' Verzeichnis und ist hier drinnen nicht erreichbar — Zink hätte also
|
||||||
# Zink übersetzt OpenGL auf Vulkan, Turnip liefert Vulkan direkt aus dem
|
# nichts, worauf es aufsetzen könnte. Der schnelle Pfad (Zink auf Turnip) wird
|
||||||
# Adreno-Treiber — zusammen der schnellste Weg ohne Root.
|
# eine Ebene tiefer genutzt, vom virgl-Server auf der Termux-Seite.
|
||||||
export MESA_LOADER_DRIVER_OVERRIDE=zink
|
export GALLIUM_DRIVER=virpipe
|
||||||
export GALLIUM_DRIVER=zink
|
export MESA_GL_VERSION_OVERRIDE=4.3
|
||||||
export TU_DEBUG=noconform
|
export MESA_GLES_VERSION_OVERRIDE=3.2
|
||||||
;;
|
echo " GPU-Profil: $GPU_PROFIL (im Container über virpipe)"
|
||||||
virgl)
|
|
||||||
export GALLIUM_DRIVER=virpipe
|
|
||||||
export MESA_GL_VERSION_OVERRIDE=4.3
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
echo " GPU-Profil: $GPU_PROFIL"
|
|
||||||
|
|
||||||
# ── Pakete ───────────────────────────────────────────────────────────────────
|
# ── Pakete ───────────────────────────────────────────────────────────────────
|
||||||
# Bewusst ohne empfohlene Pakete: sonst zieht Plasma Mobile eine komplette
|
# Bewusst ohne empfohlene Pakete: sonst zieht Plasma Mobile eine komplette
|
||||||
@@ -44,8 +42,14 @@ echo " GPU-Profil: $GPU_PROFIL"
|
|||||||
if ! command -v kwin_wayland >/dev/null 2>&1; then
|
if ! command -v kwin_wayland >/dev/null 2>&1; then
|
||||||
echo "── Installiere Plasma Mobile (einmalig, gut 1 GB) ──"
|
echo "── Installiere Plasma Mobile (einmalig, gut 1 GB) ──"
|
||||||
apt-get update -qq
|
apt-get update -qq
|
||||||
apt-get install -y --no-install-recommends \
|
# Bewusst OHNE --no-install-recommends: bei KDE stecken die QML-Module
|
||||||
plasma-mobile kwin-wayland plasma-workspace maliit-keyboard \
|
# traditionell in den Empfehlungen, nicht in den harten Abhängigkeiten.
|
||||||
|
# Ohne sie ist die Shell formal installiert, aber innen hohl — plasmashell
|
||||||
|
# lädt sie dann nicht und fällt wortlos auf die Voreinstellung zurück.
|
||||||
|
# Für einen Machbarkeitsbeweis ist ein paar hundert MB zu viel das kleinere
|
||||||
|
# Übel gegenüber einem Fehlschlag aus dem falschen Grund.
|
||||||
|
apt-get install -y \
|
||||||
|
plasma-mobile plasma-nano kwin-wayland plasma-workspace maliit-keyboard \
|
||||||
xdg-desktop-portal-kde qtwayland5 libqt5waylandclient5 \
|
xdg-desktop-portal-kde qtwayland5 libqt5waylandclient5 \
|
||||||
|| echo " ! Paketinstallation unvollständig — Details oben"
|
|| echo " ! Paketinstallation unvollständig — Details oben"
|
||||||
fi
|
fi
|
||||||
@@ -55,12 +59,124 @@ for b in kwin_wayland plasmashell; do
|
|||||||
else echo " ✗ $b fehlt"; fi
|
else echo " ✗ $b fehlt"; fi
|
||||||
done
|
done
|
||||||
|
|
||||||
|
# ── Welche Shell? ────────────────────────────────────────────────────────────
|
||||||
|
# Ohne gültiges Shell-Paket startet plasmashell klaglos, meldet nur beiläufig
|
||||||
|
# "starting invalid corona" und zeichnet dann nichts. Von außen sieht das aus wie
|
||||||
|
# ein Fehlschlag des Compositors und ist keiner.
|
||||||
|
#
|
||||||
|
# In Debian liefert ausgerechnet 'plasma-mobile' KEINE Shell mit, sondern nur
|
||||||
|
# QML-Module und KWin-Skripte. Die Shell steckt in 'plasma-nano' und heißt
|
||||||
|
# org.kde.plasma.nano. Der Name org.kde.plasma.mobileshell aus den KDE-Quellen
|
||||||
|
# existiert in Debian nicht. Deshalb wird nachgesehen statt geraten.
|
||||||
|
shell_suchen() {
|
||||||
|
local kandidat
|
||||||
|
for kandidat in org.kde.plasma.mobileshell org.kde.plasma.phoneshell \
|
||||||
|
org.kde.plasma.nano org.kde.plasma.desktop; do
|
||||||
|
if [ -d "/usr/share/plasma/shells/$kandidat" ]; then
|
||||||
|
printf '%s' "$kandidat"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "── Verfügbare Plasma-Shells ──"
|
||||||
|
if [ -d /usr/share/plasma/shells ]; then
|
||||||
|
ls -1 /usr/share/plasma/shells/ 2>/dev/null | sed 's/^/ /'
|
||||||
|
[ -z "$(ls -A /usr/share/plasma/shells/ 2>/dev/null)" ] && echo " (leer)"
|
||||||
|
else
|
||||||
|
echo " (Verzeichnis /usr/share/plasma/shells fehlt)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
SHELL_PAKET="$(shell_suchen || true)"
|
||||||
|
|
||||||
|
if [ -z "$SHELL_PAKET" ]; then
|
||||||
|
echo " ! Keine Shell gefunden — versuche plasma-nano nachzuinstallieren."
|
||||||
|
apt-get install -y --no-install-recommends plasma-nano plasma-mobile 2>&1 \
|
||||||
|
| tail -5 | sed 's/^/ /'
|
||||||
|
SHELL_PAKET="$(shell_suchen || true)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -n "$SHELL_PAKET" ]; then
|
||||||
|
echo " ✓ Shell: $SHELL_PAKET"
|
||||||
|
else
|
||||||
|
echo " ✗ Weiterhin keine Plasma-Shell — plasmashell hat nichts zu zeichnen."
|
||||||
|
echo " Prüfen: dpkg -L plasma-nano | grep shells"
|
||||||
|
echo " Ohne Shell ist Versuch A zum Scheitern verurteilt; XFCE zeigt dann,"
|
||||||
|
echo " ob wenigstens X-Server und GPU tragen."
|
||||||
|
fi
|
||||||
|
|
||||||
# ── GPU-Nachweis, bevor der Desktop startet ──────────────────────────────────
|
# ── GPU-Nachweis, bevor der Desktop startet ──────────────────────────────────
|
||||||
# Wenn hier schon nichts kommt, ist ein Fehlschlag von Plasma keine Aussage über
|
# Wenn hier schon nichts kommt, ist ein Fehlschlag von Plasma keine Aussage über
|
||||||
# Plasma, sondern über den GPU-Pfad. Deshalb vorher messen.
|
# Plasma, sondern über den GPU-Pfad. Deshalb vorher messen.
|
||||||
echo "── GPU-Nachweis ──"
|
echo "── Anzeige und GPU prüfen ──"
|
||||||
timeout 20 glxinfo -B 2>&1 | grep -Ei 'OpenGL (renderer|version)|Device' || echo " ! glxinfo lieferte nichts"
|
|
||||||
timeout 20 vulkaninfo --summary 2>&1 | grep -Ei 'driverName|deviceName' || echo " ! vulkaninfo lieferte nichts"
|
# Erst der X-Server. Wenn schon der nicht erreichbar ist, sagt jeder GL-Test
|
||||||
|
# darunter nichts aus.
|
||||||
|
if timeout 15 xdpyinfo >/tmp/hpos-xdpy.txt 2>&1; then
|
||||||
|
grep -E '^(name of display|version number|dimensions)' /tmp/hpos-xdpy.txt \
|
||||||
|
| head -3 | sed 's/^/ /'
|
||||||
|
echo " ✓ X-Server erreichbar"
|
||||||
|
else
|
||||||
|
echo " ✗ X-Server NICHT erreichbar — das wäre die Wurzel allen Übels:"
|
||||||
|
head -3 /tmp/hpos-xdpy.txt | sed 's/^/ /'
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Jeden GL-Weg einzeln und mit Rückgabewert prüfen. Stürzt glxinfo ab, kommt die
|
||||||
|
# Meldung von der Shell und nicht vom Programm — sie ginge in einer
|
||||||
|
# Kommandoersetzung verloren, und die Ausgabe wäre einfach leer. Genau das ist
|
||||||
|
# vorher passiert und sah aus wie 'kein Treiber gefunden'.
|
||||||
|
gl_test() {
|
||||||
|
local name="$1"; shift
|
||||||
|
local aus rc
|
||||||
|
aus=$(env "$@" timeout 25 glxinfo -B 2>&1); rc=$?
|
||||||
|
if printf '%s' "$aus" | grep -qi 'OpenGL renderer'; then
|
||||||
|
printf '%s\n' "$aus" | grep -Ei 'OpenGL (renderer|version)' | sed 's/^/ /'
|
||||||
|
echo " ✓ $name"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
echo " ✗ $name — Rückgabewert $rc$([ "$rc" -gt 128 ] && echo ' (abgestürzt oder abgebrochen)')"
|
||||||
|
if [ -n "$aus" ]; then
|
||||||
|
printf '%s\n' "$aus" | head -4 | sed 's/^/ /'
|
||||||
|
else
|
||||||
|
echo " (keine Ausgabe)"
|
||||||
|
fi
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# Ist der virgl-Socket überhaupt da? Fehlt er, hängt der Client bis zum Zeitlimit
|
||||||
|
# (Rückgabewert 124) statt eine Fehlermeldung zu liefern.
|
||||||
|
if ls /tmp/.virgl_test* >/dev/null 2>&1; then
|
||||||
|
echo " ✓ virgl-Socket sichtbar: $(ls /tmp/.virgl_test* 2>/dev/null | tr '\n' ' ')"
|
||||||
|
else
|
||||||
|
echo " ! Kein virgl-Socket unter /tmp — der Container sieht den Server nicht."
|
||||||
|
echo " (Termux legt ihn in sein tmp; proot-distro bindet das über --shared-tmp.)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if gl_test "OpenGL über virgl" GALLIUM_DRIVER=virpipe; then
|
||||||
|
GL_WEG=virgl
|
||||||
|
export GALLIUM_DRIVER=virpipe
|
||||||
|
else
|
||||||
|
# Hier war ein Denkfehler: schlugen beide Prüfungen fehl, wurde der
|
||||||
|
# Software-Pfad NICHT gesetzt — ausgerechnet dann nicht, wenn er am nötigsten
|
||||||
|
# ist. Und glxinfo taugt ohnehin nicht als Richter: unter Termux-X11
|
||||||
|
# scheitert es an X_GetImage mit BadMatch, weil es Pixel zurücklesen will.
|
||||||
|
# Das sagt etwas über glxinfo, nichts über OpenGL.
|
||||||
|
#
|
||||||
|
# Deshalb: Prüfungen nur zur Information, und im Zweifel immer den
|
||||||
|
# Software-Pfad. KWin und QtQuick haben je einen, der die GL-Ebene ganz umgeht.
|
||||||
|
gl_test "OpenGL in Software (llvmpipe)" LIBGL_ALWAYS_SOFTWARE=1 || true
|
||||||
|
GL_WEG=software
|
||||||
|
unset GALLIUM_DRIVER
|
||||||
|
export LIBGL_ALWAYS_SOFTWARE=1
|
||||||
|
export KWIN_COMPOSE=Q # KWin: QPainter statt OpenGL
|
||||||
|
export QT_QUICK_BACKEND=software
|
||||||
|
export QMLSCENE_DEVICE=softwarecontext
|
||||||
|
echo " → Weiter mit Software-Rendering (KWin QPainter, QtQuick software)."
|
||||||
|
echo " Träge, aber für S1 ausreichend: die Frage ist, OB es läuft."
|
||||||
|
echo " Ein scheiterndes glxinfo schließt das nicht aus — es prüft anders."
|
||||||
|
fi
|
||||||
|
echo " Verwendeter Weg: $GL_WEG"
|
||||||
|
|
||||||
# ── D-Bus ────────────────────────────────────────────────────────────────────
|
# ── D-Bus ────────────────────────────────────────────────────────────────────
|
||||||
if [ ! -e /run/dbus/system_bus_socket ]; then
|
if [ ! -e /run/dbus/system_bus_socket ]; then
|
||||||
@@ -73,23 +189,83 @@ fi
|
|||||||
# Das ist die eigentliche Wette. In diesem Modus braucht KWin weder DRM noch Seat.
|
# Das ist die eigentliche Wette. In diesem Modus braucht KWin weder DRM noch Seat.
|
||||||
echo ""
|
echo ""
|
||||||
echo "── Versuch A: kwin_wayland --x11-display ──"
|
echo "── Versuch A: kwin_wayland --x11-display ──"
|
||||||
|
echo " Umgebung: GL_WEG=$GL_WEG KWIN_COMPOSE=${KWIN_COMPOSE:-(nicht gesetzt)}"
|
||||||
|
echo " QT_QUICK_BACKEND=${QT_QUICK_BACKEND:-(nicht gesetzt)}"
|
||||||
LOGA=/tmp/hpos-s1-versuchA.log
|
LOGA=/tmp/hpos-s1-versuchA.log
|
||||||
dbus-run-session -- kwin_wayland \
|
|
||||||
|
# Die lange Optionsform statt '-p': kurze Formen ändern sich zwischen den
|
||||||
|
# Plasma-Fassungen leichter als lange, und eine unbekannte Kurzoption wird still
|
||||||
|
# ignoriert statt bemängelt. Genau das ist der Verdacht.
|
||||||
|
#
|
||||||
|
# Und statt einen Namen zu raten, werden die vorhandenen Shells der Reihe nach
|
||||||
|
# ausprobiert. 'invalid corona' im Protokoll ist das Abbruchkriterium — es sagt,
|
||||||
|
# dass plasmashell nichts zeichnen wird, ohne dass man hinschauen muss.
|
||||||
|
beenden_versuch() {
|
||||||
|
[ -n "${PID_A:-}" ] && kill "$PID_A" 2>/dev/null
|
||||||
|
pkill -x kwin_wayland 2>/dev/null
|
||||||
|
pkill -x plasmashell 2>/dev/null
|
||||||
|
sleep 3
|
||||||
|
}
|
||||||
|
|
||||||
|
starte_mit_shell() {
|
||||||
|
local shell="$1"
|
||||||
|
: >"$LOGA"
|
||||||
|
dbus-run-session -- kwin_wayland \
|
||||||
--x11-display "$DISPLAY" \
|
--x11-display "$DISPLAY" \
|
||||||
--width "$BREITE" --height "$HOEHE" \
|
--width "$BREITE" --height "$HOEHE" \
|
||||||
--xwayland \
|
--xwayland \
|
||||||
-- plasmashell -p org.kde.plasma.phoneshell \
|
-- plasmashell ${shell:+--shell-plugin "$shell"} \
|
||||||
>"$LOGA" 2>&1 &
|
>"$LOGA" 2>&1 &
|
||||||
PID_A=$!
|
PID_A=$!
|
||||||
echo " gestartet (PID $PID_A), warte 25 s auf die Oberfläche …"
|
sleep 25
|
||||||
sleep 25
|
kill -0 "$PID_A" 2>/dev/null || return 1
|
||||||
|
grep -q 'invalid corona' "$LOGA" && return 2
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
if kill -0 "$PID_A" 2>/dev/null; then
|
KANDIDATEN="$SHELL_PAKET"
|
||||||
echo " ✓ Versuch A läuft noch — jetzt in die Termux:X11-App wechseln und schauen."
|
for w in org.kde.plasma.mobileshell org.kde.plasma.nano; do
|
||||||
|
case " $KANDIDATEN " in *" $w "*) ;; *) KANDIDATEN="$KANDIDATEN $w" ;; esac
|
||||||
|
done
|
||||||
|
|
||||||
|
ERFOLG=0
|
||||||
|
for shell in $KANDIDATEN; do
|
||||||
|
[ -d "/usr/share/plasma/shells/$shell" ] || continue
|
||||||
echo ""
|
echo ""
|
||||||
echo " Beenden mit: pkill -f kwin_wayland"
|
echo " → Versuche Shell: $shell"
|
||||||
|
starte_mit_shell "$shell"
|
||||||
|
case $? in
|
||||||
|
0) echo " ✓ läuft, und plasmashell meldet keine ungültige Shell."
|
||||||
|
ERFOLG=1; break ;;
|
||||||
|
2) echo " ✗ 'invalid corona' — diese Shell trägt nicht."
|
||||||
|
grep 'invalid corona' "$LOGA" | tail -1 | sed 's/^/ /'
|
||||||
|
beenden_versuch ;;
|
||||||
|
*) echo " ✗ Prozess sofort beendet."
|
||||||
|
tail -n 15 "$LOGA" | sed 's/^/ /' ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ "$ERFOLG" = 1 ] && kill -0 "$PID_A" 2>/dev/null; then
|
||||||
|
echo ""
|
||||||
|
echo " ✓ Versuch A läuft — jetzt in die Termux:X11-App wechseln und schauen."
|
||||||
|
echo " Verwendete Shell: $shell"
|
||||||
|
echo " Beenden mit: pkill -x kwin_wayland"
|
||||||
echo " Protokoll: $LOGA"
|
echo " Protokoll: $LOGA"
|
||||||
tail -n 25 "$LOGA" 2>/dev/null | sed 's/^/ /'
|
tail -n 20 "$LOGA" 2>/dev/null | sed 's/^/ /'
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
if kill -0 "${PID_A:-0}" 2>/dev/null; then
|
||||||
|
# Läuft noch, aber keine Shell hat getragen: KWin steht, plasmashell zeichnet
|
||||||
|
# nichts. Das ist ein Teilerfolg und soll auch so benannt werden — der
|
||||||
|
# Compositor ist der schwierige Teil, die Shell der austauschbare.
|
||||||
|
echo ""
|
||||||
|
echo " ! KWin läuft, aber keine der vorhandenen Shells ließ sich laden."
|
||||||
|
echo " Der Compositor ist damit bewiesen, die Shell nicht."
|
||||||
|
echo " Nächster Schritt von Hand, zeigt die eigentliche Ursache:"
|
||||||
|
echo " plasmashell --shell-plugin org.kde.plasma.mobileshell"
|
||||||
|
echo " Protokoll: $LOGA"
|
||||||
|
tail -n 20 "$LOGA" 2>/dev/null | sed 's/^/ /'
|
||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|||||||
@@ -65,6 +65,55 @@ require_termux() {
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Prüft, ob die Grundlage steht, BEVOR ein Beweis losläuft. Ohne das scheitert ein
|
||||||
|
# Test mitten im Ablauf und sieht aus wie ein inhaltlicher Fehlschlag, obwohl nur
|
||||||
|
# die Vorbereitung fehlt — die irreführendste Sorte Fehler.
|
||||||
|
voraussetzungen_pruefen() {
|
||||||
|
local distro="${1:-debian}" fehlt=0
|
||||||
|
|
||||||
|
section "Voraussetzungen"
|
||||||
|
|
||||||
|
if ! have proot-distro; then
|
||||||
|
fail "proot-distro ist nicht installiert"
|
||||||
|
hint "Nachholen mit: bash spike/00-bootstrap-termux.sh"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 'cannot execute: required file not found' heißt NICHT, dass das Skript fehlt.
|
||||||
|
# Es heißt, dass der Interpreter aus seiner Shebang-Zeile fehlt. Der Unterschied
|
||||||
|
# kostet sonst eine halbe Stunde Suche an der falschen Stelle.
|
||||||
|
local pfad interpreter
|
||||||
|
pfad="$(command -v proot-distro)"
|
||||||
|
if ! proot-distro list >/dev/null 2>&1; then
|
||||||
|
fail "proot-distro lässt sich nicht ausführen"
|
||||||
|
interpreter="$(head -1 "$pfad" 2>/dev/null | sed 's|^#!||; s| .*||')"
|
||||||
|
log " Datei: $pfad"
|
||||||
|
log " Shebang: ${interpreter:-(keine)}"
|
||||||
|
if [ -n "$interpreter" ] && [ ! -x "$interpreter" ]; then
|
||||||
|
fail "Der Interpreter $interpreter fehlt oder ist nicht ausführbar."
|
||||||
|
hint "Das ist die Ursache, nicht proot-distro selbst."
|
||||||
|
hint "Reparieren mit: pkg install -y bash coreutils proot proot-distro"
|
||||||
|
else
|
||||||
|
hint "Reparieren mit: pkg reinstall -y proot-distro"
|
||||||
|
fi
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
ok "proot-distro ausführbar"
|
||||||
|
|
||||||
|
# Anmeldeversuch statt Pfad- oder Ausgabeprüfung: proot-distro hat sein
|
||||||
|
# Ablageformat gewechselt, und danach lag das Rootfs woanders als erwartet.
|
||||||
|
# Diese Prüfung fragt nicht, wo etwas liegt, sondern ob es funktioniert.
|
||||||
|
if proot-distro login "$distro" -- true >/dev/null 2>&1; then
|
||||||
|
ok "$distro-Rootfs lauffähig"
|
||||||
|
else
|
||||||
|
fail "$distro-Rootfs fehlt oder startet nicht"
|
||||||
|
hint "Nachholen mit: bash spike/00-bootstrap-termux.sh"
|
||||||
|
fehlt=1
|
||||||
|
fi
|
||||||
|
|
||||||
|
return $fehlt
|
||||||
|
}
|
||||||
|
|
||||||
# Fragt am Ende jedes Beweises nach dem, was nur ein Mensch beurteilen kann:
|
# Fragt am Ende jedes Beweises nach dem, was nur ein Mensch beurteilen kann:
|
||||||
# ob es tatsächlich funktioniert hat. Das Ergebnis geht ins Protokoll.
|
# ob es tatsächlich funktioniert hat. Das Ergebnis geht ins Protokoll.
|
||||||
verdict() {
|
verdict() {
|
||||||
|
|||||||
Executable
+102
@@ -0,0 +1,102 @@
|
|||||||
|
#!/data/data/com.termux/files/usr/bin/bash
|
||||||
|
# HPOS — SSH-Zugang zu Termux einrichten. Reines Entwicklerwerkzeug.
|
||||||
|
#
|
||||||
|
# Für die Arbeit am Projekt ist ein SSH-Zugang deutlich angenehmer als die
|
||||||
|
# Bildschirmtastatur: echte Tastatur, Zwischenablage, Verlauf, und über sshfs
|
||||||
|
# lassen sich die Dateien auf dem Telefon direkt im Editor des Rechners öffnen.
|
||||||
|
#
|
||||||
|
# Termux' sshd lauscht auf Port 8022, nicht 22 — Ports unter 1024 darf eine
|
||||||
|
# gewöhnliche App nicht belegen.
|
||||||
|
#
|
||||||
|
# Aufruf in Termux: bash ~/hpos/tools/dev-ssh.sh
|
||||||
|
set -uo pipefail
|
||||||
|
|
||||||
|
SCHLUESSEL_ABLAGE="/sdcard/hpos-id.pub"
|
||||||
|
|
||||||
|
if [ -t 1 ]; then
|
||||||
|
C_OK=$'\033[32m'; C_WARN=$'\033[33m'; C_ERR=$'\033[31m'
|
||||||
|
C_HEAD=$'\033[1;36m'; C_DIM=$'\033[2m'; C_OFF=$'\033[0m'
|
||||||
|
else
|
||||||
|
C_OK=""; C_WARN=""; C_ERR=""; C_HEAD=""; C_DIM=""; C_OFF=""
|
||||||
|
fi
|
||||||
|
kopf() { printf '\n%s══ %s ══%s\n' "$C_HEAD" "$*" "$C_OFF"; }
|
||||||
|
ok() { printf '%s ✓%s %s\n' "$C_OK" "$C_OFF" "$*"; }
|
||||||
|
warn() { printf '%s !%s %s\n' "$C_WARN" "$C_OFF" "$*"; }
|
||||||
|
fehl() { printf '%s ✗%s %s\n' "$C_ERR" "$C_OFF" "$*"; }
|
||||||
|
hinweis() { printf '%s %s%s\n' "$C_DIM" "$*" "$C_OFF"; }
|
||||||
|
|
||||||
|
case "${PREFIX:-}" in
|
||||||
|
*com.termux*) : ;;
|
||||||
|
*) fehl "Dieses Skript läuft in Termux auf dem Telefon."; exit 1 ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
kopf "OpenSSH"
|
||||||
|
if command -v sshd >/dev/null 2>&1; then
|
||||||
|
ok "bereits installiert"
|
||||||
|
else
|
||||||
|
pkg install -y openssh || { fehl "Installation fehlgeschlagen"; exit 1; }
|
||||||
|
ok "installiert"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ── Anmeldung ────────────────────────────────────────────────────────────────
|
||||||
|
# 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.
|
||||||
|
kopf "Anmeldung"
|
||||||
|
mkdir -p "$HOME/.ssh" && chmod 700 "$HOME/.ssh"
|
||||||
|
|
||||||
|
if [ -r "$SCHLUESSEL_ABLAGE" ]; then
|
||||||
|
if grep -qxFf "$SCHLUESSEL_ABLAGE" "$HOME/.ssh/authorized_keys" 2>/dev/null; then
|
||||||
|
ok "Öffentlicher Schlüssel bereits hinterlegt"
|
||||||
|
else
|
||||||
|
cat "$SCHLUESSEL_ABLAGE" >>"$HOME/.ssh/authorized_keys"
|
||||||
|
chmod 600 "$HOME/.ssh/authorized_keys"
|
||||||
|
ok "Öffentlichen Schlüssel aus $SCHLUESSEL_ABLAGE übernommen"
|
||||||
|
fi
|
||||||
|
elif [ -s "$HOME/.ssh/authorized_keys" ]; then
|
||||||
|
ok "authorized_keys vorhanden"
|
||||||
|
else
|
||||||
|
warn "Kein öffentlicher Schlüssel gefunden."
|
||||||
|
hinweis "Bequemer Weg — auf dem RECHNER ausführen:"
|
||||||
|
hinweis " adb push ~/.ssh/id_ed25519.pub $SCHLUESSEL_ABLAGE"
|
||||||
|
hinweis " (oder ~/.ssh/id_rsa.pub) und dieses Skript erneut aufrufen."
|
||||||
|
echo
|
||||||
|
printf ' Stattdessen jetzt ein Passwort setzen? [j/N] > '
|
||||||
|
read -r MIT_PASSWORT
|
||||||
|
case "${MIT_PASSWORT:-n}" in
|
||||||
|
j|J) passwd || { fehl "Passwort nicht gesetzt"; exit 1; } ;;
|
||||||
|
*) fehl "Ohne Schlüssel oder Passwort ist keine Anmeldung möglich."; exit 1 ;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ── Dienst ───────────────────────────────────────────────────────────────────
|
||||||
|
kopf "sshd"
|
||||||
|
pkill sshd 2>/dev/null && hinweis "alte Instanz beendet"
|
||||||
|
sleep 1
|
||||||
|
if sshd; then ok "läuft auf Port 8022"; else fehl "Start fehlgeschlagen"; exit 1; fi
|
||||||
|
|
||||||
|
# ── Adresse ──────────────────────────────────────────────────────────────────
|
||||||
|
kopf "Verbinden"
|
||||||
|
IP=$(ip -4 addr show 2>/dev/null | awk '/inet .*(wlan|swlan)/ {print $2}' | cut -d/ -f1 | head -1)
|
||||||
|
[ -z "$IP" ] && IP=$(ip -4 route get 1.1.1.1 2>/dev/null | awk '{print $7; exit}')
|
||||||
|
BENUTZER=$(whoami)
|
||||||
|
|
||||||
|
cat <<TEXT
|
||||||
|
Vom Rechner aus:
|
||||||
|
|
||||||
|
ssh -p 8022 ${BENUTZER}@${IP:-<telefon-ip>}
|
||||||
|
|
||||||
|
Dateien im Editor des Rechners bearbeiten:
|
||||||
|
|
||||||
|
mkdir -p ~/telefon
|
||||||
|
sshfs -p 8022 ${BENUTZER}@${IP:-<telefon-ip>}:/data/data/com.termux/files/home ~/telefon
|
||||||
|
# lösen mit: fusermount3 -u ~/telefon
|
||||||
|
|
||||||
|
Gut zu wissen:
|
||||||
|
|
||||||
|
· sshd überlebt keinen Neustart von Termux — dann dieses Skript erneut,
|
||||||
|
oder schlicht 'sshd' aufrufen.
|
||||||
|
· Port 8022 statt 22, weil eine gewöhnliche App keine Ports unter 1024
|
||||||
|
belegen darf.
|
||||||
|
· Der Dienst ist im ganzen WLAN erreichbar. In fremden Netzen abschalten:
|
||||||
|
pkill sshd
|
||||||
|
TEXT
|
||||||
Executable
+141
@@ -0,0 +1,141 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# HPOS — scrcpy installieren. Läuft auf dem RECHNER, nicht auf dem Telefon.
|
||||||
|
#
|
||||||
|
# scrcpy ist in Debian 12 nicht enthalten; erst ab trixie-backports, und dort in
|
||||||
|
# contrib statt main. 'apt install scrcpy' scheitert deshalb mit "Paket kann nicht
|
||||||
|
# gefunden werden". Das Projekt liefert aber ein eigenständiges Linux-Paket, das
|
||||||
|
# ohne Systemabhängigkeiten und ohne root auskommt.
|
||||||
|
#
|
||||||
|
# Installiert wird nach ~/.local — nichts außerhalb des Benutzerverzeichnisses.
|
||||||
|
#
|
||||||
|
# Aufruf: ./tools/install-scrcpy.sh [--deinstallieren]
|
||||||
|
set -uo pipefail
|
||||||
|
|
||||||
|
ZIEL="$HOME/.local/opt/scrcpy"
|
||||||
|
STARTER="$HOME/.local/bin/scrcpy"
|
||||||
|
|
||||||
|
if [ -t 1 ]; then
|
||||||
|
C_OK=$'\033[32m'; C_WARN=$'\033[33m'; C_ERR=$'\033[31m'
|
||||||
|
C_HEAD=$'\033[1;36m'; C_DIM=$'\033[2m'; C_OFF=$'\033[0m'
|
||||||
|
else
|
||||||
|
C_OK=""; C_WARN=""; C_ERR=""; C_HEAD=""; C_DIM=""; C_OFF=""
|
||||||
|
fi
|
||||||
|
kopf() { printf '\n%s══ %s ══%s\n' "$C_HEAD" "$*" "$C_OFF"; }
|
||||||
|
ok() { printf '%s ✓%s %s\n' "$C_OK" "$C_OFF" "$*"; }
|
||||||
|
warn() { printf '%s !%s %s\n' "$C_WARN" "$C_OFF" "$*"; }
|
||||||
|
fehl() { printf '%s ✗%s %s\n' "$C_ERR" "$C_OFF" "$*"; }
|
||||||
|
hinweis() { printf '%s %s%s\n' "$C_DIM" "$*" "$C_OFF"; }
|
||||||
|
|
||||||
|
if [ "${1:-}" = "--deinstallieren" ]; then
|
||||||
|
rm -rf "$ZIEL" "$STARTER"
|
||||||
|
ok "Entfernt: $ZIEL und $STARTER"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
command -v curl >/dev/null 2>&1 || { fehl "curl wird gebraucht."; exit 1; }
|
||||||
|
command -v tar >/dev/null 2>&1 || { fehl "tar wird gebraucht."; exit 1; }
|
||||||
|
|
||||||
|
case "$(uname -m)" in
|
||||||
|
x86_64|amd64) ARCH=x86_64 ;;
|
||||||
|
aarch64|arm64) ARCH=aarch64 ;;
|
||||||
|
*) fehl "Keine fertigen Pakete für $(uname -m). Dann aus den Quellen bauen."; exit 1 ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
# ── Herunterladen ────────────────────────────────────────────────────────────
|
||||||
|
kopf "Aktuelle Fassung ermitteln"
|
||||||
|
URL=$(curl -sfL https://api.github.com/repos/Genymobile/scrcpy/releases/latest \
|
||||||
|
| python3 -c "
|
||||||
|
import json, sys
|
||||||
|
d = json.load(sys.stdin)
|
||||||
|
for a in d['assets']:
|
||||||
|
if a['name'].startswith('scrcpy-linux-$ARCH') and a['name'].endswith('.tar.gz'):
|
||||||
|
print(a['browser_download_url'])
|
||||||
|
break
|
||||||
|
" 2>/dev/null)
|
||||||
|
|
||||||
|
if [ -z "$URL" ]; then
|
||||||
|
fehl "Kein passendes Paket für linux-$ARCH gefunden."
|
||||||
|
hinweis "Releases prüfen: https://github.com/Genymobile/scrcpy/releases"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
ok "$(basename "$URL")"
|
||||||
|
|
||||||
|
kopf "Herunterladen"
|
||||||
|
TMP=$(mktemp -d)
|
||||||
|
trap 'rm -rf "$TMP"' EXIT
|
||||||
|
if ! curl -fL --progress-bar -o "$TMP/s.tar.gz" "$URL"; then
|
||||||
|
fehl "Download fehlgeschlagen."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
tar xzf "$TMP/s.tar.gz" -C "$TMP" || { fehl "Entpacken fehlgeschlagen."; exit 1; }
|
||||||
|
|
||||||
|
QUELLE=$(find "$TMP" -maxdepth 1 -type d -name 'scrcpy-linux-*' | head -1)
|
||||||
|
[ -n "$QUELLE" ] || { fehl "Unerwarteter Aufbau des Archivs."; exit 1; }
|
||||||
|
|
||||||
|
kopf "Installieren"
|
||||||
|
rm -rf "$ZIEL"
|
||||||
|
mkdir -p "$(dirname "$ZIEL")" "$(dirname "$STARTER")"
|
||||||
|
mv "$QUELLE" "$ZIEL"
|
||||||
|
chmod +x "$ZIEL/scrcpy" "$ZIEL/adb" 2>/dev/null || true
|
||||||
|
ok "nach $ZIEL"
|
||||||
|
|
||||||
|
# ── Starter mit passendem adb ────────────────────────────────────────────────
|
||||||
|
# Das Paket bringt ein eigenes adb mit, das neuer sein kann als das im System.
|
||||||
|
# Trifft ein anderes adb auf einen laufenden Server, beendet es ihn — und genau
|
||||||
|
# das kappt eine bestehende WLAN-Verbindung zum Telefon mitten in der Arbeit.
|
||||||
|
# Deshalb bekommt scrcpy dasselbe adb wie die übrigen Skripte.
|
||||||
|
SYSTEM_ADB=""
|
||||||
|
for k in "${ADB:-}" "$HOME/Android/Sdk/platform-tools/adb" $(command -v adb 2>/dev/null); do
|
||||||
|
[ -n "$k" ] && [ -x "$k" ] && { SYSTEM_ADB="$k"; break; }
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ -n "$SYSTEM_ADB" ]; then
|
||||||
|
V_SYS=$("$SYSTEM_ADB" version 2>/dev/null | sed -n 2p)
|
||||||
|
V_MIT=$("$ZIEL/adb" version 2>/dev/null | sed -n 2p)
|
||||||
|
hinweis "System-adb: $V_SYS"
|
||||||
|
hinweis "Mitgeliefert: $V_MIT"
|
||||||
|
if [ "$V_SYS" != "$V_MIT" ]; then
|
||||||
|
warn "Verschiedene Fassungen — scrcpy bekommt das System-adb,"
|
||||||
|
hinweis "sonst würde der adb-Server neu starten und die WLAN-Verbindung abreißen."
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
cat >"$STARTER" <<STARTER_ENDE
|
||||||
|
#!/bin/sh
|
||||||
|
# Erzeugt von tools/install-scrcpy.sh — nicht von Hand ändern.
|
||||||
|
# Setzt bewusst dasselbe adb wie die Provisioning-Skripte: ein abweichendes
|
||||||
|
# beendet den laufenden adb-Server und trennt damit das Telefon.
|
||||||
|
[ -n "\${ADB:-}" ] || ADB="${SYSTEM_ADB:-$ZIEL/adb}"
|
||||||
|
export ADB
|
||||||
|
export SCRCPY_SERVER_PATH="$ZIEL/scrcpy-server"
|
||||||
|
exec "$ZIEL/scrcpy" "\$@"
|
||||||
|
STARTER_ENDE
|
||||||
|
chmod +x "$STARTER"
|
||||||
|
ok "Starter: $STARTER"
|
||||||
|
|
||||||
|
# ── Prüfen ───────────────────────────────────────────────────────────────────
|
||||||
|
kopf "Prüfen"
|
||||||
|
if FEHLT=$(ldd "$ZIEL/scrcpy" 2>/dev/null | grep 'not found'); then
|
||||||
|
fehl "Fehlende Bibliotheken:"
|
||||||
|
printf '%s\n' "$FEHLT" | sed 's/^/ /'
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
ok "Keine fehlenden Bibliotheken"
|
||||||
|
ok "$("$STARTER" --version 2>&1 | head -1)"
|
||||||
|
|
||||||
|
case ":$PATH:" in
|
||||||
|
*":$HOME/.local/bin:"*) ok "~/.local/bin liegt in PATH" ;;
|
||||||
|
*) warn "~/.local/bin fehlt in PATH"
|
||||||
|
hinweis "In ~/.bashrc ergänzen: export PATH=\"\$HOME/.local/bin:\$PATH\"" ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
kopf "Loslegen"
|
||||||
|
cat <<'TEXT'
|
||||||
|
scrcpy Bildschirm spiegeln, Zwischenablage beidseitig
|
||||||
|
scrcpy --max-size 1024 weniger Bandbreite, flüssiger über WLAN
|
||||||
|
scrcpy --turn-screen-off Telefonbildschirm aus, spart Akku
|
||||||
|
scrcpy --stay-awake Bildschirm bleibt an, solange gespiegelt wird
|
||||||
|
|
||||||
|
Tastatur und Maus des Rechners wirken direkt im Telefon — auch in Termux.
|
||||||
|
Deinstallieren: ./tools/install-scrcpy.sh --deinstallieren
|
||||||
|
TEXT
|
||||||
Reference in New Issue
Block a user