The current Android emulator sources, which are located on [1], are based on a very old fork of the QEMU upstream sources. The fork itself was created in 2006, iirc, with several modifications to make it usable on Windows and OSX, a flurry of other fixes, and plenty of Android-specific features. While over the time, many upstream features have been back-ported manually to the Android codebase, but both source lines have evolved in ways that make them extremely divergent.
To support ARM64 emulation, a new codebase [2], currently named "qemu-android", and based on QEMU 2.0, has been setup (with a _lot_ of support from Linaro, thanks again).
At the moment, qemu-android is a minimally modified version of QEMU 2.0, that includes a few patches required to support Android running on a new virtual board named "ranchu" [3].
It currently lacks many features to be a usable alternative for the SDK. However, we plan to improve it considerably in order to emulate the next major Android release with it.
The old emulator will be maintained and used to emulate system images of previous releases. While it would be nice to have a single binary capable of emulating all platform releases, achieving this may require too much work.
1) Main differences between "ranchu" and "goldfish":
We use the name "ranchu" to identify the new kernel configuration supported by the new codebase. The major difference with "goldfish" is that it tries to rely less on goldfish-specific devices, and more on existing ones provided by the upstream kernel.
For example, it uses virtio-block devices to emulate the NAND and SDCard devices (which require their own virtual devices in the old codebase). Note that this also has the potential of providing much better performance (likely but untested so far).
There are no plans to back-port it to 3.4 or earlier. On the other hand, we need similar configurations for other CPU architectures (32-bit ARM, x86, x86_64, MIPS and possibly MIPS64).
Technically, "ranchu" on ARM64 is based on "mach-virt", an ARM-specific paravirtualized platform. Ideally, I would love if the kernel provided a single paravirtualized platform that could vary only on the emulated CPU, but it seems that something like this doesn't exist, i.e. emulating an x86 device still essentially requires emulating a more or less complete PC.
I would love to discuss with people on this list about the best way to move forward with ranchu. Porting goldfish-specific patches from one kernel branch to the other has always been a hassle, and a source of surprises, so anything that can reduce this load would be welcomed. For example, I know that Linaro has experimented with replacing the goldfish pipe with virtio-char, but early results gave noticeable performance degradation (which might be critical for GPU emulation).
Ranchu is not really documented at the moment, so people will have to look at the sources in both the kernel and qemu-android repositories. Hopefully, I'll come up with a detailed doc like the existing docs/GOLDFISH-VIRTUAL-HARDWARE.TXT
2) Main differences between the old and new codebases
2.1) Source code size:
- The old codebase is about 400K of lines of code, split between 100K of Android-specific code, and 300K of QEMU-specific one (though with some patches not found in usptream).
- The new codebase is about 1500K of lines of code, with only 8K of Android-specific code (at the moment).
The patches for the new codebase add support for the following 'goldfish' virtual devices, which are also part of 'ranchu': framebuffer, audio, battery, pipe. They also add support for the "ADB bridge" (which makes the guest system visible and usable through "adb"), as well as the Android console (more precisely a subset of console commands).
Note that GPU emulation is a work-in-progress, you can look at the "ranchu-opengles" branch on the qemu-android repository if you want to play with it.
2.2) Build:
To build the old codebase, one has to checkout a few repositories from the AOSP source servers (ProTip: use 'repo' with 'repo init -u
https://android.googlesource.com/platform/manifest -b ub-tools-master' to get a minimal AOSP checkout that let you build the emulator), then use external/qemu/android-rebuild.sh to rebuild everything and run a minimal unit test suite.
The scripts/rebuild.sh script there can be used to rebuild a qemu-system-aarch64 executable for all 3 supported host platforms.
At some point, the qemu-android and rebuild scripts will be moved to the AOSP servers as well. I'm currently undecided about how to best package the dependencies (glib, libffi, sdl, etc...)
2.3) Launching:
The Android emulator is typically launched by calling the 'emulator' program, which is a tiny wrapper that will find the AVD's virtual CPU type, then launch the appropriate emulation "engine" (e.g. emulator64-arm) based on it. It also modifies the library search path to ensure the engine finds the GPU emulation libraries (e.g. libOpenglRender.so) and the PC BIOS images (required for x86 emulation).
The emulation engines are built by android-rebuild.sh, they are essentially a shell around the old QEMU fork that adds a custom UI and some Android specific features (e.g. ADB bridge, console) in a single executable.
For ARM64 support, emulator64-arm64 is instead another wrapper that is used to launch the real qemu-system-aarch64 executable (built from the qemu-android sources). Its main purpose is to translate the Android emulator-specific command-line options into the corresponding QEMU command-line one, which is generally very error-prone to setup correctly.
Its source is under external/qemu/android/qemu-launcher/, note that this source currently only supports ARM64, but this will change very soon.
I will soon create a new post detailing how to build the qemu-android binaries and use them with 'emulator'.
3) Code refactoring
Having two different codelines is never easy. At a minimum, it means a different set of features and bugs to care for and maintain. To reduce this burden, we've started refactoring the Android-specific part of the old emulator code base to make it easy to port to the new code base.
Ideally, I'd like to have a single static library (let's call it 'android-emulation') that could be linked to either one of the two code bases, and which could have its own set of unit and regression tests.
Another reason why this is important is to make the Android-specific patches to the new QEMU code base as minimal as possible. This would make the code easier to rebase on top of newer versions of upstream QEMU.
This requires defining a proper library interface, with clearly-defined semantics for object lifetimes, event handling, so expect more about this in a future post.
In the meantime, don't be too surprised to see a lot of changes in the old code base related to this.
4) Testing
We need it, and a lot of it :)
While we're setting up a Google-internal test infrastructure to better detect regressions in the emulator itself, SDK system images and the platform build, we also need to setup a reasonable test suite as part of the open-source tree. This will help third-party contributors and ensure issues are detected more quickly during development.
There is no firm plans on how to achieve this right now, but I've slowly being adding unit tests to the Android-specific parts of the old code base, and will keep doing so.
There is also a new set of AOSP build products named "qemu_$ARCH" (e.g. qemu_arm-userdebug), which can be used to build a minimal version of the Android system (without any Dex runtime or graphics interface). The goal is to use its root shell or adb connection to install/run various test programs to perform overall testing of specific emulation features, at a pretty low level.
This should also be a good way to identify issues related to emulator changes, compared to the one that happen routinely by platform changes that were not sufficiently tested (which are much more routine at this point :-( ).
5) Relationship with upstream
In an ideal world, we would not need a fork, and all code would live on the upstream QEMU git.
In reality, things are different: there is little chance that the upstream team would want to maintain 100K+ lines of code that are completely specific to Android, and for good reason. That's why the refactoring effort is so important, we need to find a way to maintain the Android-specific QEMU patches as small as possible, and push as much stuff into the android-emulation library.
Even with smaller changes, it's crucial to have a good set of tests, that exercise these Android-specific features, added to the QEMU test suite, and clear documentation about the implementation being added. This may require a stub or minimal mock version of android-emulation.
Finally, we may want to dedicate serious engineering resources to better continuous integration of upstream QEMU that would also exercise the Android bits.
Until we reach such a situation, we will have to maintain a separate fork and continue to rebase it on top of recent QEMU changes.
- Digit