Update: I have now updated the post with a solution that actually works. There is a disclaimer though: future system updates will not update your Email and Exchange packages; you’ll have to always do it manually.
I once had a Samsung Galaxy S (GT-i9000). It was a beautiful phone that I used, rooted and installed Cyanogenmod on (right up to JellyBean) and thoroughly enjoyed. And then I decided that I wanted to fix the GPS contact on the phone using a documented soldering solution. So that’s how I got to order a Nexus 5 :D
Jokes aside, I was thrilled to get my hands on a Nexus 5 last week. My Galaxy S had served me well for many years mainly due to great quality hardware back then and I chose the Nexus 5 for the same reason - a quad core processor and 2GB RAM will surely last me a while. There was one problem though and as I found out, it was a fairly widespread problem - corporate emails that use ActiveSync would not work. The problem was documented and also fixed, but there was no fix available for the Nexus 5 yet, unless you had Cyanogenmod.
I had decided to not root my phone for at least six months and even after rooting, not install Cyanogenmod for another six months, so my chances of getting a fix were dependent on Google releasing an update. This looked like a good chance to get my hands on some android patching and building, so I decided to give it a go. To summarize, I did the following:
- Rooted my phone
- Locate the fix
- Built the new apks from the AOSP source
- Removed the Email apks
- Installed the new apks
My phone is alive and syncing emails, so here’s a more detailed description of what I did. I am not going to write about rooting the phone or setting up the android development environment. That stuff is well documented - just make sure you get the binary images from reliable sources, like the original website.
Locate the fix
Comment #174 in the bug report pointed to the Cyanogenmod patch review system which had the patch that fixed the problem. The Google engineers unfortunately were not helpful enough to make any such note. I verified in the downloaded AOSP source that these changes were in place.
I just stuck to master and did not bother going for any specific branches to do a backport because (1) it’s java code, so it ought to be largely device independent, i.e. it shouldn’t break anything on my phone if it’s wrong and (2) I’d expect that it should be possible for the apps to be independently built and installed, which they were. Since the code on master and building with java 1.7 did not work, I installed the 1.6 jdk and checked out the android-4.2.2_r1 branch in AOSP. In fact, the code on 4.2.2_r1 branch will not even build with java 1.7. On the code end, the CyanogenMod change was slightly different, but the problem was in fact fixed on the 4.2.2_r1 branch with this revision:
commit d92a75c707461188e8743149476e8f49ef191b42 Author: Tony Mantler <email removed> Date: Fri Nov 15 12:45:53 2013 -0800 Make sure the client certificate is always installed b/11678638 Change-Id: Iafe200d14b72678324758fe08b03c8ea7bb9dc5c
So there was no need to actually patch anything.
Build the packages
Building the individual packages is very simple:
$ make showcommands Email Exchange2
EXPERIMENTAL_USE_JAVA7_OPENJDK allowed me to use OpenJDK to build java programs instead of the proprietary Oracle Java.
showcommands is an additional target that gives a verbose mode.
Exchange2 are the package names. One could get those package names by looking for the
LOCAL_PACKAGE_NAME variable in the
Android.mk in the package directory (
Remove the old packages
Before removing, always backup. It’s easy to do this from
adb, using the commands:
$ adb pull /system/app/EmailGoogle.apk backup/ $ adb pull /system/app/Exchange2Google.apl backup/
Once this is done, get into adb shell and get root:
$ adb shell phone:/$ su
You’ll get a prompt on your phone confirming root access, which you need to allow. Now remount the
/system filesystem in read-write mode using the following command:
phone:/# mount -o remount,rw /system
Once the remount succeeds, remove the package files using the commands below. Also remove the odex files since they’ll be regenerated for the new packages:
phone:/# rm /system/app/EmailGoogle.apk phone:/# rm /system/app/EmailGoogle.odex phone:/# rm /system/app/Exchange2Google.apk phone:/# rm /system/app/Exchange2Google.odex
Install new packages
Installing the newly built packages is also just as simple. First, copy the packages to your sdcard:
$ adb push out/target/product/generic/system/app/Exchange2.apk /sdcard/ $ adb push out/target/product/generic/system/app/Email.apk /sdcard/
and then copy those packages to /system/app/ and give them appropriate permissions:
$ adb shell phone:/$ su phone:/# cp /sdcard/Email.apk /system/app/ phone:/# cp /sdcard/Exchange2.apk /system/app/ phone:/# chmod 644 /system/app/Email.apk phone:/# chmod 644 /system/app/Exchange2.apk
Reboot your phone and let the phone optimize your app (i.e. generate the odex file) for your phone. ActiveSync should now start working on your phone!
No, it is not a java program, it is in assembly, which was possible because I recently flashed Cyanogenmod on my phone. Here it is:
.text .global _start _start: mov r7, #1 mov r0, #42 swi #0
The program simply returns 42 and exits. I used my own cross-built binutils (--target=armv-android-eabi) to build this and simply copied it over to my phone, chmod and executed it. You need to put it outside your sdcard environment however, since you cannot execute anything in /sdcard. A Stackoverflow thread helped figure out the right opcode for the syscall.
It took me all of 6 hours to figure this out. 5 minutes to figure out the above code and 5 hours and 55 minutes to realize and fix the last line from