资讯动态

DiPlay 仪表盘投屏实战:DiLink 4 ADB 私有显示屏路由原理与配置全解

发布时间:2026/10/9 9:58:46 来源:尧图企业网站定制
移动开发智能硬件音视频【免费下载链接】DiPlayIndependent CarPlay receiver for compatible Android head units. Wired and wireless public preview.项目地址https://gitcode.com/gh_mirrors/di/DiPlay点击查看免费下载本文围绕 DiPlay 仓库中的 docs/DILINK4_CLUSTER.md 展开系统讲解“DiLink 4 cluster video via ADB实验性”这一功能它如何让 2022 款 BYD SealDiLink 4.0 / Android 10在保留中控 CarPlay 主流的同时把独立地图流通过本地 ADB 直投到仪表盘的私有虚拟显示屏上。读完本文你将掌握该功能的启用步骤、私有显示屏识别规则、am start-activity直投命令链、启动令牌token与 5 秒重试机制、仪表盘安全区校准流程以及它与 DiLink 5/5.1、DiLink 3 集群显示的优先级关系和原厂地图挂起stock-map hold的恢复日志设计。1. 功能定位与适用前提DiPlay 默认将 CarPlay 主流画面放在主机head unit上而 DiLink 4 车型的仪表盘是一块由车机厂商私有容器服务托管的虚拟显示屏Android 标准 API 无法直接寻址。该实验功能的做法是主 CarPlay 流保留在主机上另起一个独立 Activity 专门承载仪表盘流stream 111通过已授权的本地 ADB 把该 Activity 路由到私有显示屏。来自文档的适用范围声明需要特别留意贡献者在2022 款 BYD SealDiLink 4.0 / Android 10上实测过该方案更新后的分支仍需要实车复测其他固件均未实车验证该路线不会移动任何既有任务task也不会改变 OEM 的投屏模式。从源码结构看这一“实验性”定位直接体现为多重保守校验显示目标必须精确匹配、启动令牌逐次轮换、实际显示确认优先于 shell 应答。设置项的界面文案可见 common/src/main/res/values/strings.xml 中的adb_cluster_activity_mode“DiLink 4 cluster video via ADB (experimental)”、adb_cluster_authorize“Authorize ADB / retry cluster routing”等条目。2. 启用步骤四步完成按 docs/DILINK4_CLUSTER.md 的 Setup 章节完整操作流程为开启车辆原生的仪表盘地图/投屏模式cars native cluster-map/projection mode并全程保持其处于激活状态在 DiPlay 设置中打开DiLink 4 cluster video via ADB (experimental)开关点击Authorize ADB / retry cluster routing在车机弹出的调试授权提示中批准。本地 ADB 必须可用后台重试永远不会再次请求授权源码中adb.connect(mayAsk false)保证了这一点见 AdbClusterRouter.kt连接或重连 iPhone 并打开 Apple 地图。主 CarPlay 画面继续留在中控独立地图出现在仪表盘上。对应持久化开关为adb_cluster_activity_enabled与既有集群地图开关cluster_map_enabled分开存储定义于 AirPlayPersistence.ktKEY_CLUSTER_MAP、KEY_ADB_CLUSTER_ACTIVITY。3. 私有显示屏的识别精确匹配拒绝一切猜测该路线从dumpsys display的输出中实时探测当前逻辑显示 ID而不是假设“仪表盘就是 display 1”。目标显示必须同时满足三个硬条件解析逻辑见 AdbClusterRouter.displayId()行内包含mBaseDisplayInfoDisplayInfo{fission_bg_xdjaVirtualSurface, displayId …只显示的基础信息不匹配带mOverrideDisplayInfo的记录也不匹配层叠编号分辨率为精确的real 1920 x 720属主为com.xdja.containerservice (uid 1000)——即比亚迪 XDJA 容器服务拥有的显示。解析要求候选 ID 唯一candidates.singleOrNull()且大于 0目标缺失、出现多个候选歧义、属主或几何不符一律拒绝。显示名称的精确匹配定义在 DiLink4ClusterDisplay.kt// 2022 Seal / DiLink 4.0: 1920x720 logical display, 1920x624 observed activity area. const val NAME fission_bg_xdjaVirtualSurface // Exact name and geometry only. Do not select arbitrary virtual or passenger displays. fun matches(name: String, width: Int, height: Int): Boolean name NAME width 1920 height 720值得注意的是accepts()还会接受1280×480的投影面——那是 DiLink 3 车型报告的同一显示名的小尺寸面板它走的是通用逐显示流而非本功能的 1920×720 标定配置见 DiLink4ClusterDisplay.kt#L16-L21 的注释仅凭宽高比不足以识别仪表盘。单元测试 AdbClusterRouterTest.kt 明确覆盖了这些拒绝分支display 0、1280 x 720错误几何、com.passenger属主、两个候选并存、以及把mBaseDisplayInfo换成mOverrideDisplayInfo的诱饵记录全部返回null而 DiLink4ClusterDisplayTest.kt 进一步断言shared_fission_bg_xdjaVirtualSurface_0这类相似名称、以及 1280×720 / 1920×1080 / 640×240 / 2560×960 等几何均不被接受。4. ADB 直投链路命令构造、令牌校验与 5 秒重试4.1 直投命令识别到显示 ID 后路由层构造的 shell 命令为AdbClusterRouter.launchCommand()am start-activity --display $display -f 0x18000000 -n $pkg/com.shilapi.xcertplay.AdbClusterActivity --es cluster_launch_token $token在构造前有三道require校验显示 ID 必须大于 0包名必须匹配严格的com.example.Foo形式正则防 shell 注入令牌必须是规范形式的 UUID。-f 0x18000000对应 Android 的FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_MULTIPLE_TASK使仪表盘 Activity 以独立任务启动不与中控主任务合并。此方法遵循文档致谢中提到的、由 寒叙Hanxu4131发布的 legacy platform-21 实现LegacyClusterTarget.kt、LegacyClusterMap.kt、ClusterMapActivity.kt。测试 AdbClusterRouterTest.directLaunchUsesIndependentTaskAndRejectsMainDisplay() 验证了命令前缀、令牌附加以及display 0、含分号的非法包名、非法令牌均被拒绝accepted()则要求输出包含Starting: Intent {或Status: ok且不含任何 error/exception/permission denial 字样。4.2 shell 成功不等于可见输出令牌与真实显示确认文档明确“一次成功的 shell 启动并非可见输出的证明。”实现上AdbClusterActivity.kt 与同文件的ClusterActivityOutput每次启动生成一个随机 UUID 作为cluster_launch_token随 intent extra 传入 Activity。AdbClusterActivity在onCreate中先校验AdbClusterRouter.enabled()与ClusterActivityOutput.acceptsToken(token)任何一项不满足立即finish()过期的 Activity 无法挂接最新表面Activity 优先使用root.display?.displayId确认实际所在显示部分固件会向视图报告display 0此时回退到AdbClusterRouter.verify()在 ADB 的逐显示 Activity 历史dumpsys activity activities中各Display #N分节下的ActivityRecord中精确匹配本包名 本任务号activityDisplay()只认Display #N (activities from top to bottom)分节内的Hist #n: ActivityRecord{… ttask}记录且要求唯一匹配见 AdbClusterRouter.kt#L41-L55 与测试verifiesOnlyExactTaskInsidePerDisplayHistory()只有confirm()中“令牌未过期 实际显示 ID 与探测到的目标一致”才通过随后才把 Surface 交给 stream 111。4.3 重试与撤销未确认的启动在 5 秒后重试ClusterActivityOutput.retry()使用main.postDelayed(retryTick, 5_000L)AdbClusterActivity.kt#L151-L155关闭功能开关或销毁宿主 Activity 时closeRoute()会递增 generation、清空令牌、取消队列中所有重试、释放原厂地图租约并finish()旧 Activity——即文档所说的“取消排队重试并使启动令牌失效”启动失败不会永久卡死ensure()中每次尝试都绑定独立的 generation/epoch过期令牌的结果在回到主线程时直接丢弃并释放 OEM 状态completeLaunch()每次路由尝试都会把探测结果写入应用私有目录下的adb-cluster-route.txt含时间戳、ADB 访问状态、routeTarget、stockMapHoldReady、shell 原始输出截断至 1500 字符、launchAccepted标志最终并入常规诊断导出报告文件写入失败也被runCatching兜底不会让launchPending状态卡死。5. 仪表盘 Activity 的布局策略1920×720、透明与黑幕文档“Layout and navigation”一节对应的实现约束如下流与纹理缓冲固定 1920×720、100% 缩放。DiLink4ClusterDisplay.streamConfig()DiLink4ClusterDisplay.kt#L28-L34在此分辨率上构建AirPlayDisplayConfig并复用 DiLink 5 的 marker 安全边距作为校准起点safeAreaDrawOutside保持开启让地图背景继续铺满 Activity透明、不可聚焦AdbClusterActivity设置透明背景、FLAG_NOT_FOCUSABLE与全屏沉浸式标志保证仪表盘的原厂仪表元素车速等保持可见黑幕兜底waitingTextView 为黑色全屏层updateStream()在ClusterActivityOutput.streamActive false时显示——即流不活跃时仪表盘被纯黑覆盖断开的 iPhone 不会在仪表盘上留下冻结的地图焦点丢失不会解除 stream 111 的挂接渲染生命周期由纹理ClusterVideoTexture持有源码注释“Losing focus must not detach stream 111”。测试 DiLink4ClusterDisplayTest.fullPanelStreamKeepsContentAndReusesDilink5SafeArea() 对每一种Content变体断言 1920×720、100% 缩放与安全区一致savedMarkerOffsetsMoveSafeAreaWithoutChangingResolution()则验证 marker 偏移只移动安全区而不改变流尺寸。6. 仪表盘安全区校准编辑盒与预览窗“Cluster safe area · edit box”打开一个贴合fitted的编辑器拖动绿色边缘调整安全区外框会在校准期间实时镜像到仪表盘上且即使 iPhone 未连接也可以打开编辑器时启动的是一个仅预览的窗口复用已授权的本地 ADB——它不启动 CarPlay、不挂起原厂地图期间仍需保持车辆原生仪表盘投屏处于激活状态关闭dismiss编辑器只关闭预览窗并使未完成的启动失效已存在的 CarPlay 窗口不受影响Save 在新安全区重新连接后生效Cancel 保留已保存的映射外框在编辑器关闭或离开设置页时清除该映射使用独立的偏好键cluster_safe_area_1920x720见 AirPlayPersistence.kt#L856-L865矩形会被clampTo(1920, 720)约束不会覆盖主显示的映射Reset恢复到基于 marker 偏移的默认布局defaultSafeAreaRect()修改连接设置后可能仍需手动重插一次。实现上ClusterActivityOutput.beginSafeAreaPreview()/updateSafeAreaPreview()持有previewRectActivity 内的SafeAreaEditorView仅在预览矩形非空时显示尺寸固定按 1920×720 渲染测试editorDefaultMatchesTheCurrentMarkerSafeArea()保证编辑器默认框与当前 marker 安全区在 1 像素误差内对齐。7. 仪表盘内容选择与转向卡片针对本模式仪表盘内容dashboard content的行为未设置时默认Map with turn card即使用 iPhone 自带玻璃拟态转向卡片已保存的选择会被保留对应cluster_content偏好Map with custom turn card改用 DiPlay 自绘的 maneuver 覆盖层支持实时位置/尺寸控制偏好键包括cluster_turn_card_overlay_size/x_percent/y_percent/opacity_percent见 AirPlayPersistence.kt#L87-L90界面提供 2% 步进的位置调节、Small/Medium/Large 尺寸与不透明度档位turn_card_overlay_note说明自定义卡片在直行段也保持显示且无需重连即可生效自定义卡片复用上游的信息条展示由手机提供的到达时间、剩余时长与剩余里程缺失的总量保持空白转向指引在路线结束/过期/断连时清除且流不活跃时整体隐藏地图朝向由手机的仪表盘流控制DiPlay 端不做干预。卡片绘制由AdbClusterActivity内的ClusterTurnCardView完成位置/透明度/夜间模式均由ClusterActivityOutput.setTurnCard()统一驱动并同步到 ActivityAdbClusterActivity.kt#L83-L89。8. 与 DiLink 5/5.1、DiLink 3 的优先级关系这是该实验功能最重要的边界来自文档“Scope and credit”一节并有对应测试佐证DiLink 5/5.1 与公开集群显示始终优先即使 ADB 开关已保存。判定逻辑在 AdbClusterRouter.enabled()DiLink51ClusterLayout.supported()基于机型指纹或ClusterMapPresentation.findDisplay()找到公开显示时ADB 路线立即让位。AdbClusterSelectionTest.kt 的三个用例分别验证DiLink 5 显示存在时enabled()为 false已验证的 DiLink 5.1 指纹即便侧屏缺失不回退到 ADB私有显示未确认前原始虚拟流保持不动若确认发生在 CarPlay 已启动之后DiPlay 会重连一次以请求 1920×720并在该过渡期间黑幕覆盖仪表盘测试absentPrivateTargetKeepsTheVirtualStreamEvenWhenAdbIsEnabled()验证目标缺失时回退到 1280×720 的虚拟流配置仅关闭 ADB 开关不会动已保存的集群地图启用偏好测试turningOffAdbKeepsTheExistingClusterMapPreference()验证cluster_map_enabled不受adb_cluster_activity_enabled影响选中 DiLink 4 ADB 选项后自动 DiLink 3 集群模式命令被抑制路由报告中的diLink3ModeSwitchSuppressed字段。原因仅凭已安装的 AMap 适配包无法判断车型代际而 DiLink 3 的集群模式切换命令可能把 DiLink 4 仪表盘切到半屏或关闭其原生投屏挂起的 DiLink 3 恢复日志recovery journal会被保留直到 ADB 选项被取消勾选用户选择的原生投屏模式本身保持不变USB 重连与颜色控制沿用 main 分支上的既有实现文档同时坦承自动化测试无法在其他车上建立可见位置的证据。9. 可选能力原厂地图挂起与 HUD 文本文档“Optional stock map and HUD text”一节描述了两项默认关闭的可选能力9.1 原厂地图挂起stock-map hold该路线与 PR #187 共享解码表面只有一个属主。挂起默认关闭一旦选择“按组件/包挂起”修改 OEM 状态前先写恢复日志journal每次启动前检查状态在失败、停止、或崩溃后下一次应用启动时恢复精确的原始状态恢复失败则保留日志使用已授权的本地 ADB持续重试若恢复无法完成下一次挂起请求将被拒绝——在恢复成功之前原厂地图可能保持禁用状态force-stop 也无法保证立即恢复。实现见 BydOemClusterNavi.kt挂起目标为com.byd.automap包或其MeterActivity组件通过pm default-state/enable/disable/disable-user/disable-until-used --user 0 component命令操作command()方法BydOemClusterNavi.kt#L76-L88并以DIPLAY_PM_RC:0哨行确认命令成功日志格式为TARGET:originalState:leaserelease()失败后每 30 秒重试一次且“即使 acquire 尚未落盘日志也始终入队释放”。配置开关为oem_cluster_holdBydOutputSettings.kt 中KEY_OEM_CLUSTER_HOLD。holdForLaunch()是阻塞调用注释明确只允许在 ADB 路由工作线程上执行绝不可在主线程调用。9.2 HUD 文本HUD 文本默认关闭且让位于活跃导航导航结束走文本清除时先清转向/里程记录既有的固件、接收端/版本与签名证书限制依然有效DiLink 4 集群视频不代表 DiLink 4 HUD 支持本次 PR 未附带经过验证的 DiLink 4 HUD 接收端配置receiver profile。诊断导出中会包含固件、已安装接收端版本、证书与权限元数据供评估新配置使用——文档特别提醒不要仅凭包的存在就添加配置。PR #187 中被删除的 fork 应用 ID/build 变更与 HUD 诊断工具被有意排除在本路线之外。10. 关键偏好键速查偏好键作用定义位置adb_cluster_activity_enabledDiLink 4 ADB 集群视频实验开关AirPlayPersistence.kt#L76cluster_map_enabled既有集群地图启用偏好ADB 开关关闭时保持不变AirPlayPersistence.kt#L75cluster_content仪表盘内容选择默认 Map with turn cardAirPlayPersistence.kt#L81cluster_safe_area_1920x720仪表盘专用安全区映射独立于主显示AirPlayPersistence.kt#L856-L865cluster_turn_card_overlay_*自定义转向卡片尺寸/位置/不透明度AirPlayPersistence.kt#L87-L90oem_cluster_hold原厂地图挂起模式默认关闭BydOutputSettings.kt#L2411. 致谢与许可文档保留了完整的署名直接am start-activity --display … -f 0x18000000方案沿用 寒叙Hanxu4131发布的 legacy platform-21 实现涉及LegacyClusterTarget.kt、LegacyClusterMap.kt与ClusterMapActivity.kt实车测试与反馈来自 ojjj13实现与调试协助来自 ChatGPT/CodexDiPlay/xcertplay 原作者及既有许可声明继续保留仓库内见 docs/licenses/ 目录。12. 测试与诊断入口汇总该功能的回归保障集中在以下测试均可在仓库中直接阅读AdbClusterRouterTest.kt显示 ID 解析、歧义/错误几何拒绝、直投命令构造与 shell 输出判定、逐显示 Activity 历史验证AdbClusterSelectionTest.kt开关互不覆盖、DiLink 5/5.1 优先、目标缺失时虚拟流回退DiLink4ClusterDisplayTest.kt1920×720/100% 流配置、marker 偏移与安全区换算、相似显示名拒绝ClusterActivityStateTest.kt仪表 Activity 状态机小窗/全图/覆盖态切换与重连判定运行期诊断应用私有目录下的adb-cluster-route.txt路由报告与常规诊断导出AdbClusterRouter.report()。适用前提与限制小结本功能面向 DiLink 4 车型实测为 2022 BYD Seal / DiLink 4.0 / Android 10依赖已授权的本地 ADB 与车辆原生仪表盘投屏模式其他固件未经验证DiLink 5/5.1 与公开集群显示机型下该开关自动失效。若在目标车上启用后地图不可见应先检查routeTarget是否探测到私有显示、ADB 授权状态以及诊断导出中的launchAccepted与实际显示确认结果。赞分享移动开发智能硬件音视频【免费下载链接】DiPlayIndependent CarPlay receiver for compatible Android head units. Wired and wireless public preview.项目地址https://gitcode.com/gh_mirrors/di/DiPlay点击查看免费下载相关推荐INAV 仪表盘显示DASHBOARD完整指南I2C OLED 显示屏配置、页面机制与硬件改造INAV 仪表盘显示DASHBOARD完整指南I2C OLED 显示屏配置、页面机制与硬件改造 INAVNavigation enabled fligh无人机嵌入式智能硬件终极指南OpenCore Legacy Patcher解决老Mac投影仪多屏显示问题 ️终极指南OpenCore Legacy Patcher解决老Mac投影仪多屏显示问题 ️ 还在为老款Mac连接投影仪或多显示器时遇到黑屏、分辨率异常或操作系统固件驱动开发告别显示困扰OpenCore-Legacy-Patcher投影仪与多屏输出全攻略告别显示困扰OpenCore Legacy Patcher投影仪与多屏输出全攻略 老旧Mac升级新版macOS后外接投影仪或显示器时是否遇到过画面闪烁、分辨操作系统固件驱动开发上一篇witty-ops-cases案例分析20节点160卡跑baichuan-7B模型内存溢出问题深度解析下一篇iTrustee_tzdriver完全指南开启ARM服务器机密计算之旅创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