DEV Community

Megh Rana
Megh Rana

Posted on • Edited on

Booting Modern Android on Ancient Hardware: How I Revived a Dead Device with Android 13

Smartphone companies nowadays (some atleast) support phones till 5 or even 7 years, but this was not always the case. Android phones were notorious in the past for getting very sparse software support.

I own a phone, which was semi popular for its time, the OPPO A37f. It has 2GB of ram, which according to its time was ok. 16GB of internal memory, expandable with a micro-sd card of course. The SOC was the Snapdragon 410, aka MSM8916. MSM8916 has a surprising amount of support from the development community, it has quite good linux-mainline support. (https://github.com/msm8916-mainline)

Now this phone also was nicely supported by its past developers before i even touched the phone's bootloader. I must thank each and every one of the developers who have done so much work figuring out to actually unlock the bootloader ( It is a whole seperate story, maybe another post?) and develop trees for it. A little context, in AOSP development, there's these things which are very important called "trees". These trees are the device configuration which helps the AOSP build system build the correct packages and drivers for the device.

So, how did i start this task? Well thanks to a fellow developer, Ricky Cheung, the phone had already booted LineageOS-19.0, which is Android 12. now, as this is a very very old phone in terms of google depracation speed, even android 12 becomes very difficult. One major reason being the kernel.

THE KERNEL: the phone has a kernel (not official source, but ported kernel source) of version 3.10 . Now google, very sanely does not support kernels older than 5.4 in the latest release ( 16 as of now), and even back then kernels older than 4.4 had problems. Along with that, a lot of other things ( which will be detailed later), like the legacy camera hal, were killed by AOSP devs.

Now, thanks to another developer, the process of actually patching the LineageOS source, sort of dirty but ok-enough patches are done to the LineageOS source is not necessary. A fork of LineageOS was made by developer (Khalvat-M) named LineageOS-UL ( UL stands for ULTRA LEGACY) , so the process was not as complicated as before.

So, you say, if you have trees for android 12, a patched source for android 13, how hard could it be? and oh boy could you further from the truth. Well, technically if you were not me, and an actual smart developer who has experience of doing this already, it wouldn't be that hard, but at that time i had very very less idea of what i was doing, so this was a learning experience for me too.

Another important mention before i actually explain how i did it, i had the help of acroreiser, a fellow Ukrainian developer, who owns a Lenovo A6010 ( also msm8916) who had already done it for his A60xx.
So now you say, with referrence trees you still had problems? YES.

What is exactly needed for android 12 to 13? well first of all, encryption. https://github.com/Meghthedev/device_oppo_A37/commit/86e3d8ad9182ae60399da005226b47dcad0605a6 and https://github.com/Meghthedev/device_cyanogen_msm8916-common/commit/09889348bf2de95e9e5f244eae5a4559c1bca412 . Why? Well from android 13, google encourages FILE BASED ENCRYPTION (FBE), while FULL DISK ENCRYPTION, or FDE is depracated. So, we initially don't want to deal with headaches of managing a ultra legacy device which has 100 other problems to deal with to also manage a new encryption standard.

Then, i did : https://github.com/Meghthedev/device_oppo_A37/commit/e19a8ac4da33d304a00d8aed3db77e3bb6367b13
what this basically does, is remove references to a2dp module ( a2dp is advanced audio distribution profile) as anyways audio policy manager would fail, so why not remove it from the start.

Along with that, there are a few unintresting commits, which i will share below in case it piques your interest or you are interested to do it for some device of your own. ( https://github.com/Meghthedev/device_oppo_A37/commits/lineage-20)

This (https://github.com/Meghthedev/device_oppo_A37/commit/8dac01fe15d345b7bac0f8103d3c3764caa93a64) is a very important commit, reason i will explain soon, but just remember, without this a lot of problems could've occured ( atleast thats what i think, i am not 100% sure)

I also had to do kernel toolchain shenanigans like (https://github.com/Meghthedev/device_oppo_A37/commit/7380fd0c65c088777fa71b442a045c1067f0eca6) which reason i'm not entirely sure why this device in particular needs the kernel toolchain to be defined in this way, but that's just how legacy devices are.

With all this done, the device tree was wrapped up, end of story? oh we have just started. the phone uses a common tree, cyanogen/msm8916-common. So, of course it also has changes required. Most of the changes (https://github.com/Meghthedev/device_cyanogen_msm8916-common/commits/lineage-20) are just undo-ing a change google has done, like for example, google recommends that the kernels now should build with LLVM Binutils and LineageOS has their own kernel build system which enforces LLVM, which is great and all for modern devices, but not for our 3.10 legacy kernel. so, https://github.com/Meghthedev/device_cyanogen_msm8916-common/commit/3d2bd6a57fac1f73a6927d6e0ea9ea8985dfb93e.

Except this, quite a lot of packages were dropped in Android 13, so i had to either substitute that with some other package or drop it entirely. Another option which i had but didn't do, was track that package myself, either in-tree or outside, but that's not ideal and just adds more work, i mean if the device can work without it, why not reduce the amount of legacy dependencies. Now with all the legacy stuff done, i also had to do the actual commits needed for android 13, Bluetooth related flags ( Google/AOSP changed the bluetooth logic and so now stuff had to be defined in tree in a different manner than before, so of course those changes i did)

Ok, so are we ready to fire up the build?

============================================
PLATFORM_VERSION_CODENAME=REL
PLATFORM_VERSION=13
LINEAGE_VERSION=20.0-20240528-UNOFFICIAL-A37
TARGET_PRODUCT=lineage_A37
TARGET_BUILD_VARIANT=eng
TARGET_BUILD_TYPE=release
TARGET_ARCH=arm
TARGET_ARCH_VARIANT=armv8-a
TARGET_CPU_VARIANT=cortex-a53
HOST_ARCH=x86_64
HOST_2ND_ARCH=x86
HOST_OS=linux
HOST_OS_EXTRA=Linux-5.4.0-100-generic-x86_64-Ubuntu-22.04.4-LTS
HOST_CROSS_OS=windows
HOST_CROSS_ARCH=x86
HOST_CROSS_2ND_ARCH=x86_64
HOST_BUILD_TYPE=release
BUILD_ID=TQ3A.230901.001
OUT_DIR=out
PRODUCT_SOONG_NAMESPACES=device/cyanogen/msm8916-common device/oppo/A37 hardware/qcom-caf/msm8916 vendor/qcom/opensource/data-ipa-cfg-mgr vendor/qcom/opensource/dataservices
============================================
Enter fullscreen mode Exit fullscreen mode

Yes! but as i started the build, i faced the kernel shenanigans as i mentioned few commits above, but thats a whole seperate story for later. My first and one of my main hurdles in compilation and even booting later, was that the HALs ( Hardware Abstraction Layers) were not getting built. this included the display hal, audio hal, and media hal. Usually for Qualcomm devices, these hals are by caf ( now linaro) in hardware/qcom-caf/msm8916/halfolder. Now the display hal not getting compiled meant, no display of course. It let me compile further, but the device would get stuck at the OPPO splash screen.

Logs below:

01-01 00:09:27.871   367   367 E vndksupport: Could not load /vendor/lib/hw/camera.vendor.msm8916.so from default namespace: dlopen failed: library "libqdMetaData.so" not found: needed by /system/vendor/lib/hw/camera.vendor.msm8916.so in namespace (default).

01-01 00:09:22.357   310   310 F DEBUG   : *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
01-01 00:09:22.358   310   310 F DEBUG   : LineageOS Version: '20.0-20250412-UNOFFICIAL-A37'
01-01 00:09:22.358   310   310 F DEBUG   : Build fingerprint: 'OPPO/A37fw/A37f:5.1.1/LMY47V/1519717163:user/release-keys'
01-01 00:09:22.358   310   310 F DEBUG   : Revision: '0'
01-01 00:09:22.358   310   310 F DEBUG   : ABI: 'arm'
01-01 00:09:22.358   310   310 F DEBUG   : Timestamp: 1970-01-01 00:09:22.115671166+0000
01-01 00:09:22.358   310   310 F DEBUG   : Process uptime: 2s
01-01 00:09:22.358   310   310 F DEBUG   : Cmdline: /system/bin/bootanimation
01-01 00:09:22.358   310   310 F DEBUG   : pid: 255, tid: 304, name: BootAnimation  >>> /system/bin/bootanimation <<<
01-01 00:09:22.358   310   310 F DEBUG   : uid: 1003
01-01 00:09:22.358   310   310 F DEBUG   : signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x00000000
01-01 00:09:22.358   310   310 F DEBUG   : Cause: null pointer dereference
01-01 00:09:22.358   310   310 F DEBUG   :     r0  e2352068  r1  00000005  r2  000002d0  r3  00000500
01-01 00:09:22.358   310   310 F DEBUG   :     r4  e8564460  r5  00000003  r6  00000000  r7  00000000
01-01 00:09:22.358   310   310 F DEBUG   :     r8  e65754c0  r9  000002d0  r10 00000500  r11 e2352068
01-01 00:09:22.359   310   310 F DEBUG   :     ip  e542d264  sp  e2f10c90  lr  e259cd43  pc  00000000
01-01 00:09:22.359   310   310 F DEBUG   : backtrace:
01-01 00:09:22.359   310   310 F DEBUG   :       #00 pc 00000000  <unknown>
01-01 00:09:22.359   310   310 F DEBUG   :       #01 pc 00003d41  /system/vendor/lib/egl/eglsubAndroid.so (BuildId: 3a4ad23e0dbdceaa820c95e1c1e942ac)
01-01 00:09:22.359   310   310 F DEBUG   :       #02 pc 000040e7  /system/vendor/lib/egl/eglsubAndroid.so (BuildId: 3a4ad23e0dbdceaa820c95e1c1e942ac)
01-01 00:09:22.359   310   310 F DEBUG   :       #03 pc 0000da3c  /system/vendor/lib/egl/libRBEGL_adreno.so (qeglDrvAPI_eglCreateWindowSurface+784) (BuildId: 4f13ee6facc884e62073deffce7953b7)
01-01 00:09:22.359   310   310 F DEBUG   :       #04 pc 000141c5  /system/lib/libEGL.so (void* android::eglCreateWindowSurfaceTmpl<int, void* (*)(void*, void*, ANativeWindow*, int const*)>(android::egl_display_t*, android::egl_connection_t*, void*, ANativeWindow*, int const*, void* (*)(void*, void*, ANativeWindow*, int const*))+152) (BuildId: 8c37d857d9b4241ec7eaf32b254dcb59)
01-01 00:09:22.359   310   310 F DEBUG   :       #05 pc 00014105  /system/lib/libEGL.so (android::eglCreateWindowSurfaceImpl(void*, void*, ANativeWindow*, int const*)+44) (BuildId: 8c37d857d9b4241ec7eaf32b254dcb59)
01-01 00:09:22.359   310   310 F DEBUG   :       #06 pc 00012f9f  /system/lib/libEGL.so (eglCreateWindowSurface+34) (BuildId: 8c37d857d9b4241ec7eaf32b254dcb59)
01-01 00:09:22.359   310   310 F DEBUG   :       #07 pc 0000abd7  /system/lib/libbootanimation.so (android::BootAnimation::readyToRun()+1614) (BuildId: f5c2998086717897d2c41a9e6617bf5c)
01-01 00:09:22.359   310   310 F DEBUG   :       #08 pc 0000d6c5  /system/lib/libutils.so (android::Thread::_threadLoop(void*)+116) (BuildId: 2352df31a7b68412dc606ed1a2c1c09a)
01-01 00:09:22.359   310   310 F DEBUG   :       #09 pc 000ac673  /apex/com.android.runtime/lib/bionic/libc.so (__pthread_start(void*)+40) (BuildId: 6f8198bccd6e1cdfd541678b7b77e0ca)
01-01 00:09:22.360   310   310 F DEBUG   :       #10 pc 00062add  /apex/com.android.runtime/lib/bionic/libc.so (__start_thread+30) (BuildId: 6f8198bccd6e1cdfd541678b7b77e0ca)
Enter fullscreen mode Exit fullscreen mode

So, now what to do? well i tried a bunch of stuff which i did not even push to github. For example, acro ( acroreiser ) uses in-tree display,audio,media hals, so i thought why not try that? maybe it fixes my issue? no it didn't. Eventually if i recall correctly, i was able to build the hals by including them in the SOONG_NAMESPACES. for some reason the build system was not able to pick up those hals as it was not seeing the folders. So, manually adding it to path fixed the issue.

Now of course like in any AOSP compilation, there will be errors but they were mostly easily resolved, like how you would resolve for any other new phone. and now, it was done, build completed:
Package Complete: out/target/product/A37/lineage-20.0-202504151148-UNOFFICIAL-A37.zip

build completed successfully (02:57:06 (hh:mm:ss))

You might see, that it technically took me two years to do this lol. I unfortunately had to take a break from all technical development to give time to studies for my 11th and 12th grade. Anyways, i flashed the build on my phone, like a eager child on his birthday who just got gifts and wants to open them. I see the LineageOS boot animation, i get super excited, so close to the finishing line!!!! i waited, and waited, for 10 minutes and i decided that it was enough for the night, i will debug why its stuck on boot animation in the morning.

So, i slept. waking in the morning, i did my normal schedule, went and came back from the gym, and before breakfast, i turned on my pc, connected the phone, did a clean flash of the rom, and started logcat command to take logs, and went to take breakfast. I thought that if i let it run for whatever time it takes me to do breakfast, it will have plenty of logs i can look at and trim through later.

You will never ( ok maybe not never, but anways) guess what happened. The screen was black! Now this might not sound very exciting, but it kind of is. As you know, the phone was stuck looping on the boot animation the day before, and now it was a black screen. It could mean one of two things, one which is very unlikely that the phone crashed so hard while booting that it decided to shut itself off, or........ IT BOOTED!

It did boot into the system. I now know the reason for the extremely long boot time, it was due to the engineering build. For context, android has 3 build types, user, userdebug, and eng. Engineering build, or eng build is never shipped in production, but is amazing for testing as logs can be easily taken so debugging can take place. So later i did do a userdebug build for release, and the boot time was 30s, which is quite respectable for such a device.

So, i tested everything and contrary to my beliefs, everything worked great, and it was even smoother than Android 12 build. Because of course google themselves also did optimsations from their side as well lol.

Screenshot

Top comments (0)