Android Source Diving – Video Tutorial

Dave Smith
Dave Smith
Android Source Diving – Video Tutorial

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.

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).

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.