In a fairly fast-paced talk, Karim Yaghmour presented the internals of Android systems at the Android
Builders Summit. The talk focused on things like
Android's application development model, the parts and pieces that make it
up, and its startup sequence. It gave
an overall picture of a system that is both familiar and not.
Yaghmour is the lead author of Building Embedded Linux
Systems and has done Linux kernel development along the way. He developed the
Trace Toolkit (LTT) in 1999, which has since been taken over by another
École Polytechnique de Montréal graduate, Mathieu Desnoyers,
as LTT next generation (LTTng). Desnoyers is "doing a much better
job" with it than he did, he said with a chuckle. He also developed
relayfs, which is an efficient way to relay large amounts of data from
kernel to user space. He is now doing Android development and training.
With a slide showing Kirk and Spock from the original Star Trek,
and the line "it's Linux, Jim, but not as we know it", Yaghmour
pointed out that Android is a "strange beast" that
"looks weird, feels weird, and acts weird". That's because it
doesn't have the traditional Linux user space, but instead has its own user
space that sits atop a somewhat non-standard Linux kernel.
For example, there is no "entry point" to an application for Android.
Developers create components that get bundled together as applications.
An application consists of multiple components, some of which may be shared
with other applications. Each application
is hosted in a Linux process. Any of those components can disappear
while the system is running because its application process goes away.
That can be because the application is no longer needed or because of memory pressure from other
being loaded. That means that components need
"lifecycle management". Essentially, components need to be
able to come back again the way they were before being killed.
Android also uses messages called "intents" that are sent between
components. Yaghmour said they are like "polymorphic Unix
signals" that can be sent to a specific component or service, but
can also be broadcast. Applications can register their interest in various
intents by specifying Intent Filters in their manifest files.
Remote procedure calls (RPCs) (or inter-process communication aka IPC) are
done using the "Binder" in Android
because "System V IPC sucks", at least according to comments
in the Android code. The Binder allows components to talk to services and
for services to talk to each other. The Binder is not used directly,
however, and instead interfaces are defined using an interface definition
language (IDL). Those IDL definitions are fed to a tool that generates
Java code to handle the communication.
The development environment for Android is "fantastic",
Yaghmour said. The Android SDK provides everything that is needed to
create applications. The problems come when trying to develop a device
that runs Android, he said, because the "glue that allows all these
APIs to talk to the kernel is not documented anywhere". For a
"normal" embedded Linux system, you generally just need the kernel, a C
library, and BusyBox, which is generally enough to allow you to build any
but for Android, the picture is much more complex.
It is still the Linux kernel at the bottom, but that's about it that is
the same as a normal Linux system. The
kernel has numerous patches applied to it for things like wakelocks and the
Binder, but it is recognizably Linux. Above that, things start to change.
There are a number of libraries available, some of which appear in other systems
(Linux, BSD, etc.), like WebKit and SQLite, but some are Android-specific,
like the libc
Android has its own init, which is not based on either
System V init, or on BusyBox's, partly because it doesn't use the latter.
Instead of BusyBox, Android has something called Toolbox that fills the
same role, but not as well. Yaghmour said that the first thing he does on
an Android system is to replace Toolbox with BusyBox. It was a political
decision not to use BusyBox, rather than a technical one, he said. There
are also various libraries to support hardware like audio devices, cameras,
GPS devices, and so on, all of which are implemented in C or C++.
Android uses Java Native Interface (JNI) to talk to any of that lower level
code from the Java-based code that makes up (most of) the rest of user
space. The Dalvik virtual machine uses JNI to call those libraries. The
system classes (in the android.* namespace), as well as the Apache
Harmony-based standard Java classes (in java.*) sit atop of
Dalvik, as does
the all-important System Server. Above those are the stock Android
applications along with any other applications installed by the user (from
the Market or elsewhere).
Android replaces the Java virtual machine with Dalvik, and the JDK with
classes from Apache Harmony. To create .dex files for Dalvik, the
Java is first processed by the Java tools to create .class files,
which are then post-processed by dx to produce the files used by
Dalvik. One interesting thing noted by Yaghmour is that .dex
files are typically half the size of the equivalent .class files.
The layout of the native Android user space is very different than standard
Linux as well. There
is no /bin or /etc, which nearly every standard Linux
tool expects to find. The two main directories in Android are
/data (for user data) and /system (for the core system
components). But some of the expected directories are present, like
/dev and /proc.
After that relatively high-level overview of the Android system, Yaghmour
looked at the Android startup sequence, starting with the bootloader. That
bootloader implements a protocol called "fastboot" that is used to control
the boot process over USB using a tool of the same name on a host system.
The bootloader contains code to copy various portions of the code around on
the flash (for returning to a stock image for example), and allows users to boot
from a special partition that contains a recovery program (via a magic key
sequence at boot time). Some of these are features that might make their way
into U-Boot or other bootloaders, he said.
The flash layout of a typical device has multiple partitions to support
Android, including "boot" (which is where the kernel resides), "system",
"userdata", and "cache" (the latter three corresponding the mounted
/system, /data, and /cache filesystems on a
running Android system). Yaghmour noted that Android does not follow the
Filesystem Hierarchy Standard (FHS) with its filesystems, but it also doesn't
conflict with that standard, which allows folks to install FHS filesystems
Newer Android releases are using the ext4 filesystem, rather than the
yaffs2 filesystems used on earlier devices. That's because the latest
devices are not using a classic NAND flash chip, and instead are using
something that looks like an SD card to the processor. The kernel treats
it like a block device. Because the newer devices have multicore
processors, Google wanted a filesystem that is optimized for SMP, he said,
thus the move from yaffs2 to ext4.
Once the kernel has booted, it "starts one thing and one thing
only" and that is the init process. Init parses /init.rc
and runs what it finds there. Typically that means it creates mount points
and mounts filesystems, starts a low-memory handler that is specific to
Android (and runs before the kernel's out-of-memory (OOM) killer), starts a
bunch of services (including the servicemanager which manages Binder
contexts), and starts the "root" of the Java process tree, Zygote (aka
Zygote is the parent process of all application processes in the system.
It "warms up the cache of classes" so that applications start
quickly, and starts the System Service. The System Service is a key part
of the Android system, but one that is not very well documented.
"Anything that is important that is running in the system is housed
inside the System Service", Yaghmour said. That includes services
for various hardware devices (battery, lights, vibrator, audio, sensors,
etc.), as well as managers for things like alarms, notifications,
activities, and windows (i.e. the window manager).
The System Service starts the ActivityManager to do what its name implies,
manage activities. It is "one of the most important services"
in Android, he said. It handles starting activities, broadcasting events,
and more. He likened it to the kernel's scheduler.
activity needs to be started, for example, the ActivityManager asks
Zygote over a
socket to do so.
The hardware devices are generally accessed via their services, which call
into an underlying library that is typically provided by a vendor. For
things like LEDs, Android provides a .h file that describes the
interface and vendors create a C program that implements it. It is similar
for other devices like GPS, audio, camera, and so on. For WiFi,
wpasupplicant is used, while Bluetooth support comes from BlueZ.
Because of GPL concerns, Android talks to BlueZ via D-Bus, which may be
controversial in some quarters, Yaghmour said. In answer to a question
from an audience member, he noted that Google wanted to avoid having its
partners have to explain licensing to their engineers. So, it chose not
to use GPL-covered software other than the kernel to keep user space "free"
of licensing concerns. That gets a little blurrier with the inclusion of
BlueZ, but the "theory" is that the GPL does not apply to code
that talks to it via D-Bus. Some may disagree with that theory, he said.
It must have been hard to pull together a reasonable look at Android's guts
that would fit into a 50-minute slot, but Yaghmour largely succeeded in
doing so. There were undoubtedly lots of details passed over, but
attendees definitely got a good feel for what goes on inside the phone that
many of their pockets.
to post comments)