Thanks to visit codestin.com
Credit goes to github.com

Skip to content

feat: Android 8 (API 26) support — NDK retarget, devtmpfs fix, LF normalization, mount hardening#42

Merged
ExTV merged 4 commits into
ExTV:mainfrom
vitorsaldiva:feature/android8-support
Jun 14, 2026
Merged

feat: Android 8 (API 26) support — NDK retarget, devtmpfs fix, LF normalization, mount hardening#42
ExTV merged 4 commits into
ExTV:mainfrom
vitorsaldiva:feature/android8-support

Conversation

@vitorsaldiva

@vitorsaldiva vitorsaldiva commented Jun 14, 2026

Copy link
Copy Markdown
Contributor

Summary

Extends minimum supported Android version from API 28 to API 26 (Android 8.0) by fixing four independent root causes that together prevented QEMU + the VM guest from working on API 26 devices.

Fixes: #28


Commits

1. feat: add Android 8 (API 26) support with iconv shim

Retargets the NDK toolchain from android28 to android26 throughout the Dockerfile and adds a hand-rolled iconv shim required for the glib build at API 26 (where iconv is not in the NDK sysroot). Lowers minSdk to 26 in the Android project.

2. fix(build): add .gitattributes to enforce LF line endings for Linux scripts

Windows git core.autocrlf=true silently converted LF→CRLF on checkout. When Docker COPY'd init-podroid into the initramfs the shebang became #!/bin/sh\r, causing the kernel to fail init with ENOENT and fall back to mounting /dev/vda directly — booting stale overlay content with old inittab gettys instead of the current squashfs, so boot-stage markers were never emitted and the VM appeared stuck indefinitely.

  • Added .gitattributes: eol=lf for all *.sh, Dockerfile, init-podroid, and build-rootfs/files/**; binary assets marked accordingly
  • Normalized all affected working-copy files from CRLF to LF

3. feat(init): enhance virtual filesystem mounting logic in init script

Intermediate step hardening the early-boot mount sequence before the root-cause fix below.

4. fix(build): fix devtmpfs boot panic, Dockerfile heredoc parse error, and Android 8 docs

The definitive boot-panic fix, addressing three separate issues found during API 26 testing:

devtmpfs mount panic (exitcode=0x00002000 / Attempted to kill init!)

  • util-linux mount stops option parsing at the first non-option argument when POSIXLY_CORRECT is set; -o flags placed after the mountpoint were silently dropped, causing EPERM"must be superuser to use mount" even for root
  • CONFIG_DEVTMPFS_MOUNT=y pre-mounts /dev before /init runs; a second mount call returns EBUSY. Additionally, size=2M is invalid for ramfs-backed devtmpfs → EINVAL. Either failure exits with MNT_EX_FAIL=32, which set -e propagated as PID 1 exit → kernel panic
  • Fix: move -o flags before device/mountpoint; add || true to devtmpfs mount; remove size=2M; add mkdir -p guards; add [podroid-init] echo markers throughout

Dockerfile heredoc parse error (Docker BuildKit)

  • RUN cat > file << EOF ... [section] heredocs were broken by BuildKit treating [section] lines as unknown build instructions
  • Fix: replace the heredoc with COPY build-tools/cross-android-aarch64.ini; extract the Meson cross-compilation config to build-tools/cross-android-aarch64.ini

Documentation

  • README.md, CONTRIBUTING.md, CLAUDE.md: update Android min version 9+8+, add build-tools/ to project layout, document the devtmpfs and Dockerfile quirks for future contributors

Testing

Device Android Result
Asus Zenfone 4 (Z01KD) 8.0 (API 26), arm64 ✅ Full boot; Ready! detected by BootStageDetector in ~55 s, no timeout fallback triggered

The guest-side fixes (init-podroid, .gitattributes) are host-OS agnostic and require no API-level guards in the Android app.


Checklist

  • Tested on a real arm64 device
  • README.md updated (user-facing: new minimum Android version)
  • CLAUDE.md updated (architecture change: NDK target, build-tools layout, devtmpfs behaviour)
  • CONTRIBUTING.md updated (min version, new build-tools/ directory)
  • Code style matches surrounding files
  • No premature abstractions — each change is the smallest fix for its root cause

vitorsaldiva and others added 4 commits June 8, 2026 20:38
Retarget NDK toolchain from android28 to android26 throughout Dockerfile,
add hand-rolled iconv shim for API-26 glib build, lower minSdk to 26.

Fixes: ExTV#28

Co-authored-by: Copilot <[email protected]>
…cripts

Windows git core.autocrlf=true was silently converting LF→CRLF in all
shell scripts on checkout. When Docker COPY'd init-podroid into the
initramfs the shebang became #!/bin/sh\r, causing the kernel to fail
init with ENOENT (error -2) and fall back to mounting /dev/vda directly.
This booted the old overlay-upper content (with stale inittab having
tty1-6 gettys) instead of the current squashfs, so boot-stage markers
were never emitted and the VM appeared stuck.

Changes:
- Add .gitattributes: force eol=lf for *.sh, Dockerfile, init-podroid,
  all build-rootfs/files/** scripts and configs; mark binary assets
- Normalize all affected working-copy files from CRLF to LF

Both the initramfs /init and the squashfs init.d scripts now carry
correct LF endings, fixing VM boot on all platforms.

Co-authored-by: Copilot <[email protected]>
…and Android 8 docs

- init-podroid: move mount -o flags before device/mountpoint (util-linux stops
  getopt at first non-option arg when POSIXLY_CORRECT is set; options after the
  mountpoint were silently dropped, causing EPERM -> 'must be superuser to use
  mount' even for root)
- init-podroid: add '|| true' to devtmpfs mount and remove 'size=2M'
  (CONFIG_DEVTMPFS_MOUNT=y pre-mounts /dev before /init runs; a second mount
  returns EBUSY, and size= is invalid for ramfs-backed devtmpfs causing EINVAL;
  either failure exits util-linux with MNT_EX_FAIL=32, propagated by set -e as
  exit(32) = kernel exitcode=0x00002000 'Attempted to kill init!')
- init-podroid: add mkdir -p /proc /sys /dev /run guard and [podroid-init]
  diagnostic echo markers throughout the boot sequence
- Dockerfile: replace 'RUN cat > file << EOF ... [binaries]' heredoc with
  'COPY build-tools/cross-android-aarch64.ini' to fix Docker BuildKit parse
  error (BuildKit treats [section] lines in heredocs as unknown instructions)
- build-tools/cross-android-aarch64.ini: new file containing the Meson
  cross-compilation config for aarch64-android26, extracted from the heredoc
- README.md, CONTRIBUTING.md, CLAUDE.md: update Android min version 9+ -> 8+,
  add build-tools/ to project layout, document devtmpfs and Dockerfile quirks

Co-authored-by: Copilot <[email protected]>
@ExTV ExTV merged commit 1f3124b into ExTV:main Jun 14, 2026
@vitorsaldiva

Copy link
Copy Markdown
Contributor Author

Additional test results

Asus Zenfone 4 (ASUS_Z01KD) — Android 8.0 (API 26), arm64

Full boot confirmed. Alpine Linux terminal reached, podroid:~# prompt active. Kernel 7.0.10 on aarch64 (/dev/hvc0).

Zenfone 4 — Android 8.0 boot


Samsung Galaxy S24 Ultra — Android 16, arm64

Full boot confirmed on Android 16. Alpine Linux terminal reached, podroid:~# prompt active. Kernel 7.0.10 on aarch64 (/dev/hvc0).

S24 Ultra — Android 16 boot


Device Model Android API Arch Result
Asus Zenfone 4 ASUS_Z01KD 8.0 26 arm64 ✅ Full boot
Samsung Galaxy S24 Ultra SM-S928 16 36 arm64 ✅ Full boot

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug] - Android 8 [end of support?]

2 participants