A practical approach to the AOSP build system

Introduction

The Android open-source project (AOSP) is quite complex and it can be hard to find a good way to get more familiar with it. I’m going to try a practical approach, by adding an Android application to the system image, while at the same time describing the relevant parts of the build process. As you might already know, the Android source is built using make, and this blog post assumes some knowledge in how to write makefiles.

If you want to follow this guide, start by setting up the development environment according to the AOSP web site:

http://source.android.com/source/index.html

After setting up the environment, finish a full build for the emulator (replacing -j5 with a value suitable for your computer):

https://gist.github.com/3810365#file_build_platform.sh

Now, lets have a look at the steps involved.

envsetup.sh

When building, you usually start with sourcing the file build/envsetup.sh to setup your build environment. It basically adds a lot of shell commands to your bash environment, e.g:

  • hmm() – print short help menu
  • lunch() – prints lunch menu (available build targets)
  • add_lunch_combo() – adds a new entry to the lunch menu
  • mm() –  Builds all of the modules in the current directory

It also sources any vendorsetup.sh files found under vendor/*/vendorsetup.sh, vendor/*/*/vendorsetup.sh and device/*/*/vendorsetup.sh, which allows vendors to add their own products to the lunch menu using the add_lunch_combo function. An example of the a vendorsetup.sh is the Samsung Maguro product directory (device/samsung/maguro):

https://gist.github.com/3810365#file_vendorsetup.sh

You can try calling one of the commands after sourcing envsetup.sh:

https://gist.github.com/3810365#file_call_hmm.sh

lunch

Next thing is to select target using the lunch menu, which was added to your bash shell environment after sourcing envsetup.sh. After making your selection, the chosen product and variant is verified and environment variables are set, including:

  • export TARGET_PRODUCT=$product – The chosen product
  • export TARGET_BUILD_VARIANT=$variant – The chosen variant
  • export TARGET_BUILD_TYPE=release – Only release type is available. Use choosecombo if you want to select type.
  • export ANDROID_BUILD_TOP=$(gettop) – The build  root directory.
  • export ANDROID_TOOLCHAIN=... – The toolchain directory for the prebuilt cross-compiler matching the target architecture
  • export PATH=... – Among other stuff, the prebuilt toolchain is added to PATH.
  • export ANDROID_PRODUCT_OUT=... – Absolute path to the target product out directory
  • export ANDROID_HOST_OUT=... – Absolute path to the host out directory

Check out some of the variables by typing:

https://gist.github.com/3810365#file_check_env_variables.sh

Building the platform

You previously finished a platform build by running the following commands:

https://gist.github.com/3810365#file_build_platform.sh

Depending on the type of build you selected, the result can be varying. However, a typical build results in the following images:

  • boot.img – Native system boot image.
  • ramdisk.img – Ramdisk rootfs.
  • recovery.img – Recovery image.
  • ramdisk-recovery.img – Ramdisk rootfs for Recovery.
  • system.img – System data (/system directory)
  • userdata.img – User data (/data directory)

These images is what makes up the Android system, with one exception. The Android kernel is not a part of the AOSP, and must be built separately. We will get back to this later…

Building a module

Now, in order to dig a little deeper into the build system, navigate to the Music application in packages/apps/Music and build it using mm:

https://gist.github.com/3810365#file_build_module.sh

The main makefile for this module is called Android.mk and is located in $ANDROID_BUILD_TOP/packages/apps/Music:

https://gist.github.com/3810365#file_music_app.mk

The make file sets a few module specific build variables and includes the BUILD_PACKAGE variable to tell make how to build this particular module. The BUILD_PACKAGE variable is defined in a file called config.mk located at $ANDROID_BUILD_TOP/build/core/config.mk. Lets have a look at the relevant parts of it:

https://gist.github.com/3810365#file_config.mk

As you can see, there are several build variables defined in this file. They basically references a separate make file which handles that particular type of build. For example, the BUILD_PACKAGE variable refers to the file $ANDROID_BUILD_TOP/build/core/package.mk. Other build notable build variables are:

  • CLEAR_VARS – Includes the file $ANDROID_BUILD_TOP/build/core/clear_vars.mk. Clears all LOCAL_* variables (with the exeption of LOCAL_PATH) to ensure that any previously built modules does not affect the current module.
  • BUILD_PACKAGE – Includes the file $ANDROID_BUILD_TOP/build/core/package.mk. Defines how packages (*.apk) are built. The build is controlled by setting LOCAL_* variables as seen in the Music application example above.
  • BUILD_PREBUILT – Includes the file $ANDROID_BUILD_TOP/build/core/prebuilt.mk. Defines how pre-built modules should be handled, e.g. a pre-compiled jar file.
  • BUILD_JAVA_LIBRARY – Includes the file $ANDROID_BUILD_TOP/build/core/java_library.mk. Defines how shared java libraries should be built.
  • BUILD_STATIC_JAVA_LIBRARY – Includes the file $ANDROID_BUILD_TOP/build/core/static_java_library.mk. Defines how static java libraries should be built. Includes java_library.mk as well.
