AndroidAutomotive模块介绍(二)应用及接口介绍

前言

上一篇文章中从整体角度描述了 Android Automotive 模块。本篇文章将对 Android Automotive 中的 APP 以及 API 部分展开描述。
上一篇:AndroidAutomotive模块介绍(一)整体介绍
下一篇:AndroidAutomotive模块介绍(三)CarService服务

正文

1、CarServiceApp

Android Automotive 为系统定制了一些专门适用车载系统的应用,以代替传统的手机应用模块。

1.1 代码路径

代码路径为:/android/packages/apps/Car

1.2 应用

代码路径应用如下所示:

ubuntu16-017:/android/packages/apps/Car$ ls -l
total 76
drwxrwxr-x  6  domain users 4096 Nov  9  2022 Cluster
drwxrwxr-x  6  domain users 4096 Nov  9  2022 Dialer
drwxrwxr-x  3  domain users 4096 Jun  7  2022 externallibs
drwxrwxr-x  5  domain users 4096 Nov  9  2022 Hvac
drwxrwxr-x  5  domain users 4096 Nov  9  2022 LatinIME
drwxrwxr-x  5  domain users 4096 Nov  9  2022 Launcher
drwxrwxr-x  5  domain users 4096 Nov  9  2022 LensPicker
drwxrwxr-x 18  domain users 4096 Nov  9  2022 libs
drwxrwxr-x  5  domain users 4096 Nov  9  2022 LinkViewer
drwxrwxr-x  6  domain users 4096 Nov  9  2022 LocalMediaPlayer
drwxrwxr-x  5  domain users 4096 Nov  9  2022 Media
drwxrwxr-x  6  domain users 4096 Nov  9  2022 Messenger
drwxrwxr-x  6  domain users 4096 Nov  9  2022 Notification
drwxrwxr-x  3  domain users 4096 Jun  7  2022 Overview
drwxrwxr-x  5  domain users 4096 Nov  9  2022 Radio
drwxrwxr-x  6  domain users 4096 Nov  9  2022 Settings
drwxrwxr-x  3  domain users 4096 Jun  7  2022 Stream
drwxrwxr-x  5  domain users 4096 May 11  2023 SystemUpdater
drwxrwxr-x  5  domain users 4096 Nov  9  2022 tests

原生提供了许多应用,介绍如下:

应用描述
Cluster仪表板
Dialer电话
Hvac空调
LatinIME输入法
Launcher桌面
LensPicker活动窗口选择应用(Launcher)
LinkViewer二维码
LocalMediaPlayer本地播放器
Media媒体应用
Messenger消息管理应用(消息及TTS)
Notification通知
Overview音源声卡选择应用
Radio收音机
Settings设置
Stream音源管理应用
SystemUpdater系统升级
test测试
libs支持库

2、CarServiceApi

2.1 代码路径

CarServiceApi 代码路径为 /android/packages/services/Car/car-lib。

ubuntu16-017:/android/packages/services/Car/car-lib$ ls -l
total 32
-rw-r--r-- 1  domain users 7494 Nov  9  2022 Android.bp
-rw-r--r-- 1  domain users  932 Nov  9  2022 AndroidManifest.xml
-rw-r--r-- 1  domain users 1535 Nov  9  2022 Android.mk
drwxrwxr-x 4  domain users 4096 Nov  9  2022 api
drwxrwxr-x 4  domain users 4096 Jun  7  2022 native
drwxrwxr-x 4  domain users 4096 Jun  7  2022 src
drwxrwxr-x 3  domain users 4096 Jun  7  2022 src_feature_future

如上所示,Android.bp 是 car-lib 的编译文件;AndroidManifest.xml 是编译配置文件;Android.mk 描述了添加 car-lib 到系统编译中;api 文件夹中描述了 car-lib 所支持的接口描述 txt 文件;native 文件夹中保存了 car-lib 所需的 libcarpowermanager 库,关于 CarPower 模块的回调信息;src 中描述了 car-lib 提供的接口代码;src_feature_future 文件夹下主要保存 FeatureConfiguration.java 文件,以静态变量的方式保存有关 feature 的默认状态。

2.2 Api 介绍

