Building an Android Automotive OS might not be a difficult task on its own, but the lack of good tutorials makes it exceptionally hard. It only gets harder if you don’t have at hand any specialized hardware like R-Car or Dragonboard. However, you can easily get a Raspberry Pi – a small ARM-powered, multi-usage computer and a perfect candidate to run AAOS. To make the process easier for everyone struggling with this kind of task, in this article, I’ll explain step-by-step how to build and run the latest version: Android Automotive OS 13.
Let’s get started!
To build the system, you will need a Linux. You can use WSL or MacOS (remember, you need a case-sensitive file system), but pure Linux is the best option.
As in the previous article, you need a Raspberry Pi 4B microcomputer, a power adapter (or you can power it from your PC with a USB cable), a memory card, and a display. It’s nice to have a touchscreen, but you can use your mouse and, optionally, a keyboard if more convenient.
Another nice-to-have element is a USB-TTL bridge for debugging. Find my previous article for more details on how to use it.
If you’re looking for the effortless way, go to https://github.com/grapeup/aaos_local_manifest and follow the readme. There are just a few commands to download, build and create a writeable IMG file for your Raspberry. But you need a few hours to download and build it anyway. Warning! It may not start if you won’t adjust the display settings (see below for details).
Adjusting AOSP to make it AAOS
This project is based on Raspberry Vanilla by KonstaT – a great AOSP port for Raspberry Pi. It covers everything you need to run a pure Android on your Raspberry – an adjusted kernel, hardware drivers, etc. However, there is no automotive build, so you need to construct it.
There are four repositories in github.com/grapeup regarding AAOS – three forks based on Raspberry Vanilla and one new one.
The repository aaos_local_manifest contains a list of modified and new repositories. All significant changes are located in
device/brcm/rpi4 and device/brcm/rpi4-car projects defined in the
manifest_brcm_rpi4.xml file. In the readme of this repository, you’ll find steps to clone and build the project.
The next repository, aaos_device_brcm_rpi4, contains three elements:
The first and most important is to utilize the new
rpi4-car project and remove conflicting items from the base project.
aosp_rpi4.mk file, there is a new line
$(call inherit-product, device/brcm/rpi4-car/rpi4_car.mk)
to include a new project.
device.mk file, the product characteristic is changed to „
automotive,nosdcard„, and all custom overlays are removed, along with the overlay directory next to the file.
manifest.xml file, the „
android.hardware.automotive.vehicle„ HAL (Hardware Abstraction Layer) is added.
The second element is to configure the build for the display I use. I had to set the screen resolution in
vendor.prop and set the screen density in
BoardConfig.mk. You probably don’t need such changes if you use a standard PC monitor, or you need some other one for your custom display. Be aware that the system won’t start at all if the resolution configured here is not supported by your display.
The last element contains my regional/language settings in
aosp_rpi4.mk. I’ve decided to use this file, as it’s not automotive-related, and to leave it in the code to show how to adjust it if needed.
The main part
The most major changes are located in the aaos_device_brcm_rpi4_car repository.
rpi4_car.mk file is based on
device/generic/car/common/car.mk with few changes.
Conditional, special settings for the Generic System Images are removed along with the emulator configuration (
device/generic/car/common/config.ini) and the emulator audio package (
Instead, you need a mixture of vendor-specific and board-specific components, not included in the common/car makefile designed for an emulator.
Android Automotive OS is strictly coupled with an audio engine, so you need to add an automotive audio control package
(email@example.com) to make it work, even if you don’t want to connect any speakers to your board. Also, AAOS uses a special display controller with the ability to use two displays at the same time (
firstname.lastname@example.org), so you need to include it too. The next part is SELinux policy for real boards (not an emulator).
BOARD_SEPOLICY_DIRS += device/generic/car/common/sepolicy
Then you need to add permissions to a few pre-installed, automotive-oriented packages, to allow them to run in the system or user spaces.
PRODUCT_COPY_FILES += device/google/cuttlefish/shared/auto/preinstalled-packages-product-car-cuttlefish.xml:$(TARGET_COPY_OUT_PRODUCT)/etc/sysconfig/preinstalled-packages-product-car-cuttlefish.xml
The next component is EVS – Exterior View System introduced to AAOS 13. Even if you don’t really want to connect multiple cameras to the system so far, you have to include the default implementation of the component and configure it to work as a mock.
DEVICE_PACKAGE_OVERLAYS += device/google/cuttlefish/shared/auto/overlay
ENABLE_EVS_SERVICE ?= true
ENABLE_MOCK_EVSHAL ?= true
ENABLE_CAREVSSERVICE_SAMPLE ?= true
ENABLE_SAMPLE_EVS_APP ?= true
ENABLE_CARTELEMETRY_SERVICE ?= true
CUSTOMIZE_EVS_SERVICE_PARAMETER := true
PRODUCT_PACKAGES += email@example.com
PRODUCT_COPY_FILES += device/google/cuttlefish/shared/auto/evs/init.evs.rc:$(TARGET_COPY_OUT_VENDOR)/etc/init/init.evs.rc
BOARD_SEPOLICY_DIRS += device/google/cuttlefish/shared/auto/sepolicy/evs
The last part is to adjust variables for a system when running. You set two system properties directly in the makefile (to allow a forced orientation and to enable the AVRCP Bluetooth profile).
PRODUCT_SYSTEM_DEFAULT_PROPERTIES += \
In the end, you override the following system variables, using predefined and custom overlays.
PRODUCT_PACKAGE_OVERLAYS += \
PRODUCT_PACKAGE_OVERLAYS allows us to overwrite any value from a property file located in the source code. For example, in our case the overlay root directory is
device/brcm/rpi4-car/overlay, so the file
device/brcm/rpi4-car/overlay/frameworks/base/core/res/res/values/config.xml overwrites properties from the file
Let’s dive into properties changed.
- frameworks/base/core/res/res/values/config.xml file:
- config_useVolumeKeySounds disables usage of hardware volume keys, as they are not present in our setup,
- config_voice_capable enables data-only mode, as there is no possibility to make a voice call from our board,
- config_sms_capable disables SMS capabilities for the same reason,
- networkAttributes and radioAttributes sets the system to use WiFi, Bluetooth and ethernet connections only, as there is no GSM modem onboard,
- config_longPressOnPowerBehavior disables long-press on a power button, as there is no power button connected,
- config_disableUsbPermissionDialogs disables USB permission screen, as it shouldn’t be used in the AAOS,
- config_defaultUiModeType enables the automotive launcher by default,
- config_defaultNightMode enables night mode as the default one.
- frameworks/base/packages/SettingsProvider/res/values/defaults.xml file:
- def_wifi_on enables WiFi by default,
- def_accelerometer_rotation sets the default orientation,
- def_auto_time enables obtaining time from the Internet when connected,
- def_screen_brightness sets the default screen brightness,
- def_bluetooth_on enables Bluetooth by default,
- def_location_mode allows applications to use location services by default,
- def_lockscreen_disabled disables the lockscreen,
- def_stay_on_while_plugged_in sets the device to stay enabled all the time.
packages/apps/Car/LatinIME/res/layout/input_keyboard.xmlfile sets the default foreground color of the default keyboard, as the default one is not very readable. Set
textColorparameters to adjust it.
packages/apps/Car/LatinIME/res/values/colors.xmlsets colors or symbol characters on the default keyboard and the letter/symbols switch on the bottom right corner.
packages/apps/Car/SystemUI/res/values/colors.xml sets the background color of the status bar quick settings to make the default font color readable.
packages/apps/Car/SystemUI/res/values/config.xmlhides brightness settings from the top bar, as it doesn’t work without a special drivers for the display.
- packages/apps/Settings/res/values/config.xml file:
- config_show_call_volume disables volume control during calls,
- config_show_charging_sounds disables charging sounds,
- config_show_top_level_battery disables battery level icon.
- packages/modules/Wifi/service/ServiceWifiResources/res/values/config.xml enables 5Ghz support for the WiFi.
packages/services/Car/service/res/values/config.xmldisables running a dedicated application when the system starts up or a driver is changed.
You can read more about each of those settings in the comments in the original files which those settings came from.
The very last repository is aaos_android_hardware_interfaces . You don’t need it, but there is one useful property hardcoded here. In Android, there is a concept called HAL – Hardware Abstraction Layer. For AAOS, there is VHAL – Vehicle Hardware Abstraction Layer. It is responsible, among others, for HVAC – Heating, Ventilation, and Air Conditioning. In our setup, there is no vehicle hardware and no physical HVAC, so you use
android.hardware.automotive.vehicle@V1-emulator-service whose default implementation is located under
hardware/interfaces/automotive/vehicle. To change the default units used by HVAC from imperial to rest-of-the-world, you need to adjust the
The building process for AAOS 13 for Raspberry Pi is much easier than the one for AAOS 11. The kernel is already precompiled and there is much less to do.
Just call those three commands:
make bootimage systemimage vendorimage
On a Windows laptop (using WSL, of course) with the i7-12850HX processor and 32GB RAM, it takes around 1 hour and 40 minutes to accomplish the build.
Creating a bootable SD card
There are two options – with or without the
mkimg.sh script. The script is located under
device/brcm/rpi4 directory and linked in the main directory of the project as
rpi4-mkimg.sh. The script creates a virtual image and puts 4 partitions inside –
boot, system, vendor, and
userdata. It’s useful because you can use Raspberry Pi Imager to write it into an SD card however, it has a few limitations. The image always has 7GB (you can change it by adjusting the
IMGSIZE variable in the script), so you won’t use the rest of your card, no matter how big it is. Besides that, you always need to write 7GB to your card – even if you have to update only a single partition, and including writing zeros to an empty userdata partition.
The alternative way is to write it on the card by hand. It’s tricky under Windows as WSL doesn’t contain card reader drivers, but it’s convenient in other operating systems. All required files are built in the
out/target/product/rpi4 directory. Let’s prepare and write the card. Warning! In my system, the SD card is visible as
/dev/sdb. Please adjust the commands below not to destroy your data.
OK, let’s clean the card. You need to wipe each partition before wiping the entire device to remove file systems signatures.
sudo umount /dev/sdb*
sudo wipefs -a /dev/sdb*
sudo wipefs -a /dev/sdb
Now let’s prepare the card. This line will use
fdisk to create 4 partitions and set flags and filesystems.
echo -e "n\n\n\n\n+128M\na\nt\n0c\nn\n\n\n\n+2G\nn\n\n\n\n+256M\nn\np\n\n\nw\n" | sudo fdisk /dev/sdb
The last step is to write data and prepare the last partition.
sudo dd if=boot.img of=/dev/sdb1 bs=1M
sudo dd if=system.img of=/dev/sdb2 bs=1M
sudo dd if=vendor.img of=/dev/sdb3 bs=1M
sudo mkfs.ext4 -L userdata /dev/sdb4
sudo umount /dev/sdb*
Android Automotive OS is a giant leap for the automotive industry. As there is no production vehicle with AAOS 13 so far, you can experience the future with this manual. What’s more, you can do it with a low-budget Raspberry Pi computer. This way, I hope you can develop your applications and play with the system easily without an additional layer of using emulators. Good luck and happy coding!