「Androidアプリ開発者」は世界中に溢れていますが、「Androidそのもの」をビルドした経験があるエンジニアは驚くほど少数です。最近、特定用途向けの組み込みデバイス(KIOSK端末)のOSを設計するプロジェクトで、Google Mobile Services (GMS) を完全に排除した純粋なAndroid環境を構築する必要がありました。そこで直面したのは、IDEでKotlinを書くのとは次元が違う、Linuxカーネルと巨大なビルドシステムが絡み合う泥沼の世界でした。
私たちが普段手にする「スマホ」は、AOSPという骨格に、各メーカーの皮膚(UI)とGoogleの魂(GMS)が宿ったキメラのような存在です。本稿では、この骨格であるAOSP (Android Open Source Project) を素の状態で動かす際に直面した技術的課題、特にソースコードの同期とハードウェア抽象化レイヤー(HAL)の罠について、実体験を元に共有します。
ビルド環境の構築とrepoツールの正体
まず、開発環境のスペックについて触れておく必要があります。Android 14 (UpsideDownCake) のフルビルドを行うには、MacBook Airのような一般向けのラップトップでは歯が立ちません。今回のプロジェクトでは、以下の仕様を持つUbuntu 22.04 LTSサーバーを用意しました。
- CPU: AMD Ryzen 9 7950X (16 cores/32 threads)
- RAM: 64GB DDR5 (リンク時にSwapが発生すると死活問題になります)
- Storage: 2TB NVMe SSD (ソースコードだけで250GB以上、ビルドアーティファクトを含めると500GBを超えます)
ここで最初の障壁となるのが、ソースコードの取得です。通常のGitコマンドでは太刀打ちできません。GoogleはGitの上に構築されたPythonスクリプトである repo ツールを提供しています。これは何百ものGitリポジトリを単一のワークスペースとして管理するためのラッパーです。
manifest.xml というファイルに定義された、カーネル、フレームワーク、アプリ、ツールチェーンなど、数百のリポジトリの集合体です。
「Naive Approach」の失敗:repo syncの深淵
プロジェクト初期、ディスク容量を節約しようとして、安易に以下のコマンドを実行してしまいました。
repo init -u https://android.googlesource.com/platform/manifest -b android-14.0.0_r1
repo sync -c -j8 --no-tags --no-clone-bundle
一見、効率的なコマンドに見えますが、これが後のデバッグ作業を困難にしました。--no-tags オプションを使用したことで、特定のセキュリティパッチレベルに対応するタグ情報が欠落し、ビルドエラーが発生した際に「どのバージョンのライブラリが競合しているのか」を特定する術を失ってしまったのです。また、ネットワーク帯域が不安定な環境で並列数 -j8 を指定した結果、同期途中でハングアップし、.repo ディレクトリが破損する事態に陥りました。
SoongビルドシステムとBoardConfig.mkの最適化
AOSPのビルドシステムは、かつてのGNU Makeから、Go言語ベースのSoong(およびBlueprintファイル)へと移行しています。しかし、デバイス固有の設定は依然として BoardConfig.mk などのMakeファイルに依存しており、このハイブリッド構造が複雑さを増しています。
以下は、特定ハードウェア向けに最小限の構成でビルドを通すための、device.mk の重要な設定例です。不要なプリインストールアプリを削除し、ビルド時間を短縮するためのテクニックを含んでいます。
# device/mycompany/mydevice/device.mk
# 継承設定:AOSPの基本構成を引き継ぐ
$(call inherit-product, $(SRC_TARGET_DIR)/product/full_base.mk)
# 不要なGoogle製アプリやサービスをオーバーライド
# これによりsystemイメージのサイズを大幅に削減
PRODUCT_PACKAGES += \
Launcher3QuickStep \
Settings \
SystemUI
# デバッグ用の不要なモジュールを除外
PRODUCT_PACKAGES_DEBUG :=
# プロパティ設定:ダルビックVM(ART)のヒープ最適化
PRODUCT_PROPERTY_OVERRIDES += \
dalvik.vm.heapstartsize=8m \
dalvik.vm.heapgrowthlimit=192m \
dalvik.vm.heapsize=512m
# 重要:ブートアニメーションをカスタムロゴに変更する場合
# PRODUCT_COPY_FILES += \
# device/mycompany/mydevice/bootanimation.zip:system/media/bootanimation.zip
この設定において特に重要なのは、PRODUCT_PACKAGES の選定です。ここで指定されたモジュールのみがシステムイメージに含まれます。多くの場合、generic_system_image (GSI) の設定を継承しがちですが、商用デバイス向けには不要なデバッグツールが含まれているため、ホワイトリスト方式でパッケージを追加していくアプローチが、セキュリティとパフォーマンスの両面で推奨されます。
Vendor BlobとHALの「黒い画面」問題
ビルドが成功しても、実機に焼いた瞬間に「画面が真っ暗」あるいは「ブートループ」という現象に遭遇します。これは9割方、プロプライエタリなバイナリ(Vendor Blobs)の欠如が原因です。Android公式サイトでも言及されていますが、GPUドライバ、Wi-Fiファームウェア、センサーHALなどはオープンソースではありません。これらはチップセットベンダー(QualcommやMediaTek)から提供されるバイナリを vendor/ ディレクトリに配置する必要があります。
私たちは当初、Project Trebleの恩恵によりGSIだけで起動すると期待していましたが、現実にはSoC固有のInitスクリプト(init.rc)との不整合により、Zygoteプロセスがクラッシュを繰り返していました。解決策は、LineageOSなどのカスタムROMコミュニティが公開している extract-files.sh スクリプトを解析し、実機から必要なバイナリを吸い出して再配置することでした。
| 比較項目 | Pure AOSP | GMS搭載 Android | Custom ROM (Lineage等) |
|---|---|---|---|
| システムサイズ | 約 1.5GB - 2GB | 4GB以上 | 2GB - 3GB |
| プッシュ通知 | 独自実装が必要 | FCM (Firebase) | 独自 or MicroG |
| 位置情報精度 | GPSハードウェアのみ | Google Location Service (高精度) | UnifiedNlp |
| WebView | AOSP WebView (古い) | Chrome / System WebView | Chromium Build |
表からも分かる通り、AOSP単体では現代的なスマホ体験を提供するのは困難です。特にWebViewの実装は、セキュリティパッチが遅れがちなAOSP版ではなく、Chromiumを自前でビルドして組み込む工数が発生します。
AOSP採用時の重大な注意点
ビジネス要件としてAOSPを採用する場合、最も懸念すべきは「アプリの互換性」です。多くの商用アプリはGoogle Play開発者サービス(Play Services)に依存しています。Map API、SafetyNet(現在はPlay Integrity API)、プッシュ通知などが動作しません。
また、WebViewの実装にも注意が必要です。AOSPに同梱されているWebViewは更新頻度が低く、最新のWeb標準に対応していない場合があります。セキュリティ要件が厳しいプロジェクトでは、最新のChromiumを定期的にビルドし、System WebViewとして署名・配置するCI/CDパイプラインの構築が不可欠となります。これを見落とすと、アプリ内ブラウザ経由での脆弱性がそのまま放置されることになります。
結論
AOSPは、単なる「無料のOS」ではなく、ハードウェアとソフトウェアの境界線を制御できる強力なプラットフォームです。しかし、その自由の代償として、ドライバの管理、セキュリティパッチの適用、そしてGoogleサービスへの非依存化という重い責任が伴います。もしあなたがカスタムデバイスの開発を検討しているなら、repo sync を叩く前に、そのデバイスが誰のために、どのようなエコシステムの中で動くのかを設計レベルで深く考慮する必要があります。それが、成功するAndroidプロダクトと、起動ロゴで止まる文鎮との分かれ道となるのです。
Post a Comment