Android车载开发之AAOS快速入门
在正式介绍Android Automotive OS之前,我们先弄清两个概念:Android Auto和Android Automotive OS。
一、概述
在正式介绍Android Automotive OS之前,我们先弄清两个概念:Android Auto和Android Automotive OS。
Android Auto
Android Auto 不是操作系统,而是一个应用或一个服务。当 Android 手机通过无线或有线方式连接到汽车时,Android 系统会将使用 Android Auto 服务的所有应用投屏到汽车上。所有的计算、渲染都是运行在 Android 手机上,汽车屏幕负责显示,同时将用户的交互动作传回给手机,作用类似于CarPlay。
Android Automotive OS
Android Automotive OS(AAOS)是一款基于 Android 的车载信息娱乐系统。车载系统是专为提升驾驶体验而优化的独立 Android 设备。借助 Android Automotive OS,用户可直接将您的应用安装到车载系统上,而不是手机上。平时大家所说的Android座舱开发也就属于这一类。
二、Android Automotive OS架构
以下是 Android Automotive OS (AAOS)的架构组成。
从图中可以看到,系统被分为四层:
-
应用层(Application Framework):包括 Google 开发的系统应用(launcher、短信、电话、联系人等),OEM 开发的定制化应用和其他第三方开发的应用。
-
服务层(Service Layer):Java 编写的 API,比如构建 UI、通知、生命周期管理等,应用层可以使用这些 API 构建 Android 应用程序。
-
硬件抽象层(HAL):向服务层提供硬件设备访问 API。
-
系统层(BSP):系统层级硬件驱动、线程管理、内存管理、电源管理等。
其中,蓝色是由Google开发的Android部分,绿色是OEM负责(贴牌厂商),红色注意是BSP和三方的应用组成。其中 Google 在 AOSP 中实现的跟汽车相关的应用或服务称为 Google Automotive Service(GAS),具体包括: -
Google 地图和导航:用于从 A 点到 B 点的导航,具有智能地址、路线、加油站和充电站搜索功能。
-
Google 助手:语音个人助理,用于控制各种车辆功能(可扩展)或向用户提供信息。
-
Google 应用商店:提供和管理第三方应用。
-
设置引导:创建车辆用户资料账户和连接设置。
-
汽车键盘:适合汽车操作的键盘,用于操作触摸屏并支持多种语言。
作为 OEM 或汽车制造商,如果不需要整合具有 GAS 的平台版本,那么只需下载开源的 AOSP 源代码,然后集成自己的应用程序和服务即可。因为无法使用 Google 服务,国内大多数的智能汽车搭载的是自己研发的AAOS 。
2.1 Frameworks & Libraries
为了在汽车上创建一个人机界面(HMI),操作系统需要提供各种框架和库来开发和集成各种应用,并制定适用于汽车系统和用户场景的规则和限制。
UI Frameworks
SystemUI / CarSystemUI 管理中央屏幕的显示结构和布局。用户可以在必要时对其进行定制,改变界面上的元素和内容(如屏幕顶部的状态栏,主页面底部的导航栏,以及主要页面和 HVAC 控制条)。此外,还可以通过 SystemUI 管理系统主题(颜色、字体和样式)。
Google 将 SystemUI 定义为 "一个持久的进程,为系统提供 UI,但在 system_server 进程之外"。其中继承自 SystemUI 的 SystemUIApplication 定义了一组 UI 相关的服务,比如 SystemBars、PowerUI。
Android Automotive 最重要的扩展之一是 DrivingUxRestrictions 框架。它已经被整合到 Google 提供的应用程序中。该框架使用 OEM 指定的配置文件,并防止驾驶人员在某些驾驶情况下的触摸操作,避免因驾驶人员分心而发生的交通事故。当然,OEM 可以扩展和定制这个框架。
Car-lib
除了为实现 HMI UI 框架外,Google 还提供了大量在其他层的功能。下面重点介绍三个可以大量减少我们开发工作的服务。
-
CarInfoManager :根据开发策略,OEM 可能希望用一个平台版本管理多个车辆版本。CarInfoManager 可以用来动态地调整 HMI。作为一个代理组件,它提供关于车辆模型、版本和其他相关车辆属性的静态信息。
-
CarPowerManager:信息娱乐系统及其应用的行为主要取决于车辆的系统状态。基于通用的状态机模型,通过 CarPowerManager 与车辆 HAL 和车辆微控制器单元(VMCU)进行通信。应用可以在特定状态或状态变化时执行特定行为。
-
CarProjectionManager:有效整合和处理不同的投屏技术是当今信息娱乐系统的一个关键要求。用户应该可以在 Android Auto、Apple CarPlay 或其他镜像技术之间自由选择。通过 CarProjectionManager 开发的应用,可以保证在建立连接、管理智能手机和关闭连接时与系统具有相同的行为。
2.2 Android Automotive OS
以下是一个更详细的Android Automotive OS架构。
Application Framework
通常被称为 "HMI 层",应用框架包含了系统和用户的应用程序。我们的建议是,在设计应用程序时,它们只负责显示和小型的计算逻辑,以避免阻塞主线程,并将核心业务逻辑放到服务层的系统服务。这种设计的好处是在未来的更新更容易,且可以为不同的汽车品牌实现不同的人机界面设计。
Service Layer
系统服务包含在服务层中,由 SystemServer 启动。它们以系统进程的形式运行,这使它们拥有普通 Android 服务所不具备的额外权限。OEM 厂商可以利用这些服务开发其他应用程序,而不需要编写重复的代码。此外,OEM 也可以将服务作为一个额外的安全层,以避免应用程序和硬件抽象层之间的直接通信。
Vehicle HAL
VHAL 的作用是向系统服务层公开通用的汽车接口,且接口可扩展、与特定车辆型号无关。这些接口包括:
-
访问&发送车辆 ECU 的信号
-
访问从车辆 ECU 到 IVI 操作系统产生的信号
-
访问车辆网络上的面向服务的功能(例如 SOME-IP)
三、Automotive快速上手
3.1 环境搭建
Google 官方的系统镜像暂时无法下载,需要添加其他OEM厂商的镜像,推荐 Volvo 和 Polestar。以 Volvo 为例,打开Android Studio的SDK Manager, 添加SDK Update Site。
Name: Volvo System Image
URL:https://developer.volvocars.com/sdk/volvo-sys-img.xml
Polestar的镜像URL地址是:https://developer.polestar.com/sdk/polestar2-sys-img.xml
然后,切换到SDK Platforms页面,选中Volvo,下载镜像。
接下来,选择设备类型 Automotive 下的 Volvo XC40创建AAOS虚拟机,选择 x86 Images 下的 Android 10.0 (Volvo XC40)。
创建成功之后,启动虚拟机,查看运行效果。
除了 Drawer、Video、座椅、空调等 Icon 以外还有 Map、BT、Google Assistant 这几个常用 App。Car 使用说明 App 的截图如下:
3.2 创建项目
打开Android Studio创建一个Android项目,创建时选择 Automotive/ No Activity选项即可,如下图。
然后添加automotive依赖,如下所示。
implementation("androidx.car.app:app-automotive:1.2.0")
3.2.1 开发代码
创建 一个CarAppService,它是应用和主机之间通信的桥梁,代码如下。
import android.content.pm.ApplicationInfo
import androidx.car.app.CarAppService
import androidx.car.app.Session
import androidx.car.app.validation.HostValidator
class CarService:CarAppService() {
override fun createHostValidator(): HostValidator {
return if (applicationInfo.flags and ApplicationInfo.FLAG_DEBUGGABLE != 0) {
HostValidator.ALLOW_ALL_HOSTS_VALIDATOR
} else {
HostValidator.Builder(applicationContext)
.addAllowedHosts(R.array.hosts_allowlist)
.build()
}
}
override fun onCreateSession(): Session {
return CarSession()
}
}
CarAppService需要重写两个方法:createHostValidator和onCreateSession。其中,在createHostValidator方法中返回信任的主机白名单, 在onCreateSeesion方法中返回CarSession。白名单参考:androidx.car.app.R.array.hosts_allowlist_sample。
然后,创建 Session,它是应用打开之后,返回第一个显示的页面,代码如下。
import android.content.Intent
import androidx.car.app.Screen
import androidx.car.app.Session
class CarSession: Session() {
override fun onCreateScreen(intent: Intent): Screen {
return CarScreen(carContext)
}
}
CarSession中需要创建一个Screen,它控制页面中显示的元素和数据,代码如下。
import androidx.car.app.CarContext
import androidx.car.app.Screen
import androidx.car.app.model.Action
import androidx.car.app.model.ItemList
import androidx.car.app.model.ListTemplate
import androidx.car.app.model.Row
import androidx.car.app.model.Template
class CarScreen(carContext: CarContext) : Screen(carContext) {
override fun onGetTemplate(): Template {
val row = Row.Builder()
.setTitle("Hello Automotive OS")
.build()
val list = ItemList.Builder().addItem(row).build()
return ListTemplate.Builder()
.setSingleList(list)
.setTitle("Hello World")
.setHeaderAction(Action.APP_ICON)
.build()
}
}
3.3.2 配置Manifest 文件
接下来,需要配置一下Manifest 文件。首先,标记应用为汽车应用:
<application>
...
<meta-data
android:name="com.android.automotive"
android:resource="@xml/automotive_app_desc" />
...
</application>
对应的automotive_app_desc代码如下。
//res/xml/automotive_app_desc.xml
<?xml version="1.0" encoding="utf-8"?>
<automotiveApp>
<uses name="template"/>
</automotiveApp>
然后,标记使用的最小API版本。
<application>
...
<meta-data
android:name="androidx.car.app.minCarApiLevel"
android:value="1" />
...
</application>
如果主机应用的版本不支持当前的API版本,会通知更新主机应用。
然后注册CarAppService:
<application>
...
<service
android:name="com.xzh.car.CarService"
android:exported="true">
<intent-filter>
<action android:name="androidx.car.app.CarAppService" />
</intent-filter>
</service>
...
</application>
声明使用和未使用的功能:
<manifest>
...
<uses-feature
android:name="android.hardware.type.automotive"
android:required="true" />
<uses-feature
android:name="android.software.car.templates_host"
android:required="true" />
<uses-feature
android:name="android.hardware.wifi"
android:required="false" />
<uses-feature
android:name="android.hardware.screen.portrait"
android:required="false" />
<uses-feature
android:name="android.hardware.screen.landscape"
android:required="false" />
<uses-feature
android:name="android.hardware.camera"
android:required="false" />
...
</manifest>
和开发手机应用不同的是需要同时声明不使用的功能,否则应用可能无法在不支持这些功能的汽车中使用。
声明Automotive OS中使用的Activity:
<application>
...
<activity
android:name="androidx.car.app.activity.CarAppActivity"
android:exported="true"
android:label="Hello World"
android:launchMode="singleTask"
android:theme="@android:style/Theme.DeviceDefault.NoActionBar">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<meta-data
android:name="distractionOptimized"
android:value="true" />
</activity>
...
</application>
其中 distractionOptimized 为 true 时表示应用可以在驾驶时使用。完成上述配置之后,启动模拟器,然后运行项目。
3.3 示例代码
考虑到大家对Car开发还不是很熟悉,官方提供了一些实例,代码链接:https://github.com/android/car-samples。其兼顾了 Phone 和 Automotive 两种开发场景。将 App 共通的 Car 部分放 置在 Common Module 里,各自的逻辑放在独立的 Module 中。
好处是编译 Phone Task 的话生成的 Apk 安装在 Phone 上,当其进入 Android Auto 模式之后会自动加 载 Common 里的 Car 逻辑。而编译到 Automotive 的 Apk 可直接运行在 AAOS 上,以执行 Common 逻辑和特有的 Car 逻辑。有点需要注意的是该 Sample 的 Gradle 和 AGP 版本需要升级到最新,才能编译通过。
可以利用 DHU 将手机转为 Android Auto 模式,这样的话就可以测试 App 的 Auto 模式下的表现。
不过,Automotive 的 Sample Apk 运行到 Volvo 和 Polestar2 模拟器中都是如下结果,貌似无法正常使用。
经过日志排查和文档确认发现 Sample 依赖了 Car 中最新的特性,需要 AAOS 去下载和安装最新版的 Google Automotvie App Host Apk。
该 App 需要 11 及以上的 AAOS 系统,而 Volvo 和 Polestar2 公开的最新的版本都是 10 该 App 在 APK Downloader 等网站上均无法直接下载。Volvo 的 AAOS Emulator 上 GooglePlay 无法连接网络。
如果有知道怎么解决的,可以帮忙解答一下。
参考文档:
https://juejin.cn/post/7204670801243652154
https://developer.android.com/training/cars/apps?hl=zh-cn
https://github.com/android/car-samples
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)