share

ENGINEERING

11min read

How to Build your Own Android Based on AOSP

Mobile applications developing options allow developers to extend the functionality of stock operating systems provided by the major players in the mobile industry. However, sometimes it is not enough, especially if our requirements are larger than powers of the provided SDK to a specific platform. Thanks to Android openness, we can create the operating system that will be crafted according to our needs.

In the following tutorial, I will explain how the process of creating your customized version of Android system using AOSP looks like in general. We will go through all the phases: starting from setting up the environment, through building and uploading to a physical device, and ending by changing the system behavior and functionality. Ready to explore Android building system?

Android Open Source Project

Android Open Source Project is an open software stack for a wide range of mobile devices and a corresponding open source project led by Google. Simply put, it means that everyone can download Android sources and create their own customized version of an operating system, to put it shortly—build Android!

AOSP in numbers

We have to be aware that working with Android sources involves dealing with a huge amount of code. The Android AOSP Nougat 7.1.1 release has 518 repositories, 48 million lines of code in 27 languages. It’s estimated that to develop such project in a year we would need 16075 developers, in one month - 192075 folks. Moreover, it would cost more than $2 billion dollars! But no worries—we don’t want to reinvent the wheel. We simply want to use what the experienced developers have been creating for us for almost 10 years.

Building

In this Android AOSP tutorial, I will show how to build the customized system based on Android Nougat release on a Nexus 5X device.

Preparing a machine

First things first. You need to remember about few steps that need to be taken before you even start developing. There is a great documentation provided by Google that describes this process step by step. First of all, we need to choose a branch because some of the steps are determined by the version we plan to build. We will compile a version based on an android-7.1.1r24_ tag. It corresponds to N4F26T release tag and supports the Nexus 5X device that will serve us to test a build.

Establishing a build environment

Currently, Android build supports two platforms - Linux and Mac OS. We need to install a bunch of required packages like JDK, Git, Python and more. Remember - this step is platform-specific so in order to go through, just follow an instruction provided here. I know it takes some time but fortunately, we need to do it only once.

Downloading the source

The Android sources are nothing different than a bunch of Git repositories hosted by Google. To operate on all of them Google provides a Repo tool that makes it easier to work with them in the context of Android platform. After the installation, we initialize the working directory. We chose a specific tag so to download them we need to call

repo init -u https://android.googlesource.com/platform/manifest -b android-7.1.1_r24

and then repo sync. Now we have a lot of time until almost 50 GB of sources download so it’s a perfect moment to take a nice coffee break.

Preparing for a build

As sources are already downloaded, we can prepare the environment to start a build. The sources included in AOSP are not enough to build the whole Android. It requires additional libraries related to hardware to run on a specific device. For Nexus 5X these binaries can be downloaded from here. Each binary is a self-extracting script in a compressed archive. They have to be extracted and run in the root of source tree. This installs all files in a vendor directory.

Setup environment

Android build system provides a lot of scripts and tools to make the build process easier and more convenient for a developer. To initialize directory we run a . build/envsetup.sh from root of source tree. Next, we need to choose a target for our build. We can select one of three variants: user, userdebug and eng. Each configuration is suited to various purposes. User build has limited access and is dedicated to production builds, userdebug and eng are for development purposes. They differ as far as an access to development and debugging tools are concerned. To set up the exact configuration for Nexus 5X device, run lunch aosp_bullhead-eng command.

Starting to build a code

Now comes the long-awaited moment of starting the build process. Android build system uses make. It allows building in parallel tasks when -jN argument is passed. N is a number of threads being used for the build. The command make -j4 starts a build process and now we have to be patient because depending on the machine we are building on, it can take even a few hours. You can track all the console output during the build and in the end, you’ll see something similar to

### make completed successfully (02:27:48 (hh:mm:ss)) ####

