As you might know I'm not much of an Android user (let alone developer) but in order to figure out how something low level works you sometimes need to peek at how vendor kernels handles this. For that it is often useful to add additional debugging.
One such case is QMI communication going on in Qualcomm SOCs. Joel Selvaraj wrote some nice tooling for this.
To make use of this a rooted device and a small kernel patch is needed
and what would be a no-brainer with Linux Mobile took me a moment to
get it to work on Android. Here's the steps I took on a Pixel 3a to
first root the device via Magisk, then build the patched kernel and
put that into a boot.img
to boot it.
Flashing the factory image
If you still have Android on the device you can skip this step.
You can get Android 12 from
developers.google.com. I've
downloaded sargo-sp2a.220505.008-factory-071e368a.zip
. Then put the
device into Fastboot mode (Power
+ Vol-Down
), connect it to your
PC via USB, unzip/unpack the archive and reflash the phone:
unpack sargo-sp2a.220505.008-factory-071e368a.zip
./flash-all.sh
This wipes your device! I had to run it twice since it would time out
on the first run. Note that this unpacked zip contains another zip
(image-sargo-sp2a.220505.008.zip
) which will become useful below.
Enabling USB debugging
Now boot Android and enable Developer mode by going to Settings → About then touching Build Number (at the very bottom) 7 times.
Go back one level, then go to System → Developer Options and enable "USB Debugging".
Obtaining boot.img
There are several ways to get boot.img
. If you just flashed Android
above then you can fetch boot.img
from the already mentioned
image-sargo-sp2a.220505.008.zip
:
unzip image-sargo-sp2a.220505.008.zip boot.img
If you want to fetch the exact boot.img
from your device you can use
TWRP (see the very end of this post).
Becoming root with Magisk
Being able to su
via adb
will later be useful to fetch kernel
logs. For that we first download Magisk as APK. At the time of writing
v28.1 is
current.
Once downloaded we upload the APK and the boot.img
from the previous
step onto the phone (which needs to have Android booted):
adb push Magisk-v28.1.apk /sdcard/Download
adb push boot.img /sdcard/Download
In Android open the Files app, navigate to /sdcard/Download
and
install the Magisk APK by opening the APK.
We now want to patch boot.img
to get su
via adb
to work (so we
can run dmesg
). This happens by hitting Install
in the Magisk app,
then "Select a file to patch". You then select the boot.img
we just
uploaded.
The installation process will create a magisk_patched-<random>.img
in /sdcard/Download
. We can pull that file via adb
back to our
PC:
adb pull /sdcard/Download/magisk_patched-28100_3ucVs.img
Then reboot the phone into fastboot (adb reboot bootloader
) and
flash it (this is optional see below):
fastboot flash boot magisk_patched-28100_3ucVs.img
Now boot the phone again, open the Magisk app, go to SuperUser at the bottom and enable Shell.
If you now connect to your phone via adb
again and now su
should
work:
adb shell
su
As noted above if you want to keep your Android installation pristine
you don't even need to flash this Magisk enabled boot.img
. I've flashed
it so I have su
access for other operations too. If you don't want
to flash it you can still test boot it via:
fastboot boot magisk_patched-28100_3ucVs.img
and then perform the same adb shell su
check as above.
Building the custom kernel
For our QMI debugging to work we need to patch the kernel a bit and
place that in boot.img
too. So let's build the kernel first. For
that we install the necessary tools (which are thankfully packaged in
Debian) and fetch the Android kernel sources:
sudo apt install repo android-platform-tools-base kmod ccache build-essential mkbootimg
mkdir aosp-kernel && cd aosp-kernel
repo init -u https://android.googlesource.com/kernel/manifest -b android-msm-bonito-4.9-android12L
repo sync
With that we can apply Joel's kernel patches and also compile in the touch controller
driver so we don't need to worry if the modules in the initramfs match the kernel. The kernel
sources are in private/msm-google
. I've just applied the diffs on top with patch
and modified
the defconfig and committed the changes. The resulting tree is
here.
We then build the kernel:
PATH=/usr/sbin:$PATH ./build_bonito.sh
The resulting kernel is at
./out/android-msm-pixel-4.9/private/msm-google/arch/arm64/boot/Image.lz4-dtb
.
In order to boot that kernel I found it to be the simplest to just
replace the kernel in the Magisk patched boot.img
as we have that
already. In case you have already deleted that for any reason we can
always fetch the current boot.img
from the phone via TWRP (see below).
Preparing a new boot.img
To replace the kernel in our Magisk enabled
magisk_patched-28100_3ucVs.img
from above with the just built kernel
we can use mkbootimg
for that. I basically copied the steps we're
using when building the boot.img
on the Linux Mobile side:
ARGS=$(unpack_bootimg --format mkbootimg --out tmp --boot_img magisk_patched-28100_3ucVs.img)
CLEAN_PARAMS="$(echo "${ARGS}" | sed -e "s/ --cmdline '.*'//" -e "s/ --board '.*'//")"
cp android-kernel/out/android-msm-pixel-4.9/private/msm-google/arch/arm64/boot/Image.lz4-dtb tmp/kernel
mkbootimg -o "boot.patched.img" ${CLEAN_PARAMS} --cmdline "${ARGS}"
This will give you a boot.patched.img
with the just built kernel.
Boot the new kernel via fastboot
We can now boot the new boot.patched.img
. No need to flash that onto
the device for that:
fastboot boot boot.patched.img
Fetching the kernel logs
With that we can fetch the kernel logs with the debug output via adb
:
adb shell su -c 'dmesg -t' > dmesg_dump.xml
or already filtering out the QMI commands:
adb shell su -c 'dmesg -t' | grep "@QMI@" | sed -e "s/@QMI@//g" &> sargo_qmi_dump.xml
That's it. You can apply this method for testing out other kernel patches as well. If you want to apply the above to other devices you basically need to make sure you patch the right kernel sources, the other steps should be very similar.
In case you just need a rooted boot.img
for sargo you can find a
patched one here.
If this procedure can be improved / streamlined somehow please let me know.
Appendix: Fetching boot.img from the phone
If, for some reason you lost boot.img
somewhere on the way you can always use
TWRP to fetch the boot.img
currently in use on your phone.
First get TWRP for the Pixel 3a. You can boot that directly by putting your device into fastboot mode, then running:
fastboot boot twrp-3.7.1_12-1-sargo.img
Within TWRP select Backup → Boot and backup the file. You can then use adb shell
to locate the backup in /sdcard/TWRP/BACKUPS/
and pull it:
adb pull /sdcard/TWRP/BACKUPS/97GAY10PWS/2025-04-02--09-24-24_SP2A220505008/boot.emmc.win
You now have the device's boot.img
on your PC and can e.g. replace the kernel or make
modifications to the initramfs.