16 June 2014
Two years ago I wrote a blog post complaining that the Android build system was broken. At the time, Eclipse ADT and Ant were the blessed solutions and they just hadn't scaled with the platform. Third-party solutions existed for both tooling and IDE but they always felt a bit illegitimate and at risk for problems. My post joined the cries of others who knew that something had to be done.
In the two years since he and the tools team have transformed the landscape of how Android development is done. A first-party Gradle plugin now provides the powerful and dynamic platform on which any app of quality is built. Ownership of the Android plugin inside IntelliJ IDEA (with a sprinkle of branding) yields a development environment that moves mountains for you.
Neither the Gradle plugin nor the IntelliJ IDEA plugin (known bundled as Android Studio) are at a v1.0 yet. They're both still beta (albeit arguably in the sense that GMail was circa 2008).
Why was all of this important and why is it important for Google moving forward?
Developers are the top of the funnel for Android's continued success. Without quality development tools there are no quality apps, without quality apps there are no quality users, and without quality users the developers will flee. Half of the developer flow in this funnel comes from the tools and the other half from APIs. This post is about the former.
My first exposure to Android was the M3 pre-release SDK's emulator (pictured). The emulator started up quickly and was responsive. Each successive release up to and beyond version 1.0 added much needed functionality to both the OS and the emulator. And in each successive release the emulator slowed.
Android's pubescent period (otherwise known as Honeycomb) and its eventual emergence into adulthood had a devestating effect on emulator performance. Despite our development environments becoming more powerful, two factors outpaced Moore's law:
Working with Intel, Google eventually released an x86 version of the emulator which eliminated ARM emulation and leveraged virtualization technologies built-in to CPUs. This was better. In fact, it was so much better that a lot of people were satisfied — myself included.
Recently, a company called Genymotion was formed around the work of a project that compiled Android to run in a VirtualBox VM. They not only delivered an experience that was faster and simpler than the x86 emulator, but they provided much-needed tools for modern app development. Easier sensor controls, touchscreen input using a remote device, and screen capture support for both images and video are just some of these features which really make the product shine.
Hopefully none of what I've covered is news to you. But now I am ready to start talking about this post's true topic:
All existing emulator solutions are terrible.
The management interface for creating, configuring, and starting emulators is a minimumly-viable Swing app. While the low quality list view is actually fine, the configuration pane is a mess (pictured).
This screen lacks any design to facilitate the correct behavior. The instruction set is usually defaulted to ARM which has to be fully emulated (very slow). Use of the host GPU is defaulted to off which means that the display pipeline will not be hardware accelerated (again, very slow). Unless you've been Googling passive-aggressive phrases about the emulator speed you might never even cross HAXM.
The pain does not cease once the emulator is running (whether using optimal settings or not). Each instance requires significant system resources and the performce of the contained OS will vary wildly. Instances will occasionally hang, crash, or disappear from
adb's visibility requiring manual restarts. Controls and interfaces to a few of the sensor are present, but they are far from comprehensive.
Genymotion is a step up from the first-party offering. It has fewer options for configuration because it is already set up for optimal performance. As previously mentioned, its sensor and developer controls are much more rich and useful.
The initial downside of Genymotion is the required user account and strange pricing of commercial licenses (and lack of a site license). They also are not without problems which plague the actual use of the emulator. The VirtualBox images occasionally get corrupted or stuck which require a trip in the depths of your filesystem for manual purging. The free license cripples functionality that would otherwise exist if they hadn't explicitly disabled it (screenshot, recording). Their pricing model for commercial use also does not reflect the amount of utility you actually receive.
We put up with these solutions because they are an improvement compared to what came prior. However, they are nowhere near what we truly need or deserve.
Android needs a simulator for day-to-day development and testing.
A machine with a similar set of controls designed to provide a realistic imitation of the operation of a vehicle, aircraft, or other complex system, used for training purposes.
A simulator is a shim that sits between the Android operating system runtime and the computer's running operating system. It bridges the two into a single unit which behaves closely to how a real device or full emulator would at a fraction of the overhead.
The most well known simulator to any Android developer is probably (and ironically) the one that iOS develoers use from Apple. The iPhone and iPad simulators allow quick, easy, and lightweight execution of in-development apps. If you haven't seen this simulator in action, I would encourage you to take a two-minute tour of one before continuing this post.
What does a simulator buy us that a traditional emulator does not?
There always will be a need for a proper emulator for acceptance testing your application in an environment that behaves exactly like a device. For day-to-day development this is simply not needed. Developer productivity will rise dramatically and the simplicity through which testing can now be done will encourage their use and with any luck improve overall app quality.
Android actually already has two simulators which are each powerful in different ways, but nowhere near powerful enough. Before we talk about them, let's cover why a simulator is a perfect fit for Android development.
Apps are text files of Java The Language™, compiled with
javac to JVM bytecode, transformed with
dex to Dalvik bytecode, zipped up into an
.apk, and signed using
jarsigner. Other tools like
zipalign and ProGuard are optionally a part of this toolchain but since they aren't usually used in development we can safely ignore them. Prior to the invocation of
javac, all of the resources of an app must be parsed with
aapt for code generation and special encoding of some files. This is a lot of steps!
Using a simulator would reduce this to a single step: compilation with
javac. We are already relying on the JVM for running our IDE, our build system, and our compilation. Why aren't we leveraging it for running a simulated OS?
Ok so I glossed over two other toolchain components we'd need to run our class files in a JVM-hosted simulator:
aaptwhose only responsibility was generation of
Rfiles would still be needed. Thankfully the slower operations this resource step performs (image optimization and text file encoding) wouldn't be needed. XML files can be read on-the-fly as text by the simulator. Images don't need optimized since they are just being displayed from the local filesystem.
Imagine how quick the time between modifying your source code and running the application becomes when the only steps needed are a resource scan,
javac, and copying a string. Oh, but do you have a ton of dependencies? Not a problem since all that's needed is appending the file path of the
.jar file onto the JVM classpath.
The prospect of this "exploded"
.apk application should get you seriously excited.
Even more exciting is that there are already two simulators which work with these exploded apps. The first and most well known is Robolectric, a tool for running unit tests on the JVM. The second is named "layoutlib" which is far less known but is used daily by every Android developer.
Robolectric runs a compiled version of the OS in a separate classloader using techniques like bytecode rewriting and proxies. This puts most of the real OS infrasture at your disposal for unit testing code paths of your app that have to touch Android code. People often abuse Robolectric for testing the wrong things but it usually works because the real OS code is used by default.
It takes about two seconds for Robolectric to initialize. Most of this time is creating the custom classloader and initializing all the proxy classes. Once running application code is loaded into the classloader and run like normal Java code. The resources are lazily resolved directly from the source files.
"layoutlib" is a module whose purpose is to run view code on the JVM including parsing layout XML and loading resources. If you've ever used the layout designer or layout preview in either Eclipse or IntelliJ IDEA/Android Studio then you have used this library.
Running your view code (including custom views) is done like any other Java code. The classes inside the library fake out the
Context and the resource loading it brings. The rendering pipeline is also simply mapped into normal Java rendering primitives so you can see real-time updates of your layouts.
Both of these libaries use very clever techniques to simulate parts of Android to great success. Neither one is suited to running an application during development which is what we are after.
There are hurdles to be tackled in building a simulator that can host development applications. If you'll remember from above, we already have a pared down version of
aapt, a simple representation of the signing key, and are leveraging
javac and the JVM classpath for loading code and libraries. Let's enumerate what else is required — none of which are insurmountable.
Thankfully these are all solvable problems. Each one just needs the right person with the time and effort to tackle it. However, therein lies another problem.
The single greatest hurdle to the creation of the simulator we deserve is the time, effort, and desire required to build and maintain it. Sorry, tools team! I'm told they're hiring.
— Jake Wharton