Friday, June 28, 2013

Building Android on Fedora

Background

I've been waiting for a "Goldilocks" tablet for some time — something with a bigger screen than a 7-inch tablet but easier to hold with one hand than a 10-inch.  Barnes & Noble's Nook HD+ fits the bill, but I was never interested in running B&N's crippled flavor of Android.  (There was an early port of CyanogenMod for the Nook HD+, but it would only run off of a microSD card; it could not be installed on the device's internal storage.)  So I continued waiting.

Then I stumbled on this article, which led me to look into the current state of CyanogenMod on the Nook HD+, which led me to discover that it can now be installed on the device's internal storageBooyah!

I've had the Nook HD+ for about a week now, and it's exactly what I hoped for.  The 9-inch 1920x1280 screen is great for e-books and magazines, web browsing, and videos.  The dual-core 1.5 GHz OMAP processor and 1 GB of RAM are not world-beating, but they're perfectly adequate for these activities.  I don't share the complaints that some people have about occasional unresponsiveness.  (It probably helps that my previous tablet was a Nook Color.)  And unlike my wife's ASUS TF700, I can comfortably hold the Nook HD+ in one hand for several hours.
This is not a dig at the TF700.  It's an awesome device, with performance that blows away the Nook HD+.  Like every other 10-inch tablet that I've ever picked up, however, it's just bit too large and heavy to be comfortably held in one hand for an extended period.

The Problem ... and Project

Back to those videos ... I prefer to rip videos to DVD ISO files, rather than simple MP4s.  I actually enjoy a lot of the DVD extras — particularly commentary tracks.  I discovered an app called Wondershare Player that will play DVD ISOs on the tablet; just open the ISO file in File Manager, and it takes you to the DVD's main menu.

DVD ISO files are often larger than 4 GB, the largest file that can be stored on a FAT32 file system.  Microsoft has introduced a new file system called exFAT to address the limitations of FAT32 on larger flash drives.  (64 GB SD cards are generally pre-formatted as exFAT.)  Unfortunately, exFAT is both proprietary and heavily patent encumbered, so it won't be supported by open source software such as CyanogenMod any time soon.

But Android is Linux, and ext4 (the most widely used Linux file system) can store files as large as 16 TB.  Sure enough, CyanogenMod will happily use an ext4-formatted SD card.  The problem is that ClockWorkMod Recovery (CWM) will not; it is hardcoded to expect a FAT32-formatted partition.

This is where I get in trouble.  CWM is also Linux, so how hard could it be to make it recognize an ext4-formatted SD card?  It turns out to be very conceptually simple to change the filesystem type; it's a simple edit to CWM's equivalent of /etc/fstab.  The challenge lies in setting up an environment to actually build a modified recovery image.

Ubuntu, Fedora, or Both?

I've been a Red Hat/Fedora user for at least 15 years.  I'm not about to switch to Ubuntu just because that's what Google uses.  On the other hand, experience has taught me that it's pretty much impossible to build Android, including CyanogenMod, on either Red Hat Enterprise Linux or Fedora, and building ClockworkMod Recovery requires a CyanogenMod build environment.  (The CWM source is distributed as part of the CyanogenMod source.)

The usual solution to this problem is to create a full-fledged Ubuntu virtual machine.  This certainly works, but it limits the performance of the build environment in a couple of ways.  First, there's the overhead that comes from running in a VM, particularly when it comes to I/O.  Second, the VM can never use all of the resources of the host system; some amount of CPU, I/O, and memory has to be reserved for the host operating system.  If I create a VM with 24 GB of RAM (on my 32 GB workstation), that VM will never be able to use the remaining 8 GB of memory in the machine, regardless of whether the host operating system is doing anything useful with it.

Instead of creating a virtual machine, I decided to set up Ubuntu 12.04 LTS in a chroot.  chroot is not widely used these days.  It has (rightly) fallen out of favor as a security mechanism, and virtualization is usually an easier route to software compatibility.  For the reasons described above, however, it's a good tool for this particular use case.

Creating the chroot

After creating and mounting a file system for the environment (at /mnt/ubuntu), I used the debootstrap command to download and extract a minimal Ubuntu system.

# yum install debootstrap
# debootstrap --arch=amd64 precise /mnt/ubuntu

To provide the illusion of an actual running operating system, the chroot environment will need access to several bits of the larger filesystem tree.  (Remember that this setup is intended to provide software compatibility, not security.)

# mount -o bind /proc /mnt/ubuntu/proc
# mount -o bind /dev /mnt/ubuntu/dev
# mount -o bind /sys /mnt/ubuntu/sys
# mount -o bind /lib/modules /mnt/ubuntu/lib/modules

These can be added to /etc/fstab, if desired.  (The last one is required by the Android build process.  For some reason it insists on running depmod on the host on which it is running.)

Setting the Locale

# chroot /mnt/ubuntu
# echo 'LANG="en_US.UTF-8"' > /etc/default/locale
 

Adding User Information to the chroot

The chroot environment has its own copy of /etc/passwd and /etc/group.  Any non-root users that will use the environment must be added — with the correct UIDs and GIDs.


# groupadd -g 1000 pilcher
# adduser --uid 1000 --gid 1000 --disabled-password --gecos 'Ian Pilcher' pilcher
# su - pilcher
$ exit

Android Build Requirements

Android requires the schedtool package, which is in Ubuntu's "Universe" repository.  This repository must be added.

# echo 'deb http://us.archive.ubuntu.com/ubuntu/ precise universe' >> /etc/apt/sources.list
# apt get-update
# apt get install curl wget make bison schedtool python-software-properties git
# apt-get install g++-multilib flex xsltproc lib32z1 unzip gperf zip libxml2-utils

Building Android also requires Oracle Java 6.  As is their wont, Oracle have forced Canonical to remove the sun-java6 package from their partner archive.  They also make it painful to download it directly.  (No Larry, you can't have my firstborn son's social security number.)  Thankfully, these fine folks have created a couple of packages which do the dirty work for you.

# add-apt-repository ppa:webupd8team/java
# apt-get update
# apt-get install oracle-java6-installer
# apt-get install oracle-java6-set-default

Finally, download the repo tool.

# wget -P /usr/local/bin https://dl-ssl.google.com/dl/googlesource/git-repo/repo
# chmod 0755 /usr/local/bin/repo

Conclusion

That's it.  I now have an Ubuntu 12.04-compatible Android build environment.  To use the environment as my normal user, I do the following.

$ sudo chroot /mnt/ubuntu
# su - pilcher