当前位置: 首页 > news >正文

Android车机开发-TTRSXXXAIDL技术总结

一、AIDL有什么作用?

        车机系统将核心硬件资源(音频、车辆总线、显示、电话)的能力抽象成一个个独立的​​系统服务 (System Services)​​。这些服务运行在拥有高权限的独立进程(如 system_server)中。

        AIDL是连接​​客户端 (Client)​​(你的App)和​​服务端 (Server)​​(系统服务)的桥梁。这种架构实现了彻底的​​解耦​​:

  • ​App开发者​​:无需知道音频如何通过HAL层驱动硬件,只需调用 TTRSCarAudioAIDL.getInstance().reqPlayControl(...)

  • ​系统服务开发者​​:只需维护好AIDL接口的稳定,无需关心上层有多少个App在调用它。

这种解耦是大型系统可维护、可扩展的基础。

二、实战AIDL类

TTRSCarAudioAIDL:音频路由与策略的执行者

它远不止是一个“播放/暂停”的控制器,而是一个复杂的​​音频路由和管理中心​​。

        1.​​Zone(区域)与 Group(音组)概念​​:

        zoneId(0: 主驾, 1: 副驾, 2: 后排): 这揭示了系统支持​​独立音频分区(Multi-zone Audio)​​。例如,主驾听导航,副驾可以通过耳机听音乐,互不干扰。这是通过底层音频DSP硬件和Android Audio Framework的深度定制实现的。

        groupId(0: 媒体, 1: 通话, 2: 铃声, 3: 导航, 4: 语音): 这不是简单的音量条,而是​​音频策略(Audio Policy)​​ 的核心。不同Group有不同的行为:

        ​​Ducking(闪避)​​: 当groupId=4(语音助手)说话时,系统会自动降低groupId=0(媒体)的音量,说完后再恢复。

        ​​Muting(静音)​​: 来电时(groupId=1),系统可能会静音媒体和导航。

这些策略通常由服务端的 AudioPolicyManager配置,AIDL客户端只是触发和执行这些策略。

        ​​2.音频焦点 (Audio Focus) 的协作​​:

        ​getCurrentMainAudioFocus()onCurrentMainAudioFocusChanged回调是​​音频焦点机制​​的体现。这是一个​​协作式​​的机制:

        ​你的音乐App在播放前,需要请求音频焦点。——如果导航正在占用焦点,服务端会通过回调通知导航App“你失去了焦点”,导航App应该暂停或降低音量。

        然后你的音乐App才能开始播放。——AUDIO_TYPE_PLAY/PAUSE/STOP这些状态不仅是播放状态,更是焦点状态的映射。

        ​​3.Connection Management (连接管理)​​:

        ServiceConnector+ autoRebind+ DeathRecipient构成了一个​​生产级的重连机制​​。

  • ​死亡回调 (binderDied)​​: 当服务端进程意外崩溃时,客户端的Binder代理会收到通知,此时可以清理本地资源并触发重连。
  • ​指数退避 (Exponential Backoff)​​: 代码中 executeDelayed(..., 10000)是一种简单的重试策略,在实际项目中可能会升级为更复杂的指数退避算法,避免在服务端瘫痪时所有客户端疯狂重连,加剧系统负担。

TTRSCarInfoAIDL:车辆信号的抽象层

        它的作用是将​​连续、底层的车辆总线信号​​转换为​​离散、语义化的应用级事件​​。

从信号到信息 (Signal -> Information)​​:

        车辆CAN总线上的数据是原始的、高频的(如车速信号0xAA,值0x2B,单位0.1km/h)。

        这个服务的工作就是监听这些信号,进行​​转换、过滤、聚合​​,然后通过 onPropertyValueChange(int i, String s)回调上报。参数 i是信号ID(如 0x21704F22),s是转换后的值(如 "driver_door: open")。这种抽象让App开发者处理的是“车门开闭”,而不是晦涩的CAN ID和字节解析。

        ​​缓存与状态持久化​​:

        使用 MMKVUtils缓存车辆型号等信息是至关重要的。车辆信号服务可能在系统启动后一段时间才可用,而App可能需要立即知道车辆型号来加载相应的UI主题或配置。缓存提供了​​降级处理​​的能力,保证了用户体验的连贯性。

        ​​监听与轮询​​:

  • ​监听 (Listener)​​: 用于变化频繁的信号,如车速、转速。效率高,是事件驱动模式。
  • ​轮询 (Polling)​​: getVehicleInfo()用于获取不常变化的静态信息,如VIN号、车辆型号。App在需要时主动查询。

TTRSCarModeAIDL:系统级人机交互的网关

代码示例:

public class TTRSCarModeAIDL {private static TTRSCarModeAIDL instance = null;public static int SCREEN_STATUS = -1;public static TTRSCarModeAIDL getInstance() {if (instance == null) {instance = new TTRSCarModeAIDL();}return instance;}private static WeakReference<IGestureBehavorCallback> callbackWeakReference;private final CarModeListener listener = new CarModeListener();static class CarModeListener extends ICarModeListener.Stub {@Overridepublic  void onNaviMediaVisualFocusStatusChanged(String str){}@Overridepublic void onTopPackageNameChange(int zoneId, String packageName) throws RemoteException {}@Overridepublic void onReqControlOverlayReply(String replyReqInfo) throws RemoteException {}@Overridepublic int[] getListenerType() throws RemoteException {return new int[0];//CarModeConstant.CARMODE_NOTIFY_TYPE_REQ_OVERLAY_REPLY}@Overridepublic void onInterruptOverlay(String interruptInfo) throws RemoteException {}@Overridepublic void onVehicleSystemPrivacyStatusChange(boolean status) throws RemoteException {}@Overridepublic void onScreenStatusChange(int status) throws RemoteException {if (status != SCREEN_STATUS && callbackWeakReference.get() != null) {callbackWeakReference.get().onSuccess();callbackWeakReference.clear();}SCREEN_STATUS = status;}@Overridepublic void onStrStatusChange(int state){}@Overridepublic void onCabinKeyEventDispatched(int keyCode, int keyEventType, int keyEventFlag, int keyEventTime,long downTime, long eventTime) throws RemoteException {}@Overridepublic void onStartProcessComplete(int i) throws RemoteException {}@Overridepublic void onScreenShowStatusChange(String s, int i) throws RemoteException {}}private class AVSDeathRecipient implements IBinder.DeathRecipient {@Overridepublic void binderDied() {Log.i(TAG, "CarMode binderDied");}}private volatile boolean autoRebind = false;private final ServiceConnector<ICarMode> carModeConn = new ServiceConnector<ICarMode>() {@Overrideprotected void onConnected(@Nullable ICarMode iCarMode) {Log.i(TAG, "CarMode onConnected" + iCarMode);registerListener();
//            try {
//                iCarMode.asBinder().linkToDeath(new AVSDeathRecipient(), 0);
//            } catch (RemoteException e) {
//                Log.e(TAG, e.getMessage());
//            }}@Overrideprotected void onDisconnect() {Log.i(TAG, "CarMode onDisconnect");}@Overrideprotected void onConnectFailed(int errorCode) {Log.i(TAG, "CarMode onConnectFailed" + errorCode + " autoRebind: " + autoRebind);if (errorCode == ERROR_CODE_INTENT_NO_FOUND) {ThreadUtil.executeDelayed(()-> {if (autoRebind) {this.connect();}},10000);} else if (errorCode == ERROR_CODE_RECONNECT_TIME_OUT) {if (autoRebind) {connect();}}}@NonNull@Overrideprotected Intent getIntent() {Intent intent = new Intent("com.toyota.carmode.action");intent.setComponent(new ComponentName(SERVICE_PACKAGE, SERVICE_CLASS));return intent;}@NonNull@Overrideprotected ICarMode asService(@NonNull IBinder iBinder) {return ICarMode.Stub.asInterface(iBinder);}@NonNull@Overrideprotected String getTag() {return TAG;}};private ICarMode getCarMode() {ICarMode iCarMode = carModeConn.getService();if (iCarMode != null && iCarMode.asBinder().isBinderAlive()) {return iCarMode;}return null;}public void bindTTRSService() {Log.i(TAG, "CarMode bindTTRSService");autoRebind = true;carModeConn.connect();}public void unbindTTRSService() {Log.i(TAG, "CarMode unbindTTRSService");autoRebind = false;carModeConn.disconnect();ICarMode iCarMode = getCarMode();if (iCarMode != null && listener != null) {try {iCarMode.unregisterListener(listener);} catch (RemoteException e) {Log.d(TAG, "RemoteException = " + e);}}}public void registerListener() {ICarMode iCarMode = getCarMode();if (iCarMode != null) {try {Log.i(TAG, "CarMode registerListener");iCarMode.registerListener(listener);} catch (RemoteException e) {Log.e(TAG, "RemoteException = " + e);}}}/*** 本地音乐翻页功能** @param zoneId  CarModeConstant.CARMODE_ZONEID_D:0 // D席 CarModeConstant.CARMODE_ZONEID_P:1 // P席* @param keyType 1: List翻页_上一页 2: List翻页_下一页*/public void reqControlSoftKey(int zoneId, int keyType, IGestureBehavorCallback behavorCallback) {ICarMode iCarMode = getCarMode();if (iCarMode != null) {try {iCarMode.reqControlSoftKey(zoneId, keyType);Log.d(TAG, "reqControlSoftKey" + "--zoneId:" + zoneId + "--keyType:" + keyType);if (behavorCallback != null){behavorCallback.onSuccess();}} catch (RemoteException e) {com.autoai.log.Log.e(TAG, "error", e);}} else {Log.d(TAG, "iCarMode" + "does not bind !! ");}}public void reqControlScreenLight(int zoneId, int keyType, IGestureBehavorCallback callback) {ICarMode iCarMode = getCarMode();if (iCarMode != null) {try {callbackWeakReference = new WeakReference<>(callback);iCarMode.reqControlScreenLight(zoneId, keyType);callback.onSuccess(IGestureBehavorCallback.TOAST);Log.i(TAG, "reqControlScreenLight" + "--zoneId:" + zoneId + "--keyType:" + keyType);} catch (RemoteException e) {com.autoai.log.Log.e(TAG, "error", e);}}}public int getScreenLight() {ICarMode iCarMode = getCarMode();if (iCarMode != null) {try {int screenStatus = iCarMode.getScreenStatus();
//                Log.i(TAG, "getScreenStatus:" + screenStatus);return screenStatus;} catch (RemoteException e) {com.autoai.log.Log.e(TAG, "error", e);}}return 1;}public void startAircondition(String appName,Intent intent){ICarMode iCarMode = getCarMode();if (iCarMode != null) {try {Log.i(TAG, "startAircondition " + appName);iCarMode.startApp(appName,intent);} catch (RemoteException e) {com.autoai.log.Log.e(TAG, "error", e);}}}
}

超越App沙盒​​:

        安卓应用默认运行在各自的沙盒中,无法直接相互调用或控制系统UI。

        reqControlSoftKeystartAircondition打破了沙盒限制。它允许一个App(如手势识别App)去模拟点击另一个App(如音乐App)的按钮,或者直接启动空调App。这需要系统服务拥有极高的权限,并负责协调这些跨进程交互。

显示控制与DRM​​:

        reqControlScreenLight不仅仅是调节亮度。在车机上,这可能关联着​​DRM(数字版权管理)​​ 策略。例如,当车辆行驶速度超过一定值时,系统服务可能会拒绝播放视频或调暗屏幕,以防止驾驶员分心。这个AIDL调用最终会由服务端根据一系列安全策略来决定是否执行。

TTRSVRControlAIDL:状态机与复杂交互的典范

这个类展示了如何用代码处理现实世界中的复杂状态。

复杂的电话状态机​​:

        电话状态 (phoneState) 不是一个简单的“开”或“关”,而是一个有十多个状态的​​状态机​​。handlePhoneCommand方法的核心就是一个巨大的状态机处理逻辑。

​        为什么需要状态机?​​ 因为用户的一个“挂断”手势,在不同的状态下意义完全不同:

  • ​状态1(来电)​​ -> 执行“拒接”。
  • ​状态3(通话中)​​ -> 执行“结束当前通话”。
  • ​状态5(通话中且又来新来电)​​ -> 执行“结束当前通话”可能不合适,也许应该执行“切换通话”。这里的逻辑极其复杂,需要产品严格定义。

        这个状态机的正确实现,是​​车规级可靠性​​的体现,避免了在错误状态下发出错误指令导致通话混乱。

​异步与同步命令​​:

  • processCommandSync: 同步调用,调用方会阻塞等待结果。用于需要立即知道结果的操作,如接听电话。
  • onProcessCommandAsyncResult: 异步回调,用于耗时较长的操作,如语音识别处理。服务端处理完后,会通过这个回调通知客户端结果。

三、AIDL总结

        AIDL接口通过明确定义车机系统的能力边界,确保了应用行为的一致性和可控性,同时依托连接管理、状态监听与重试机制保障可靠性。

        在Binder传输层实施权限检查以增强安全性,并通过清晰的接口契约支持系统与应用的独立演进以提升可维护性,再结合批量操作、异步回调及无UI线程阻塞设计,有效控制IPC开销,从而全面实现高性能的生态运行。

四、扩展:HAL与AIDL的联系

        如果要彻底理解这些AIDL的价值,必须将其置于Android系统的完整架构中审视,而最终一切都将指向​​HAL(Hardware Abstraction Layer)​​。

完整的垂直调用链:​

        这些AIDL接口实际上是一个更漫长调用链的​​客户端入口​​。这个调用链通常是:

​App (应用层) -> AIDL Client -> System Service (系统服务) -> JNI -> HAL Interface -> HAL Implementation (HAL实现) -> Kernel Driver (内核驱动) -> Hardware (硬件)​​。