I achieved this result on a gaming laptop with Intel® Core™ i7-4720HQ CPU 2.60GHz x 8 and 32 GB RAM of memory on board. The same process on Macbook Pro with Intel® Core™ i5-4288U CPU 2.60GHz × 4 and 16 GB RAM takes 4 hours and 47 minutes. We can speed up our rebuild when we run build with ccache compilation tool. This works very well when we want to rebuild all sources again from the scratch. The duration of my rebuild was two times shorter and took 48 minutes on a gaming machine and few minutes over 2 hours on Macbook.

Uploading a build to a device

A build is ready to be uploaded to a device. We can check and verify whether the Android starts and if we had produced the system we expected. Firstly, we need to make sure that we have adb and fastboot commands available. If you are an Android developer, you have most likely already installed them with the other platform tools delivered in Android SDK. Otherwise, you can build them with regular build system. Run make adb fastboot and that’s it.

Booting into fastboot mode

This is a bootloader mode that allows flashing a device. There are two ways to run into such a state. Firstly, you can use the command adb reboot bootloader. Secondly, you can use the special key combination for Nexus 5X. Press and hold Volume Down then press and hold the Power button.

Unlocking the bootloader

Custom build can be uploaded only if a bootloader allows it. As a bootloader is locked by default, it has to be unlocked. Important! You have to be aware that it causes the removal of all user data. To unlock bootloader on Nexus 5X, go to the Settings app and enable developer options. This can be done when you tap seven times on Build number in About phone category. You should see a message confirming that fact and Developer options category added in an app. Open it and enable OEM unlocking and USB debugging. Restart a device into fastboot mode as it is described in the previous paragraph and run fastboot oem unlock. The bootloader can be re-locked using fastboot oem lock command.

Flashing

Now it’s time to flash an entire Android system. This means that all produced images write to a proper partitions on a device. Run fastboot flashall -w command. After a successful process, the device will restart.

System customization

Finally we have our own version of Android. Now it’s the time to implement some custom changes to a system.

Importing to IDE

What happens when we want to work with sources in IDE? Unfortunately, there is no officially designed IDE to work with Android Internals that fully integrates with a build system. But don’t worry! Engineers made it possible to import sources very easily. In order to do that, we need to build idegen and run script by call following

make idegen && development/tools/idegen/idegen.sh

from the source root. This produces a few files including android.ipr that allows us to import sources to Android Studio or IntelliJ. Be patient once you launch IDE first time because sources need to be indexed and it’s a quite long operation. When it finishes, we can easily browse, write and refactor code. To build code we use a terminal at the same time.

Developing

Now it’s a time to invent a change that will single out our version from the stock Android. Let’s imagine that you want to build your own Android phone for seniors. Usually, phones used by the elderly, have a feature that allows calling for help by pressing hardware button. We don’t have such button in our Nexus 5X device, but we can implement this in software. This way, we will allow initializing a call to a predefined number in emergency situations.

SOS button feature

Emergency situations require quick actions. Making a phone call should be easy and quick. The change that we implement allows making a phone call directly from the menu that appears after long pressing the power button. Once user clicks SOS position, it will start to call a predefined number.

Screens_final.jpg

This feature requires a change to an Android Framework. Framework code is located under frameworks/base/ path. So let’s code.

SOSCallManager

First, we need to add a manager class that will handle triggering an action to start a call. This class sends a simple Intent including the uri of a phone number that is stored in the global settings of the device.

public class SOSCallManager {
    ...

    private void sendCallIntent() {
        Intent intent = new Intent(Intent.ACTION_CALL);
        intent.setData(getPhoneUri());
        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        mContext.startActivity(intent);
    }

    private Uri getPhoneUri() {
        return Uri.fromParts("tel", getNumber(), null);
    }

    ...

    private String getNumber() {
        return Settings.Global.getString
                mContext.getContentResolver(), Settings.Global.SOS_CALL_NUMBER);
    }

Global actions

Long pressing the power button opens a menu with the global actions. Its content is based on a configuration in framework resources or specific overlay for a device. The config file is located in frameworks/base/core/res/res/values/config.xml. We add sos item to a resource named configglobalActionsList. _GlobalActions class parses a config file and adds item if defined.

