车载 Android之 核心服务 - CarPropertyService 解析

重要类的源码文件名及位置:

  • CarPropertyManager.java

packages/services/Car/car-lib/src/android/car/hardware/property/

  • CarPropertyService.java

packages/services/Car/service/src/com/android/car/

类的介绍:

CarPropertyManager:是CarPropertyService在客户端的代理,通过 CarPropertyManager中 提供的 API,可以设置和获取车辆各个属性的状态。但在实际使用时,CarPropertyManager 却未必是开发者使用最频繁的对象。尤其是在 Android9平台上开发时,当开发者想控制 空调相关的功能的时候,也许会使用 CarHvacManager;当想获取车辆信息的时候,也许会 使用 CarInfoManager;当想获取车辆传感器数据的时候,会使用 CarSensorManager。但其 实无论是 CarHvacManager还是 CarInfoManager或是 CarSensorManager,它们最后都会 通过 CarPropertyManager来获取设置属性,在服务端对应的都是 CarPropertyService。通 过ICarImpl中getCarService方法也可以很清楚地发现这一点,在Android 10中,谷歌官方直接推荐使用CarPropertyManager;

CarPropertyService:绝大部分与车辆硬件相关联的属性,如空调、车舱功能、车辆传感器等都是通过CarPropertyService来读取或者设置的。

类的使用:

CarPropertyManager:在安卓9中CarPropertyManger还是隐藏(hide)接口,所以不会在公开的SDK中出现,但是它十分重要。而在Android 10中,CarPropertyManger变成了车辆属性的主要API,并允许任何运行在Android Automotive OS上的应用进行调用。初看CarPropertyManger会觉得很熟悉,它的方法包括(但不限于)以下这些:

boolean registerListener(CarPropertyEventCallback callback, int prop, float rate)
boolean isPropertyAvailable(int propId, int area) 
boolean getBooleanProperty(int prop, int area)
float getFloatProperty(int prop, int area)
int getIntProperty(int prop, int area)
int[] getIntArrayProperty(int prop, int area)
<E> CarPropertyValue <E> getProperty(Class <E> clazz, int propId, int area) 
<E> CarPropertyValue <E> getProperty(int prop, int area)
<E> void setProperty()(Class <E> clazz, int propId, int area,E val) 
void setBooleanProperty(int prop, int area, boolean val)
void setFloatProperty (int prop int area, float val)
void setIntProperty (int prop, int area, int val) 

看到这些方法,就会发现和 CarHvacManager、CarVendorExtensionManager等服务中 的方法定 义 很 类 似。在 使 用 方 法 上 和 之 前 提 到 的 几 个 服 务 也 是 一 样 的。其 实,无 论 是 CarInfoManager,还是 CarSensorManager或 CarHvacManager,它们的功能都可以直接通 过 CarPropertyManager来完成。

1.CarPropertyManager的用法

熟悉了 CarHvacManager、CarVendorExtensionManager等几个相关服务的用法之后, 在 CarPropertyManager的使用上,相信读者对相关方法已经很了解了。这里再做一些简单 的补充。 关于属 性 的 获 取,在 CarPropertyManager 中 除 了 getProperty 方 法 之 外,还 有 像 getBooleanProperty、getIntProperty这样明确属性类型的获取方法。其实这些方法只是对 于getProperty方法的封装,以getIntProperty为例,它的实现是这样的:

看上去在明确知道属性类型的情况下,getBooleanProperty、getIntProperty等方法在 使用上更加简洁。但是在这里,依然推荐开发者们使用getProperty来获取相应的属性值, 因为getProperty方法返回的是 CarPropertyValue对象,其不仅包含属性值,还包含属性的 状态,而getIntProperty等方法在属性不可用的情况下,返回的是默认值,这在有的时候会 导致读取的数据不正确。 下面以 NIGHT_MODE(昼夜模式)属性为例,说明使用getProperty方法的好处。

