【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.pswp.cn/bicheng/74435.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/74435.shtml
英文地址,請注明出處:http://en.pswp.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()如下的樣例…