2.2.1 编译
2.2.1.1 编译命令

编译 Carlib 有三种不同的指令

2.2.1.1.1 make android.car

android.car 编译出的 Carlib 库包含 Car API 中定义的所有方法和实现细节。

编译结果保存到:/out/target/common/obj/JAVA_LIBRARIES/android.car_intermediates 路径下。

2.2.1.1.2 make android.car-system-stubs

android.car-system-stubs 包含了 Car 服务端的 API 接口定义,但不包含实际的实现代码。主要用于在开发 Car 服务时进行编译和链接,以便在编译时检查代码的正确性。确保 Car 服务与 Car 应用之间的通信接口正确对接。

2.2.1.1.3 make android.car-stubs

make android.car-stubs 包含了 Car 应用的 API 接口定义,但并不包含实际的实现代码。主要用于在开发 Car 应用时进行编译和链接,以便在编译时检查代码的正确性。确保 Car 应用与 Car 服务之间的通信接口正确对接。

2.2.1.2 编译文件

下面通过 Android.bp 文件分析下 car-lib 编译逻辑:

// 编译 libcarpowermanager 静态库,主要编译文件是 native 目录下的 CarPowerManager 相关文件
cc_library {name: "libcarpowermanager",aidl: {export_aidl_headers: true,local_include_dirs: ["src",],},cflags: ["-Wall","-Werror","-Wextra","-Wno-unused-parameter",],include_dirs: ["packages/services/Car/car-lib/native/include",],shared_libs: ["libbinder","liblog","libutils",],srcs: ["src/android/car/ICar.aidl","src/android/car/hardware/power/ICarPower.aidl","src/android/car/hardware/power/ICarPowerStateListener.aidl","native/CarPowerManager/CarPowerManager.cpp",],
}java_library {name: "android.car.cluster.navigation",proto: {type: "lite",},static_libs: ["libprotobuf-java-lite"],srcs: ["src/android/car/navigation/navigation_state.proto"]
}// android.car 库,是 Carlib API 库
java_library {name: "android.car",srcs: ["src/**/*.java","src_feature_future/**/*.java","src/**/I*.aidl",],static_libs: ["android.hardware.automotive.YFvehicle-V2.0-java"],aidl: {include_dirs: ["system/bt/binder",],},exclude_srcs: ["src/android/car/storagemonitoring/IoStats.aidl","src/android/car/storagemonitoring/IoStatsEntry.aidl",],product_variables: {pdk: {enabled: false,},},installable: true,
}// android.car-stubs 库,Car 应用端的 API 接口定义,不包含实现代码逻辑。
java_library_static {name: "android.car-stubs",srcs: [":android.car-stub-docs",],libs: ["android.car",],product_variables: {pdk: {enabled: false,},},compile_dex: true,dist: {targets: ["dist_files"],}
}// android.car-system-stubs 库。Car 服务端 API 接口定义,不包含实现代码逻辑。
java_library_static {name: "android.car-system-stubs",srcs: [":android.car-system-stubs-docs",],libs: ["android.car",],product_variables: {pdk: {enabled: false,},},compile_dex: true,dist: {targets: ["dist_files"],}
}

在源码中添加 AndroidAutomotive 相关编译,包括 APP、Jar 包、CarService 服务等,编译文件在 /android/packages/services/Car/car_product/build/car.mk 文件中。

# Automotive specific packages 添加 Automotive 应用编译
PRODUCT_PACKAGES += \CarFrameworkPackageStubs \CarService \CarDialerApp \OverviewApp \CarLauncher \CarSystemUI \LocalMediaPlayer \CarMediaApp \CarMapsPlaceholder \CarSettings \android.car \car-frameworks-service \com.android.car.procfsinspector \libcar-framework-service-jni \CarHvacApp \# should add to BOOT_JARS only once 添加 Carlib Jar 包编译
ifeq (,$(INCLUDED_ANDROID_CAR_TO_PRODUCT_BOOT_JARS))
PRODUCT_BOOT_JARS += \android.carPRODUCT_HIDDENAPI_STUBS := \android.car-stubsPRODUCT_HIDDENAPI_STUBS_SYSTEM := \android.car-system-stubsPRODUCT_HIDDENAPI_STUBS_TEST := \android.car-test-stubs
2.2.2 Api 分类

