【Android】VehiclePropertyAccess引起CarService崩溃

VehiclePropertyAccess引起CarService崩溃

VehiclePropertyAccess

VehiclePropertyAccess属性,用于定义车辆属性的访问权限。权限包括

  • 读:READ,只可以读取,不能写入。
VehiclePropertyAccess:READ
  • 写:WRITE,只可以写入,不能读取。
VehiclePropertyAccess:WRITE
  • 读写
VehiclePropertyAccess:READ_WRITE

这些车辆属性被定义在Vechile的types.hal中。编译时,会被转成VehiclPropConfig,记录到每个车辆属性中。
对于车辆属性的操作,在Android11版本,调用CarService注册监听属性,如果违反了其权限规定,会导致CarService崩溃。

原生CarService因为属性注册崩溃

违反VehiclePropertyAccess权限,导致的CarService崩溃
请添加图片描述
某应用调用 CarPropertyManager的registerCallback接口,注册监听属性ID。该操作,导致CarService反复崩溃

崩溃代码流程分析
  • CarPropertyService.java,应用调用registerListener注册监听属性ID
 @Overridepublic void registerListener(int propertyId, float updateRateHz,ICarPropertyEventListener iCarPropertyEventListener) throws IllegalArgumentException{}
  • CarPropertyService.java,服务端对应registerListener的实现
