[GUIDE] Optimize Linux for Android Development

Recently, I built a new development system. After installing Xubuntu 16.04 and configuring it for Android OS dev, I went down the rabbit hole of system performance tuning. This is intended to be a “living guide”, kept up-to-date with fresh information as packages / options become deprecated, old adages become irrelevant, and so on.

Everyone is encouraged to comment with suggestions for improvements, but please, cite references! While researching this topic, I found a ton of misinformation and out-of-date recommendations. My goal is to provide a comprehensive, one-stop resource.

  1. ccache
  2. IDE setup and tuning
  3. Move /tmp to tmpfs
  4. Add stuff to PATH
  5. Swap and swappiness

As mentioned in Google’s own build environment docs, leveraging ccache is a two step process. Plenty of real world tests have been done but I don’t believe in quoting statistics, as mileage will vary from system to system. The bottom line is it results in an easy performance boost, even if gains might be relatively small.

First, add the following line to ~/.bashrc or equivalent. I prefer zsh with oh-my-zsh (so it would be ~/.zshrc) but that’s another topic.

export USE_CCACHE=1

Then, from the root of the build directory (i.e. ~/aospsource), run the following two commands:

prebuilts/misc/linux-x86/ccache/ccache -M 50G
ccache -M 50G

50G seems about right for my purposes. Keep an eye on the ~/.ccache folder and see if it fills up, there may be a benefit to adding more for certain use cases.

Using IntelliJ IDEA (or Android Studio) greatly increases productivity for Android OS development. Navigating and editing files is amazingly fast, but it takes a bit of work to get the main build tree project loading properly. A few scripts exist to help, along with this great post by Shuhao Wu. However, some of the info needs to be updated for JDK 1.8 and Android N.

Source envsetup from the root of the build directory to begin:

source build/envsetup.sh

Then, make idegen:

make idegen

Run the idegen script to generate the necessary files:

development/tools/idegen/idegen.sh

Before loading the project, configure IntelliJ IDEA. Start by editing idea64.vmoptions (or studio64.vmoptions, located in ~/.AndroidStudio2.2/) – create the file if it does not exist:

-server
-Xms2048m
-Xmx4096m
-XX:ReservedCodeCacheSize=1024M
-XX:+UseCodeCacheFlushing
-XX:+UseCompressedOops
-XX:+UseConcMarkSweepGC
-XX:+UseParNewGC
-XX:ParallelGCThreads=8
-XX:+AggressiveOpts
-XX:+CMSClassUnloadingEnabled
-XX:CMSIncrementalDutyCycleMin=0
-XX:-TraceClassUnloading
-XX:+TieredCompilation
-Dsun.io.useCanonCaches=false
-Djava.net.preferIPv4Stack=true
-Djsse.enableSNIExtension=true

Open IDEA/AS, click File > Project Structure > Project, and set some default JDK information for 1.8. Project SDK should be 1.8.

Then navigate to the SDK tab, under Classpath, remove all the jars.

Now open the project file (android.ipr) generated by idegen. Back in the Project Structure, navigate to Modules > Dependencies, and remove everything except <Module source> and the java version line.

At this point, Shuhao’s guide digressed a bit from my findings. My build tree is lacking out/target/common/R, for the purpose of Sources. This is still under investigation, but the project appears to load fine in both IntelliJ IDEA and Android Studio. Compilation is still done from the command line, but navigating and coding should be considerably faster. Finally, in the same directory as the idegen.sh script, another script called intellij-gen.sh exists to make project files for individual modules if needed.

Moving /tmp to a tmpfs in RAM is “faster, more efficient, and more secure” according to Canonical themselves. It’s easy, too. Simply add this to the end of /etc/fstab:

# tmpfs to ramdisk
tmpfs /tmp tmpfs defaults,noatime,mode=1777 0 0

After a reboot, it’s good to go.

Another productivity catalyst is to add commonly used tools and scripts to PATH. If the environment has been set up according to my guide mentioned above, then ~/bin is already in PATH thanks to repo. Go ahead and throw things in there. As an example, I use mkboot to modify images almost every day. Extract the entire package (ARM folder, dtbTool, the scripts etc.) and now it can be called from any directory.

Swap and swappiness relate to the use of a swap disk, essentially an overflow when RAM is at the limit. The main issue (among others) is that swap is stored on disk, exponentially slower than RAM. Luckily, it’s use can be limited to only when absolutely necessary. Furthermore, according to this table, overall swap space can be minimized when hibernation isn’t needed, reclaiming precious hard drive space.

It also helps to increase the watches limit for IntelliJ performance. These tweaks have been combined to avoid redundantly editing sysctl.

Simply add two lines to the end of /etc/sysctl.conf :

vm.swappiness = 1
fs.inotify.max_user_watches = 524288

Reboot and everything should be ready!

  1 comment for “[GUIDE] Optimize Linux for Android Development

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.