I’ve been experimenting with postmarketOS for a long time now. My long-term aspiration is to set up a phone that I can use as a daily driver. I need to overcome a lot of obstacles to achieve this.
Today, my goal is to encrypt the main partition. So if I lose the phone, it doesn’t have all my messaging, email and credentials totally unencrypted. This is a hard requirement before moving forward with a lot of other things.
Encrypting the main partition is a lot more complex on pmOS compared to a regular computing device. On most other devices (desktop, laptop server or even a Raspberry Pi) I would usually boot into a minimal environment with the tools necessary for partitioning, encrypting installation, etc.
postmarketOS takes a rather distinct approach to installation: instead of running the installation and setup process on the device, an entire disk image must be build on another computer, and then flashed over onto the phone. This approach works really well if you have a dozens or hundreds of devices and makes things a bit simpler for devices that don’t have physical keyboards. Personally: I would have preferred a simple installation via SSH.
Preparing a workspace VM
To create a device image, I need a privileged environment with pmbootstrap
.
I’m going to use a VM for this to avoid messing up my system.
First, create a disk image for the VM:
qemu-img create workspace.img 20G
Then, download the Alpine “virtual” image, and run a VM with both the disk and the Alpine installation image installed (notes on qemu usage):
qemu-system-x86_64 --enable-kvm \
-nic user \
-nographic \
-m 1G \
-smp cores=2 \
-drive file=alpine-virt-3.17.3-x86_64.iso,format=raw \
-drive file=workspace.img,format=raw
You might have to drop --enable-kvm
if you hardware doesn’t support KVM. If
you’re on aarch64
just use the aarch64
image and qemu-system-aarch64
. You
don’t need to use x86_64
, this is just what matches my architecture.
In the VM, use setup-alpine
and go through the Alpine installation process.
Nothing special needs to be done here.I didn’t bother setting up ssh
here and
left an empty root password.
Then turn off the VM with poweroff
, and start it again, this time without the
installation media and exposing a directory on the host via 9p
:
qemu-system-x86_64 --enable-kvm \
-nic user \
-nographic \
-m 1G -smp cores=2 \
-drive file=workspace.img,format=raw \
-virtfs local,path=/home/hugo/workspace/oneplus/output,mount_tag=output,security_model=mapped-xattr
Log in as root, and then edit /etc/apk/repositories
. Uncomment the edge
repositories and remove everything else. E.g.:
http://dl-cdn.alpinelinux.org/alpine/edge/main
http://dl-cdn.alpinelinux.org/alpine/edge/community
http://dl-cdn.alpinelinux.org/alpine/edge/testing
Run apk update && apk upgrade -a
and then reboot
(the kernel likely gets
updated, so it’s best to boot into the new one).
Building the device images
Install pmbootstrap
. It also expects either sudo
or doas
to be installed
and configured. sudo
is the easier choice, since it comes pre-configured to
allow root
to use it for anything (and I’ll be using user root
).
apk add pmbootstrap sudo
pmbootstrap
uses sudo
a lot. Simply building an image has 155
invocations of so it would need to be configured with NOPASSWD
, plus a
dedicated user for it, and then need to sudo -u newuser pmbootstrap
each
call. I’m going to skip this pointless indirection entirely:
alias pmbootstrap="pmbootstrap --as-root"
Now initialise it:
pmbootstrap init
The default work path is fine, and so is the edge
channel. However, for
vendor and device pick the ones matching your phone. That’s oneplus
and
enchilada
respectively for me. See pmOS#Devices to find yours.
There’s a variety of user interfaces available. phosh
is a simple user
friendly one, but not very flexible, tweakable nor developer-oriented. I’m
going with sxmo-de-sway
. sxmo
takes some learning to initially
understand (especially if you’re coming from iOS/Android), but it’s the most
hackable one and a very good target if you’re wanting to develop applications
and test them on phones.
Additional packages can be specified at this time. For example:
zsh,docs,git,neovim,font-noto-cjk,cargo,yubikey-manager,dino,telegram-desktop,bubblewrap
Now it’s time to build the actual image. Contrary to what I initially expected
pmbootstrap build
does not build the image (this command builds a single
package). It’s pmbootstrap install
that builds an image, and pmbootstrap export
creates some handy symlinks to it.
To build an image with full disk encryption, use pmbootstrap install --fde
.
Put together, it all looks something like this:
# pmbootstrap install --fde
[... lots of output ommitted ...]
# pmbootstrap export
[13:34:56] (rootfs_oneplus-enchilada) install device-oneplus-enchilada
[13:34:58] (rootfs_oneplus-enchilada) install postmarketos-mkinitfs
[13:35:00] (rootfs_oneplus-enchilada) mkinitfs postmarketos-qcom-sdm845
[13:35:03] Export symlinks to: /tmp/postmarketOS-export
[13:35:03] * boot.img (Fastboot compatible boot.img file, contains initramfs and kernel)
[13:35:03] * initramfs-extra (Extra initramfs files in /boot)
[13:35:03] * initramfs (Initramfs)
[13:35:03] * vmlinuz (Linux kernel)
[13:35:03] * oneplus-enchilada.img (Rootfs with partitions for /boot and /)
[13:35:03] NOTE: chroot is still active (use 'pmbootstrap shutdown' as necessary)
[13:35:03] DONE!
# ls -l /tmp/postmarketOS-export/
total 0
lrwxrwxrwx 1 root root 74 Apr 12 13:30 boot.img -> /root/.local/var/pmbootstrap/chroot_rootfs_oneplus-enchilada/boot/boot.img
lrwxrwxrwx 1 root root 75 Apr 12 13:30 initramfs -> /root/.local/var/pmbootstrap/chroot_rootfs_oneplus-enchilada/boot/initramfs
lrwxrwxrwx 1 root root 81 Apr 12 13:30 initramfs-extra -> /root/.local/var/pmbootstrap/chroot_rootfs_oneplus-enchilada/boot/initramfs-extra
lrwxrwxrwx 1 root root 81 Apr 12 13:30 oneplus-enchilada.img -> /root/.local/var/pmbootstrap/chroot_native/home/pmos/rootfs/oneplus-enchilada.img
lrwxrwxrwx 1 root root 73 Apr 12 13:30 vmlinuz -> /root/.local/var/pmbootstrap/chroot_rootfs_oneplus-enchilada/boot/vmlinuz
Now mount the directory that’s exposed from the host. Note that output
here
matches the value provided for mount_tag
when specified when running qemu
:
mount -t 9p -o trans=virtio output /mnt
An copy the images out:
cp /tmp/postmarketOS-export/boot.img /mnt/
cp /tmp/postmarketOS-export/oneplus-enchilada.img /mnt/
It is now safe to turn off the virtual machine: poweroff
.
Flashing the images onto the device
I’m assuming the device is already unlocked (otherwise check the Devices wiki page linked above). Make sure the USB cable is not plugged into the phone and then press and hold VolUp+Power. After it boots, it will indicate “Fastboot” mode and once it’s in the menu you can release first VolUp, then Power. Now plug the USB cable onto the phone and the other end of it to your other computer.
Flash the images onto the device and then reboot it:
doas fastboot flash boot boot.img
doas fastboot flash userdata oneplus-enchilada.img
doas fastboot reboot
During the initial boot, the main partition will be extended to occupy all of the disk.
The initial installation is now done.