Hello, Android Car App!

This article is the entry for day 5 in the KINTO Technologies Advent Calendar 2024 🎅🎄
I'm Onuma, an Android engineer in the Mobile Development Group at KINTO Technologies. I primarily work on developing the My Route, a mobility service app.
In this article, I'll guide you through the process of building Android Automotive OS and developing in-vehicle apps, including both Android Automotive and Android Auto applications.
Running Android Automotive OS on a Raspberry Pi
What is Android Automotive OS?
Android Automotive is an in-vehicle platform built on Android and integrated into the AOSP framework. It supports pre-installed Android apps for IVI systems, as well as second- and third-party Android apps. For more details, refer to the official documentation → https://developer.android.com/training/cars?hl=ja#automotive-os
What is AOSP?
AOSP stands for Android Open Source Project, and all the elements that make up the Android OS are open source and available to the public.
The latest OS developed by Google is released as open source after a certain non-disclosure period. Device developers customize the released OS by adding features or making modifications to suit their specific needs before installing it on smartphones, tablets, and other devices.
What to prepare to build Android Automotive OS
- PC *It is necessary to meet the hardware requirements mentioned later.
- Display *A touch monitor is better.
- RaspberryPi 4B
- MicroSD
16GB should be enough. - MicroHDMI-HDMI cable
Hardware Requirements for Building
- OS: Ubuntu 22.04
- Intel Gold 6226R (16 cores, 32 threads)
- At least 16 GB of RAM
- HD: 1TB
*Note: Building on Windows or Mac OS is not supported.
I tried to create an environment on AWS EC2 to build, but I gave up since the Free Tier couldn't meet the required specifications.
Set Up the Build Environment
Install the necessary tools for building.
sudo apt-get install git-core gnupg flex bison build-essential zip curl zlib1g-dev libc6-dev-i386 libncurses5 lib32ncurses5-dev x11proto-core-dev libx11-dev lib32z1-dev libgl1-mesa-dev libxml2-utils xsltproc unzip fontconfig
Add Repo and Local_Manifest
Android OS consists of a large collection of source code.
Repo is used to check out Android source code. The components are loosely coupled, with each one being managed and developed in an independent Git repository. Repo
is a tool that manages these numerous Git repositories based on a management file called a Manifest file.
## Install the Repo launcher
repo init -u [https://android.googlesource.com/platform/manifest](https://android.googlesource.com/platform/manifest) -b android-13.0.0\_r35 --depth=1
## Add the local_manifest
git clone [https://github.com/grapeup/aaos_local_manifest.git](https://github.com/grapeup/aaos_local_manifest.git) .repo/local\_manifests
Add dav1d under line 46 <!-- FFmpeg -->
of .repo/local_manifests/manifest_brcm_rpi4.xml
## Add missing dav1d library to local_manifest
<!-- FFmpeg -->
<project path="external/dav1d" name="raspberry-vanilla/android_external_dav1d" remote="github" revision="android-13.0" />
Compile
. build/envsetup.sh
lunch aosp_rpi4-userdebug
make bootimage systemimage vendorimage -j$(nproc)
Flashing and Deploying Images
Clean the MicroSD card.
sudo umount /dev/sdb*
sudo wipefs -a /dev/sdb*
sudo wipefs -a /dev/sdb
Then create four partition tables and flash the images to the MicroSD card.
There are three images to flash onto the microSD card: boot.img
, system.img
, and vendor.img
.
As I thought I could flash the images using the command sudo dd if=boot.img of=/dev/sdb1 bs=1M
, I gave it a try, but the steps were too complicated. So, I used a partition editing tool called GParted.
Boot Android Automotive OS
Insert the microSD card into the Raspberry Pi to boot. It's convenient if you connect a touch monitor to the Raspberry Pi, you can operate it without a mouse. But I don't have a touch monitor, so I'm connecting a PC monitor instead ;-;
Develop In-Vehicle Apps that Run on Android Auto and Android Automotive OS
Next, I'll walk you through the basics of implementing and debugging in-vehicle apps on Android. While Android Auto works by connecting your smartphone to display apps on the car's screen, Android Automotive OS has Android built directly into the vehicle system, allowing apps to be installed directly.
This time, I implemented a navigation app as a trial. The following development environment is a Mac.
Supported app categories and corresponding Android APIs
Category | Description | Corresponding Android API |
---|---|---|
Media | Apps for music, podcasts and audiobooks | Use the MediaBrowserService to browse content and control playback. Use the MediaSession to notify the system of playback status and metadata. |
Navigation | Turn-by-turn navigation with audio and visual guidance | Use the NavigationManager from the CarAppLibrary to control navigation start, end, destination setting, and turn-by-turn guidance. |
Point of Interest (POI) | Apps to find locations such as parking lots, EV charging spots, gas stations, etc. | Use the PlaceClient to implement features such as finding locations, getting more information, and Place Autocomplete. Use the PlaceListMapTemplate from the CarAppLibrary to view POIs on a map. |
Messaging (Android Auto only) |
Hands-free message replies with voice input | Use the MessagingManager from the CarAppLibrary to control sending and receiving messages, voice input, and sending template messages. |
Game | Apps for entertainment while parked | Use the ScreenManager from the CarAppLibrary to view the game screen while parked. Use the InputManager to receive control inputs for your game. |
Browser & Video | Browser integration and video playback features (specific to AAOS, often used while parked) | Use the WebTemplate from the CarAppLibrary to display web content. Use the VideoTemplate to play video content. These templates are recommended for use only while parked. |
Supplement
- I've summarized the key points from the table in the Official Documentation.
- Since new categories are added every year, even if you can't widely release your app yet, there is a possibility it could be released in the future.
- CarAppLibrary is a Jetpack library for Android Auto and Android Automotive OS app development.
- PlaceClient is a client that uses the Google Places API.
Desktop Head Unit (DHU)
-
What is a DHU? DHU is a tool for emulating the Android Auto environment on a desktop. It allows you to simulate the in-vehicle experience without using an actual in-vehicle device.
-
Why use DHU? You can test how the app operates and displays in an in-vehicle environment. It lets you debug and verify that your UI/UX complies with guidelines to avoid distracting drivers.
Run the DHU
The following are required to run the DHU:
- MacBook
- Android device
- Install the Android Auto Desktop Head Unit Emulator in the SDK Manager.
- Make sure there is a desktop-head-unit in Library/Android/sdk/extras/google/auto.
- Grant permissions to the desktop-head-unit.
chmod +x ./desktop-head-unit
- Forward the socket connection to the same port number on the Android device.
adb forward tcp:5277 tcp:5277
- Open the Auto settings on your Android device. Tap [See all apps] > [Android Auto] > [Advanced] > [Additional settings in the app]. Tap the version and permission information about 10 times to enable developer mode.
- Run the DHU.
./desktop-head-unit --usb
About Host
When running an app created for Android Auto or Android Automotive in a compatible car, the app doesn't interact directly with the car. At this stage, the connection destination is the Android Auto app on the Android device. During the DHU installation process, connecting to the actual device via USB is necessary since it needs to communicate with the Android Auto app, which serves as the host.
The Android Auto app is referred to as the host, and all Auto-compatible apps interact with this host. In the case of an Android Automotive-compatible car, the OS is built into the vehicle system itself, so Android Automotive acts as the host.
Libraries
CarAppLibrary is a Jetpack library for Android Auto and Android Automotive OS app development.
Apps built using the CarAppLibrary run through the host app rather than running directly on Auto or Automotive.
Declare the version of CarAppLibrary in the project-level build.gradle.
buildscript {
ext {
car_app_library_version = '1.4.0'
}
}
dependencies {
...
implementation "androidx.car.app:app:$car_app_library_version"
...
}
Add services and sessions
Add a class that inherits from CarAppService. You need to extend the CarAppService bound by the host.
In the intent filter, you need to declare androidx.car.app.category.POI
as the category for the car app.
<service
android:name="com.example.places.carappservice.PlacesCarAppService"
android:exported="true">
<intent-filter>
<action android:name="androidx.car.app.CarAppService" />
<category android:name="androidx.car.app.category.POI" />
</intent-filter>
</service>
The CarAppService abstract class cannot be overridden, such as onBind
or onUnbind
. The library takes care of proper interaction with the host app for you. You only need to implement createHostValidator
and onCreateSession
.
The HostValidator returned by createHostValidator
is referenced when the CarAppService is bound to verify that the host is trusted, and that the bind fails if it does not match the parameters defined by the host. ALLOW_ALL_HOSTS_VALIDATOR
is a HostValidator that can only be used for validation.
class PlacesCarAppService : CarAppService() {
override fun createHostValidator(): HostValidator {
return HostValidator.ALLOW_ALL_HOSTS_VALIDATOR
}
override fun onCreateSession(): Session {
return PlacesSession()
}
}
Add the PlacesSession class.
class PlacesSession : Session() {
override fun onCreateScreen(intent: Intent): Screen {
return MainScreen(carContext)
}
}
Template
You need to choose from predefined templates and implement them according to the guidelines. The UI and UX of car apps are restricted because the UI needs to be optimal for drivers.
Reference: Official template documentation
In addition, add the necessary permissions to access templates for displaying maps.
<uses-permission android:name="androidx.car.app.MAP_TEMPLATES" />
List Location Information
Once launched, locations will be listed.
The UI can be implemented using Composable.
Add a MainScreen
that inherits Screen
from CarAppLibrary. To display the list of locations and a map, return a PlaceListMapTemplate
using onGetTemplate
. Templates are implemented using the Builder Design Pattern. Pass the items to be listed using setItemList
and build the template to return.
Use ItemListBuilder
to build the items to be listed.
class MainScreen(
carContext: CarContext,
) : Screen(carContext) {
override fun onGetTemplate(): Template {
val placesRepository = PlacesRepository()
val itemListBuilder =
ItemList.Builder()
.setNoItemsMessage("No data")
placesRepository.getPlaces()
.forEach {
itemListBuilder.addItem(
Row.Builder()
.setTitle(it.name)
// Each item in the list must have a DistanceSpan added to the title or text line.
.addText(
SpannableString(" ").apply {
setSpan(
DistanceSpan.create(
Distance.create(Math.random() * 100, Distance.UNIT_KILOMETERS),
),
0,
1,
Spannable.SPAN_INCLUSIVE_INCLUSIVE,
)
},
)
.setOnClickListener {
screenManager.push(DetailScreen(carContext = carContext, placeId = it.id))
}
.setMetadata(
Metadata.Builder()
.setPlace(
Place.Builder(CarLocation.create(it.latitude, it.longitude))
.setMarker(PlaceMarker.Builder().build())
.build(),
)
.build(),
).build(),
)
}
return PlaceListMapTemplate.Builder()
.setTitle("Places")
.setItemList(itemListBuilder.build())
.build()
}
}
View detailed location information
Use PaneTemplate to implement the detail screen.
class DetailScreen(carContext: CarContext, private val placeId: Int) : Screen(carContext) {
private var isFavorite = false
override fun onGetTemplate(): Template {
val place = PlacesRepository().getPlace(placeId)
?: return MessageTemplate.Builder("Place not found")
.setHeaderAction(Action.BACK)
.build()
val navigateAction = Action.Builder()
.setTitle("Navigate")
.setIcon(
CarIcon.Builder(
IconCompat.createWithResource(
carContext,
R.drawable.baseline_navigation_24
)
).build()
)
.setOnClickListener { carContext.startCarApp(place.toIntent(CarContext.ACTION_NAVIGATE)) }
.build()
val actionStrip = ActionStrip.Builder()
.addAction(
Action.Builder()
.setIcon(
CarIcon.Builder(
IconCompat.createWithResource(
carContext,
R.drawable.baseline_favorite_24
)
).setTint(
if (isFavorite) CarColor.RED else CarColor.createCustom(
Color.LTGRAY,
Color.DKGRAY
)
).build()
)
.setOnClickListener {
isFavorite = !isFavorite
// To capture updates to the screen state, call invalidate() to call `onGetTemplate` again.
invalidate()
}.build()
)
.build()
return PaneTemplate.Builder(
Pane.Builder()
.addAction(navigateAction)
.addRow(
Row.Builder()
.setTitle("Coordinates")
.addText("${place.latitude}, ${place.longitude}")
.build()
).addRow(
Row.Builder()
.setTitle("Description")
.addText(place.description)
.build()
).build()
)
.setTitle(place.name)
.setHeaderAction(Action.BACK)
.setActionStrip(actionStrip)
.build()
}
}
Launch the app
Possible Errors When Trying to Launch Other Apps
Caused by: androidx.car.app.HostException: Remote startCarApp call failed
An error may occur when attempting to start navigation (where startCarApp is called). This is likely because a navigation app is not installed. You can easily find a navigation app by searching in the Play Store on the emulator.
Vehicle Properties Available in the App
Although not yet verified, the following properties should be available. The setting values may be adjustable in the emulator. Reference
- Vehicle Speed
The current speed of the vehicle can be obtained. It is typically provided in km/h and is used for actions based on speed limits and driver assistance features. - Fuel Level
For gasoline vehicles, you can obtain the remaining fuel level in the tank. This can be used for features like "low fuel" warnings or suggestions for the nearest fuel station. - Battery Level
For EVs and Hybrids, you can monitor the state of the vehicle's battery. It is used to display charging status or remaining battery levels. - Door Status
The open/closed status of each door (front, rear, trunk, and hood) can be obtained. You can set up notifications when a door is left open or alerts to prevent forgetting to close it. - Light Status
The on/off status of the vehicle lights (headlights, high beams, fog lights, etc.) can be obtained. This allows for night mode switching and providing feedback to the driver. - Engine Status
The on/off/idling status of the engine can be obtained. The application can restrict certain actions when the engine is off. - Parking Brake Status
The status of whether the parking brake is applied or released can be obtained. This can be used to control app functionality and interactions while parked. - Gear Position
The position of the shift lever (Park, Reverse, Neutral, Drive, etc.) can be obtained. This allows for automatic activation of the back camera and interface changes based on the gear selection. - Tire Pressure
The tire information such as tire pressure can be obtained. This allows notification of low pressure warnings and maintenance alerts. - External Temperature
The external temperature can be obtained, allowing it to be used for weather-based interfaces or driver notifications based on driving conditions. - Seat Occupancy Status
The presence of passengers in each seat and seatbelt usage can be obtained. This is used to display warnings when seat belts are not fastened for safety reasons. - Window Status
The open/closed state of each window can be obtained. For example, a notification can be sent if a window is left open when the vehicle is turned off. - HVAC Status
The settings and status of the vehicle's air-conditioning system (heating, cooling, fan speed, and airflow direction) can be obtained. This allows the app to manage a comfortable in-car environment. - GPS Location
The vehicle's current GPS location can be obtained. This enables navigation apps and location-based services. - Wiper Status
The operational state of the wipers can be obtained. This helps adjust the UI based on weather and visibility conditions.
Conclusion
Thank you for reading to the end.
Android Automotive OS
The quality of the Android open source is well-maintained, making it easy enough for a beginner to clone, build, and boot it. However, the required PC specs are quite high. One of our engineers pointed out that boards with Android Automotive OS pre-installed are available worldwide, and I couldn't help but think, "Why didn’t you tell me sooner?" Nonetheless, getting the OS up and running was a highly rewarding experience.
Auto and Automotive App Development
This article ended up providing a broad overview of in-vehicle app development, but we discovered that the implementation process involves just a few steps.
That said, the concepts of host app and emulator setup can be somewhat challenging to grasp.
Since automotive app development doesn't allow for much UI customization, the real challenge and fun lie in refining what the app can do. In the future, as autonomous driving becomes mainstream, more categories may emerge, allowing drivers to enjoy gaming and other experiences.
Bonus
Reflecting on my childhood memories of driving, I was inspired by Hyuga-san's article to create AI-generated music. Here's what I came up with. It turned out pretty good and atmospheric. I suppose only my colleagues would stick around this long. Looking forward to hearing your thoughts! https://soundcloud.com/numami-775711983/5qclozsqk1mz
関連記事 | Related Posts

The story of how I struggled with the character code when I got OGP in Kotlin

KINTO ONE Operation: Preparations for the Launch of the New Prius

Advancement of Windows Kitting Automation: Introducing Windows Autopilot

Advent Calendar 2023 Announcement

Meet Our New Team Members: May 2024 Update

Room Migration
We are hiring!
【KINTO FACTORYバックエンドエンジニア】KINTO FACTORY開発G/大阪
KINTO FACTORYについて自動車のソフトウェア、ハードウェア両面でのアップグレードを行う新サービスです。トヨタ・レクサスの車をお持ちのお客様にOTAやハードウェアアップデートを通してリフォーム、アップグレード、パーソナライズなどを提供し購入後にも進化続ける自動車を提供するモビリティ業界における先端のサービスの開発となります。
【PdM】/KINTO FACTORY開発G/東京・大阪
KINTO FACTORYについて自動車のソフトウェア、ハードウェア両面でのアップグレードを行う新サービスです。トヨタ・レクサスの車をお持ちのお客様にOTAやハードウェアアップデートを通してリフォーム、アップグレード、パーソナライズなどを提供し購入後にも進化続ける自動車を提供するモビリティ業界における先端のサービスの開発となります。