Some time ago, I started to wonder wheter it would be possible to update the old Linux kernel for the GT-I9300 variant (international version) of the Galaxy S3 to a more recent version. A newer kernel could not only bring new features and speed improvements, but also lots of security fixes that are not yet patched. Furthermore, porting a more recent Android version to the device would be much more easier. Making a newer kernel work with an older user space is much easier than making an old kernel work with a new user space. And isn't it the spirit of free software to be able to use the newest and shiny software on arbitrary hardware, regardless of its age?
But why Galaxy S3? Wouldn't it be better to take a more recent device that was already released with a newer kernel? I work on the Galaxy S3 because I use it as my daily driver and I have a spare device that I can use for development. Besides the Galaxy S2, it is still the best supported device by Replicant which was my original reason to start working with this phone. And especially in regards to the mainline kernel, it actually turns out to be a really good choice, but more about that in another post.
It's pretty easy, isn't it?
Just get the newest kernel, build it for your target platform and flash it to the device. Unfortunately, it doesn't work like this in the case of phones. But if your laptop or PC is well supported by the Linux kernel, these are the only steps necessary to get the latest kernel working. Some GNU/Linux distributions even provide backports of recent kernel versions, but they normally add a few patches on top of the mainline kernel.
The situation is completely different with practically all Android-based smartphones. Google maintains a common Android kernel tree that contains lots of patches to make the kernel work with the Android user space. There is an ongoing effort to get these patches into the mainline kernel and the situation actually looks pretty good nowadays. You only need a few patches on top of the mainline kernel to be compatible with the most relevant parts of the Android user space. The common Android kernel is based on an older kernel version that has long-term support. So the only challenge is to get a few Android-specific patches working with the latest kernel or we could stay with the common Android kernel and only have to build it, right?
Again, no, it doesn't work like this. If you are lucky, you will see some error messages on the screen and maybe a few other signs of life. The reason is that the phone manufacturers add a huge amount of out-of-tree code to the kernel to get support for their hardware. The added code mainly consists of drivers and support for the SoC. And as the manufacturers also base their changes on an old long-term support kernel version at the beginning of the development, the kernel that comes with the phone on the release date is already pretty out-of-date. 1-3 million lines of out-of-tree code are normal for a smartphone. So this is the point where it becomes really difficult to get a newer kernel working. And it is the reason why the manufacturers themselves don't bother updating their kernels to a newer version after the release.
Kernel version 3.0 - make that old
The latest released kernel source code from Samsung for the Galaxy S3, that I am aware of, contains a kernel based on the 3.0.31 kernel version. This version was released on 7 May 2012. The phone became first available on 29 May 2012. So besides some patches here and there, Samsung has probably never updated the kernel, not even to a newer minor release. CyanogenMod merged the latest release that is available for the 3.0.x kernel series. This updated the kernel to the 3.0.101 version which was released on 22 Oct 2013. So the kernel is only a little more than three years behind. And by the way, I even found a few remains from the 2.6 kernel when poking through the source code.
The difference in age is even worse when you want to port the out-of-tree code to a newer kernel version or if you want to merge a more recent kernel version because then the release date of the 3.0 kernel becomes relevant which is 21 Jul 2011, more than five years ago. The minor releases in the 3.0.x branch only include backports of important fixes from later versions. So the kernel doesn't include any of the substantial changes that were made to the Linux kernel in the last five years, except for a few changes that were backported by Samsung or CyanogenMod. The backports make it actually more difficult or outright impossible to merge a newer kernel, e.g. a 3.2.x kernel version, because some fixes were adapted for the older kernel and cause conflicts when merging a newer kernel.
Merging a newer kernel
There is another reason that makes merging with newer kernel releases very difficult. A version control system like Git expects a common ancestor when merging two branches. But Samsung only releases archives of the source code without the Git history. Samsung is not required by the GPLv2 licence to release the Git history but it would be very helpful. Google publishes Git repositories of the kernels for their Nexus devices, but I am not aware of any project supporting Nexus devices that managed to merge major kernel releases.
Without the Git history, Git has a very hard time to resolve conflicts when merging and you end up with a huge amount of conflicts so that it's just too much work to go through all of them. This happened when I merged with the 3.2.x mainline kernel tree. I was able to get a partial merge working. The end result is not maintainable because there is too much unmerged code and you end up in the middle between two kernel versions. Merging more recent kernel versions becomes even more harder and you will end up with numerous bugs that no one else has. Dorimanx targeted the Galaxy S2 and he did partial merges up to Linux 3.14, but he stopped working on it in 2014. The Galaxy S2 (GT-I9100) uses the same kernel sources.
In the end, all of these efforts don't really bring a newer kernel to the device and we end up with an unmaintainable mess. The goal should be to have an easily maintainable kernel that makes future kernel updates possible. In the next post, I will explain why going mainline is the only solution and how far I've got with getting the mainline kernel working.