/**
 * Show the global actions dialog (creating if necessary)
 * @param keyguardShowing True if keyguard is showing
 */
public void showDialog(boolean keyguardShowing, boolean isDeviceProvisioned) {
...

/**
 * Create the global actions dialog.
 * @return A new dialog.
 */
private GlobalActionsDialog createDialog() {

...

} else if (GLOBAL_ACTION_KEY_SOS_CALL.equals(actionKey)) {
    if (!TextUtils.isEmpty(Settings.Global.getString(
            mContext.getContentResolver(), Settings.Global.SOS_CALL_NUMBER))) {
        mItems.add(getSOSAction());
    }
}

An item in a power button dialog is an implementation of Action class. We can return an instance of SinglePressAction class with an overridden onPress() method that initializes a SOS call when users tap on it.

private Action getSOSAction() {
    return new SinglePressAction(com.android.internal.R.drawable.emergency_icon,
            R.string.global_action_sos_button) {
        @Override
        public void onPress() {
            mSOSCallManager.performSOSCall();
        }

        @Override
        public boolean showDuringKeyguard() {
            return true;
        }

        @Override
        public boolean showBeforeProvisioning() {
            return false;
        }
    };
}

The entire change of this feature in a framework can be found on Github.

Rebuilding components

Changes in the code are ready. It’s a time to recompile sources and verify the result on a device. We don’t need to follow the same procedure with compiling the entire system and flashing a device using fastboot. Instead, we can rebuild only particular components and replace them on a device. In order to do that call make -j4 framework services. If the platform is completely built, the names of the components passed are optional because the build system rebuilds only the components that have been changed. Now we have to upload what we built to a device. Before pushing files we put the system partition in a writable mode. By default, it is only readable. For this, we use adb remount command. Next call adb sync system that causes the files in a working directory to be synchronized with those on a device. In the end we restart a phone to load an uploaded version of rebuilt components during boot. We can restart a phone from power menu or using adb reboot command.

Changing a number

A number to perform SOS call is stored in global system preferences. Using adb we can simply change the value from a terminal by typing

adb shell settings put global sos_call_number <number>

I have to admit that it’s not the most convenient way to do so. For this purpose, we would add a possibility to edit in Settings application.

Emergency information

Android Nougat introduced Emergency information. This is a simple precaution that could prove very useful in emergency situations. The medical data can be filled out in Users section in Settings app. It seems to be a good place to add the next position with sos call number. The application that collects and provides medical data is stored in packages/apps/EmergencyInfo/. We add a few changes that will display another field with SOS call number. The user will be able to edit a system preference inside this application. The sources of this change are available on Github.

Emergency_photo.jpg

Conclusion

Projects centered around the development of applications are a significant part of the mobile development world. Building your own version of Android system is not that popular and needs special cases to start considering customization. I strongly believe that taking part in such projects is a great opportunity to learn and get to know how to build Android phone from source. It definitely contributes to Android developer’s progress. The challenges you encounter are unique. As for me, I had the great chance to customize Android sources for a mobile payment device in project Albert - along with my team. It was a lot of fun! We’re looking forward to the next Android Internals challenges!

share


MichałSenior Software Engineer

LEARN MORE

Contact us if you have any questions regarding the article or just want to chat about technology, our services, job offers and more!

POLIDEA NEWSLETTER

Sign in and expect sharp insights, recommendations, ebooks and fascinating project stories delivered to your inbox

The controller of the personal data that you are about to provide in the above form will be Polidea sp. z o.o. with its registered office in Warsaw at ul. Przeskok 2, 00-032 Warsaw, KRS number: 0000330954, tel.: [0048795536436], email: [hello@polidea.com] (“Polidea”). We will process your personal data based on our legitimate interest and/or your consent. Providing your personal data is not obligatory, but necessary for Polidea to respond to you in relation to your question and/or request. If you gave us consent to call you on the telephone, you may revoke the consent at any time by contacting Polidea via telephone or email. You can find detailed information about the processing of your personal data in relation to the above contact form, including your rights relating to the processing, HERE.

Data controller:

The controller of your personal data is Polidea sp. z o.o. with its registered office in Warsaw at ul. Przeskok 2, 00-032 Warsaw, KRS number: 0000330954, tel.: [0048795536436], email: [hello@polidea.com] (“Polidea”)

Purpose and legal bases for processing:

 

Used abbreviations:

GDPR – Regulation (EU) 2016/679 of the European Parliament and of the Council of 27 April 2016
on the protection of natural persons with regard to the processing of personal data and on the free movement
of such data, and repealing Directive 95/46/EC (General Data Protection Regulation)

ARES – Polish Act on Rendering Electronic Services dated 18 July 2002

TL – Polish Telecommunications Law dated 16 July 2004

1)        sending to the given email address a newsletter including information on Polidea’s new projects, products, services, organised events and/or general insights from the mobile app business world |art. 6.1 a) GDPR, art. 10.2 ARES and art. 172.1 TL (upon your consent)