从这段源码中,可以很直观地看到使用getProperty方法,与getBooleanProperty方法 获取昼夜状态相比,可以更准确地判断当前属性的状态,并在属性不支持或不可用时,使用 更合理的处理逻辑。因此,虽然 getProperty方法会增加源码的数量,但在大部分情况下, 依然推荐大家使用该方式获取属性。

        在注册 监 听 属 性 变 化 方 面,CarPropertyManager 提 供 更 细 颗 粒 度 的 监 听 方 法, registerListener① 方法可以监听单个属性值的变化,开发者可以通过在注册监听器时传入 属性ID指定监听器所对应的属性。同时,可以指定数据上报的频率,与5.2节介绍的一样, 该频率与属性类型和其他监听器的频率有关,并不能保证数据会以传入的期望频率进行上 报。监听属性的方式,可参考以下源码:

CarPropertyManager.CarPropertyEventListener mCarPropertyEventListener = new CarPropertyManager.CarPropertyEventListener() {@Overridepublic void onChangeEvent(CarPropertyValue value) {}@Overridepublic void onErrorEvent(int propId, int zone) {}};mCarPropertyManager.registerListener(mCarPropertyEventListener,VehiclePropertyIds.PERF_VEHICLE_SPEED,/ * rate=* / 5);

2.CarPropertyManager的相关类

除了和 CarPropertyManager相关的这几个 Manager之外,在之前的例子中,还出现了 如 VehiclePropertyIds、CarPropertyValue、CarPropertyConfig等相关的辅助类,由于种类 繁多,有必要在这里梳理一下各个辅助类的作用。

(1)VehiclePropertyIds,CarPropertyManager都是通过属性ID来对应具体的功能的, 不同功能对应不同的ID,VehiclePropertyIds中列出了所有在 VehicleHAL 中定义的功能 属性,是AndroidAutomotiveOS官方定义的属性集合。

(2)VehicleAreaDoor,许多功能点都分多个区域,在设置、获取相应属性时,需要传入区域 参数,VehicleAreaDoor定义了与车门相关的区域值,在使用与车门相关的属性时配套使用。

(3)VehicleAreaMirror,与 VehicleAreaDoor类似,多区域定义,后视镜区域值。

(4)VehicleAreaSeat,多区域定义,座位区域值。

(5)VehicleAreaWheel,多区域定义,车胎区域值。

(6)VehicleAreaWindow,多区域定义,车窗区域值。

(7)VehicleAreaType,区域类型是用以区分一个属性所对应的位置的。对于非多区域 属性,往往使用 VEHICLE_AREA_TYPE_GLOBAL 作为其区域ID。每个区域属性都必 须使用预定义的区域类型,即车门、车窗、座椅、轮胎、后视镜中的一个。每种区域类型都有 一组在区域类型的枚举中定义的位标记,也就是前文中使用的像SEAT_ROW_1_LEFT 这 53 第 5 章 CarPropertyService———车辆属性服务 样具体的区域值。

(8)VehicleLightState,灯光状态,开、关、日间。

(9)VehicleLightSwitch,灯光切换,开、关、日间、自动。

(10)VehicleOilLevel,油量状态。

以上这些辅助类中,都定义了相关的静态变量,同时,这些值都与 VehicleHAL 的相关 定义一一对应,在 CarAPI中将其再次定义是为了方便上层应用使用。

        除了以上 几 个 定 义 静 态 变 量 的 辅 助 类 以 外,还 会 经 常 用 到 CarPropertyConfig 和 CarPropertyValue这两个模板类。CarPropertyConfig和 CarPropertyValue非常有用,通 过前者能获取到一个属性的静态参数,如取值范围、类型、支持的区域等;通过后者能获取 一个属性的值和状态。

        这里举两个简单的例子。

        (1)通过 CarPropertyManager获取当前车辆支持的属性(注意,需要拥有对应属性的 权限才能获取)。

CarPropertyConfig对象的成员变量如表5-4所示。

开发者可以通过以上成员变量对应的 get方法获取具体的值。对于区域属性来说, CarPropertyConfig中还封装了额外的方法方便开发者获取特定区域的取值,AreaConfig类 的getMinValue、getMaxValue方法可以返回某一属性特定区域的取值范围。

        (2)通过 CarPropertyManager获取当前的车速。

        CarPropertyValue对象的成员变量如表5-5所示。

虽然看上去很简单,但实际使用过程中会涉及较多的判断,开发者可以进一步对属性进 行封装管理,并总结一些有用的实践。CarPropertyConfig和 CarPropertyValue这两个类 同样 和 VehicleHAL 中 的 定 义 的 结 构 体 相 关 联,CarService 会 将 从 HAL 层 获 取 的 VehiclePropConfig和 VehiclePropValue① 分别转换为CarPropertyConfig和CarPropertyValue。

