Many were very sad when google chose not to update Nexus 7 2012 to Android 6.0 Marshmallow. This simple guide will show you how to build Android 6.0 Marshmallow for Nexus 7 2012. And for the lazy, I also have a pre-built AOSP Marshmallow image set to download on the bottom of this page. Since Nexus 7 was originally a Google-Play-equipped device, you can legally install Google Apps on this image and enjoy a full Google Android 6.0 experience on your Nexus 7. That part, however, is up to you to do yourself. I am not offering GApps downloads here.
For fun, to make this work a few very cool hacks had to be done, read further below in the "cool hacks" section about them, if you care.
#get Android M AOSP into folder called M mkdir L mkdir M cd M repo init -u https://android.googlesource.com/platform/manifest -b android-6.0.0_r1 repo sync -j4 cd .. #get latest L AOSP into folder called L cd L repo init -u https://android.googlesource.com/platform/manifest -b android-5.1.1_r1 repo sync -j4 cd .. #get blobs (except widevine) cd M wget https://dl.google.com/dl/android/aosp/asus-grouper-lmy47v-f395a331.tgz wget https://dl.google.com/dl/android/aosp/broadcom-grouper-lmy47v-5671ab27.tgz wget https://dl.google.com/dl/android/aosp/elan-grouper-lmy47v-6a10e8f3.tgz wget https://dl.google.com/dl/android/aosp/invensense-grouper-lmy47v-ccd43018.tgz wget https://dl.google.com/dl/android/aosp/nvidia-grouper-lmy47v-c9005750.tgz wget https://dl.google.com/dl/android/aosp/nxp-grouper-lmy47v-18820f9b.tgz #wget https://dl.google.com/dl/android/aosp/widevine-grouper-lmy47v-e570494f.tgz tar xvfz asus-grouper-lmy47v-f395a331.tgz tar xvfz broadcom-grouper-lmy47v-5671ab27.tgz tar xvfz elan-grouper-lmy47v-6a10e8f3.tgz tar xvfz invensense-grouper-lmy47v-ccd43018.tgz tar xvfz nvidia-grouper-lmy47v-c9005750.tgz tar xvfz nxp-grouper-lmy47v-18820f9b.tgz #tar xvfz widevine-grouper-lmy47v-e570494f.tgz dd if=extract-asus-grouper.sh bs=14466 skip=1 | tar xvz dd if=extract-broadcom-grouper.sh bs=14464 skip=1 | tar xvz dd if=extract-elan-grouper.sh bs=14490 skip=1 | tar xvz dd if=extract-invensense-grouper.sh bs=14456 skip=1 | tar xvz dd if=extract-nvidia-grouper.sh bs=14460 skip=1 | tar xvz dd if=extract-nxp-grouper.sh bs=14452 skip=1 | tar xvz #dd if=extract-widevine-grouper.sh bs=14446 skip=1 | tar xvz rm *grouper-lmy47v*.tgz extract-*-grouper.sh #cool binary patch for GL blobs echo -n dmitrygr_libldr | dd bs=1 seek=4340 conv=notrunc of=vendor/nvidia/grouper/proprietary/libEGL_tegra.so echo -n dgv1 | dd bs=1 seek=6758 conv=notrunc of=vendor/nvidia/grouper/proprietary/libEGL_tegra.so echo -n dmitrygr_libldr | dd bs=1 seek=3811 conv=notrunc of=vendor/nvidia/grouper/proprietary/libGLESv1_CM_tegra.so echo -n dgv1 | dd bs=1 seek=6447 conv=notrunc of=vendor/nvidia/grouper/proprietary/libGLESv1_CM_tegra.so #cool binary patch for GPS blob printf "malloc\0" | dd bs=1 seek=5246 conv=notrunc of=vendor/broadcom/grouper/proprietary/glgps #get old device sources cp -Rvf ../L/device/asus/grouper device/asus/grouper #apply source patch to Nfc package (sadly we must mess with platform code here) cd packages/apps/Nfc/ git apply ../../../../packages-apps-Nfc.patch cd ../../.. #apply source patch to vendor repo cd vendor git apply ../../vendor.patch cd .. #apply source patch to device repo cd device/asus/grouper git apply ../../../../device-asus-grouper.patch cd ../../.. #get kernel cd .. git clone https://android.googlesource.com/kernel/tegra.git cd tegra git checkout remotes/origin/android-tegra3-grouper-3.1-lollipop-mr1 -b l-mr1 #apply kernel patch git apply ../kernel.patch #build kernel export CROSS_COMPILE=`pwd`/../M/prebuilts/gcc/linux-x86/arm/arm-eabi-4.8/bin/arm-eabi- export ARCH=arm make tegra3_android_defconfig make -j4 cp arch/arm/boot/zImage ../M/device/asus/grouper/kernel cd ../M #build Android source build/envsetup.sh lunch aosp_grouper-userdebug make -j4
#get blobs (Except widevine) wget https://dl.google.com/dl/android/aosp/asus-tilapia-lmy47v-6272610e.tgz wget https://dl.google.com/dl/android/aosp/broadcom-tilapia-lmy47v-e9d05927.tgz wget https://dl.google.com/dl/android/aosp/elan-tilapia-lmy47v-5f509df5.tgz wget https://dl.google.com/dl/android/aosp/invensense-tilapia-lmy47v-066fff5f.tgz wget https://dl.google.com/dl/android/aosp/nvidia-tilapia-lmy47v-05744cf3.tgz wget https://dl.google.com/dl/android/aosp/nxp-tilapia-lmy47v-7a361708.tgz #wget https://dl.google.com/dl/android/aosp/widevine-tilapia-lmy47v-2844d74a.tgz tar xvfz asus-tilapia-lmy47v-6272610e.tgz tar xvfz broadcom-tilapia-lmy47v-e9d05927.tgz tar xvfz elan-tilapia-lmy47v-5f509df5.tgz tar xvfz invensense-tilapia-lmy47v-066fff5f.tgz tar xvfz nvidia-tilapia-lmy47v-05744cf3.tgz tar xvfz nxp-tilapia-lmy47v-7a361708.tgz #tar xvfz widevine-tilapia-lmy47v-2844d74a.tgz dd if=extract-asus-tilapia.sh bs=14466 skip=1 | tar xvz dd if=extract-broadcom-tilapia.sh bs=14464 skip=1 | tar xvz dd if=extract-elan-tilapia.sh bs=14490 skip=1 | tar xvz dd if=extract-invensense-tilapia.sh bs=14456 skip=1 | tar xvz dd if=extract-nvidia-tilapia.sh bs=14460 skip=1 | tar xvz dd if=extract-nxp-tilapia.sh bs=14452 skip=1 | tar xvz #dd if=extract-widevine-tilapia.sh bs=14446 skip=1 | tar xvz #cool binary patch for GL blobs echo -n dmitrygr_libldr | dd bs=1 seek=4340 conv=notrunc of=vendor/nvidia/tilapia//proprietary/libEGL_tegra.so echo -n dgv1 | dd bs=1 seek=6758 conv=notrunc of=vendor/nvidia/tilapia//proprietary/libEGL_tegra.so echo -n dmitrygr_libldr | dd bs=1 seek=3811 conv=notrunc of=vendor/nvidia/tilapia/proprietary/libGLESv1_CM_tegra.so echo -n dgv1 | dd bs=1 seek=6447 conv=notrunc of=vendor/nvidia/tilapia/proprietary/libGLESv1_CM_tegra.so #cool binary patch for GPS blob printf "malloc\0" | dd bs=1 seek=5246 conv=notrunc of=vendor/broadcom/tilapia/proprietary/glgps #bring in libstlport which the ril sadly needs cp -Rvf ../L/external/stlport external/stlport #apply source patch to device tree cd device/asus/tilapia git apply ../../../../device-asus-tilapia.patch cd ../../.. #apply source patch to vendor repo cd vendor git apply ../../vendor.patch cd .. #build it source build/envsetup.sh lunch aosp_tilapia-userdebug make -j4
Nexus 7.2012's GL libraries were made to work with Android L, and no sources are provided. Android M changed one thing around that make it not work: dlopen() is now POSIX complaint. While this may sound like a good thing, and it is, it still breaks NVIDIA's GL libraries. Why? Well, they each insist on loading each-other using dlopen. And what do they pass to dlopen? Strings like "egl/libGLESv2_tegra.so". Why is this a problem? Well, the POSIX spec says that if dlopen is passed a path that includes a slash, no searching is done for the requisite library besides in the current working directory. If no slash is present, a search through a system-specific library search path happens. Previously in android, the latter behaviour happened all the time, and since /system/lib was in the search path, asking dlopen to locate "egl/libGLESv2_tegra.so" would corectly find and load "/system/lib/egl/libGLESv2_tegra.so". In M this is no longer the case, since dlopen will only search the current working directory. For most android processes, this is just "/". This is why a simple (but dirty, wrong, and ultimately incomplete) way to solve this problem is to symlink "/egl" to "/system/lib/egl". But this is a bad solution, since technically any app can change its working directory, and then it will no longer be able to use OpenGL. Clearly a better solution is needed.
NVIDIA's libraries do not call dlopen directly. They call "NvOsLibraryLoad" - an NVIDIA-specific wrapper around dlopen. The implementation of this funtion resides in "libnvos.so". This is our opportunity! Curious information: Due to peculiarities of the ELF format, when a binary baz imports function foo() from libbar.so, nowhere in baz's ELF file does it say that foo() must from from libbar. In fact there are two separate records. One that says that libbar is "NEED"ed, and another that says that there is an import of function "foo". What that means is that if the process were to also load libxyz, which also exported foo(), there is no way to be sure which foo() would get called. Why do we care? Well, consider our problems. We can repalce a NEED record in NVIDIA's libraries with one referencing a library we control, like "libdgv1.so", replace the name of the function they call to load libraries from "NvOsLibraryLoad" to something else, "like dmitrygr_libldr", implement that function in terms of the real "NvOsLibraryLoad" in "libdgv1.so", while fixing paths, and as long as "libdgv1.so" has a NEED record referencing libnvos.so, all will go well. This is in fact what I did. Thus the binary patches to the NVIDIA libraries are minimal (two strings each). The implementation of "libdgv1.so" I am providing under AOSP license as part of this post. I would like to once-again emphasize that just symlinking "/egl" is not a proper solution, since any app that changes its working directory (which is OK and allowed) will thus be unable to use OpenGL.
Nexus 7.2012's GPS library was also only made for Android L, and does not work in M. Here the reason is simple. It relies on OpenSSL, which in M was replaced by BoringSSL. Fun thing is, though, they are fully compatible. So why does GPS fail? Ha! Broadcom, for some reason used an internal OpenSSL function "CRYPTO_malloc" in their GPS library. "CRYPTO_malloc" just allocates memory. This fix was easy. I binary edited the IMPORT entry in gps daemon to use "malloc" instead and life went on. It is a simple binary patch as well.
In their infinite wisdom, NVIDIA decided to directly read files in the filesystem from their kernel. This is always 100% unequivocally a bad idea, as you can read all about here: LINK. The guilty party was an ALS driver. I was not about to let this proceed. I modified the kernel driver to instead have a sysfs entry that one could write that file to (it has a single calibration value). This would be nice and easy, except this changes the behaviour of this calibration form pull (by kernel) to push (by userspace). So now I had to find who writes that file the kernel used to read, and replace that code with writing a sysfs node. This is where things took a turn for the scandalous. The only things touching this file was a binary-only executable that NVIDIA supplies, named "sensors-config". It was a small one, and I figured i'll just binary patch it. I disassembled it, and I was horrified. It was a spaghetti-themed nightmare, full of calls to "system()". I decided to rewrite it. I produced a fully working replica of this binary in source, and am releasing my code under AOSP license as well. As a bonus, now I could teach this binary to write to the sysfs node of the modified drver.
Camera
Camera was not working for a long time. I spent a lot of time debugging, only to eventually find out that it does work, and it is the AOSP Camera app that does not. There goes half my night...
grouper(WiFi) | tilapia(3G) |
Download patches if you want to make the build yourself: => [PACKAGE YOU'LL NEED (mirror)] <=
If you're not a person who wants to build android yourself from source, here is fully usable userdebug image. Tested: Sensors, NFC, WiFi, Bluetooth, Camera, GPS. Fastboot-flashable images here => [FASTBOOT IMAGES (mirror)] <= Or, if you prefer to flash from TWRP => [TWRP flashable zip (mirror)] (updated) <= |
Download patches if you want to make the build yourself: => [PACKAGE YOU'LL NEED (mirror)] <=
If you're not a person who wants to build android yourself from source, here is fully usable userdebug image. Tested: Sensors, NFC, WiFi, Bluetooth, Camera, GPS. Fastboot-flashable images here => [FASTBOOT IMAGES (mirror)] <= Or, if you prefer to flash from TWRP => [TWRP flashable zip (mirror)] <= |