Personal data:name, email address

2)       statistical, analytical and reporting purposes |art. 6. 1 f) GDPR (based on legitimate interests pursued by Polidea, consisting in analysing the way our services are used and adjusting them to our clients’ needs, as well as developing new services)

Personal data:name, email address

Withdrawal of consent:

You may withdraw your consent to process your personal data at any time.

Withdrawal of the consent is possible solely in the scope of processing performed based on the consent. Polidea is authorised to process your personal data after you withdraw your consent if it has another legal basis for the processing, for the purposes covered by that legal basis.

Categories of recipients:

Your personal data may be shared with:

1)       authorised employees and/or contractors of Polidea

2)       persons or entities providing particular services to Polidea (accounting, legal, IT, marketing and advertising services) – in the scope required for those persons or entities to provide those services to Polidea

 

Retention period:

1)       For the purpose of sending newsletter to the given email address – for as long as the relevant consent is not withdrawn

2)       For statistical, analytical and reporting purposes – for as long as the relevant consent is not withdrawn

Your rights:

 

Used abbreviation:

GDPR – Regulation (EU) 2016/679 of the European Parliament and of the Council of 27 April 2016
on the protection of natural persons with regard to the processing of personal data and on the free movement
of such data, and repealing Directive 95/46/EC (General Data Protection Regulation)

According to GDPR, you have the following rights relating to the processing of your personal data, exercised by contacting Polidea via [e-mail, phone].

1)       to access to your personal data (art. 15 GDPR) by requesting sharing and/or sending a copy of all your personal data processed by Polidea

2)       to request rectification of inaccurate personal data
(art. 16 GDPR) by indicating the data requiring rectification

3)       to request erasure of your persona data (art. 17 GDPR); Polidea has the rights to refuse erasing the personal data in specific circumstances provided by law

4)       to request restriction of processing of your personal data (art. 18 GDPR) by indicating the data which should be restricted

5)       to move your personal data (art. 20 GDPR) by requesting preparation and transfer by Polidea of the personal data that you provided to Polidea to you or another controller in a structured, commonly used machine-readable format

6)       to object to processing your personal data conducted based on art. 6.1 e) or f) GDPR, on grounds relating to your particular situation (art. 21 GDPR)

7)       to lodge a complaint with a supervisory authority,
in particular in the EU member state of your habitual residence, place of work or place of the alleged infringement if you consider that the processing
of personal data relating to you infringes the GDPR
(art. 77.1 GDPR)

No obligation to provide data:

Providing your personal data is not obligatory, but necessary for Polidea to provide you the newsletter service

Refusal to provide the above data will result in inability to receive the newsletter service.

Profiling

In the process of providing the newsletter service, we make decisions in an automated way, including profiling, based on the data you provide.

 

“Profiling” means automated processing of personal data consisting of the use of your personal data to evaluate certain personal aspects relating to you, in particular to analyze or predict aspects concerning your personal preferences and interests.

 

The automated decisions are taken based on the analysis of clicked and viewed content. They affect the targeting of specific newsletter content to selected users registered to receive the newsletter service, based on the anticipated interests of the recipient.