The result of the build can be found in the target output directory, e.g.
$ANDROID_BUILD_TOP/out/target/product/<product name>/APPS

A closer look at the core makefiles

How does the build system know what to build? The answer to this question is fairly complex and involves lots of build files, but a very simplistic view of the process can be seen in the image below. Most of the involved files have been abstracted away to get a feeling for how a build is triggered.

When invoking make in the build root after setting up the environment (sourcing envsetup.sh and calling lunch), make finds the default Makefile in the build root, which in turn includes the main makefile in build/core/main.mk. The main makefile includes lots of other makefiles based on what make target. Assuming the default target, three of the more important ones are highlighted in the image below: config.mk, definitions.mk and Makefile.

Very simplistic view of the build system

Short description of what the different makefiles actually do:

  • main.mk
    • Verify correct java version
    • Setup build version (user, userdebug, eng)
    • Fnd all Android.mk files in the platform build
    • Filter out what Android.mk files (modules) to actually include in build
  • config.mk
    • Setup the internal build system files as described earlier (CLEAR_VARS, etc.)
    • Find the board config file (BoardConfig.mk) based on lunch selection.
    • Sanity check the board config file
    • Setup tools, e.g. aapt, proguard, flex, etc.
  • definitions.mk
    • Define LOTS of make macros, e.g. my-dir, all-subdir-makefiles, add-prebuilt-file, etc.
    • Macros are later used in the other build files.
  • Makefile
    • Define target variables for e.g. recovery image, system image, ramdisk image, ota package, etc.

As described earlier, each module defines its own Android.mk file, specifying the type of module by calling the correct build file for that module, e.g. $(BUILD_PACKAGE) for building an APK.

Summary

This was a high level overview of the Android build system based on the Jellybean source code. To make the blog post relatively short, it barely touches many important parts such as board and product definitions, module makefiles and target output. In the following post, I will show how to add an APK to the system image.

This Post Has 12 Comments

  1. Thanks looks really good. I think “I’m going to try a practical approach, by adding an Android application to the system image” was a bit misleading, I only learned at the end of the blog post that this will be covered in the next blog post. ;-)

  2. Hehe, sorry. It got quite large when putting it all in one post, so I decided to split it up. I’ll add the next post asap =)

    / Tomas

  3. Good info thanks for the info regarding “mm” building of single module
    Silly me. When try to do some small change in some source codes, I build the whole ROM which takes almost one hour. Then another small change and build again for one hour. Very time consuming.
    Now that I try the “mm” command and save lot of time just building one module rather than whole ROM.
    let me see If I have got this right. for example I want to build only “package_apps_settings”. In terminal have to

    build/envsetup.sh
    lunch and select device.
    cd Go to Directory ….app/settings/
    mm

    Is that right?

    1. Yes, you’re basically correct. However, you might need to build the whole ROM one time before building your module.

  4. I have a question regd the Android.mk. In my Library project having Android.mk has include $(BUILD_PACKAGE)line? Does that means my library project is creating its .apk file ? Please Reply

  5. Marvelous!!

  6. Hi, great overview – thanks for this!

    Would you be able to advise about correct procedure signing AOSP release builds.
    I cannot find any official documentation on source.android.com website, neither on books.

    I was looking into:
    http://www.kandroid.org/online-pdk/guide/release_keys.html

    and following step by step.. but my “make” created files with testkey, not with release key..

    Thanks

  7. HI,

    How can I turn ON system update OTA?
    I need to make system update enable by default.

    Thanks & Regards
    Ashish Shende

  8. How do I get to print $BUILD_NUMBER? I want to use BUILD_NUMBER in one of my shell script, while build android build.

  9. Hi,
    it’s a very helpful post, just after that,
    what are the steps to add a specific android app to to the system image?
    I’m so grateful if you help me,
    Thanks & Regards
    Wael Ouni

  10. In framework/base/core/res, I added some layout files (xml) and updated code that used R.layout.new_layout.
    However, when I rebuilt system image, i had received an error that “new_layout cannot be resolved or is not a field”.
    Please help me to resolve this issue.
    Thanks & Best regards!

Leave a Reply

Close Menu