3.进一步了解 CarPropertyManager 

通过前文的介绍,读者应该已经了解了 CarPropertyManager的重要性。因此有必要进 一步了解 CarPropertyManager背后的原理,更全面地掌握它。 熟悉 Android的读者应该知道,在 Android中往往一个 Manager会对应一个Service,例如 ActivityManager对应着 ActivityManagerService;PackageManager对应着PackageManagerService。 它 们 运 行 在 不 同 的 进 程 中,通 过 Binder 这 一 IPC 机 制 进 行 通 信。 同 样 地,与 CarPropertyManager相对应的是 CarPropertyService这一服务。 同时,读者如果对车辆电子电器的架构有一定了解,那么应该知道,各个具体的功能往 往有对应的电子控制单元(ElectronicControlUnit,ECU)进行控制。例如,控制座椅位置 的命令,最终需要发送到负责控制座椅的 ECU 中才能使座椅移动。 因此,一次控制命令的调用过程大致如图5-1所示。

上层的应用通过 CarAPI提供的接口进行设置,最终通过车辆总线将命令发送给对应 的 ECU,ECU 返 回 结 果 给 CarService,并 通 过 回 调 通 知 相 关 应 用。 这 一 过 程 中 的 ① VehiclePropConfig和 VehiclePropValue定义在/hardware/interfaces/automotive/vehicle/2.0/types.hal文件中。 55 第 5 章 CarPropertyService———车辆属性服务 VehicleHAL非 常 重 要,它 指 的 是 制 造 商 实 现 的 硬 件 抽 象 层 服 务,实 现 了 Android AutomotiveOS定义的相关硬件抽象层接口。由于不同汽车制造商与ECU 的通信方式、标 准、数据格式都不尽相同,所以需要对其进行抽象,统一接口,而具体逻辑则由汽车制造商自 己实现。关于 VehicleHAL的具体内容,会在后面的章节再展开。 下面通过源码,进一步了解 CarPropertyManager中的具体实现,建议读者在阅读的同 时打开源码文件进行查看。 以下是 CarPropertyManager的构造函数实现:

在 CarPropertyManager的构造函数中,获得了ICarProperty的远程对象,通过该远程 对象就可以调用 CarPropertyService。关于 Binder机制的具体实现及 AIDL 的调用过程, 在此就不做展开了①。 再来看看 CarPropertyManager的setProperty的调用过程:

通过 mService对象,调用 CarPropertyService中对应的方法:

这里出现了一个新的对象 mHal,它是 PropertyHalService对象的实例。

接着调用 VehicleHal的set方法,虽然对象命名叫 VehicleHal,但该 VehicleHal对象 依然是在CarService进程中定义并创建的对象。还没有看到对 HAL层的Binder调用。接着往下:

VehicleHal中的set方法只是进一步调用了 HalClient对象的setValue方法。

在 HalClient的setValue方法中,终于发现这个 mVehicle对象是一个 HIDL调用的远 程对象,通过它,实际上调用的是抽象层 VehicleHal的实现。这里涉及了 Android8.0引入 的 HIDL机制,不详细展开了①。随着 HIDL 机制的引入,VehicleHal运行在独立的进程 中,由设备制造商或汽车制造商进行实现。

        以上就是一次完整的设置属性值的调用过程,可以看到设置命令最终将发送给制造商 实现的 VehicleHal进程,并由 VehicleHal最终完成该次调用。

        再来追踪 VehicleHal中的事件的传递过程。

        通过设置的流程,可以发现发起 HIDL调用的远程对象是被 HalClient对象所持有的, 与 VehicleHal的 直 接 交 互 是 在 HalClient 中 完 成 的。 因 此 事 件 的 向 上 传 递 也 是 从 HalClient开始的。在收到上报的事件之前,上层应用首先要注册相应的监听方法。

        当应用调用 CarPropertyManager的registerListener方法时,其会调用 CarPropertyService 的registerListener方法。

上述源码进一步 调 用 PropertyHalService的 subscribeProperty 方 法,中 间 会 再 经 过 VehicleHal.java的调用,最后调用 HalClient中的subscribe方法,调用的路径和设置的流 程是一样的。在此省略一些中间过程,直接来看 HalClient的subscribe方法的实现:

  这里将 mInternalCallback对象传递给了 Hal层。mInternalCallback对象的实例是继 承了IVehicleCallback.Stub的 HIDL桩对象,实现如下:              

