自動車のスマホ化 - Android Automotive OS完全入門!
はじめに
Turing株式会社のUX Engineeringチームでエンジニアをしています佐々木です。Turingは「We Overtake Tesla」をミッションに完全自動運転EVの開発をしています。UX Engineeringチームは、車載インフォテインメント (IVI : In-Vehicle Infotainment) システムの開発を担当しており、Android Open Source Project (AOSP) をベースに車載OSを開発しています。
本記事では、AOSPの枠組みに含まれるAndroid Automotive OS (AAOS)を概説し、また、実機でAAOSを体験するためにRaspberryPi 4BでAAOS13.0を実行する方法を紹介します。
Android Automotive OSの概要
Android Automotive OS (AAOS) は自動車特有の要件や機能を追加したAndroid OSであり、一般的なスマートフォンやタブレット端末と同じAOSPの枠組みで開発が行われています。AAOSは、2017年3月にGoogleによって発表され、2018年2月にAAOS搭載のVolvo Polestar 2が発表されました。他にもHonda Accord, Chevrolet Tahoe, Rivian R1Tなどの市販車に搭載されています。
AAOSを搭載したVolvo EX30は2023年夏頃に日本で発売予定
混乱しやすいのが、Android AutoとAAOSの違いです。これらは似て非なるものです。Android Autoは、互換性のあるIVIシステムにユーザーのスマートフォン上で動作するアプリケーション等を反映するプラットフォームです。一方のAAOSは車載ハードウェア上で直接動作するオペレーティングシステムです。AAOSは、車両と密に連携することができ、エアコンの温度調節や窓の開閉などを行うことができます。さらに、Googleのアプリとサービスを提供するパッケージであるGoogle Automotive Services (GAS) に対応すれば、Google Playにアクセスでき、Google MapsやGoogle Assistantなどが利用できます。
それでは、スマホやタブレット端末向けのAndroidとAAOSの違いはどこにあるのでしょうか。以下では、実機でAAOSを体験し、主な違いを見ていきます。
AAOS13.0をRaspberryPi 4Bで実行する
それでは早速、実機でAAOSを体験してみましょう。ここでは、入手しやすいRaspberryPi 4BでAAOS13.0を実行します。
AAOSのホーム画面
通常、エッジデバイスでAndroidを実行するためには、ドライバやハードウェアのサポートが必要です。RaspberryVanillaはRaspberryPiでAndroidを実行するためにドライバやハードウェアの対応を行っているプロジェクトであり、定期的にアップデートされています。以下では、GrapeUp社が行っているRaspberryVanillaのAAOSカスタムプロジェクトを題材とします。
実行環境
Amazonのリンクを付与しますので、購入の参考にしてください。
-
PC(マシンスペックは下記のビルド要件を参照ください)
-
ディスプレイ
操作のためタッチ機能が付いているとよいですが、お手持ちのHDMIポートが付いているモニターで問題ありません。タッチ機能がない場合は、別途マウスを用意してください。 -
RaspberryPi 4B
RaspberryPi 4B -
MicroSD
16GBあれば十分です。
MicroSD -
MicroHDMI-HDMIケーブル
MicroHDMI-HDMIケーブル -
USB-TTLシリアルアダプタ(デバッグ用)
USB-TTLシリアルアダプタ -
ジャンパ線メスーメス 3本(デバッグ用)
ジャンパ線メスーメス
ビルド要件
Androidは大きなプロジェクトであり、ビルドにはマシンパワーが必要です。RAMは32GB以上(64GB以上を推奨)、ディスク容量は余裕を持って512GB以上であることが望ましいです。物理マシンが用意できない場合は、AWS EC2などを利用するとよいでしょう。筆者のマシンスペックは以下です。
- OS : Ubuntu 20.04
- CPU: Intel(R) Xeon(R) Gold 6226R (16コア、32スレッド)
- RAM: 128GB
- HD: 4TB
ビルド
それでは、ビルドしていきましょう。マシンスペックによりますが、通常フルビルドには1時間以上かかります。
-
ビルド環境の構築
sudo apt update sudo apt-get install git gnupg flex bison build-essential zip curl zlib1g-dev gcc-multilib g++-multilib libc6-dev-i386 libncurses5 lib32ncurses5-dev x11proto-core-dev libx11-dev lib32z1-dev libgl1-mesa-dev libxml2-utils xsltproc unzip fontconfig sudo apt-get install bc coreutils dosfstools e2fsprogs fdisk kpartx mtools ninja-build pkg-config python3-pip sudo pip3 install meson mako jinja2 ply pyyaml
-
repoのインストール
Androidは巨大なプロジェクトであり、大量のGitリポジトリで開発が行われています。そこで、これら多くのリポジトリを一元的に管理するためにGoogleによって開発されたrepoというツールを用います。
cd mkdir ~/bin PATH=~/bin:$PATH curl https://storage.googleapis.com/git-repo-downloads/repo > ~/bin/repo chmod a+x ~/bin/repo
-
repoの初期化
Androidプロジェクトを初期化します。今回はAndroid13.0 revision 35を指定します。
repo init -u https://android.googlesource.com/platform/manifest -b android-13.0.0_r35 --depth=1
-
local_manifestの追加
git clone https://github.com/grapeup/aaos_local_manifest.git .repo/local_manifests
AAOSは
.repo/manifest.xml
というファイルを使用して、どのリポジトリをプロジェクトに含めるかを管理します。カスタムリポジトリを追加する場合は、.repo/local_manifests/
にmanifestファイルを作成します。今回のプロジェクトでは.repo/local_manifests/manifest_brcm_rpi4.xml
で追加するリポジトリを定義しています。 -
local_manifestの変更
公開されているリポジトリでは、dav1dが不足しています。そこで、
.repo/local_manifests/manifest_brcm_rpi4.xml
の46行目<!-- FFmpeg -->
以下にdav1dを追記します。https://github.com/grapeup/aaos_local_manifest/pull/5<!-- FFmpeg --> <project path="external/dav1d" name="raspberry-vanilla/android_external_dav1d" remote="github" revision="android-13.0" />
また、以下の27行目のandroid_buildと35行目のandroid_build_soongのrevisionをandroid-13.0からandroid-13.0.0_r35に変更します。
<project path="build/make" name="raspberry-vanilla/android_build" remote="github" revision="android-13.0.0_r35" > <project path="build/soong" name="raspberry-vanilla/android_build_soong" remote="github" revision="android-13.0.0_r35" >
-
リポジトリの同期
-j
オプションで並列数を指定します。ネットワークを圧迫するため、並列数は大きくしすぎないようにしましょう。repo sync -j8
-
コンパイル
. build/envsetup.sh lunch aosp_rpi4-userdebug make bootimage systemimage vendorimage -j$(nproc)
イメージの書き込みとデプロイ
ビルドが完了したら、次はMicroSDにイメージを書き込み、RaspberryPi 4Bにデプロイしていきます。
-
MicroSDをクリーン
# MicroSDの認識を確認 lsblk # MicroSDをクリーン sudo umount /dev/sdb* sudo wipefs -a /dev/sdb* sudo wipefs -a /dev/sdb
-
4つのパーティションテーブルを作成
# パーティションテーブルの作成 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 # パーティションが4つに区切られたことを確認 lsblk sdb 8:16 1 119.2G 0 disk ├─sdb1 8:17 1 128M 0 part ├─sdb2 8:18 1 2G 0 part ├─sdb3 8:19 1 256M 0 part └─sdb4 8:20 1 116.8G 0 part
-
イメージ書き込み
MicroSDに書き込むイメージは
boot.img
,system.img
,vendor.img
の3つです。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*
-
MicroSDをRaspberryPiに挿入して起動
無事に起動できると冒頭のホーム画面(Launcherアプリ)が表示されます。Launcherアプリには、地図表示やラジオ再生の機能があります。他にも車載アプリの代表例としてHVAC (Heating, Ventilation, and Air Conditioning)があります。
HVACアプリ
デバッグ
AAOSの開発において、kernel logやAndroidコマンドラインツールのAndroid Debug Bridge (adb)でログが見れることは必須です。以下では、RaspberryPi 4Bでシリアル通信を行いkernel logを確認する方法とadbコマンドの有効化について紹介します。
シリアル通信でkernel logを確認
-
RaspberryPi 4BとPCを接続する
RaspberryPi 4Bのpin6: Ground、pin8: GPIO14 (TXD)、pin10: GPIO15 (RXD)とPCをUSB-TTLシリアルアダプタで接続します。
RaspberryPi 4Bとシリアル通信用USBデバイスの接続方法
(図:RaspberryPi Documentation, USB-TTLシリアルアダプタ)
-
シリアル通信を行う
今回はgtktermというツールを用います。# gtktermのインストール sudo apt install gtkterm # gtktermの起動 sudo gtkterm
ConfigurationからPortを選択し、下記の設定画面を開きます。Baud Rateを
115,200
に設定し、接続します。
gtktermの設定
adbの有効化
-
Wi-Fiの接続
RaspberryPi 4Bをadb接続するPCと同じネットワークに接続してください。
-
シリアル通信でAndroidコンソールにrootとしてログインし、TCP経由でadbを有効化
su setprop service.adb.tcp.port 5555 stop adbd start adbd # ipアドレスを確認 ifconfig wlan0
-
RaspberryPi 4Bにadbで接続
cd platform-tools # 先程、確認したipアドレスを入力 adb connect ipアドレス:5555
-
logを確認
adb logcat # log 06-13 05:45:52.626 774 1023 D EglHelper: createEglContext start 06-13 05:45:52.632 774 1023 D EglHelper: createEglContext done 06-13 05:45:52.632 774 1023 D EglHelper: createEglSurface start 06-13 05:45:52.632 774 1023 D EglHelper: createEglSurface done
logを確認することができました。
Android Automotive OSとは何なのか?
こうしてRaspberryPi 4BでAAOSを動かしてみることで、スマホやタブレット端末向けのAndroidとAAOSでは、いくつかアプリの変更があることが確認できます。実際には、ここから自社開発の車両に合わせてアプリ(OEM Apps)を独自に開発していきます。そのためには、AAOSのシステムアーキテクチャ全体の理解が必要です。以下では、AAOSのアーキテクチャを確認しながら、スマホやタブレット端末向けのAndroidとAAOSの主要な違いについて見ていきます。
Android Automotive OSのアーキテクチャ図
Apps
まずは、アプリケーションレイヤーを見てみましょう。AOSP Appsには、CalendarやCameraなどデフォルトアプリが含まれています。これらはpackages/apps/
にあります。また、packages/apps/Car/
を見ると、先ほどRaspberryPi 4Bで動かしたLauncherやHVACがあります。アプリ名はAndroid.bp
で定義されており、例えばLauncherは /packages/apps/Car/Launcher/Android.bp
でCarLauncherとして定義されています。
OEM Appsは各社OEM(Original Equipment Manufacturing : ここでは自動車メーカーを指す)が開発したアプリです。例えば、Volvo EX30のLauncherアプリは下記のように、車速やテルテール、マップ、音楽アプリなどが含まれておりAOSPのデフォルトアプリとは大きく異なります。
Volvo EX30のLauncherアプリ
3rd Party Appsは文字通り、GoogleやOEM以外が開発を行い、提供しているアプリです。AAOS向けのアプリは運転者の注意を妨げないように設計する必要があり、スマホやタブレット向けのアプリと異なる開発ガイドラインが設けられています。例えば、遅延時間について「ボタンは2秒以内に反応する」「アプリは10秒以内に起動する」「アプリのコンテンツは10秒以内に読み込まれる」といった条件が定められています。
これらアプリを最終的にビルドに含めるにはdevice/
のmakefileで設定します。今回のプロジェクトでは、device/brcm/rpi4_car/rpi4_car.mk
でpackages/services/Car/car_product/build/car.mk
を継承して設定を適用しています。
# device/brcm/rpi4_car/rpi4_car.mk line 112
$(call inherit-product, packages/services/Car/car_product/build/car.mk)
# packages/services/Car/car_product/build/car.mk line 122
PRODUCT_PACKAGES += \
CarFrameworkPackageStubs \
CarService \
CarShell \
CarDialerApp \
CarRadioApp \
OverviewApp \
CarLauncher \
CarSystemUI \
LocalMediaPlayer \
CarMediaApp \
CarMessengerApp \
CarHTMLViewer \
CarHvacApp \
CarMapsPlaceholder \
CarLatinIME \
CarSettings \
CarUsbHandler \
android.car \
car-frameworks-service \
com.android.car.procfsinspector \
libcar-framework-service-jni \
ScriptExecutor
System ServicesとVehicle HAL
次に、上図のCar API, CarService, VHAL(Vehicle Abstraction Layer)について確認してみましょう。これらは、アプリが車両情報を用いる場合に必要になります。以下では例としてHVACで運転席のエアコン温度を設定する場合を考えてみます。
HVACにおける通信
まず、HVACアプリのボタンでエアコン温度を設定すると、Car APIを使用してリクエストがCar Serviceに送られます。Car Serviceはリクエストを受け取ると、パーミッションやリクエストが妥当かを検証し承認します。例えば、走行中においてドア開閉のリクエストを受け取ったときは、リクエスト通りに実行すると危険なので拒否します。Car Serviceはリクエストを承認したらVHALを通じてECUに信号を送ります。VHALはCar Serviceから受け取った信号を車両プロトコル(CAN, LIN, FlexRayなど)を用いてECU(Electronic Control Unit)に伝達し、ECUがエアコン温度を変更します。変更が完了すると、ECUはVHALに車両プロトコルで信号を送ります。VHALはこの信号を適切な形式に変換し、Car Serviceに送ります。最終的に、Car ServiceからCar APIを通じてHVACアプリに変更が反映されます。
独自のAndroid Automotive OSを開発するためには?
ここまでの内容から、AAOSは自動車特有の要件や機能を追加したAndroid OSであり、AOSPの枠組みで開発されていることが確認できたかと思います。AOSPで車載アプリやVHALの参照実装、Car APIやCar Serviceが提供されているため、OEMはユーザー体験に注力して独自のAAOS開発を行うことができます。それでは、OEMが独自のAAOSを開発するためには何が必要でしょうか。大きく以下の3つに分けて考えることができるでしょう。
-
OEM Apps
ユーザー体験を考え、OEM独自のアプリを開発します。一般にAAOS搭載の市販車は、LauncherやHVAC、設定アプリを作り込んでいます。スマホ向けのAndroidアプリと同様にJava, Kotlin, Unityなどを用いて開発ができます。
-
HAL (VHAL)
車両ハードウェアに合わせてHALを実装し、OEM Appsが車両と連携できるようにします。通常はCやC++で実装されます。
-
Device Configuration
車載ハードウェアに合わせてWi-FiやBluetoothなどのデバイス設定ファイルを作成します。例えば、今回題材としたプロジェクトでは
device/rpi4_car/overlay/
でRaspberryPi 4Bのデバイス設定の一部を行っています。
おわりに
本記事ではAAOSを概説し、実機でAAOS 13.0を体験しました。さらに、AAOSのアーキテクチャを見ながら主なコンポーネントの役割を理解し、独自のAAOSを開発に必要な3項目を整理しました。自動車特有の要件はありますが、AAOSの開発はスマホ(Android OS)開発と同等であり、Linux OSやAndroidアプリの開発知識を活かすことができます。
筆者が所属するTuring UX Engineeringチームでは独自のAAOSを開発しており、開発メンバーを募集しています。車載OS、音声認識、ナビゲーションなどIVIシステムの開発に興味がある方はぜひ、弊社求人一覧およびWantedlyをご覧ください。ソフトウェアの力でユーザ体験を向上させ、優しさと格好よさを兼ね備えた自動運転EVを作っていきましょう。
Discussion
手元環境で追試したところ、
lunch
コマンドの実行時にビルドエラーが発生し先に進めませんでした。fork 元の raspberry-vanilla での更新に従って android-13.0.0_r52 を使用したところ、ビルドが走り出しました。ご参考まで。