Voiding the warranty on my Samsung Galaxy S3

score

2014-02-16

So I’ve recently been messing around rooting my phone (Samsung Galaxy S3), and someone recommended me the PAC ROM. (N.B. beware of their forums. If you have an ad-blocker it will try to send you into an alert-redirect loop.)

The prelude

Great, works just fine, rooted my phone, what more could I want? …ah, yes. As soon as I started getting used to it, I realized that some of its built-in programs, notably the Settings app, had some serious stability issues (read: crashed at the drop of a hat).

Curious as to how this could happen I reproduced the crash once more and hooked the phone up to logcat, only to find that some part of the settings app was getting an IndexOutOfBoundsException when altering some apps’ privacy settings. That confirmed my fear that this would be a programmer error, and not just an issue with how I’ve set up my phone.

I hopped along over to the github repository for the PAC ROM’s settings app, cloned it, fired up IntelliJ in the hopes of being able to iron out the bug and recompile it there and then, only to find that it relies on PAC / Cyanogen specific features… I should have known! I can’t compile it without linking against the ROM I’m using.

The light

The way to do this became clear quite immediately: I’d have to recompile the entire ROM. It’s probably theoretically possible to grab the right version of the git repositories that I need, and thus not have to recompile the entire thing, but I had trouble even matching the line numbers of the exception to the code so I couldn’t really tell what commits I should be pulling out.

I headed over to the main repository, which just contains a little readme and some bootstrapping XML file. After following the readme instructions and waiting several hours for things to download and compile, I ran into a couple of snags.

A bumpy ride

Python gets hissy

The first and most immediate problem was that every Python script required for the build process was written for Python 2, but running in Python 3! This caused some SyntaxErrors and failed builds rather quickly.

To get around this, I installed “python2-virtualenv”, set up a nice virtual environment somewhere deep in my home directory, and sourced the bin/activate script1.

cd ~
virtualenv2 py2-venv
. py2-venv/bin/activate

The Python scripts involved in the build process then ran without a hitch.

JNI… Just Not Intuitive!

…That is, until we hit the next bumps in the road!

First, missing libraries. No sweat. Missing gperf. No sweat. Missing ccache. I was led to believe that this was optional, but again, no sweat – just a simple pacman -S ccache2 and we’re done.

But then I hit a rather mysterious error… some auto-generated “.h” file in the Chromium repository somehow managed to get invalid characters in its identifiers! HashSet<E> is not valid C, last time I checked!

After a little googling, I found that someone had hacked together a rather elaborate and somewhat inefficient solution to the problem, so I’ll share the more efficient and easier-to-type version here.

In external/chromium_org/base/android/jni_generator/jni_generator.py, you will need to modify a few lines. They start out looking like this:

  def __init__(self, namespace, fully_qualified_class, natives,
               called_by_natives):
    self.namespace = namespace
    self.fully_qualified_class = fully_qualified_class
    self.class_name = self.fully_qualified_class.split('/')[-1]
    self.natives = natives
    self.called_by_natives = called_by_natives
    self.header_guard = fully_qualified_class.replace('/', '_') + '_JNI'

You will need to add .replace("<E>", "") to three of the lines, so that it looks like this:

  def __init__(self, namespace, fully_qualified_class, natives,
               called_by_natives):
    self.namespace = namespace.replace("<E>", "")
    self.fully_qualified_class = fully_qualified_class.replace("<E>", "")
    self.class_name = self.fully_qualified_class.split('/')[-1]
    self.natives = natives
    self.called_by_natives = called_by_natives
    self.header_guard = fully_qualified_class.replace('/', '_').replace("<E>", "") + '_JNI'

It’s definitely a hack, but it works. It simply removes <E> from the generated names. From then on, everything compiled fine. A few warnings about not finding PNGCrush, but that turned out to be optional anyway, so everything worked fine.

I then uploaded the ROM to my phone. I was seriously thinking “this is it… this is where my phone gets hard-bricked”…

The end result

After installing the newly-built ROM on my phone and upgrading Google Apps using CyanogenMod’s latest, I found that my phone actually became consistently faster and more stable, especially compared with the ROM I had downloaded from the site. Not only that, but it’s now running Android 4.4 with all of PAC’s juicy modifications! Win-win!


Note: This article has been updated on 2021-12-15 to fix broken links and reformat some elements. (Again on 2023-09-16)