通过IVehicleCallback,制造商实现的 VehicleHal进程就可以将事件传递给 CarService 进程了。有兴趣的读者可以进一步追踪当IVehicleCallback的onPropertyEvent方法被调 用后,事件又是如何传递给应用注册的监听器的。

        上文出现了一些新的对象,为了便于理解,整理上述类之间的关系,见图5-2。

在 CarService中虽然有 VehicleHal类,但该类并不直接调用 HIDL 方法,而是进一步 调 用 HalClient 封 装 的 方 法,HalClient 才 是 真 正 与 HAL 层 打 交 道 的 类。 同 时, PropertyHalService处理与 CarPropertyService相关的业务逻辑,在后面的内容中,还会接触 InputHalService、PowerHalService,VehicleHal会将不同的事件分发给对应的类进行处理。 总体来说,通过 CarPropertyService的层层调用,最后通过IVehicle与实现了车辆硬件 抽象层的进程通信。VehicleHal进程由各个厂家进行实现,再进一步将消息发送给关联的 ECU,实现控制功能。

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

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

相关文章

航芯ACM32G103开发板评测 02-GPIO输入输出

航芯ACM32G103开发板评测 02-GPIO输入输出 航芯ACM32G103开发板评测 GPIO输入输出应用 软硬件平台 ACM32G103 Board开发板 MDK-ARM Keil GPIO输出典型应用——点灯 GPIO输入典型应用——按键 GPIO 功能概述 GPIO 是通用输入/输出&#xff08;General Purpose I/O&#x…

[Flutter]WindowsOS中相关配置

Flutter项目在Windows平台上如何配置 目录 Flutter项目在Windows平台上如何配置 写在开头 正文 1、OS准备 2、编译环境准备 ① 下载AndroidStudio ② 下载dart ③ 下载flutter ④ 下载并安装VS ⑤ 在AS中配置dart和flutter 3、配置中遇到的问题 写在结尾 写在开头…

C++ stack使用、模拟实现、OJ题

目录 一、介绍 二、常用函数 三、模拟实现 四、OJ练习题 1、最小栈 2、栈的压入、弹出序列 3、逆波兰表达式(后缀转中缀) 4、中缀转后缀思路 5、用栈实现队列 一、介绍 stack是一种容器适配器&#xff0c;专门用在具有后进先出操作的上下文环境中&#xff0c;其删除…

自动驾驶论文

文章目录 一、Convolutional Social Pooling for Vehicle Trajectory Prediction二、QCNet&#xff1a;Query-Centric Trajectory Prediction三、VectorNet: Encoding HD Maps and Agent Dynamics from Vectorized Representation 一、Convolutional Social Pooling for Vehicl…

iOS 小组件开发

iOS14之后Apple引入了新的WidgetKit&#xff0c;舍弃了原有额TodayExtension。 开发准备&#xff1a; 新的WidgetExtension只能通过SwiftUI进行开发&#xff1b; Widget有三种尺寸&#xff1a;systemSmall、 systemMedium、systemLarge&#xff0c;三种尺寸对应固定的UI类型布…

vba之与excel司龄计算

Sub 插入新列并计算司龄()Dim ws As WorksheetDim lastRow As LongDim i As LongDim entryDate As DateDim yearsOfService As Double 指定要操作的工作表Set ws ThisWorkbook.Sheets("测试") &#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#x…

BIND-DNS配置介绍