  • ​你的App​​:调用 TTRSCarAudioAIDL.setGroupVolume(zoneId, groupId, volume, flags)
  • ​CarAudio System Service​​:接收这个AIDL调用,进行权限验证、参数校验、音频策略计算。
  • ​Service to HAL​​:服务通过JNI调用到​​原生(Native)​​ 代码,然后调用Android定义的硬件抽象接口,例如 android.hardware.audio@version::IDevice::setVolume()
  • ​HAL Implementation​​:这是由芯片厂商(如Qualcomm)或设备制造商(OEM)​​必须实现​​的代码库(.so文件)。它接收标准的HAL接口调用,并将其转换为对特定硬件平台的操作。例如,它将抽象的 setVolume调用,转换成写入特定音频编解码器芯片寄存器的具体值。
  • ​Driver & Hardware​​:HAL实现通过Linux内核驱动最终操控硬件芯片,物理电压发生变化,扬声器的声音随之变大或变小。​

        这些AIDL接口是​​面向应用开发者的最终抽象​​,它们站在HAL的肩膀之上。HAL抽象了​​硬件差异​​,让安卓系统可以移植到成千上万种不同的硬件平台上。而这些AIDL系统服务则在此基础上,抽象了​​车规功能​​,将车辆特有的、复杂的功能(多音区、车辆总线、座舱控制)封装成一套统一的、安全的、可靠的服务接口,从而让应用开发者能够聚焦于用户体验和创新,而无需深究底层硬件的具体实现。

具体以车辆信号为例:​

        当 TTRSCarInfoAIDL的监听器上报 onPropertyValueChange(0x21704F22, "true")(表示驾驶员车门开启)时,背后隐藏的是一条穿越HAL的数据流:

  1. 物理车门开关传感器状态改变,产生一个中断。
  2. 车身控制器通过CAN总线将包含此信号的数据帧广播出去。
  3. 车机的CAN控制器接收到数据帧,内核中的CAN驱动解析它。
  4. ​Vehicle HAL​​ 的实现(由车企提供)正在轮询或监听驱动暴露的CAN数据。它识别出这是车门信号,并将其转换为标准的 android.hardware.automotive.vehicle@VERSION::IVehicleHal::get调用。
  5. ​CarSystem Service​​(TTRSCarInfoAIDL的服务端)通过Vehicle HAL接口查询或订阅该信号。
  6. 服务端拿到信号值后,通过Binder IPC回调给所有注册了监听的App进程中的 CarInfoPropertyListener

AIDL与HAL的分工与协作:​

​        ​AIDL (App -> Service)​​:解决的是​​进程间通信(IPC)​​ 和​​服务化​​的问题。它定义了App与系统服务之间的通信契约,关注的是权限、状态同步和业务逻辑的编排。

        ​​HAL (Service -> Hardware)​​:解决的是​​硬件差异性​​的问题。它定义了系统服务与硬件厂商实现之间的通信契约,旨在将安卓框架与设备特定的硬件驱动隔离开。Google定义了标准的HAL接口(如 audio.h, vehicle.h),高通、TI、NXP等厂商负责用代码实现这些接口,以适配他们自己的芯片。

http://www.dtcms.com/a/461926.html

相关文章:

  • dedecms制作网站教程平面设计广告设计
  • 龙岗区住房和建设局在线网站作图工具
  • 导数、偏导数与梯度:机器学习数学基础
  • 六安市裕安区建设局网站天津企朋做网站的公司
  • 企业做淘宝客网站有哪些四平做网站佳业
  • 网站建立与推广手机商城网站
  • OpenAI Whisper 语音识别模型:技术与应用全面分析
  • C++17 新特性:std::optional —— 优雅处理函数返回值
  • 你好,因用户投诉并经平台审核,发现账号已发布的服务所选类目与小程序运营内容不符合,亲测有效
  • 怎样设计一个系统?
  • 橙色守护者
  • MySQL笔记---事务
  • 火车采集wordpress百色seo关键词优化公司
  • CVPR 2025 | 频率动态卷积FDConv,标准卷积的完美替代,即插即用,高效涨点!
  • 外贸企业用什么企业邮箱?2025 全球畅邮 TOP3,海外客户沟通无障碍
  • 做网站要注意些什么要求html制作个人简历
  • 第6篇 OpenCV RotatedRect如何判断矩形的角度
  • 响水做网站杭州网站设计手机
  • java面试-0135-InputStream不能重复读取原因及解决?√
  • C++之类的继承与派生
  • Yudao单体项目 springboot Admin安全验证开启
  • 电子商务网站建设风格网站建设技术的实现
  • 【Frida Android】基础篇2:Frida基础操作模式详解
  • 应用于ElasticSearch的C++ API——elasticlient
  • MyISAM存储引擎的特点
  • 伺服滑差补偿方案
  • 无锡网站建设排名安徽网站开发建设
  • 【C++】探秘string的底层实现
  • 建设卡开通网银网站学做网站 空间 域名
  • 基于Simulink的太阳能单极性移相控制光伏并网逆变器