@Override
public void registerListener(int propId, float rate, ICarPropertyEventListener listener)
{if (DBG) {Slog.d(TAG, "registerListener: propId=0x" + toHexString(propId) + " rate=" + rate);}if (listener == null) {Slog.e(TAG, "registerListener: Listener is null.");throw new IllegalArgumentException("listener cannot be null.");}IBinder listenerBinder = listener.asBinder();CarPropertyConfig propertyConfig;Client finalClient;synchronized (mLock) {propertyConfig = mConfigs.get(propId);if (propertyConfig == null) {// Do not attempt to register an invalid propIdSlog.e(TAG, "registerListener:  propId is not in config list: 0x" + toHexString(propId));return;}ICarImpl.assertPermission(mContext, mHal.getReadPermission(propId));// Get or create the client for this listenerClient client = mClientMap.get(listenerBinder);if (client == null) {client = new Client(listener);}client.addProperty(propId, rate);// Insert the client into the propId --> clients mapList<Client> clients = mPropIdClientMap.get(propId);if (clients == null) {clients = new CopyOnWriteArrayList<Client>();mPropIdClientMap.put(propId, clients);}if (!clients.contains(client)) {clients.add(client);}// Set the HAL listener if necessaryif (!mListenerIsSet) {mHal.setListener(this);}// Set the new rateif (rate > mHal.getSampleRate(propId)) {mHal.subscribeProperty(propId, rate);}finalClient = client;}// propertyConfig and client are NonNull.mHandler.post(() ->getAndDispatchPropertyInitValue(propertyConfig, finalClient));
}
  • 两个主要流程:注册属性,获取属性初始值并派发
  public void subscribeProperty(HalServiceBase service, int property,float samplingRateHz, int flags) throws IllegalArgumentException {if (DBG) {Slog.i(CarLog.TAG_HAL, "subscribeProperty, service:" + service+ ", " + toCarPropertyLog(property));}VehiclePropConfig config;synchronized (mLock) {config = mAllProperties.get(property);}if (config == null) {throw new IllegalArgumentException("subscribe error: config is null for property 0x"+ toHexString(property));} else if (isPropertySubscribable(config)) {SubscribeOptions opts = new SubscribeOptions();opts.propId = property;opts.sampleRate = samplingRateHz;opts.flags = flags;synchronized (mLock) {assertServiceOwnerLocked(service, property);mSubscribedProperties.put(property, opts);}try {mHalClient.subscribe(opts);} catch (RemoteException e) {Slog.e(CarLog.TAG_HAL, "Failed to subscribe to " + toCarPropertyLog(property), e);}} else {Slog.e(CarLog.TAG_HAL, "Cannot subscribe to " + toCarPropertyLog(property));}
}
  • VehicleHal.java, isPropertySubscribable判断车辆属性是否可读,如果不可读不能注册。比如属性ID是"VehiclePropertyAccess:READ",就不能注册了。
static boolean isPropertySubscribable(VehiclePropConfig config) {if ((config.access & VehiclePropertyAccess.READ) == 0|| (config.changeMode == VehiclePropertyChangeMode.STATIC)) {return false;}return true;
}
  • 接下来,获取属性初始值。哪怕不能注册的属性ID,也会去获取,所以导致了上面的CarService崩溃问题。CarPropertyService.java
private void getAndDispatchPropertyInitValue(CarPropertyConfig config, Client client) {        List<CarPropertyEvent> events = new LinkedList<>();int propId = config.getPropertyId();if (config.isGlobalProperty()) {CarPropertyValue value = mHal.getPropertySafe(propId, 0);if (value != null) {CarPropertyEvent event = new CarPropertyEvent(CarPropertyEvent.PROPERTY_EVENT_PROPERTY_CHANGE, value);events.add(event);}} else {for (int areaId : config.getAreaIds()) {CarPropertyValue value = mHal.getPropertySafe(propId, areaId);if (value != null) {CarPropertyEvent event = new CarPropertyEvent(CarPropertyEvent.PROPERTY_EVENT_PROPERTY_CHANGE, value);events.add(event);}}}try {client.getListener().onEvent(events);} catch (RemoteException ex) {// If we cannot send a record, its likely the connection snapped. Let the binder// death handle the situation.Slog.e(TAG, "onEvent calling failed: " + ex);}
}
  • HalClient.java,getValue,获取属性ID的值。
VehiclePropValue getValue(VehiclePropValue requestedPropValue) {final ObjectWrapper<VehiclePropValue> valueWrapper = new ObjectWrapper<>();int status = invokeRetriable(() -> {ValueResult res = internalGet(requestedPropValue);valueWrapper.object = res.propValue;return res.status;}, mWaitCapMs, mSleepMs);if (StatusCode.INVALID_ARG == status) {throw new IllegalArgumentException(getValueErrorMessage("get", requestedPropValue));}if (StatusCode.OK != status || valueWrapper.object == null) {// If valueWrapper.object is null and status is StatusCode.Ok, change the status to be// NOT_AVAILABLE.if (StatusCode.OK == status) {status = StatusCode.NOT_AVAILABLE;}Log.e(TAG, getPropertyErrorMessage("get", requestedPropValue, status));throw new ServiceSpecificException(status,"Failed to get property: 0x" + Integer.toHexString(requestedPropValue.prop)+ " in areaId: 0x" + Integer.toHexString(requestedPropValue.areaId));}return valueWrapper.object;
}
  • 如果是VehiclePropertyAccess:READ的属性,上述代码会抛出ServiceSpecificException异常。导致CarService崩溃。code 4,ACCESS_DENIED。

Android12修复方式

android12已修复该问题。使用了getPropertySafe,捕获异常。

/*** Return property or null if property is not ready yet or there is an exception in HAL.*/
@Nullable
public CarPropertyValue getPropertySafe(int mgrPropId, int areaId) {        
try {return getProperty(mgrPropId, areaId);} catch (Exception e) {Slog.e(TAG, "get property value failed for property id: 0x "+ toHexString(mgrPropId) + " area id: 0x" + toHexString(areaId)+ " exception: " + e);return null;}
}

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

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

相关文章

【Go】Go语言并发模型:MPG

Go 语言并发模型&#xff1a;MPG Go 的并发模型主要由三个部分构成&#xff1a; M (Machine) 系统线程&#xff0c;用于实际执行任务。 P (Processor) 逻辑处理器&#xff0c;负责管理和调度 goroutine。每个 P 拥有一个本地队列和关联的全局 G 队列。 G (Goroutine) Go 语言…

SpringCloud配置中心:Config Server与配置刷新机制

文章目录 引言一、Config Server基础架构1.1 Server端配置1.2 配置文件命名规则 二、Config Client配置2.1 Client端配置2.2 配置注入与使用 三、配置刷新机制3.1 手动刷新配置3.2 使用Spring Cloud Bus实现自动刷新3.3 配置仓库Webhook自动触发刷新 四、高级配置管理策略4.1 配…

PyTorch生成式人工智能实战:从零打造创意引擎

PyTorch生成式人工智能实战&#xff1a;从零打造创意引擎 0. 前言1. 生成式人工智能1.1 生成式人工智能简介1.2 生成式人工智能技术 2. Python 与 PyTorch2.1 Python 编程语言2.2 PyTorch 深度学习库 3. 生成对抗网络3.1 生成对抗网络概述3.2 生成对抗网络应用 4. Transformer4…

allure结合pytest生成测试报告

结合 pytest 和 Allure 可以生成详细而美观的测试报告&#xff0c;帮助测试人员和开发者更好地理解测试结果。这包括测试的执行情况、步骤、附件&#xff08;如截图&#xff09;、分类以及优先级标记。下面是如何在 pytest 中使用 Allure 生成测试报告的步骤&#xff1a; 安装…

STM32标准库开发中断流程

在STM32标准外设库&#xff08;SPL&#xff09;开发中&#xff0c;外设中断的处理流程通常如下&#xff1a; 一、标准库外设中断处理流程 &#xff08;1&#xff09;使能外设时钟 在使用任何外设之前&#xff0c;都必须打开外设的时钟。例如&#xff0c;使用USART1的中断&…

【计算机网络】-计算机网络期末复习题复习资料

一、计算机网络体系结构&#xff08;800字&#xff09; 1. OSI参考模型 七层结构&#xff1a;物理层→数据链路层→网络层→传输层→会话层→表示层→应用层 各层核心功能&#xff1a; 物理层&#xff1a;比特流传输&#xff08;如RJ45、光纤接口&#xff09; 数据链路层&…

31天Python入门——第9天:再学函数

你好&#xff0c;我是安然无虞。 文章目录 再学函数1. 变量在函数中的作用域2. 函数的参数传递.补充学习: 不定长参数*args和**kwargs 3. 值传递和引用传递补充学习: 把函数作为参数传递 4. 匿名函数5. python中内置的常用函数zip()map()filter()all()any() 6. 函数练习 再学函…

EasyUI数据表格中嵌入下拉框

效果 代码 $(function () {// 标记当前正在编辑的行var editorIndex -1;var data [{code: 1,name: 1,price: 1,status: 0},{code: 2,name: 2,price: 2,status: 1}]$(#dg).datagrid({data: data,onDblClickCell:function (index, field, value) {var dg $(this);if(field ! …

【C语言】多进程/多线程

【C语言】多进程/多线程 参考链接多进程/多线程服务器1. 多进程服务器2. 多线程服务器 结语参考链接 参考链接 c 中文网 菜鸟 c 多进程/多线程服务器 多进程和多线程是常用的并发编程技术。它们都允许程序同时执行多个任务&#xff0c;提高了系统的资源利用率和程序的运行效率…

mysql 磐维(opengauss)tidb误删数据之高级恢复

Mysql参考&#xff1a; Mysql 8.0 XtraBackupMysqlbinlog 完全恢复 - 墨天轮 Mysql 8.0 XtraBackupMysqlbinlog 完全恢复[TOC]# 一、安装mysql 8.0.19## 1.1https://www.modb.pro/db/509223MySQL 的全量备份、增量备份与 Binlog 时间点恢复_mysqlbinlog自动备份吗-CSDN博客文章…

3. 轴指令(omron 机器自动化控制器)——>MC_SetPosition

机器自动化控制器——第三章 轴指令 11 MC_SetPosition变量▶输入变量▶输出变量▶输入输出变量 功能说明▶时序图▶重启动运动指令▶多重启运动指令▶异常 MC_SetPosition 将轴的指令当前位置和反馈当前位置变更为任意值。 指令名称FB/FUN图形表现ST表现MC_SetPosition当前位…

从 @SpringBootApplication 出发,深度剖析 Spring Boot 自动装配原理

在 Spring Boot 的开发旅程中&#xff0c;SpringBootApplication 注解堪称开启便捷开发之门的钥匙。它不仅是一个简单的注解&#xff0c;更是理解 Spring Boot 自动装配原理的重要入口。接下来&#xff0c;我们将以SpringBootApplication 为切入点&#xff0c;深入探究 Spring …

MySQL面试专题

1.什么是BufferPool&#xff1f; Buffer Pool基本概念 Buffer Pool&#xff1a;缓冲池&#xff0c;简称BP。其作用是用来缓存表数据与索引数据&#xff0c;减少磁盘IO操作&#xff0c;提升效率。 Buffer Pool由缓存数据页(Page) 和 对缓存数据页进行描述的控制块 组成, 控制…

调用百度api实现语音识别(python)

该代码实现了一个企业级的语音识别解决方案,通过调用百度语音识别API,实现实时录音识别和对已有音频语音识别功能。 百度智能云:请自行访问百度智能云,开通免费的语音识别功能,获取API_KEY和SECRET_KEY。操作按照百度流程即可,可免费申请。 首先,配置下百度API和描述下错…

KRaft模式

目录标题 Kraft模式**1. 什么是Kraft模式&#xff1f;****2. 为什么引入Kraft模式&#xff1f;****3. 核心优势****4. 架构与工作原理****5. 部署与配置要点****6. 适用场景与最佳实践****总结**KIP-833: Mark KRaft as Production Ready除了Kraft模式&#xff0c;Kafka还有以下…

单片机电路中常见的英文术语及缩写

以下是单片机电路中常见的英文术语及缩写的解释及其作用说明&#xff0c;按功能分类整理&#xff0c;便于理解&#xff1a; 一、核心术语 MCU (Microcontroller Unit) • 中文&#xff1a;微控制器单元 • 作用&#xff1a;单片机的核心芯片&#xff0c;集成CPU、存储器、外设接…

常见框架漏洞之一:Thinkphp5x

ThinkPHP是为了简化企业级应⽤开发和敏捷WEB应⽤开发⽽诞⽣的&#xff0c;是⼀个快速、兼容⽽且简单的轻量级国产PHP开发框架&#xff0c;诞⽣于2006年初&#xff0c;原名FCS&#xff0c;2007年元旦正式更名为 ThinkPHP&#xff0c;遵循Apache2开源协议发布&#xff0c;从Stru…

2025年优化算法:龙卷风优化算法(Tornado optimizer with Coriolis force,TOC)

龙卷风优化算法&#xff08;Tornado optimizer with Coriolis force&#xff09;是发表在中科院二区期刊“ARTIFICIAL INTELLIGENCE REVIEW”&#xff08;IF&#xff1a;11.7&#xff09;的2025年智能优化算法 01.引言 当自然界的狂暴之力&#xff0c;化身数字世界的智慧引擎&…

面试中如何回答性能优化的问题

性能问题和Bug不同,后者的分析和解决思路更清晰,很多时候从应用日志(文中的应用指分布式服务下的单个节点)即可直接找到问题根源,而性能问题,其排查思路更为复杂一些。 对应用进行性能优化,是一个系统性的工程,对工程师的技术广度和技术深度都有所要求。一个简单的应用…

CMake 函数和宏

CMake 函数 CMake 函数定义语法如下, 其中 name 为函数名, <arg1> 为参数名, <commands> 为函数体. 函数定义后, 可以通过 name 调用函数. 函数名允许字母数字下划线, 不区分大小写. function(name [<arg1> ...])<commands> endfunction()如下的样例…