一、主要配置文件 /etc/named.conf options { //Option 段全部配置 listen-on port 53 { 127.0.0.1; };//表示BIND将在53端口监听&#xff0c;若需要对所有IP进行监听&#xff0c;则修改为// listen-on port 53 { any; }; directory "/var/named"…

yongyou builder 业务流设计相关bug

今天发现了yongyou builder的一个问题&#xff0c;我有一个实体&#xff08;主机预测&#xff09;&#xff0c;另外一个实体&#xff08;业务员预测&#xff09;&#xff0c;要将多张业务员预测的单据合并从一个主机单据&#xff0c;并且如果多张单据下面的表体行中存在相同的销…

(六)数码管动态刷新

文章目录 如何实现利用人眼的余晖效应&#xff08;100hz无闪烁&#xff09;1ms刷一个数码管 8个看起来就是一块亮的 结合前面内容进行操作前面内容传送门&#xff1a;如何段选原理图代码写法这里借助isp复制共阴数码管码值 如何位选原理图代码写法 如何消隐在每次 段选 赋值之前…

[数理统计]中国科技技术大学缪柏其

中国科学技术大学 数理统计 缪柏其 笔记正在不断完善中,博主还有其他上万字精品笔记 ​编辑P10 前言1-统计思想 41:33 介绍了数理统计的重要性和应用领域。主讲人强调了统计学与数学的区别&#xff0c;指出统计学是以数据为研究对象的一门科学&#xff0c;强调了统计思想的重…

面试算法79:所有子集

题目 输入一个不含重复数字的数据集合&#xff0c;请找出它的所有子集。例如&#xff0c;数据集合[1&#xff0c;2]有4个子集&#xff0c;分别是[]、[1]、[2]和[1&#xff0c;2]。 分析 如果集合中包含n个元素&#xff0c;那么生成子集可以分为n步&#xff0c;每一步从集合中…

K8S集群部署MySql

挂载MySQL数据卷 在k8s集群中挂载MySQL数据卷 需要安装一个NFS。 在主节点安装NFS yum install -y nfs-utils rpcbind 在主节点创建目录 mkdir -p /nfs chmod 777 /nfs 更改归属组与用户 chown -R nfsnobody:nfsnobody /nfs 配置共享目录 echo "/nfs *(insecure,rw,s…

linux更改登录shell

从bash修改成python 在/etc/passwd下可以更改用户登录bash 例 root:x:0:0:root:/root:/bin/bash //更改bin/bash为/bin/python&#xff0c;就可以用root登录python页面了从python修改成bash 方法一 重启页面按e进入内核编辑模式linux16这行后添加&#xff1a;init/bin/…

Linux操作系统基础(3):Linux终端的使用

1. Linux终端的介绍 Linux 终端是指在 Linux 操作系统下用于与用户进行交互的命令行界面&#xff08;基于文本的交互&#xff09;。它是用户与操作系统进行直接交互的主要方式&#xff0c;可以通过输入命令来执行各种操作&#xff0c;如文件管理、进程控制、系统配置等。 Lin…

【WPF.NET开发】WPF中的输入

本文内容 输入 API事件路由处理输入事件文本输入触摸和操作侧重点鼠标位置鼠标捕获命令输入系统和基元素 Windows Presentation Foundation (WPF) 子系统提供了一个功能强大的 API&#xff0c;用于从各种设备&#xff08;包括鼠标、键盘、触摸和触笔&#xff09;获取输入。 本…

CTF流量分析经典例题详解

目录 入门题型 题目&#xff1a;Cephalopod(图片提取) 题目&#xff1a;特殊后门(icmp协议信息传输) 题目&#xff1a;手机热点(蓝牙传输协议obex,数据提取) 题目&#xff1a;想蹭网先解开密码(无线密码破解) 进阶题型 题目&#xff1a;抓到一只苍蝇(数据包筛选,数据提…

React16源码: React.Children源码实现

React.Children 1 ) 概述 这个API用的也比较的少&#xff0c;因为大部分情况下&#xff0c;我们不会单独去操作children我们在一个组件内部拿到 props 的时候&#xff0c;我们有props.children这么一个属性大部分情况下&#xff0c;直接把 props.children 把它渲染到我们的jsx…

蓝牙物联网智能车用语音控制系统模块设计

随着信息产业的快速发展&#xff0c;简单的控制操作机器已经不能满足人类的欲望&#xff0c;利用语音识别技术让机器理解人类的语言&#xff0c;以及实现人机交互成为新的研究内容。对用户来说&#xff0c;这种人机交互的方式当是最自然的一种方式。同时&#xff0c;使人们在车…

塔夫特原则

塔夫特原则&#xff08;Tuftes Principles&#xff09;是由数据可视化专家爱德华塔夫特&#xff08;Edward Tufte&#xff09;提出的一组指导性原则&#xff0c;旨在帮助人们创建清晰、有效和有力的数据可视化图表。这些原则强调了以数据为核心&#xff0c;通过简洁、准确和易于…