Android Automotive 的 carlib 是一个用于 Car 应用开发的库,提供了一系列 API 接口供开发者使用。

CarApi 类图如下所示:
在这里插入图片描述

下表是所有 Car-lib API 接口描述:

接口类说明
CarAudioManager用于管理车辆音频统的接口,可以控制音量、音频输入输出等功能
CarSensorManager用于访问车辆传感器数据的接口,可以获取车辆的加速度、转向角度、车辆倾斜角度等传感器数据
CarInfoManager用于获取车辆信息的接口,可以获取车辆的VIN码、车辆速度、车辆位置等信息
CarDiagManager用于控制汽车EOL/Diag系统的接口
CarAppFocusManager设置和监听当前应用焦点的接口
CarPackageManager提供专用的和包管理相关的接口
CarNavigationStatusManager为仪表盘提供导航状态的接口
CarCabinManager控制汽车座舱系统的接口(CarPropertyManager 代替)
CarDiagnosticManager监控诊断数据的接口
CarHvacManager控制空调系统的接口(CarPropertyManager 代替)
CarPowerManager接收电源状态变化的接口
CarProjectionManager投屏管理接口
CarPropertyManager与车辆属性交互的接口
CarVendorExtensionManager访问厂商扩展车辆属性的接口(CarPropertyManager 代替)
CarInstrumentClusterManager配合仪表控制的接口(CarPropertyManager 代替)
CarTestManagerBinderWrapper仅用于系统测试
VmsSubscriberManager供地图服务订阅者使用的接口
CarBluetoothManager提供和特定的汽车蓝牙管理器交互的接口
CarStorageMonitoringManager检索闪存信息的接口
CarDrivingStateManager获取与驾驶状态相关信息的接口
CarUxRestrictionsManager获取驾驶过程中用户体验限制的接口
CarConfigurationManager显示存储在系统中的车辆配置值的接口
CarTrustAgentEnrollmentManager授权可信任设备的接口
CarMediaManager接收媒体音源变化的接口
CarBugreportManager报告错误的接口

Car-lib 常用的接口类有:

  • CarApiManager:

用于管理Car API的接口,可以通过该接口获取Car的各种功能模块,如 CarInfoManager、 CarSensorManager 等。

  • CarInfoManager:

用于获取车辆信息的接口,可以获取车辆的VIN码、车辆速度、车辆位置等信息。

  • CarSensorManager:

用于访问车辆传感器数据的接口,可以获取车辆的加速度、转向角度、车辆倾斜角度等传感器数据。

  • CarAudioManager:

用于管理车辆音频系统的接口,可以控制音量、音频输入输出等功能。

  • CarNavigationManager:

用于车辆导航功能的接口,可以获取车辆当前位置、目的地信息等。

  • CarPackageManager:

用于管理Car应用包的接口,可以安装、卸载、启动 Car 应用。

  • CarProjectionManager:

用于管理车辆投影功能的接口,可以控制车辆的投影屏幕显示。

  • CarInputManager:

用于处理车辆输入事件的接口,可以处理车辆上的按键事件、触摸事件等。

2.3 Api 使用方法

CarService 中各个服务本质上是 AIDL 接口的实现类,属于 Server 端,而对应的 Client 端就需要一个 IBinder 对象来访问 Server 端的方法,这些 IBinder 对象在 Car API 中被封装在一个个 XXXManager 类中。

Car API 与 CarService 中的服务,名称上存在对应关系,所以很好理解。例如:CarWatchdogManager 对应 CarWatchdogService,CarMediaManager 对应 CarMediaService。

不过也有例外:CarInfoManager、CarSensorManager、CarHvacManager、CarCabinManager、CarVendorExtensionManager 都对应 CarPropertyService。但是在 Android 11 中这些 Manager 都已经过时,Google 建议统一使用 CarPropertyManager。

对于 Car SDK 的调用,在 Android 9 与 Android 10 版本略有不同。

2.3.1 Car 类

