This post intends to gather all the information you need to start a project on Android. It is not tied to a specific version but instead tries to be generic across all of them.
Development environment
Before being able to develop on Android, we need to set up the development environment. This section will differentiate two types of development: system and application. The reason is that some costumers are just interested in developing an Android application on top of our system release without modifying the system.
System development
If you wish to build the entire Android system from scratch, know that it requires a Linux machine or at least a Linux Virtual Machine (VM). Mac OS systems are also supported but will not be covered on this post. The Android Open-Source Project (AOSP) provides a website with lots of useful information about Android system development.
Regarding the development environment, you need to first make sure to comply with the AOSP requirements. Note that it requires a 64-bit version of Linux.
- https://source.android.com/source/requirements.html
- https://source.android.com/source/initializing.html
The JAVA JDK requirement can be hard to follow so here is a summary:
- For Android 2.3 (Gingerbread) to 4.4 (KitKat)
- Recommended OS: Ubuntu Precise (12.04)
- Need the Sun Java development kit (JDK 1.6).
- Installation instructions provided in the following post.
~$ sudo apt-get install git gnupg flex bison gperf build-essential \ zip curl libc6-dev libncurses5-dev:i386 x11proto-core-dev \ libx11-dev:i386 libreadline6-dev:i386 libgl1-mesa-glx:i386 \ libgl1-mesa-dev g++-multilib mingw32 tofrodos \ python-markdown libxml2-utils xsltproc zlib1g-dev:i386 ~$ sudo ln -s /usr/lib/i386-linux-gnu/mesa/libGL.so.1 /usr/lib/i386-linux-gnu/libGL.so
- For Android 5.x (Lollipop) to 6.x (Marshmallow)
- Recommended OS: Ubuntu Trusty (14.04)
- Need OpenJDK v7.
~$ sudo apt-get install openjdk-7-jdk ~$ sudo apt-get install git-core gnupg flex bison gperf build-essential \ zip curl zlib1g-dev gcc-multilib g++-multilib libc6-dev-i386 \ lib32ncurses5-dev x11proto-core-dev libx11-dev lib32z-dev ccache \ libgl1-mesa-dev libxml2-utils xsltproc unzip
- For Android 7.x (Nougat) to 12 (S)
- Recommended OS: Ubuntu Xenial (16.04)
- Need OpenJDK v8.
~$ sudo apt-get install openjdk-8-jdk ~$ sudo apt-get install git-core gnupg flex bison gperf build-essential \ zip curl zlib1g-dev gcc-multilib g++-multilib libc6-dev-i386 \ lib32ncurses5-dev x11proto-core-dev libx11-dev lib32z-dev ccache \ libncurses5-dev libgl1-mesa-dev libxml2-utils xsltproc unzip
- For Android 12.1 (S) and above
- Recommended OS: Ubuntu Focal (20.04)
- Need OpenJDK v8.
~$ sudo apt-get install openjdk-8-jdk ~$ sudo apt-get install git-core gnupg flex bison gperf build-essential \ zip curl zlib1g-dev gcc-multilib g++-multilib libc6-dev-i386 \ lib32ncurses5-dev x11proto-core-dev libx11-dev lib32z-dev ccache \ libncurses5 libgl1-mesa-dev libxml2-utils xsltproc unzip
Note that if you machine OS isn't the recommended OS version, we recommend using Docker or schroot to have a proper build environment. In addition to the AOSP requirements, the following packages are needed to build Freescale components: ~$ sudo apt-get install uuid uuid-dev liblz-dev liblzo2-2 liblzo2-dev \ lzop curl u-boot-tools mtd-utils android-tools-fsutils \ device-tree-compiler gdisk m4 libz-dev libssl-dev bc
Next step is downloading the source code. To do so you need the repo
tool which has been developed especially for Android in order to manage the hundreds of Git repositories this project contains.
- https://source.android.com/source/downloading.html
~/$ curl https://commondatastorage.googleapis.com/git-repo-downloads/repo > ~/bin/repo ~/$ chmod a+x ~/bin/repo ~/$ export PATH=~/bin:$PATH
The lasts steps before being able to download the Android source code for our platforms are:
Sending your SSH key is mandatory for you to have access to our private repositories. You will be notified by e-mail once your key has been added to our server. Before retrieving the source code, please first try using ssh to access the server. You should get a response listing available projects with this command: ~/$ ssh git@linode.boundarydevices.com
Only once the above command succeeds you can retrieve the entire tree. Note that if you haven't already, we strongly recommend the use of 'ssh-agent' with repo. This allows you to enter the password for your SSH key once instead of being prompted for it over and over as different repositories are accessed. If the command above fails, please examine the output of the same command using '-vvv': ~/$ ssh -vvv git@linode.boundarydevices.com
Note that you need a lot of space, Google says "at least 100GB of free disk space for a checkout, 150GB for a single build". ~/$ mkdir myandroid ~/$ cd myandroid ~/myandroid$ repo init -u https://github.com/boundarydevices/android-manifest.git -b boundary-imx-X.X.X_Y.Y.Y ~/myandroid$ repo sync
Note that the repo init
command above will change depending on the version of Android you want to build. The -b
parameter selects which branch of our manifest repository to use:
- KitKat 4.4.3: boundary-imx-kk4.4.3_2.0.1-ga
- Lollipop 5.1.1: boundary-imx-l5.1.1_2.1.0-ga
- Marshmallow 6.0.1: boundary-imx-m6.0.1_1.0.0-ga
- Nougat 7.1.1: boundary-imx-n7.1.1_1.0.0-ga
- Oreo 8.0.0: boundary-imx-o8.0.0_1.0.0-ga
- Oreo 8.1.0: boundary-imx-o8.1.0_1.3.0_8m-ga
- Android 10: boundary-android-10.0.0_2.5.0
- Android 11: boundary-android-11.0.0_2.2.0
- Android 12: boundary-android-12.0.0_1.0.0
- Android 12.1: boundary-android-12.1.0_1.0.0
- Android 13: boundary-android-13.0.0_1.0.0
- Android 14: boundary-android-14.0.0_1.2.0
Your machine is now ready to build a fresh Android image from scratch!
Application development
Setting up a machine for application development is much easier plus it works the same on every OS: Windows, Linux, Mac OS. Although application development IDE used to be Eclipse along with a plugin named ADT, this has been deprecated in favour of Android Studio. Download this IDE along with the Android SDK from the following website:
Note that this site provides the API guide as well as lots of app examples which are directly available in the IDE as part of the SDK.
Debugging Tools
The most important tool that Android offers is the Android Debug Bridge (ADB). It is mandatory to set it up as the IDE requires it in order to install/debug applications. It is also useful for system development as it allows to access the board easily, allowing to send files back and forth between the target and the host machine for instance. Under GNU/Linux systems (and specifically under Ubuntu systems), regular users can't directly access USB devices by default. The system needs to be configured to allow such access. Please follow the instructions from the AOSP website to authorize USB access to most common devices.
Details about the tool and all the commands available:
A couple of other tools might be of interest depending on your needs.
- dumpsys: provides information about the status of system services.
- systrace: analyzes the performance of your application by capturing and displaying execution times
- https://developer.android.com/tools/help/systrace.html
- systrace requires to modify the kernel configuration and add
- FUNCTION_TRACER
- FUNCTION_GRAPH_TRACER
- DYNAMIC_FTRACE
- STACK_TRACER
Build instructions
AOSP build
Initialize the environment with the envsetup.sh
script. ~/myandroid$ source build/envsetup.sh
This script gives you access to a new set of commands targeted for AOSP development. Below are detailed the most useful ones (in our opinion).
croot
: Changes directory to the top of the tree (useful when you get lost inframeworks/base
)mm
: Builds all of the modules in the current directorymmm
: Builds all of the modules in the supplied directoriescgrep
: Greps on all local C/C++ filesjgrep
: Greps on all local Java filesresgrep
: Greps on all local res/*.xml files
The next step is to choose the target board and build: ~/myandroid$ lunch ... choose nitrogenX from the list of boards
A couple of things to note on the available targets:
nitrogen6x
is meant for Nitrogen6X, Nitrogen6_Max, BDSL-i.MX6, Nitrogen6_SOM, Nitrogen_SOMv2 (starting with l511)nit6xlite
is only meant for Nitrogen6Litenitrogen6sx
is only meant for Nit6_SoloX (starting with l511)-eng
is the development configuration with additional debugging tools, root access via console/adb and more logs-userdebug
is suited for development and is closer to the user target-user
is suited for production as it provides only limited access to the device just like a stock Android phone
~/myandroid$ make 2>&1 | tee build.out
A full build will take upwards of 3 hours, but incremental builds are pretty speedy if you're changing things. In order to flash the newly created Android image into a SD Card, you can use our mksdcard.sh
script: ~/myandroid$ sudo ./device/boundary/mksdcard.sh /dev/sdX nitrogen6x
If you wish to create an .img
file, you can use our mkimage.sh
script at your own risk (using loop devices, please check it out): ~/myandroid$ sudo ./device/boundary/mkimage.sh
For instance, here is our we create the .img.gz
file for Nitrogen6sx: ~/myandroid$ sudo ./device/boundary/mkimage.sh m601-nitrogen6sx-20160726.img 3600 nitrogen6sx ~/myandroid$ gzip m601-nitrogen6sx-20160726.img
Tips & Tricks
Kernel build
Modifications made to the kernel are not automatically picked up if it has been built once already. In order to force the build of the kernel, you need to delete the kernel
.config file. Note that the kernel Makefile will detect which objects need to be re-compile. ~/myandroid$ rm kernel_imx/.config
If you wish to re-build the kernel and only the kernel, you can set the toolchain path and build it as follows:
- For Lollipop and earlier versions:
~/myandroid$ export CROSS_COMPILE=$PWD/prebuilts/gcc/linux-x86/arm/arm-eabi-4.6/bin/arm-eabi- ~/myandroid$ export ARCH=arm ~/myandroid$ cd kernel_imx ~/myandroid/kernel_imx$ make nitrogen6x_defconfig ~/myandroid/kernel_imx$ make uImage LOADADDR=0x10008000 dtbs -j8 ~/myandroid/kernel_imx$ adb push arch/arm/boot/uImage /boot/ ~/myandroid/kernel_imx$ adb push arch/arm/boot/dts/imx6q-nitrogen6x.dtb /boot/
- For Marshmallow and newer versions:
~/myandroid$ export CROSS_COMPILE=$PWD/prebuilts/gcc/linux-x86/arm/arm-eabi-4.8/bin/arm-eabi- ~/myandroid$ export ARCH=arm ~/myandroid$ cd kernel_imx ~/myandroid/kernel_imx$ make boundary_defconfig ~/myandroid/kernel_imx$ make zImage dtbs -j8 ~/myandroid/kernel_imx$ adb push arch/arm/boot/zImage /boot/ ~/myandroid/kernel_imx$ adb push arch/arm/boot/dts/imx6q-nitrogen6x.dtb /boot/
Boot image
If your latest modifications only affect kernel, ramdisk or bootscript, you do not need to start a full build but use the
bootimage target instead. ~/myandroid$ make bootimage
This will only update the components under the
output folder which then can be updated as follows as an example: ~/myandroid$ adb push $OUT/boot/imx6q-nitrogen6x.dtb /boot ~/myandroid$ adb push $OUT/boot/zImage /boot ~/myandroid$ adb push $OUT/boot/6x_bootscript /boot ~/myandroid$ adb push $OUT/boot/uramdisk.img /boot
Those modifications require a reboot in order to take effect: ~/myandroid$ adb reboot
Fastboot
Starting with our 5.1.1 GA release, fastboot can be used in order to flash the boot/recovery/system partitions. Note that the mmc card index has to be fixed in the U-Boot configuration. It is set to flash mmc1 for all configurations by default which is the eMMC on platform containing one (MAX, SOM2, SX) or the second SD slot on others (Nitrogen6x, BDSL). ~/$ adb shell reboot bootloader ~/$ fastboot -i 0x0525 flash boot $OUT/boot.img finished. total time: 3.762s ~/$ fastboot -i 0x0525 flash recovery $OUT/recovery.img finished. total time: 3.402s ~/$ fastboot -i 0x0525 flash system $OUT/system.img finished. total time: 52.153s ~/$ fastboot -i 0x0525 continue resuming boot...
However this approach required the flash/eMMC to be partitioned properly prior to flashing. Starting with the 7.1.1 Nougat release, you can flash an empty device. First you need to start Fastboot from U-Boot: => fastboot 0
Then you can send all the images using the helpers scripts from our repo: ~/myandroid$ export PRODUCT=nitrogen6x ~/myandroid$ ./device/boundary/scripts/create_gpt.sh 3600 ~/myandroid$ ./device/boundary/scripts/flash_fastboot.sh
Note that 7.1.1 Nougat generated images are now in sparse format which requires U-Boot >= v2017.03.
Specific package build
If on the other hand the modification only affect a specific package, you can rebuild only that latter by issuing: ~/myandroid$ mmm hardware/libhardware_legacy/
You can even force the rebuild in case the Android.mk doesn't see any obvious change that require re-building: ~/myandroid$ mmm -B hardware/libhardware_legacy/
System update/sync
Then the Android build process allows you to just send over changes to a USB-connected board using
adb syncwhich requires to remount the system partition first: ~/myandroid$ adb remount ~/myandroid$ adb sync
If you're changing system components, the best is to reboot as explained above but you could stop and restart the Android GUI. ~/myandroid$ adb shell 'stop && start'
Output cleanup
In order to have a clean image, making sure all the components are copied as expected and no extra feature is present, there's no need to erase the full
out/ folder. Instead, remove the "staging" folders so the build system will only copy the packages specified in your board configuration. rm -rf $OUT/{*.zip,*.img,data,system,boot,root,recovery} kernel_imx/.config
Git/Repo management
Finally, in order to add a git project as part of your custom image, you need to edit .repo/manifest.xml
which is actually a symlink to .repo/manifests/default.xml
. Note that when adding new projects, there are at least three parts defined:
remote
-- the name of the remote. this can be one that was defined in either the default manifest or local_manifest.xml.name
-- the name of the git project-- for github it has the format account_name/project_name.path
-- where the git repository should go in your local copy of the source code.revision
-- (optional) which branch or tag to use in the repository. If this attribute is omitted, repo sync will use the revision specified by the tag in the default manifest.
Here is an example that adds the CMFileManager application:
Going further
This post should enable you to get started with your project. But if you are looking for more information on some specific topics, we'll try to link our more advanced Android posts here.
- Android security part 1: application signatures & permissions
- Android security part 2: OTA updates
- Android security part 3: Security-Enhanced Linux in Android
We also try to give as much details as possible on every of our release post.