Note
๐จ๐ณ ไธญๆ็จๆท็่ฟ้ / For Chinese readers๏ผๅฎๆดไธญๆๆๆกฃ โ README_zh-CN.md
Turn any Android TV box or Android device into a tiny, always-on Ubuntu server. A Kotlin Android TV app boots a genuine Ubuntu (22.04 / 24.04 / 26.04) via a native chroot, auto-installs OpenSSH, and shows the SSH connection info right on your living-room screen.
Most TV boxes are wasted silicon โ sitting idle, running ad-riddled launchers. TVUbuntu gives that hardware a second life as a real Linux server:
- ๐ง A genuine Ubuntu userland, not a container-emulated shell. Run
apt, compile code, host services. - ๐ป SSH in from your laptop โ it behaves like any other headless Ubuntu box on your LAN.
- ๐ Always-on, low-power โ a TV box draws ~2โ3 W and can stay up 24/7 as a homelab node.
- ๐ฐ Recycle what you own โ no need to buy a Raspberry Pi or a VPS.
โโโโโโโโโโโโโโโโโโโโโโโโโโโ SSH (port 22) โโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Your Laptop / PC โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโถ โ Android TV Box (root) โ
โ $ ssh root@192.168.x.xโ โ โโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ โ โ Ubuntu chroot โ โ
โ โ โ โ โโ openssh-server โ โ
โ โ โ โ โโ nginx / PHP / DB โ โ
โ โ โ โ โโ your services โ โ
โ โ โ โโโโโโโโโโโโโโโโโโโโโโโโ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โฒ โ
โ TVUbuntu App shows host / user / password โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
| Feature | Description |
|---|---|
| ๐ง Native chroot | Uses the kernel-native chroot โ no proot binary, lighter and faster. |
| ๐ก Auto rootfs download | App downloads the minimal ubuntu-base tarball and decodes gzip on-device (avoids the box's toybox tar quirks). |
| ๐ Zero-config SSH | Installs & launches openssh-server, then displays host / user / password / port on the TV. |
| ๐ฎ TV-remote UI | D-Pad navigation, focus-scaling "cursor" animation, large high-contrast buttons โ built for a remote, not a touchscreen. |
| ๐ Multi-architecture | arm64 (real boxes), amd64 (x86_64 emulators like MuMu), armhf (32-bit ARM). |
| ๐ Multi-version | Ubuntu 22.04 (jammy) / 24.04 (noble) / 26.04 (resolute), isolated per version+arch. |
| โ๏ธ Boot auto-start | Optional "start Ubuntu on boot" + launch-on-boot receiver. |
| ๐ก๏ธ Robust shell layer | ShellExecutor auto-detects su modes (interactive vs su -c), streams live progress, survives large output. |
| ๐ Production web stack | One-shot bootstrap_server.sh spins up nginx + PHP-FPM + MariaDB + Redis under supervisor. |
Main UI โ Ubuntu is running and SSH connection details are shown right on the TV.
Settings โ choose Ubuntu version, CPU architecture, and enable boot auto-start.
| Layer | Choice |
|---|---|
| Language | Kotlin |
| Build | Gradle 8.5 + Android Gradle Plugin 8.2.2 |
| Min / Target SDK | 21 (Android 5.0) / 34 (Android 14) |
| UI | Material Components + TV-adapted layouts (ViewBinding) |
| Concurrency | Kotlin Coroutines |
| Runtime model | Root chroot of ubuntu-base (no systemd inside) |
| Service mgmt | supervisor (inside Ubuntu) for the web stack |
TVUbuntu/
โโโ app/
โ โโโ build.gradle.kts # App module: minSdk 21, version 1.2.2
โ โโโ proguard-rules.pro
โ โโโ src/main/
โ โโโ AndroidManifest.xml # TV Leanback launcher + boot receiver
โ โโโ assets/
โ โ โโโ start.sh # chroot bootstrap: mount, install SSH, run
โ โ โโโ stop.sh # teardown: kill sshd, unmount
โ โโโ java/com/ubuntucontroller/
โ โ โโโ MainActivity.kt # TV UI: status, start/stop, SSH card
โ โ โโโ SettingsActivity.kt # scripts / SSH / version / arch config
โ โ โโโ UbuntuService.kt # core logic: rootfs, arch, status, SSH info
โ โ โโโ ShellExecutor.kt # root shell executor (su auto-detect)
โ โ โโโ BootReceiver.kt # auto-launch on device boot
โ โ โโโ TvFocusUtils.kt # D-Pad focus helpers (TV cursor)
โ โโโ res/ # layouts, drawables, strings, colors, themes
โโโ bootstrap_server.sh # ๐ production LEMP-ish stack in one shot
โโโ build.gradle.kts # root project
โโโ settings.gradle.kts
โโโ gradle.properties
โโโ gradlew / gradlew.bat # Gradle wrapper scripts
โโโ AGENTS.md # project notes for AI agents
App (Kotlin, root)
โ deployAssets() โ push start.sh / stop.sh to /data/local/ubuntu
โ ensureRootfs() โ download ubuntu-base-<ver>-<arch>.tar.gz, gzip-decode on device
โผ
start.sh (run as root)
โโ mount proc/sys/dev/pts into rootfs
โโ fix toybox-tar symlinks / hardlinks / setuid bits
โโ chroot smoke-test (/bin/bash really runs)
โโ chroot โ apt install openssh-server (+ curl/git/nano/sudo โฆ)
โโ init root password once, enable PermitRootLogin + PasswordAuthentication
โโ chroot โ /usr/sbin/sshd -D -p <port> (+ three-layer boot: /etc/rc.local โ supervisord โ /etc/init.d/*)
โผ
MainActivity shows: SSH host (device IP) ยท user ยท password ยท port
โผ
You: ssh root@<device-ip> โ a real Ubuntu shell ๐
Engineering highlights (the tricky bits we solved):
- Architecture detection that isn't fooled (fixed in 1.2.1). Emulators like MuMu fake
uname -masaarch64while the real kernel isx86_64; TVUbuntu corrects toamd64only when the true arch is x86_64 yetunamelies. Genuine arm64 / armhf / x86 boxes keep their true arch, so Python/pip inside the chroot resolve the correct platform. Manual override remains available. - Three-layer service auto-start (new in 1.2.2). On every boot
run_ubuntu.shlaunches services in order: (1) your custom/etc/rc.local, (2)supervisordif installed, (3) a generic/etc/init.d/*sweep that auto-discovers and starts any service with an init script โ so anything you install (nginx, MySQL, Redis, Baotaโฆ) comes up on reboot without editing anything. Dangerous shutdown/mount scripts are skipped for safety. toybox tarsymlink repair. Many boxes ship atarthat drops symlinks/hardlinks/setuid bits. We rebuild them from the tarball listing so/bin/bashand/lib/ld-linuxresolve correctly.- App-side gzip decode. The box
taroften can't handle-z; the App decodes gzip in Java and passes a plain.tartotar -xf. - Live progress over a pipe.
start.shemitsUC_PROGRESS|<pct>|<msg>lines that the App renders as a real progress bar. - Safe stop fallback. If
stop.shis missing, the App force-stops viapkill+umount.
- The box must be rooted (Magisk / SuperSU / AOSP
su). - Enable Settings โ Security โ Unknown sources (or the equivalent on your firmware).
- Install:
adb install TVUbuntu.apk # or copy the APK to the box and open it from a file manager - Open Ubuntu ๆงๅถๅจ from the TV launcher. Grant root when prompted.
๐ก Grab the latest
TVUbuntu.apkfrom the Releases page.
git clone https://github.com/jiyanlin7113-rgb/TVUbuntu.git
cd TVUbuntu
# Open in Android Studio (recommended), or:
gradle wrapper # regenerate the Gradle wrapper if needed
./gradlew assembleRelease # โ app/build/outputs/apk/release/app-release.apk
โ ๏ธ The repo ships without the Gradle wrapper JAR (binary, not text-committable here). The release APK is prebuilt, or use Android Studio which supplies its own Gradle.
- Launch the app on the TV. It detects root and shows the current status.
- Press ๅฏๅจ Ubuntu (Start). First launch downloads the rootfs (~28 MB) and installs OpenSSH (~40 MB of packages) โ this can take a few minutes. Subsequent starts are instant.
- When status turns green, the SSH card shows:
- Host โ the box's LAN IP (WiFi preferred, eth0 fallback)
- User โ
root - Password โ default
Aa123456(change it in Settings) - Port โ
22(configurable)
- From your computer:
ssh root@192.168.1.x # password: Aa123456 - To stop: press ๅๆญข Ubuntu (Stop).
Open ้ ็ฝฎ (Settings) on the main screen:
| Setting | Meaning |
|---|---|
| Ubuntu ็ๆฌ | 22.04 / 24.04 / 26.04 |
| CPU ๆถๆ | auto / amd64 / arm64 / armhf (override auto-detection) |
| ๅฏๅจ/ๅๆญข่ๆฌ่ทฏๅพ | default /data/local/ubuntu/start.sh & stop.sh |
| SSH ็ซฏๅฃ / ็จๆทๅ / ๅฏ็ | connection credentials |
| ๅผๆบ่ชๅจๅฏๅจ | boot the box straight into Ubuntu |
Inside the running Ubuntu, drop in bootstrap_server.sh and run it to stand up a full
web stack managed by supervisor (no systemd in chroot):
# from your SSH session inside the box:
bash /root/bootstrap_server.shIt installs & supervises: nginx (80) ยท PHP-FPM ยท MariaDB (3306) ยท Redis (6379), plus common dev tools. Idempotent โ safe to re-run.
supervisorctl status # see all services
supervisorctl restart nginx # restart one
mysql -u root # MariaDB (unix_socket auth)| Symptom | Fix |
|---|---|
| "Root ๆชๆๆ" | Grant root to the app in Magisk/SuperSU. |
| Download fails | Confirm the box has internet; the App fetches from cdimage.ubuntu.com. |
| SSH not ready after start | Tap ๅคๅถๆฅๅฟ (Copy Log) and inspect /data/local/ubuntu/ubuntu.log. |
chroot smoke-test fails |
Usually SELinux; the script already tries setenforce 0 + chcon. Check the log. |
| Emulator shows wrong arch | Set CPU ๆถๆ = amd64 in Settings. |
- Three-layer service auto-start.
run_ubuntu.shnow runs services in order on every boot:/etc/rc.local(your custom commands, kept for backward compatibility) โsupervisord(if installed) โ a generic/etc/init.d/*sweep that auto-discovers and starts any service exposing an init script. New services boot automatically on reboot with zero config changes; dangerous system scripts (halt/reboot/mount/โฆ) are skipped for safety.
- Fixed real-environment architecture detection.
rootfsArch()now treatsuname -mas the baseline and overrides toamd64only when the true arch is x86_64 butunamewas spoofed (e.g. MuMu emulator masking itself asaarch64). Genuine arm64 / armhf / x86 devices keep their true architecture, so Python/pip inside the chroot read the correct value.
MIT ยฉ 2026 ๅๅคงๅคงไพ / jiyanlin7113-rgb. Free for personal and commercial use. Note: running a chroot requires root and is at your own risk โ it may void warranties and can brick misconfigured devices.
If TVUbuntu gave your old TV box a new life, โญ star the repo and share it! Pull requests and issue reports are very welcome. ๐ง