Android Automotive OS で動作する特権アプリ (Privileged App) の開発方法

## はじめに

Android Automotive OS（以下、AAOSと略す）のアプリ開発において、車両データ（例：エアコンの状態）を利用したいと考えるのは自然な発想だろう。しかし、AAOSでは車両データへのアクセスが厳密に管理されており、単なる読み込みであっても特別な権限が必要である。

特権アプリ（privileged app）は、このような高い権限を持つアプリであり、車両システムと直接連携するために特別に認可されている。AAOS向けのデモ開発では、通常のアプリでは実現できない機能を特権アプリで実装したいケースがある。残念ながら特権アプリの開発方法を具体的に示す記事は少ないため、その特権アプリの開発方法について確認した。


## 特権アプリの開発方法

1. AAOSのビルド環境の用意
1. ソースコードの複製
1. Android.bpの作成
1. ビルド対象にアプリを追加
1. パーミッション設定ファイルの作成
1. パーミッション設定ファイルの登録

### 特権について

車両データへのアクセスに必要な特権は[オフィシャルページ](https://developer.android.com/reference/android/car/VehiclePropertyIds)で確認することができる。例えばエアコンの設定温度(`HVAC_TEMPERATURE_SET`)を確認するためには `CONTROL_CAR_CLIMATE` という特権が必要となる。

```:https://developer.android.com/reference/android/car/VehiclePropertyIds
HVAC_TEMPERATURE_SET
...
Required Permission:
Signature|Privileged permission "android.car.permission.CONTROL_CAR_CLIMATE" to read and write property.
```

特権には下記のような種類がある

```java:特権の一部
android.car.permission.ADJUST_RANGE_REMAINING
android.car.permission.CAR_EXTERIOR_LIGHTS
android.car.permission.CAR_IDENTIFICATION
android.car.permission.CAR_MILEAGE
android.car.permission.CAR_TIRES
android.car.permission.CONTROL_CAR_CLIMATE
android.car.permission.CONTROL_CAR_SEATS
android.car.permission.CONTROL_CAR_MIRRORS
android.car.permission.CONTROL_CAR_EXTERIOR_LIGHTS
android.car.permission.READ_CAR_STEERING
android.car.permission.READ_CAR_INTERIOR_LIGHTS
...
```

下記のソースコードからも確認できる

https://android.googlesource.com/platform/packages/services/Car/+/master/car-lib/src/android/car/Car.java


### AAOSのビルド環境の用意

特権アプリはAndroid Studioではなく、AAOSのビルド環境で構築する。
ここでは [Google Pixel Tablet向けのビルド環境](https://source.android.com/docs/automotive/start/pixelxl?hl=ja)を用いて確認を進める。

https://qiita.com/rairaii/items/a3fc4fca41d169d8a518

### ソースコードの用意

調査に利用した特権アプリのサンプルソースコード

https://github.com/aRaikoFunakami/PrivilegedSampleApp/tree/v0.1.0

### ソースコードの複製

開発した特権アプリのソースコードをAAOSのビルド環境にコピーする。
Android Studioで`PrivilegedSampleApp`というプロジェクト名でアプリ開発を行った場合は次の通りに進めれば良い。

**AAOSのビルド環境にソースコードを保存するディレクトリを用意する**

```bash: 
mkdir ~/aaos_on_pixel/packages/apps/Car/PrivilegedSampleApp
```

**特権アプリのソースコードをコピーする**

```bash: 
cp -R ~/AndroidStudioProjects/PrivilegedSampleApp/automotive/src/main/*  ~/aaos_on_pixel/packages/apps/Car/PrivilegedSampleApp
```

```bash: Macで開発してLinux側にコピーする場合
cd ~/AndroidStudioProjects/PrivilegedSampleApp/automotive/src/main/ && \
tar -cf  - ./* | \
ssh <UserID>@<IP ADDRESS> \
"cd ~/aaos_on_pixel/packages/apps/Car/PrivilegedSampleApp && tar -xf -"
```

**ソースコードのディレクトリ名を変更**

```bash: 
cd ~/aaos_on_pixel/packages/apps/Car/PrivilegedSampleApp
mv java src
```

### Android.bpの作成

AAOSは [Soong](https://source.android.com/docs/setup/build?hl=ja) を用いてビルドするため `build.gradle.kts` の代わりとなる `Android.bp` ファイルを作成する。
[Android.bp](https://source.android.com/docs/setup/reference/androidbp?hl=ja) ファイルの作成は `~/aaos_on_pixel/packages/apps/Car/` 以下にあるプリインアプリ用の Android.bp などが参考になるだろう。


```bash
cd ~/aaos_on_pixel/packages/apps/Car/PrivilegedSampleApp
vi Android.bp
```

```python:Android.bp
package {
    default_applicable_licenses: ["Android-Apache-2.0"],
}

android_app {
    name: "PrivilegedSampleApp",

    srcs: [
        "src/**/*.java",
        "src/**/*.kt",
        "src/**/I*.aidl",
    ],
    aidl: {
        local_include_dirs: ["src"],
    },

    platform_apis: true,

    required: ["allowed_privapp_com.example.privilegedsampleapp"],

    certificate: "platform",

    privileged: true,

    libs: ["android.car-system-stubs"],

    static_libs: [
        "androidx.lifecycle_lifecycle-livedata",
        "androidx-constraintlayout_constraintlayout",
        "androidx.room_room-runtime",
        "car-apps-common",
        "car-media-common",
        "car-broadcastradio-support",
        "car-ui-lib",
    ],

    plugins: ["androidx.room_room-compiler-plugin"],

    resource_dirs: ["res"],

    optimize: {
        enabled: false,
    },

    dex_preopt: {
        enabled: false,
    },
}
```

### ビルド対象にアプリを追加

次の２つのファイルの `PRODUCT_PACKAGES` 変数に `PrivilegedSampleApp` を追加して、開発したアプリをAAOSのビルド対象に加える

- car_system.mk
- car.mk

```bash
vi ~/aaos_on_pixel/packages/services/Car/car_product/build/car_system.mk
```

```makefile: ~/aaos_on_pixel/packages/services/Car/car_product/build/car_system.mk
PRODUCT_PACKAGES += \
    CarFrameworkPackageStubs \
    CarService \
    CarShell \
    CarDialerApp \
    CarRadioApp \
    OverviewApp \
    CarLauncher \
    LocalMediaPlayer \
    CarMediaApp \
    CarMessengerApp \
    CarHTMLViewer \
    CarMapsPlaceholder \
    CarLatinIME \
    CarSettings \
    CarUsbHandler \
    android.car.builtin \
    libcarservicehelperjni \
    car-frameworks-service \
    com.android.car.procfsinspector \
    com.android.permission \
    PrivilegedSampleApp \
```

```bash
vi ~/aaos_on_pixel/packages/services/Car/car_product/build/car.mk
```

```makefile: ~/aaos_on_pixel/packages/services/Car/car_product/build/car.mk
# Automotive specific packages
PRODUCT_PACKAGES += \
    CarFrameworkPackageStubs \
    CarService \
    CarShell \
    CarDialerApp \
    CarRadioApp \
    OverviewApp \
    CarLauncher \
    CarSystemUI \
    LocalMediaPlayer \
    CarMediaApp \
    CarMessengerApp \
    CarHTMLViewer \
    CarMapsPlaceholder \
    CarLatinIME \
    CarSettings \
    CarUsbHandler \
    RotaryIME \
    RotaryPlayground \
    android.car.builtin \
    car-frameworks-service \
    libcarservicehelperjni \
    com.android.car.procfsinspector \
    com.android.permission \
    PrivilegedSampleApp\
```

### パーミッション設定ファイルの作成

`PrivilegedSampleApp` 用のパーミッション設定ファイルを作成する

```bash
cd ~/aaos_on_pixel/packages/services/Car/data/etc/
vi com.example.privilegedsampleapp.xml
```

開発したアプリの `AndroidManifest.xml` で指定した車載データにアクセスするための特権をパーミッション設定ファイルにも記載する。
今回は `android.car.permission.CONTROL_CAR_CLIMAT` を指定する。

```xml:com.example.privilegedsampleapp.xml
<permissions>
<privapp-permissions package="com.example.privilegedsampleapp">
<permission name="android.car.permission.CONTROL_CAR_CLIMAT"/>
</privapp-permissions>
</permissions>
```

###  パーミッション設定ファイルの登録
作成したパーミッション設定ファイル情報を `Android.bp` へ追記する。

```bash:
cd ~/aaos_on_pixel/packages/services/Car/data/etc/
vi Android.bp
```

```python:~/aaos_on_pixel/packages/services/Car/data/etc/Android.bp
prebuilt_etc {
    name: "allowed_privapp_com.example.privilegedsampleapp",
    sub_dir: "permissions",
    src: "com.example.privilegedsampleapp.xml",
    filename_from_src: true,
}
```


## 特権アプリのビルド

新規追加したアプリごとAAOSをビルドする。AAOSを一度ビルドしていた場合は、新規追加したアプリだけ差分ビルドされる。


```bash
#AOSPのビルド
. build/envsetup.sh
lunch aosp_tangorpro_car-ap1a-userdebug
m
#Automotive関連のパッケージをビルド
m android.hardware.automotive.vehicle@2.0-default-service android.hardware.automotive.audiocontrol-service.example 
```

## ビルドしたイメージを書き込む

**デバイスのロックを外す**

```bash
adb reboot bootloader
fastboot flashing unlock
```

**ビルドしたイメージを書き込む**

```bash
fastboot -w flashall
```

**Automotive 固有のファイルを追加する**

ビルドしたイメージの書き込みが終了し、デバイスが再起動する(起動画面のアニメーションが始まる)まで待ち、Automotive 固有のファイルを追加するための前処理を実行する

```bash
#Temporary disable the userdata checkpoint 
adb wait-for-device root; sleep 3; adb shell vdc checkpoint commitChanges; sleep 2 
#Enable remount
adb remount && sleep 2 && adb reboot && echo "rebooting the device" && adb wait-for-device root && sleep 5 && adb remount
```

再起動するまで待ち、Automotive 固有のファイルをデバイスにコピーする

```bash
adb sync vendor && adb reboot
```

## 動作確認

1. numberPickerで選択した数値が右側のエアコンの設定温度に反映された
1. 右側のエアコンの設定温度を変更するとnumberPickerのvalue値に反映された

![特権アプリAAOSの温度を変更.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1017489/2307da51-024d-8c65-50a5-2dd48f636b5f.gif)



## 参考情報

https://medium.com/@sreelakshmis.dilip/android-automotive-build-your-first-app-f4b882eb01e5

https://medium.com/@sreelakshmis.dilip/android-automotive-understanding-app-permissions-and-privileged-applications-c00b83df11d6


https://zenn.dev/turing_motors/articles/33b40bc64af359

https://zenn.dev/turing_motors/articles/9c18325ffdfb57

https://zenn.dev/turing_motors/articles/da663f81d871da