Car 类是 Android Automotive 的 API 接口,Car 是 Car-lib 总功能的入口,Car 类中包含许多的 Manager,通过 getCarManager(String) 获取 Car-lib 提供的接口对象。

常用方法如下:

方法描述
public static Car createCar(Context context)获取Car实例
public static Car createCar(Context context, @Nullable Handler handler)获取Car实例
public static Car createCar(@NonNull Context context, @Nullable Handler handler, long waitTimeoutMs, @NonNull CarServiceLifecycleListener statusChangeListener)获取Car实例
public Object getCarManager(String serviceName)获取子Manager
public boolean isConnected()判断是否和CarService保持连接
public void disconnect()断开和CarService的连接
2.3.1.1 createCar()

createCar() 函数是应用创建 Car 对象的调用方法,这里来分析下 createCar() 函数的代码流程,下面是 /android/packages/services/Car/car-lib/src/android/car/Car.java 文件内容

    public static Car createCar(Context context, @Nullable Handler handler) {Log.i(TAG_CAR, "createCar");Car car = null;IBinder service = null;boolean started = false;int retryCount = 0;while (true) {service = ServiceManager.getService(CAR_SERVICE_BINDER_SERVICE_NAME);if (car == null) {// service can be still null. The constructor is safe for null service.car = new Car(context, ICar.Stub.asInterface(service),null /*serviceConnectionListener*/, null /*statusChangeListener*/, handler);}if (service != null) {if (!started) {  // specialization for most common case.return car;}break;}if (!started) {car.startCarService();started = true;}retryCount++;if (retryCount > CAR_SERVICE_BINDER_POLLING_MAX_RETRY) {Log.e(TAG_CAR, "cannot get car_service, waited for car service (ms):"+ CAR_SERVICE_BINDER_POLLING_INTERVAL_MS* CAR_SERVICE_BINDER_POLLING_MAX_RETRY,new RuntimeException());return null;}try {Thread.sleep(CAR_SERVICE_BINDER_POLLING_INTERVAL_MS);} catch (InterruptedException e) {Log.e(CarLibLog.TAG_CAR, "interrupted while waiting for car_service",new RuntimeException());return null;}}// Can be accessed from mServiceConnectionListener in main thread.synchronized (car) {if (car.mService == null) {car.mService = ICar.Stub.asInterface(service);Log.w(TAG_CAR,"waited for car_service (ms):"+ CAR_SERVICE_BINDER_POLLING_INTERVAL_MS * retryCount,new RuntimeException());}car.mConnectionState = STATE_CONNECTED;}return car;}

1、通过一个 while 循环一直去创建 Car 实例,并且建立与 CarService 服务的连接,直到实例化成功或者创建次数超过最大限制 CAR_SERVICE_BINDER_POLLING_MAX_RETRY(100)。

2、service = ServiceManager.getService(CAR_SERVICE_BINDER_SERVICE_NAME);首先获取CarService的服务实例

3、car = new Car(context, ICar.Stub.asInterface(service), null , null, handler); 这里前面方法中声明,所以判断一定是null,会new一个Car实例。

4、car.startCarService(); 这里实际是去用Bind的方式启动 CarService。

5、if (retryCount > CAR_SERVICE_BINDER_POLLING_MAX_RETRY) { 这里会有个判断重试的次数,如果超过次数还没取到 CarService 服务,则会返回 null。sleep 的时间是 50ms,重试 100 次,也就是获取 Car 实例最长时间长达 5 s。

2.3.1.2 startCarService()

startCarService() 函数实际是调用 Context.bindServiceAsUser() 函数去启动 CarService 服务。

下面是 startCarService() 函数逻辑:

    private void startCarService() {Intent intent = new Intent();intent.setPackage(CAR_SERVICE_PACKAGE);intent.setAction(Car.CAR_SERVICE_INTERFACE_NAME);boolean bound = mContext.bindServiceAsUser(intent, mServiceConnectionListener,Context.BIND_AUTO_CREATE, UserHandle.CURRENT_OR_SELF);Log.i(TAG_CAR, "bindServiceAsUser bound" +bound);synchronized (mLock) {if (!bound) {Log.i(TAG_CAR, "bindServiceAsUser 1");mConnectionRetryCount++;if (mConnectionRetryCount > CAR_SERVICE_BIND_MAX_RETRY) {Log.w(TAG_CAR, "cannot bind to car service after max retry");mMainThreadEventHandler.post(mConnectionRetryFailedRunnable);} else {Log.i(TAG_CAR, "bindServiceAsUser 2");mEventHandler.postDelayed(mConnectionRetryRunnable,CAR_SERVICE_BIND_RETRY_INTERVAL_MS);}} else {Log.i(TAG_CAR, "bindServiceAsUser 3");mEventHandler.removeCallbacks(mConnectionRetryRunnable);mMainThreadEventHandler.removeCallbacks(mConnectionRetryFailedRunnable);mConnectionRetryCount = 0;mServiceBound = true;}}}

如果调用 Context.bindServiceAsUser() 启动 CarService 服务失败,会重试连接 CAR_SERVICE_BIND_MAX_RETRY (20) 次。超过尝试次数后会调用 mConnectionRetryFailedRunnable。

2.3.1.3 connect()

connect() 方法实际就是调用 startCarService() 方法,因为 connect() 是公开的,startCarService() 是私有的。connect() 函数只能调用一次,如果当前已经处于连接状态,再次调用 connect() 函数会抛 IllegalStateException 异常,client 没有捕获该异常,则会引起 client 程序的崩溃。

    public void connect() throws IllegalStateException {synchronized (mLock) {if (mConnectionState != STATE_DISCONNECTED) {throw new IllegalStateException("already connected or connecting");}mConnectionState = STATE_CONNECTING;startCarService();}}

connect() 已经弃用了,我们知道 startCarService() 就是和 CarService 建立连接,因为在 CreatCar() 里已经保证获取到 CarService,所以 connect() 不在必要。

2.3.2 示例

通过 Car.createCar() 函数可以创建 Car 对象,参数需要传入 ServiceConnection,并在 service 连接成功后,获取想要的 Manager 实例,调用 connect() 函数,当与 CarService 连接成功后,会回调 ServiceConnection 对象的 onServiceConnected() 函数完成连接。如下所示:

private final ServiceConnection mCarServiceConnection = new ServiceConnection() {@Overridepublic void onServiceConnected(ComponentName name, IBinder service) {try {CarHvacManager manager = (CarHvacManager) mCarApiClient.getCarManager(Car.HVAC_SERVICE);} catch (CarNotConnectedException e) {Log.e(TAG, "Car not connected in onServiceConnected");}}@Overridepublic void onServiceDisconnected(ComponentName name) {}
};...
Car carApiClient = Car.createCar(context, mCarServiceConnection);
carApiClient.connect();
...

但是在 Android 10 以后,Google 改写了 Car API 的使用方式,Android 10 以后构建 Car 对象不再建议传入 ServiceConnection 对象,而是使用了下面的方法。

Car carApiClient = Car.createCar(context);
CarHvacManager manager = (CarHvacManager) mCarApiClient.getCarManager(Car.HVAC_SERVICE);

Android 10 以后 Car API 的调用方式由异步方法改为了同步方法,保留了 disconnect(),但是不需要调用 connect(),这样使用起来更加简单。

这种调用方式是 CarService 不发生异常的情况下,Client 端与 CarService 的连接也不会断开,但是如果 CarService 发生异常,Client 端会被直接杀死,使用如下方式可以避免:

Car car = Car.createCar(this, workThreadHandler, 2000, new Car.CarServiceLifecycleListener() {@Overridepublic void onLifecycleChanged(@NonNull Car car, boolean ready) {// ready 在Service断开连接时会变为false
if (ready) {} else {// CarService 发生异常或连接被断开了,需要client端处理。
}}
});

通过创建 Car 对象时传入 CarServiceLifecycleListener 对象,注册回调的方式,通过回调以知道 CarService 的生命周期。

3、总结

本篇文档介绍了 AndroidAutomotive 架构中 APP 应用与 API 接口等内容,对于应用分类、功能、代码;API 接口介绍、初始化、使用方法等。

上一篇:AndroidAutomotive模块介绍(一)整体介绍
下一篇:AndroidAutomotive模块介绍(三)CarService服务

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/615355.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Sam Altman新动向!被曝公开撬金主微软的客户!

Sam Altman向大公司们推销ChatGPT企业版,这其中包括一些微软的客户! 好好好! 你小子怎么回事!金主的客户也不放过了是吧! 根据路透社4月12日的报道,OpenAI首席执行官Sam Altman本月在旧金山、纽约和伦敦举…

数据结构之单链表的相关知识点及应用

找往期文章包括但不限于本期文章中不懂的知识点: 个人主页:我要学编程(ಥ_ಥ)-CSDN博客 所属专栏:数据结构 目录 链表的概念及结构 链表与顺序表的区别与优劣势 链表的分类 单链表的实现 单链表中增加节点 单链表中尾插数据 打印单链…

新手做抖店需要掌握的技巧!这些运营方法,保证让你快速出单!

哈喽~我是电商月月 新手做抖店做不好?除了没努力的原因,还有一点,就是缺少运营的方法! 今天我就给大家普及几个运营过程中非常重要的技巧! 这都是我在运营中总结出来的能提高出单率的干货,新手建议收藏 …

常见的垃圾回收器(上)

文章目录 Serial垃圾回收器 SerialOld垃圾回收器PS POParNewCMS 常见的垃圾回收器(下) Serial垃圾回收器 SerialOld垃圾回收器 Serial是一种单线程串行回收年轻代的垃圾回收器 回收年代和算法 年轻代:复制算法 老年代:标记-整…

grpc-教程(golang版)

目录 一、介绍 二、环境准备 三、Golang中使用grpc 1.编写protobuf文件 2.服务端 3.客户端 四、proto文件详解 1.proto语法 2.数据类型 基本数据类型 数组类型 map类型 嵌套类型 编写风格 3.多服务 4.多个proto文件 五、流式传输 1.普通rpc 2.服务器流式 …

ACL 2024 commit是否提交revision版本的论文

ACL 2024 commit是否提交revision版本的论文? 有大佬知道吗?!! 哎 ARR rebuttal阶段 让我们加实验,回复一时爽。。 现在又要提交pdf到ACL会议了,是提交之前的ARR版本的稿子,还是我承诺的 revision 稿啊&…

Aritest+python+Jenkins解放双手iOS/Android自动化

ARITest、Python 和 Jenkins 可以结合在一起创建一个自动化测试解决方案,实现持续集成和持续测试的目标。以下是三者如何协同工作的基本概念: 1. **ARITest**: ARITest 是一款功能全面的自动化测试工具,提供 UI 自动化、接口自…

【python】基于pyttsx3库的字符串转音频文件

一、源码 import pyttsx3 engine pyttsx3.init() engine.setProperty(volume, 0.8) engine.setProperty(rate, 150) engine.save_to_file("Hello, World!", "output.mp3") engine.runAndWait()二、介绍 使用pyttsx3库,设置声音与速率&#x…

芯片低功耗VCLP

​VCLP(VC Low Power)是Synopsys提供的一款低功耗静态规则检查工具,它能够帮助验证和清洁IEEE 1801 Unified Power Format (UPF)低功耗设计意图,并确保UPF中的功耗意图与实现一致。VCLP通过执行语法和语义检查,有助于在…

【数据结构】习题之链表的回文结构和相交链表

👑个人主页:啊Q闻 🎇收录专栏:《数据结构》 🎉前路漫漫亦灿灿 前言 今日的习题是关于链表的,分别是链表的回文结构和相交链表的判断。 链表的回文结构 题目为:链表的回文结…

streamlit 大模型前段界面

结合 langchain 一起使用的工具,可以显示 web 界面 pip install streamlit duckduckgo-search 运行命令 streamlit run D:\Python_project\NLP\大模型学习\test.py import os from dotenv import load_dotenv from langchain_community.llms import Tongyi load…

Redis中的集群(二)

节点 集群数据结构 redisClient结构和clusterLink结构的相同和不同之处 redisClient结构和clusterLink结构都有自己的套接字描述符和输入、输出缓冲区,这两个结构的区别在于,redisClient结构中的套接字和缓冲区是用于连接客户端的,而clust…