Running android studio on Guix

by Julien Lepiller — Wed 10 June 2020

One of my motivation in my work towards better Java support in Guix is that one day, I will have a proper environment for building Android applications. In particular, I have create nani, an offline dictonary application for Japanese learners like me. This post is about my current setup and how I am able to run Android studio despite all its weirdness and embedded FHS paths.

Dependencies

The version of Android studio you can download from google is bundled with a lot of binary packages, so its dependencies are actually fairly small. The following manifest file (save it as studio-manifest.scm) contains all you need to run Android studio:

(use-package-modules base bash compression gcc gl glib linux nss pulseaudio
                     version-control virtualization xml xorg)

(packages->manifest
  (list bash git which dbus
        (list gcc "lib")

        ;; for running the android virtual devices (AVD):
        e2fsprogs qemu-minimal
        alsa-lib expat libxcomposite libxcursor libxi libxtst
        mesa nss pulseaudio (list util-linux "lib") libx11 zlib))

Download the android studio from google and decompress it in some directory (I did it on /mnt/hdd/android because my main disk doesn't have enough space for all that).

I also created symlinks in my home directory to prevent it from being filled with android's junk: ln -sv /mnt/hdd/android/home/android ~/.android and ln -sv /mnt/hdd/android/home/AndroidStudio4.0 ~/.AndroidStudio4.0.

Launching in a Container

Android studio is composed of many different programs that would each need to be patchelf'd in order to run properly on Guix. However, this is not really an option for three reasons:

  • We would need to keep track of what we patched them with (keeping them as a gc root),
  • We would have to do it all again on every update of Android studio,
  • Some tools are downloaded by gradle and modifying them will result in gradle reinstating the broken version, preventing your application from being buildable.

Instead, I am going to use Guix containers and expose libraries at the expected FHS paths: no patchelf involved!

Preparing Studio

Android studio comes with its own Java version, but I found that it was somewhat broken, so I replace it with guix' own version:

guix build icedtea
ln -sv /gnu/store/...-icedtea-3.7.0-jdk /var/guix/gcroots
rm -rf android-studio/jre
ln -sv /var/guix/gcroot/...-icedtea-3.7.0-jdk android-studio/jre

Note that even though the directory is named jre, you need a jdk.

Creating the Environment

First of all, I need to know where in the store the profile is created for my environment, so I create the environment and check the value of the $GUIX_ENVIRONMENT variable. I then copy that value to the $PROFILE variable, outside the environment:

export PROFILE=$(guix environment -C -N -m studio-manifest.scm \
  -- bash -c 'echo $GUIX_ENVIRONMENT')

Note that you will need to run that command every time you want to enter the environment, as a new version of guix will create a new profile. You may also consider using time-machine

Entering the Container

Now it is time to build and enter the container itself:

guix environment -C -N --share=$XAUTHORITY --share=/tmp/.X11-unix \
    --share=/dev/shm --expose=/etc/machine-id --expose=~ \
    --expose=$PROFILE/lib=/lib --expose=$PROFILE/lib=/lib64 --share=/dev/kvm \
    -m studio-manifest.scm -- env XAUTHORITY=$XAUTHORITY DISPLAY=$DISPLAY bash

Let's decompose this command a bit:

  • -C -N creates a container with network access.
  • --share=$XAUTHORITY --share=/tmp/.X11-unix --share=/dev/shm: this is required to run any graphical application.
  • --expose=/etc/machine-id: this is used by dbus which many graphical applications require, including studio.
  • --expose=~: studio needs to access at least some parts of your home directory. Here, we give it read-only access to your home. This works because this is enough to read symlinks that point to a location that is writable inside the container. If you didn't symlink ~/.android and co., you should share them instead.
  • --expose=$PROFILE/lib=/lib --expose=$PROFILE/lib=/lib64: this will allow studio to find its libraries in the location it expects (/lib and /lib64).
  • --share=/dev/kvm: this is required for running an AVD. Note that your user must also be in the kvm group to be able to run an AVD. Omit if you don't want to run any.
  • env XAUTHORITY=$XAUTHORITY DISPLAY=$DISPLAY: this ensure that required environment variables for Xorg are set in the container.

Running Studio

It is now time to run Android studio inside the container. Open it with this:

LD_LIBRARY_PATH=/lib ./android-studio/bin/studio.sh

or if you want to be able to run an AVD from studio, open it like this:

LD_LIBRARY_PATH=/lib:/lib/nss:$HOME/Android/Sdk/emulator/lib64/qt/lib:$HOME/Android/Sdk/emulator/lib64
    ./android-studio/bin/studio.sh

Note that the Android directory can be installed elsewhere, so you will have to adapt that command for your situation. If you installed it in the same directory as I, that would instead be:

LD_LIBRARY_PATH=/lib:/lib/nss:/mnt/hdd/android/home/Android/Sdk/emulator/lib64/qt/lib:/mnt/hdd/android/home/Android/Sdk/emulator/lib64 \
    ./android-studio/bin/studio.sh

This is terrible, but it is the only way I found to run it somewhat properly. Running it in an environment also isolates it from the system and prevents it from doing any damage to my home directory or my personal data. I hope this is useful to you!