The skill that separates good Android developers from great ones is the ability to understand how the platform works through an ability to efficiently navigate through the source.
Say what you will about open vs. closed systems and their associated pros and cons, but one of the most instructive tools that you have at your fingertips as an Android developer is the fact that the source code for the framework you are interacting with is readily available.
You need look no further to answer the question “I wonder how they did that?”
AOSP Background
The official web mirror of the Android Open Source Project (AOSP) sources is located at https://android.googlesource.com/
Here, you can browse through all the individual projects that collect together to make the entire source tree one builds into a final system image. As you can see it’s a big project, and, as an application developer, there’s a lot in here that you probably don’t care much about. But, before we get too deep into talking about the Android source code structure, let’s back up and start with a simpler approach.
Open Source Diver
There are some great tools available to assist developers in lightly browsing the source code of the framework components, without requiring you to go out and obtain the full source tree on your local machine. There are three steps you need to take:
If you don’t like to use Chrome as your daily browser, I might strongly suggest switching. As you’re about to see, there are some amazingly useful tools that are built as Chrome Extensions.
- Install the Android SDK Reference Search Extension by Roman Nurik
In addition to the many useful features this extension provides for doing searches in the SDK Documentation and jumping directly into class reference pages (which is reason enough to use it every day), every class reference page also gets tagged with a handy View Source link that jumps you straight into the web mirror of the official AOSP sources. This provides direct access to the classes you’re interested in.
There is one small drawback to relying solely on this tool. With new releases of Android, the structure of the source code tree is subject to change (especially in areas like the support library). This can temporarily break some of the source links in this extension until Roman and the team can get around to updating it (which they have been quite good about doing).
- Install the Android Resource Navigator Extension by Jeff Gilfelt
This little gem enables you to jump directly into the framework resources (i.e. styles, themes, and drawables). In this case, you will be taken to the mirror of the AOSP sources on GitHub. In addition to doing direct searches for themes and widget styles, ARN injects links into the XML views that allow you to quickly jump to other style references or even, with just a few clicks, look at framework drawables used in the default styles.
These tools allow you to get quickly into the source code without leaving your browser.
Want to see how TextView
implements its text layout? Done.
Debugging an interaction between your ViewPager
and a ScrollView
? Have a look.
Advanced Source Diver
These tools are great, and, for light investigations into 1-2 classes at a time, they are all you will need. However, hopping in and out of different browser windows can get a bit cumbersome when you really want to trace what’s going on, especially if any of the system services are involved.
To move to this level, you will need to obtain a local copy of the Android sources. Follow the instructions provided on the AOSP Site to download the Repo tool and sync a copy of whichever Android version you want to explore.
Note: For everything I’m showing here, the Android 4.2.2 sources were used.
With the sources on your machine, there is one very important script you need to
run: build/envsetup.sh
~/aosp$ source build/envsetup.sh
including device/asus/grouper/vendorsetup.sh
including device/asus/tilapia/vendorsetup.sh
including device/generic/armv7-a-neon/vendorsetup.sh
including device/generic/armv7-a/vendorsetup.sh
including device/generic/mips/vendorsetup.sh
including device/generic/x86/vendorsetup.sh
including device/lge/mako/vendorsetup.sh
including device/samsung/maguro/vendorsetup.sh
including device/samsung/manta/vendorsetup.sh
including device/samsung/toroplus/vendorsetup.sh
including device/samsung/toro/vendorsetup.sh
including device/ti/panda/vendorsetup.sh
including sdk/bash_completion/adb.bash
Running this script is part of the setup instructions for Building Android after you download the sources, but it has some side benefits for source divers. The environment setup script creates a host of useful shell commands that you cannot live without when finding your way around the source code. Here is the list of primary commands I find useful for source diving:
croot
Sometimes the simplest tools can be the most useful. This little command just takes you back to the root of the source tree, regardless of which directory you may be currently in.
cgrep, jgrep, resgrep, mgrep
These are wrappers around the standard grep
utility that will recursively search
through just C/C++, Java, resource, or make files (respectively).
When tracing code, if you end up at a method and you can’t find the corresponding
file it’s in, cgrep
/jgrep
are invaluable in picking up the trail on the other side.Similarly, resgrep
will let you quickly hunt down the definition of an XML resource.
~/aosp$ jgrep RECEIVE_BOOT_COMPLETED
./frameworks/base/core/java/android/content/Intent.java:1480: * {@link android.Manifest.permission#RECEIVE_BOOT_COMPLETED} permission
./frameworks/base/services/java/com/android/server/am/ActivityManagerService.java:4422: android.Manifest.permission.RECEIVE_BOOT_COMPLETED,
./frameworks/base/services/java/com/android/server/am/ActivityManagerService.java:14401: android.Manifest.permission.RECEIVE_BOOT_COMPLETED,
The first option is just a reference to the permission in doc comments, but the
latter lines show that ActivityManagerService
is solely responsible for checking
if applications hold this permission. We can look further by running the same query
using resgrep
:
~/aosp$ resgrep RECEIVE_BOOT_COMPLETED
./frameworks/base/core/res/AndroidManifest.xml:1428: <permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"
The permission itself is defined in the framework’s AndroidManifest.xml file (and it turns out, all framework permission elements are as well). So we can go investigate the platforms manifest if we want to find out more.
godir
This command will serve two purposes well. First, it is a useful way to jump
quickly from one file to another that may be in a completely separate section
of the directory tree (especially if you don’t yet know where that other file is
located). The Android source does this a lot; files that are logically groups are
not necessarily physically grouped in the tree.
This can help you avoid a lot of cd
hell.
The following example shows how godir
can help us quickly open all the files
associated with the AlarmManager
system service.
~/aosp$ godir AlarmManager
[1] ./cts/tests/tests/app/src/android/app/cts
[2] ./frameworks/base/core/java/android/app
[3] ./frameworks/base/docs/html/sdk/api_diff/3/changes
[4] ./frameworks/base/docs/html/sdk/api_diff/8/changes
[5] ./frameworks/base/services/java/com/android/server
[6] ./frameworks/base/services/jni
[7] ./packages/apps/Calendar/src/com/android/calendar/alerts
[8] ./packages/providers/CalendarProvider/src/com/android/providers/calendar
Select one: 2
~/aosp/frameworks/base/core/java/android/app$ gedit AlarmManager.java &
~/aosp/frameworks/base/core/java/android/app$ godir AlarmManager
[1] ./cts/tests/tests/app/src/android/app/cts
[2] ./frameworks/base/core/java/android/app
[3] ./frameworks/base/docs/html/sdk/api_diff/3/changes
[4] ./frameworks/base/docs/html/sdk/api_diff/8/changes
[5] ./frameworks/base/services/java/com/android/server
[6] ./frameworks/base/services/jni
[7] ./packages/apps/Calendar/src/com/android/calendar/alerts
[8] ./packages/providers/CalendarProvider/src/com/android/providers/calendar
Select one: 5
~/aosp/frameworks/base/services/java/com/android/server$ gedit AlarmManagerService.java
~/aosp/frameworks/base/services/java/com/android/server$ godir AlarmManager
[1] ./cts/tests/tests/app/src/android/app/cts
[2] ./frameworks/base/core/java/android/app
[3] ./frameworks/base/docs/html/sdk/api_diff/3/changes
[4] ./frameworks/base/docs/html/sdk/api_diff/8/changes
[5] ./frameworks/base/services/java/com/android/server
[6] ./frameworks/base/services/jni
[7] ./packages/apps/Calendar/src/com/android/calendar/alerts
[8] ./packages/providers/CalendarProvider/src/com/android/providers/calendar
Select one: 6
~/aosp/frameworks/base/services/jni$ gedit com_android_server_AlarmManagerService.cpp
~/aosp/frameworks/base/services/jni$ croot
~/aosp$
Note that entering a partial name brings up a list of options, and selecting the
number jumps us straight into that directory, so we can open the file.
If godir
is given a specific enough name, it will jump directly:
~/aosp$ godir AlarmManagerService.java
~/aosp/frameworks/base/services/java/com/android/server$
Notice also that we don’t have to be at the root of the tree for each request
(unlike with grep
), as godir
can be run from anywhere.
Dive Master Tips
You never dive in an unknown region without first getting some tips from the local Dive Master about places you should go and other places you should likely stay away from. The Android source is a huge tree of files; here are some tips to hopefully keep you on the right track.
System Apps
Most of the core system applications will be found in packages/apps
; source code
for applications like Browser, Launcher, and Settings can all be found here.
Additionally, a handful of applications also live in frameworks/base/packages
,
most notably SystemUI, which controls all of the system chrome for the status bar,
window shade, and soft nav buttons.
Framework Classes
Much of the framework is contained in frameworks/base/core
, with a few packages
like telephony and location living in their own directories under frameworks/base
.
It is important to realize that the Android APIs are not entirely written in Java.
Many of the framework classes have a native C/C++ component to them. AOSP typically
segments the files into a separate java/
and jni/
directory, the latter referring
to Java Native Interface and including the native components.
Framework Resources
The XML and drawable resources of the framework are located in the res/
directory
of frameworks/base/core
. You will find this file hierarchy structured similar to
what you would find in an application project, with XML resources in the drawable/
,
layout/
, values/
and xml/
directories, and image resources in the qualified
directories such as drawable-hdpi/
.
The platform also has its own Android Manifest file which contains the definition
of published system elements like permissions. Many of the system-level activities
and receivers are published here as well. This is where we saw the implementation
of RECEIVE_BOOT_COMPLETED
in our deep dive example.
System Service Structure
Most of the system services available to applications follow a common implementation
pattern. The classes accessible to applications, such as PackageManager
or
NotificationManager
, are typically found somewhere in frameworks/base/core
and are often very thin wrappers around method calls to a single service object
running in a remote process.
These service definitions, where most of the implementation code exists, are
usually found in frameworks/base/services
with names similar to their corresponding
manager, such as PackageManagerService
or NotificationManagerService
.
As we discussed earlier, these services are usually not written entirely in Java;
and may very well include a native C/C++ component. Because of this, the implementation
is typically split between the java/
and jni/
directories.
Take The Plunge
I’m hopeful that this information has given you a good exposure to the tools you can use to explore the Android source code, and the confidence to get in there and poke around. The more you understand about how Android is put together, the better the applications you develop will conform to the design conventions of the platform. You will also notice your applications performing better as your newfound understanding for the framework implementation guides you to places where you can effectively make optimizations in your code.