Run Chimera Linux bare-metal on Android devices with Halium and libhybris.
This doc assumes you already have a general knowledge in how porting a Linux distro with downstream kernel works (and ideally have an Ubuntu Touch port for example ready to use kernel artifacts from)
Since I don't yet have proper kernel/base package cports integration done for anything there's some
very rough notes in PORTING.md which boil down to having a bootloader unlocked
treble Android 9–13 device and existing Halium adapted kernel artifacts (*boot.img and modules as
needed) ready to deploy.
Currently known booting ports include:
- Halium 12 based aarch64
Volla Phone X23with kernel v5.10 and MediaTek Helio G99 (MT6789) SoC - Halium 9 based aarch64
Volla Phonewith kernel v4.4 and MediaTek Helio P23 (MT6763) SoC - Maybe even your device...?
gitfor cloning this repo and cports for package building- https://github.com/chimera-linux/cports/blob/master/Usage.md#requirements also apply
- an
apk add base-cbuild-hostaway on chimera systems
- an
- https://github.com/chimera-linux/cports/blob/master/Usage.md#requirements also apply
bashformkrootfs.shsudo(ordoas) for running specific commands asrootwget(orfetch/curl) for fetching base rootfs archive- e.g.
qemu-aarch64-static(orqemu-aarch64) for cross-architecture rootfs building- assuming binfmt configuration setup for qemu user as well
Before generating a rootfs image we need to build some required packages. Assuming you're cross-building on a foreign (non-Chimera Linux) x86_64 host:
# NOTE: adjust target Halium version as needed
halium_version=12
# NOTE: uncomment/define the below ONLY if your device uses 32-bit Halium system image
#halium_arm32=yes
git clone https://github.com/JamiKettunen/cports -b hybris
cd cports
wget https://repo.chimera-linux.org/apk/apk-$(uname -m)-3.0.0_pre12-r0.static -O apk
chmod +x apk
PATH=$PWD:$PATH
./cbuild keygen
./cbuild binary-bootstrap
pkgs="
user/base-hybris
user/halium-gsi-$halium_version.0${halium_arm32:+-arm32}
"
for p in $pkgs; do ./cbuild pkg -a aarch64 ${p}; done
./cbuild prune-pkgs -a aarch64
cd -At this point before creating new rootfs images you should always force pull latest changes locally
(or even afterward rebase the https://github.com/JamiKettunen/cports/tree/hybris clone on latest
upstream https://github.com/chimera-linux/cports/tree/master) and rebuild all packages after e.g.
rm -r packages/{main,user}/aarch64; you may want to enable ccache in etc/config.ini as follows:
[build]
ccache = yesOnce the packages are locally built you'll want to host your repo in some form, e.g. even something
as simple as python3 -m http.server -d packages/ and in config.local.sh configure them to be
used for mkrootfs.sh as well as the booted system:
REPOS=(
"https://repo.chimera-linux.org/current/main"
"https://repo.chimera-linux.org/current/user"
"@hybris-cports http://10.15.19.100:8000/main"
"@hybris-cports http://10.15.19.100:8000/user"
# TODO: enable as you wish for lldb debug symbols etc
#"https://repo.chimera-linux.org/current/main/debug"
#"https://repo.chimera-linux.org/current/user/debug"
#"@hybris-cports http://10.15.19.100:8000/main/debug"
#"@hybris-cports http://10.15.19.100:8000/user/debug"
)NOTE: Replace 10.15.19.100 (host over USB networking) if repo access outside direct USB
connection is desired! Otherwise consider running ./tethering.sh and perhaps check
out or enable the usb-internet overlay for your rootfs builds.
If needed you can transition a previous booted chimera libhybris rootfs over to using them too:
doas rm -r /hybris-cports-packages
doas sed -i '' 's|/hybris-cports-packages|http://10.15.19.100:8000|g' /etc/apk/repositories.d/99-hybris-cports.list
doas apk updateThe worse but still fine working option if you prefer to not host the local package repository anyhow
is to let mkrootfs.sh grab the packages directly from your configured $CPORTS/$CPORTS_PACKAGES_DIR
and leave a /hybris-cports-packages dir with APKINDEXes around on rootfs to keep apk happy
allowing you to upgrade packages later as needed with a workflow similar to below:
# for a one time thing it may make sense to not keep apk artifacts on rootfs if they fit in memory
ssh [email protected] mount tmpfs -t tmpfs /hybris-cports-packages
# sync everything generally
rsync -hvrPt packages/ [email protected]:/hybris-cports-packages
# if you have multiple halium-gsi-* built locally instead and just want to copy e.g. halium-gsi-12*
find packages/ -type f ! -name 'halium-gsi-*' -o -name 'halium-gsi-12*' | sed 's|packages/||' | \
rsync -hvrPt --files-from=- packages/ [email protected]:/hybris-cports-packages
ssh [email protected] apk upgrade -Ua
# the same also works for additional built cports packages, just instead e.g.
ssh [email protected] apk add my-new-package@hybris-cports
# if tmpfs on /hybris-cports-packages was used sync new APKINDEX* in place afterward to keep e.g.
# "apk upgrade -a" happy
ssh [email protected] umount /hybris-cports-packages
rsync -hvrPt --include='*/' --include='APKINDEX*' --exclude='*' packages/ [email protected]:/hybris-cports-packagesUsing config.vidofnir.sh as an example:
./mkrootfs.sh config.vidofnir.shIf without chimera-chroot, xchroot or arch-chroot around already:
git clone https://github.com/chimera-linux/chimera-install-scripts
PATH=$PWD/chimera-install-scripts:$PATHCross-architecture builds assume a working binfmt setup for static qemu-user binary for e.g. aarch64.
Additional configuration is possible through device config files such as shown above,
config.local.sh which may contain some user specific for yourself applied to every device or
environment variables which are as follows (and most seen atop mkrootfs.sh):
ARCH: target rootfs architecture; while configurable onlyaarch64really makes sense or has been tested so far.armv7will require a full from-source bootstrap since no binary packages are officially provided by Chimera Linux (currently) andx86_64Androids are very rare.DATE: https://repo.chimera-linux.org/live/ version to use for base rootfs tarballsFLAVOR: from above version URL subdir the-FLAVORarchive to use;bootstrapandfullare the only sensible choices reallyWORKDIR: mountpoint of rootfs image file during the creation processOUT_ROOTFS: rootfs image file location, you may want to move it out of/tmpdefault as neededIMAGE_SIZE:fallocate -lsize used to create the rootfs image fileAPK_CACHE: apk package cache dir on host to use when runningapkoperations inside chroot to speed up subsequent (re)builds;apk-cache(at chimera-libhybris clone toplevel) is default and when value empty/unset nothing is cachedCPORTS: existing clone location of hybris cports;cports(at chimera-libhybris clone toplevel) and~/cportsas available are automatically supported defaultsCPORTS_PACKAGES_DIR: hybris cports local packages dir containinguseretc; should always bepackages(relative to cports clone toplevel) unless using./cbuild --repository-path ...LOGIN_SHELL: login shell to use for both the non-root and root users; defaults to/bin/bashEXTRA_GROUPS: array of additional groups to include the created non-root user in; defaults towheel network aid_inputPASSWD: password to set for non-root user, when set as empty value only login via SSH pubkey (or on-device autologin); defaults to1234APK_INTERACTIVE: enableapkinteractive mode (prompt for Y/n before continuing operations) for rootfs, disabled when set as empty value on-device autologin); defaults toyesSUDO: command prefix for elevating user privileges to root;sudoanddoasas available are automatically supported defaults (and when value empty/unset)FETCH: command prefix for downloading files;wget,fetchandcurl -Oas available are automatically supported defaultsQEMU_USER_STATIC: qemu-user static binary to use when creating a cross-architecture rootfs; e.g.qemu-aarch64-staticandqemu-aarch64as available are automatically supported defaultsCHROOT_WRAPPER: command prefix for running commands inside rootfs chroot;chimera-chroot,xchrootandarch-chrootas available are automatically supported defaultsREPOS: array of repositories to use; defaults tohttps://repo.chimera-linux.org/current/main https://repo.chimera-linux.org/current/userby the means of defaultchimera-repo-mainandapk add chimera-repo-userwith noREPOSsetPKGS: array of base packages toapk add; defaults tobash rsync networkmanager ...etc.OVERLAYS: array ofoverlaysto "dump" on top of the rootfs before non-root user creation which may containdeploy.shfiles to execute inside chroot ordeploy-host.shfiles sourced in the context (variables et all) ofmkrootfs.sh; defaults tobase usbnet wayfire waydroid host-timezone host-ssh-pubkeywith device configs typically appending more onto it
While most configuration affects the whole mkrootfs.sh there's some which only affect a specific
enabled overlay's deploy-host.sh which can read variables defined via env/configuration.
TIMEZONE: timezone to use in created rootfs, e.g.Europe/Amsterdam; defaults to host/etc/localtime(symlink dereferenced)
SSH_PUBKEYS: SSH public keys to copy for both the non-root and root users in created rootfs; defaults to$HOME/.ssh/id_*.pub
WLAN_SSID: Wi-Fi network SSID the device should connect to on boot once NetworkManager is up (and kernel WLAN driver is initialized by Android container or chimera side as needed)WLAN_PASSWD: The password to be used for connecting to said network
If you wish to use a static configuration instead of DHCP and figuring out the lease given by the DHCP server (typically router):
WLAN_GATEWAY: Static IP address of the network gateway (router), e.g.192.168.1.1WLAN_ADDRESS: Static IP address of the booting device in CIDR notation, e.g.192.168.1.90/24
DNS: Comma-separated servers to use for resolving DNS queries, e.g.8.8.8.8,8.8.4.4; defaults to1.1.1.1
HALIUM_ARM32: when set to any non-empty value instead of installing 64-bit e.g.halium-gsi-10.0setuphalium-gsi-10.0-arm32for devices running 64-bit Linux kernel/userspace but 32-bit Android; automatically set whenARCHisarmv7
NOTE: We call the rootfs.img instead as ubuntu.img when using Halium initrd (and having
android-rootfs.img inside rootfs) to make the cleanest possible mount hierarchy configuration on
final rootfs without polluting it with double-mounts under /android etc.
We do this by placing the generated rootfs image as ubuntu.img on userdata filesystem root. If
it's not already unencrypted and ext4 enter e.g. bootloader mode (or FastbootD as needed) and:
fastboot format:ext4 userdata reboot recoveryWith device in e.g. UBports recovery (TWRP should work too potentially minus xz steps), run on host:
adb shell 'mountpoint -q /data || mount /data'
# NOTE: you may optionally use compression via e.g.
mv /tmp/chimera-rootfs.img /tmp/ubuntu.img && xz /tmp/ubuntu.img && \
adb push /tmp/ubuntu.img.xz /data && adb shell unxz /data/ubuntu.img.xz
# or just wait out the transfer over USB
adb push /tmp/chimera-rootfs.img /data/ubuntu.img
adb shell 'chmod 644 /data/ubuntu.img && sync && reboot'As your SSH public key (~/.ssh/id_*.pub or configured SSH_PUBKEYS file) is copied onto the rootfs
by default you should be able to log in as both hybris (default password: 1234 or configured PASSWD)
and root.
ssh [email protected]
# or
ssh [email protected]You may resize this file at will with the following if the preconfigured IMAGE_SIZE from mkrootfs.sh
(or the loaded configurations files) isn't enough and your recovery environment has resize2fs:
adb shell 'e2fsck -fy /data/ubuntu.img && resize2fs -f /data/ubuntu.img 8G'Otherwise you can resize it online (with chimera booted) but DO NOT run e2fsck outside recovery
with rootfs unmounted to avoid corrupting the filesystem!
doas resize2fs /userdata/ubuntu.img 8G
doas reboot
doas resize2fs /userdata/ubuntu.imgThis is currently the only known working GPU rendering test you can do. Auto-login via agetty-tty1
and ~/.bash_profile is enabled (including logging to /tmp/wayfire.log) by default which should
bring it up on the display but you may also launch it via conspy (tty1) as described below for
further debugging as needed:
doas touch /run/no-wayfire # prevent agetty-tty1 auto-login from re-launching wayfire
pkill wayfire
# NOTE: "doas dinitctl restart agetty-tty1" instead will break input on tty1
doas conspy 1
HYBRIS_LD_DEBUG=1 wayfire &> /tmp/wayfire.logThen you're free to run graphical clients via e.g. WAYLAND_DISPLAY=wayland-0 kgx as hybris user.
To stop Wayfire you have to pkill wayfire as ^C in the tty1 doesn't work
Running Android (LineageOS) container on top of this all is also possible with a Wayland compositor up:
doas waydroid init -s GAPPS
waydroid show-full-uiDo note that on Halium 12+ ports no official image vendor channels are available due to Waydroid
images past Android 11 having issues that need to be ironed out. You can setup some older images
built from lineage-20 (Android 13) trees regardless if you wish but they require running
waydroid show-full-ui twice.
images_url="https://sourceforge.net/projects/aleasto-lineageos/files/LineageOS%2020/waydroid_arm64"
doas mkdir -p /etc/waydroid-extra/images
doas wget "$images_url/system.img/download" -O /etc/waydroid-extra/images/system.img
doas wget "$images_url/vendor.img/download" -O /etc/waydroid-extra/images/vendor.img
doas waydroid init -f- https://github.com/JamiKettunen/cports/tree/hybris (Chimera Linux integration packages)
- https://gitlab.com/hybrisos/hybrisaports (postmarketOS libhybris pkgs before dropped)
- https://github.com/AlpHybris/alphybrisaports (latest similar musl libc project)
- https://github.com/droidian
- https://t.me/halium
