[GUIDE] Optimize Linux for Android Development

Recently, I built a new development system. After installing Ubuntu 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

  1. While following this I noticed that editing of the studio64.vmoptions file is slightly different for Android Studio, and thought I would mention a few things, as well as ask a few questions…
    I might have this setup incorrectly, but I suppose that’s where you come in.. ^_^
    I found the studio.vmoptions & studio64.vmoptions files in ~/tools/android-studio/ but this file includes the following:
    # *DO NOT* modify this file directly. If there is a value that you would like to override,
    # please add it to your user specific configuration file.
    If you follow the link found in the rest of the comments section they will tell you to save a copy of an edited version of the file to ‘hidden’ configuration folder found @ ~/.AndroidStudio2.2/
    My question is, when creating this file, should I specify only the settings from your post, or should the following options in part or in whole be included in the file as well?
    -XX:MaxPermSize=350m
    -XX:SoftRefLRUPolicyMSPerMB=50
    -da
    -Djna.nosys=true
    -Djna.boot.library.path=
    -Djna.debug_load=true
    -Djna.debug_load.jna=true
    -Dawt.useSystemAAFontSettings=lcd

    Taken from reading google’s documentation
    “…editing only your own studio.vmoptions file ensures that you don’t override important default settings for Android Studio. Therefore, in your studio.vmoptions file, override only the attributes you care about and allow Android Studio to continue using default values for any attributes you have not changed” @ https://developer.android.com/studio/intro/studio-config.html#customize_vm

    So this being the case, out of these default system settings, are there any others you think should be changed? I’m not sure if I’m being retarded or not, but I’m going to assume if you didn’t mention it – they are just getting appended to the list/are replacing specified values, and leaving the rest as is. In the mean time I guess I’ll read up on some of these settings.

    Thanks,
    Roman
    P.S. Thanks for the wonderful resources!

Leave a comment

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.