手套箱 07 · 物理按键扩展设计(Meego 5458412)

本篇回答:手套箱物理按键怎么做、为什么这么做。这是需求设计篇,与本库 02/03 篇(软按键业务流与源码)互补。

⚠️ 状态声明(必读):技术方案处于修订版待用户确认状态(2026-10-18 定稿,经红队审查修订),确认前不改业务代码;埋点 source 协议是遗留 TODO,待产品/数据方确认。本篇是方案的知识库化整理,不代表代码已落地。

基线声明:

  • 主锚点(W)=/home/zbc/car/fuben4_micarsettings/MiCarSettings-5458412,origin/dev @ 930be9145e06a0a390d5982b6d713dc381004f7c(2026-10-17),分支 feature/meego-5458412-glovebox-button。本篇行号以此为准。
  • 出货对照=/home/zbc/car/pack_a17_cn_20260923(快照,本篇未引用其行号)。
  • 平台源码=/home/zbc/pangu/xcd_xring_a17_fermi/vendor/micar。
  • 一手资料=/home/zbc/下载/test/车机Feature/Meego 5458412/(下称 M 目录):docs/技术方案-手套箱物理按键.md、scan/手套箱物理按键-代码扫描.md、research/方案红队审查.md、test/自测用例-手套箱物理按键.md。

1. 需求边界

一句话:在 Modena-L / MANN(A17)车型上,新增手套箱物理按键 GlvBoxBtnSts 触发入口,仅在 ACC/Run 下复用现有 HMI 软按键的完整开箱流程,并补物理来源埋点。交付仅限 MiCarSettings,不改 SC12/SC49、平台 AIDL 或车辆属性 SDK。

边界逐条:

边界内容依据
触发信号Body.GLOVE_BOX_BUTTON_STATUS = 0x61401781(十进制 1631590273),INT32/GLOBAL/BODY平台 Body.java:1841-1848;AIDL MiVehicleProperty.aidl:1614-1619
触发枚举ERROR=0 / NOT_PRESSED=1 / PRESSED=2 / NO_INFO=3,需求语义为 0x2: Psd平台 Body.java:6948-6953;SDK vehicle.support:0.11.70-SNAPSHOT 已含,无需升级
电源前置严格 ACC=2 或 RUN=3;OFF=0/AWAKE=1/START=4 均不允许——禁止 >=ACC,因为 START=4 > ACC平台 Driving.java:10876-10885(PowerStatus)
行为等价不可用按原因 Toast、已开启 Toast「请手动关闭手套箱」、无密码直接开箱、有密码拉密码页、错误达上限走车主账号验证——与 HMI 软按键同一份逻辑软按键主流程 GloveBoxController.kt:196-302
车型范围Modena L 27C / E4U3(fermi)、Mann 28A / E4(feynman),均 A17;不写死 device,用 POWER 配置字 + 真实信号门控配置字读取 CarConfigManager.kt:139-146;入口显隐先例 VehicleControlSettingsFragment.java:168-172
责任分界SC12 负责软件滤波、20 秒卡滞、休眠唤醒真实状态;HMI 只消费按下沿,不做 20 秒计时M 目录 kb/FDFR-Modena-L-MANN手套箱实体按键及电释放锁.md
埋点新增物理触发来源 source,不改变现有 type=1/2 的密码语义,禁止造 type=3VehicleControlReporter.kt:104-108;TrackConstants.java:532-558

2. 总体架构:为什么不能只在 Controller 里加一个属性 ID

GloveBoxController 随设置页创建/销毁,其 getPropertyIdSet() 只监听 GLOVE_BOX 与 CAR_MODE_STATUS(GloveBoxController.kt:99-102),且现有单测断言恰好两个属性(GloveBoxControllerTest.kt:107-123)。而物理按键要求页面未打开时也能响应——这决定了必须是「进程级常驻监听 + 共享业务流程」两段式:

flowchart TD
    subgraph CAR["车端(SC12 责任域)"]
        BTN["实体按键<br/>GlvBoxBtnSts 0x2:Psd"]
        SC12["SC12<br/>软件滤波/20s 卡滞/休眠唤醒"]
        VHAL["VHAL 属性<br/>GLOVE_BOX_BUTTON_STATUS<br/>0x61401781"]
        BTN --> SC12 --> VHAL
    end
    subgraph BASE["base/settingsVehicleLib(只注册分发,不写业务)"]
        VPL["VehiclePermanentListener<br/>getPropertyIdSet 新增按键属性<br/>prepared 时重注册"]
    end
    subgraph FEAT["settingsPage/VehicleBodyControl(feature 业务)"]
        PBH["GloveBoxPhysicalButtonHandler(新增)<br/>三态边沿/主线程串行<br/>每次沿重读门控/写前复查注入"]
        ORH["GloveBoxOpenRequestHandler(新增,共享)<br/>不可用Toast/已开启Toast<br/>无密码开箱/密码页/车主验证<br/>统一写入+埋点(最多一次)"]
        CTRL["GloveBoxController(改)<br/>点击分支委托共享处理器"]
    end
    WRITE["写 GLOVE_BOX=OPEN<br/>0x6140b407"]
    TRACK["埋点 TIP_OPEN_GLOVE_BOX<br/>type(密码维度)+source(触发来源)"]

    VHAL -->|"onPropertyChanged"| VPL
    VPL -->|"回调先过滤 propertyId<br/>再统一 post 主线程"| PBH
    PBH -->|"NOT_PRESSED→PRESSED 沿<br/>且门控全过"| ORH
    CTRL -->|"点击,source=HMI"| ORH
    ORH -->|"物理:beforeOpen 复查通过后<br/>GlobalCarPropertyManager.setCarProperty"| WRITE
    ORH -->|"软:setVehicleProperty(原通路)"| WRITE
    ORH -->|"reportOpenGloveBox(type, source)"| TRACK

关键结构选择(全部有代码实证):

  • 常驻宿主选 VehiclePermanentListener 而非 GlobalCarPropertyManager 或 GloveBoxModulePublishService:前者在属性服务 prepared 时先重注册属性、再通知业务回调(VehiclePermanentListener.java:103-115),覆盖休眠唤醒/服务重连;GlobalCarPropertyManager.addPropertyCallback() 只做一次性注册和转发,没有 prepared 重注册补偿(GlobalCarPropertyManager.kt:40-59);GloveBoxModulePublishService 的 keep_alive=false(settingsPage/VehicleBodyControl/src/main/AndroidManifest.xml:24-27),不能保证需要时存活。
  • base 不写业务:VehiclePermanentListener 在 settingsVehicleLib,无法反向依赖 VehicleBodyControl 的密码 UI;它只新增一个属性 ID 并复用既有分发(VehiclePermanentListener.java:393 遍历 CopyOnWriteArrayList 回调,列表声明在 :69)。
  • 注册时机:MainThreadStartTask.execute() 已在主线程完成 GlobalCarPropertyManager.init(:62)与 VehiclePermanentListener.getInstance().init()(:66);物理 Handler 放进异步段 initInAsync()(:80-117)请求初始化,不新增主线程同步属性读取。该异步段已有 app → VehicleBodyControl 的依赖先例(ChildSeatSignalSync.INSTANCE.sync(),:111)。开机覆盖由既有 BootCompleteReceiver 保证(app/src/main/AndroidManifest.xml:1615-1619),无需新增组件。

3. 架构决策记录 D1~D8

#决策理由与代码依据
D1选 VehiclePermanentListener 常驻注册按键属性prepared 重注册 + CopyOnWrite 回调列表(VehiclePermanentListener.java:69,103-115);addCarPropertyManagerCallback() 是公开入口,已连接时在调用线程立即回调 prepared(:305-313),业务留在 feature 模块不下沉
D2提炼共享 GloveBoxOpenRequestHandler需求要求「同 HMI 软按键逻辑」——提炼同一处理器而非复制近似逻辑,保证长期一致;通过构造函数注入 openProperty/beforeOpen/beforeVerifyUi 保留两条写入通路与门控差异
D3严格三态边沿只有 NOT_PRESSED→PRESSED 触发;初始/ERROR/NO_INFO/unavailable/重连一律先 UNKNOWN。依据:注册可能同步回放缓存值(CarPropertyCacheManager.java:197-223,:222 直接 callback.onChangeEvent(value)),「仍按住」与「新按下」无法区分
D4全部按键状态主线程串行不只 UI,边沿基线、prepared/released、注册幂等都 post 到同一主线程 Handler;addCarPropertyManagerCallback 可能在任意调用线程立即回调(VehiclePermanentListener.java:310-312),不串行就有基线竞态
D5最终写前复查(beforeOpen)密码/账号验证是异步回调(GloveBoxController.kt:196-219),验证期间电源/手套箱状态可能变化;物理路径在写 OPEN 前再次检查 POWER、ACC/RUN、可用且非 OPEN;软按键 beforeOpen 恒 true 保持原行为
D6独立 source,协议单独确认type=1/2 只表达密码维度(VehicleControlReporter.kt:104-108,reportOpenGloveBox 现态 :495-505);KEY_SOURCE="source" 常量已存在(TrackConstants.java:534)且有带 source 上报先例(reportEnterMirrorAdjust,:143-153),但其他事件的 SOURCE_SETTINGS=1/SOURCE_OTHER=2(:38-42)不能借用——手套箱专属枚举值待产品/数据方确认
D7仅物理入口关系统面板物理按键可能在任意前台页面触发,密码页需防控制中心遮挡——先例是 MIS 入口拉起验证 UI 前发 Intent.ACTION_CLOSE_SYSTEM_DIALOGS(GloveBoxNavigationHandler.kt:104-107,调用点 :76,:82);软按键不发,行为零回归
D8不加长期 inFlight 锁/新文案/车型硬编码密码 Activity 启动异常或无结果回调时,长期锁会永久卡死后续请求;未知 reason 需求未给文案,保持软按键默认分支(GloveBoxController.kt:288-302);车型用 POWER 配置门控而非 device 判断

4. 三态边沿状态机

内部状态只有 UNKNOWN / NOT_PRESSED / PRESSED 三个,唯一触发沿 = NOT_PRESSED→PRESSED:

stateDiagram-v2
    [*] --> UNKNOWN : 进程启动/注册无有效快照
    UNKNOWN --> NOT_PRESSED : 有效值 NOT_PRESSED(布防)
    UNKNOWN --> PRESSED : 首个有效值 PRESSED(只建基线,不触发)
    NOT_PRESSED --> PRESSED : ★按下沿,唯一触发
    PRESSED --> NOT_PRESSED : 松开(重新布防,可再触发)
    NOT_PRESSED --> NOT_PRESSED : 重复值,不触发
    PRESSED --> PRESSED : 重复值,不触发
    UNKNOWN --> UNKNOWN : ERROR/NO_INFO/未知值/unavailable
    NOT_PRESSED --> UNKNOWN : ERROR/NO_INFO/未知值/unavailable/released
    PRESSED --> UNKNOWN : ERROR/NO_INFO/未知值/unavailable/released

全转换表(含异常与生命周期行):

当前状态输入事件新状态允许触发
无有效初始快照init/prepared 读不到可用值UNKNOWN否
UNKNOWN值=NOT_PRESSED 且事件可用NOT_PRESSED否(布防)
UNKNOWN值=PRESSED 且事件可用PRESSED否(只建基线)
UNKNOWNERROR / NO_INFO / 未知值 / unavailableUNKNOWN否
NOT_PRESSED值=PRESSED 且事件可用PRESSED是(唯一)
NOT_PRESSEDNOT_PRESSED 重复NOT_PRESSED否
NOT_PRESSEDERROR / NO_INFO / 未知值 / unavailableUNKNOWN否
PRESSED值=NOT_PRESSED 且事件可用NOT_PRESSED否(重新布防)
PRESSEDPRESSED 重复PRESSED否
PRESSEDERROR / NO_INFO / 未知值 / unavailableUNKNOWN否
任意onPropertyManagerReleased()(服务断开)UNKNOWN否
任意重连后首个回调为 PRESSEDPRESSED否(快照只布防)
任意重复 init不变否(幂等,不重置基线)

要点:onPropertyManagerPrepared() 在主线程读当前快照直接建立状态,不把快照当按下沿;初始已是 PRESSED 时必须经历 PRESSED→NOT_PRESSED→PRESSED 才触发;ERROR/unavailable 恢复后的第一个有效 PRESSED 同样只建基线。这套规则是红队审查「必须修正 1」的落点(M 目录 research/方案红队审查.md)。

5. 门控顺序与最终写前复查

每次有效按下沿,主线程依次执行(顺序即语义):

  1. 重读手套箱锁型配置:CarConfigManager.getGloveBoxLockType(),仅 POWER 继续。配置未就绪时默认值是 MANUAL(CarConfigManager.kt:139-146),因此禁止启动时缓存默认值后永久关门——每次沿重新读,配置后变为 POWER 仍可工作。
  2. 电源严格判等:== ACC || == RUN,其余(OFF/AWAKE/START)退出。
  3. 读完整 GLOVE_BOX 属性:先看 MiCarPropertyValue.status 是否 AVAILABLE(工具方法 VehiclePropertyUtil.java:173-182),再看 value;null/unavailable 只能进现有不可用原因映射,禁止把空值当 CLOSE——getIntPropertyValue(null) 会返回 0(VehiclePropertyUtil.java:55-70),而 0 恰好是 CLOSE,不拦就会误判。
  4. 可用且已 OPEN:只 Toast「请手动关闭手套箱」(glove_box_close_notice,软按键同款,GloveBoxController.kt:261-263),不写属性。
  5. 其余进入共享流程:无密码直接开箱 / 密码页 / 错误达上限走车主账号验证(保留 P 挡约束,GloveBoxAccountVerifyUtils.kt:45-57,非 P 挡 Toast 不拉页)。

写前复查(beforeOpen):密码/账号验证是异步的,验证期间用户可能切电源、箱子可能已被其他途径打开。物理路径向共享处理器注入 beforeOpen:最终写 OPEN 前再次检查「POWER 配置 + 严格 ACC/RUN + GLOVE_BOX 可用且非 OPEN」,失败则不写、不上报开箱事件,只记录拦截原因。软按键 beforeOpen 恒 true,不新增二次门控。

写入通路分离:软按键仍走原 setVehicleProperty(Controller 既有通路,GloveBoxController.kt:222-229);物理入口用 GlobalCarPropertyManager.setCarProperty()(MIS 入口先例,GloveBoxNavigationHandler.kt:125-131),不用 VehiclePermanentListener 的离线排队(mWaitingVehicleDataList,VehiclePermanentListener.java:106-114),避免服务恢复后执行过期开箱意图。

sequenceDiagram
    participant VHAL as "VHAL(SC12)"
    participant VPL as "VehiclePermanentListener"
    participant PBH as "GloveBoxPhysicalButtonHandler"
    participant ORH as "GloveBoxOpenRequestHandler(共享)"
    participant UI as "密码/账号验证页"
    participant PROP as "GlobalCarPropertyManager"

    VHAL->>VPL: GLOVE_BOX_BUTTON_STATUS 变化
    VPL->>PBH: 分发(回调列表遍历)
    PBH->>PBH: 过滤 propertyId → post 主线程 → 三态边沿
    Note over PBH: 仅 NOT_PRESSED→PRESSED 继续
    PBH->>PBH: ①重读 POWER 配置 ②严格 ACC/RUN ③完整 status/value
    PBH->>ORH: onAvailableRequest(isOpened, source=PHYSICAL)
    alt 已开启
        ORH->>UI: Toast「请手动关闭手套箱」
    else 无密码
        ORH->>ORH: beforeOpen() 二次复查
        ORH->>PROP: setCarProperty(GLOVE_BOX, OPEN)
        ORH->>ORH: reportOpenGloveBox(type=1, source=物理) 仅一次
    else 有密码/达上限
        ORH->>UI: beforeVerifyUi() 关闭系统面板 → 拉起验证页
        Note over ORH,UI: source 作为不可变参数捕获进回调闭包
        UI-->>ORH: 异步回调成功
        ORH->>ORH: beforeOpen() 二次复查
        alt 复查通过
            ORH->>PROP: setCarProperty(GLOVE_BOX, OPEN)
            ORH->>ORH: reportOpenGloveBox(type=2, source=物理) 仅一次
        else 复查失败(切 OFF/AWAKE/START、已 OPEN、unavailable)
            ORH->>ORH: 不写、不报,只记录拦截原因
        end
    end

6. 并发语义:后请求覆盖前请求,source 不可变穿透

  • 单回调槽:通用密码框架 PinPasswordCheckUtils 只有一个 mCallback 槽(PinPasswordCheckUtils.kt:58),每次 goToCheckPassword 直接覆盖(:147)再起 Activity(:150-159);结果广播回来调当前槽(:64-70)。
  • singleInstance 密码页:GloveBoxPasswordDialog 为 singleInstance + 独立 taskAffinity(VehicleBodyControl/AndroidManifest.xml:30-38),onNewIntent 重建 Fragment(GloveBoxPasswordDialog.kt:59-62)。
  • 结论性语义:软/物理并发发起密码请求时,后请求替换当前页面与结果回调,前请求不再开箱;最终最多一次有效开箱和一次开箱埋点。
  • source 不共享:每次请求的 source 作为不可变参数被回调闭包捕获,穿透异步验证;禁止使用共享可变 currentSource 字段——否则后请求会污染先发起请求的上报来源。
  • 不加长期 inFlight 锁:Activity 启动异常或用户未返回结果时回调不一定到达,长期锁会把后续所有请求永久卡死(红队「必须修正 4」与建议项)。

7. 文件级改动清单(方案 §4)

#文件改动
1base/settingsVehicleLib/.../VehiclePermanentListener.javagetPropertyIdSet()(:274-303)增加 Body.GLOVE_BOX_BUTTON_STATUS;只注册分发,不写业务;复用 prepared 重注册
2新增 settingsPage/VehicleBodyControl/.../glovebox/GloveBoxPhysicalButtonHandler.kt实现 CarPropertyManagerCallback;单例 + init 幂等;onPropertyChanged 第一行过滤 propertyId 再 post 主线程;三态边沿;每次沿重读 POWER/ACC-RUN/完整状态;注入 beforeOpen 复查
3新增 .../glovebox/GloveBoxOpenRequestHandler.kt从 GloveBoxController 原样提炼:已开启 Toast、不可用原因映射、无密码开箱、密码页、车主验证、统一写入 + 一次埋点;构造函数注入 openProperty/beforeOpen/beforeVerifyUi
4改 .../glovebox/GloveBoxController.kt点击分支委托共享处理器(:115-123 改为 onAvailableRequest(tab.mIsSelected, SOURCE_HMI) / showUnavailableNotify(...));删除已迁移私有方法;getPropertyIdSet() 仍只留两个属性(:99-102);软按键不发 CLOSE_SYSTEM_DIALOGS、不加二次门控
5app/.../MainThreadStartTask.javainitInAsync()(:80-117)前段请求一次 GloveBoxPhysicalButtonHandler.init(mApplication);异步段而非主线程,不扩大冷启动耗时
6base/settingsBaseLib/.../VehicleControlReporter.ktreportOpenGloveBox(type)(:495-505)增加 source 参数,写既有 KEY_SOURCE;新增手套箱专属来源枚举(建议 HMI=1 / PHYSICAL_BUTTON=2,协议值待确认);type 语义不变,不加 type=3
+src/test/.../glovebox/ 单测三态边沿全覆盖 + 共享流程必要用例(见 §9);现有 GloveBoxControllerTest 继续跑

不改清单及依据:

不改依据
SC12 / SC49 / 平台 AIDL信号与枚举平台已具备(Body.java:1841-1848,6948-6953);用户确认仅 HMI 交付
vehicle.support 版本0.11.70-SNAPSHOT 已含目标属性
GloveBoxPasswordTools / 密码存储复用现有密码与错误上限;本需求不重做密码系统
GloveBoxModulePublishServicekeep_alive=false(模块 Manifest :24-27),不能当常驻宿主
VehiclePermanentListener 内业务逻辑base 无法依赖 feature 的密码 UI,只加属性 ID
车型/device 硬编码POWER 配置字 + 信号能力门控已覆盖目标车型
20 秒卡滞计时/软件滤波FD&FR 明确属 SC12
未知 reason 新文案保持现有默认分支,不擅自创造产品文案
TrackConstants.javaKEY_SOURCE 已存在(:534)

另注:手套箱业务源码集中在 src/main/java,无 dcddif/xcddif/f3dif 同名副本(已 find 实证),sourceSets(build.gradle:57-89)无需多副本齐改。

8. 行为对照矩阵(物理 vs 软按键)

场景物理按键预期软按键预期
初始 UNKNOWN→PRESSED只建立 PRESSED 基线,不触发不适用
初始已为 PRESSED必须松开再重新按下才触发不适用
连续 PRESSED不重复触发不适用
ERROR/NO_INFO/unavailable→PRESSED不触发;需重新 NOT_PRESSED→PRESSED不适用
NOT_PRESSED→PRESSED进入一次门控流程每次点击进入流程
OFF / AWAKE / START不执行本需求不改变
ACC / RUN允许执行本需求不改变
非 POWER 手套箱忽略并记录原因;配置变 POWER 后可工作入口按现有配置隐藏(VehicleControlSettingsFragment.java:168-172)
GLOVE_BOX null/unavailable只进原因映射,禁止空值当 CLOSE与现有不可用分支一致
不可用 + 未解防/防玩/代客复用对应 Toast(GloveBoxController.kt:288-302)与现状一致
不可用 + 未知 reason保持默认分支,不新造文案与现状一致
已开启Toast「请手动关闭手套箱」,不写属性与现状一致
无密码 + 关闭写 OPEN 一次;type=1, source=2(枚举待确认)写 OPEN;type=1, source=1
有密码 + 未达上限关系统面板后弹密码页;成功 type=2, source=2直接弹密码页;成功 type=2, source=1
密码失败/取消不写 OPEN、不上报开箱与现状一致
验证期间切 OFF/AWAKE/START 或已 OPEN/unavailable成功回调也不写、不报(beforeOpen 拦截)不新增二次门控
错误达上限 + P 挡车主验证成功清零并开箱,type=2, source=2同流程,source=1
错误达上限 + 非 P 挡复用现有提示,不拉验证、不开箱与现状一致
软/物理密码请求并发后请求覆盖前请求,最多一次有效开箱与一次事件同左
服务断开/重连立即 UNKNOWN,重连快照只布防;不排队补开过期意图本需求不改变

9. 风险表与测试矩阵摘要

主要风险与缓解(全表见 M 目录技术方案 §8):

风险缓解
初始/无效恢复/重连误开箱三态仅 NOT_PRESSED→PRESSED;released 即 UNKNOWN;快照只布防
多线程基线/注册竞态边沿、prepared/released、注册全部同一主线程 Handler 串行;init 幂等
验证期间前置条件变化仍开箱物理路径写前二次复查 POWER/ACC-RUN/可用非 OPEN
空属性当关闭可用先查完整 status 再读 value(VehiclePropertyUtil.java:55-70,173-182)
启动默认 MANUAL 永久关门每次沿重读配置,不缓存启动值
软按键回归只迁移原逻辑;写入走原通路;不加二次门控/面板行为;跑现有单测 + 双变体编译
服务恢复执行过期意图物理写入不走永久监听器离线队列(VehiclePermanentListener.java:106-114)
type 语义污染独立 source,禁 type=3
source 协议未确认手套箱专属常量名;产品/数据方确认后才允许合入
异步来源被覆盖source 不可变捕获进闭包,禁共享 currentSource
并发重复开箱沿用 singleInstance + 单回调槽后请求优先;不加易卡死锁
非设置页 tabInstanceId 误导验收时记录实际值,不解释为本次物理会话(reportOpenGloveBox 现带 KEY_TAB_INSTANCE_ID,:500)
未知 reason 无文案保持现状并显式列入测试

测试矩阵(全表在 M 目录 test/自测用例-手套箱物理按键.md,执行走 car-signal-mock-test 流程,逐例留 uiautomator/截图/logcat 三证并复位信号):

  • E01~E09 信号边沿与生命周期(9 例):初始按住不触发、连续/重复 PRESSED、松开重按、ERROR/NO_INFO/unavailable 恢复、服务断连重连、force-stop 重启不执行过期意图。
  • G01~G07 前置门控(7 例):OFF/AWAKE/START 全拒(G03 专证不是 >=ACC)、ACC/RUN 放行、MANUAL 忽略且配置变 POWER 后可恢复、属性 null/unavailable 进原因映射。
  • F01~F17 业务流程(17 例):三类不可用 Toast、未知 reason 现状记录、已开启、无密码/有密码/失败/取消、达上限 ±P 挡、软物理并发后请求为准、验证期间切电源或状态变化被写前复查拦截。
  • R01~R07 兼容与回归(7 例):现有单测全过、xcd_cn_a17 Debug/Release 编译、另一非目标变体编译防共享代码破坏、软按键全链路无回归、语音/MIS 冒烟(R07,本需求未改其通路——MIS 入口见 04 篇)。

10. 当前状态与开放问题

项状态
技术方案修订版待用户确认(2026-10-18,含红队 4 项修正);确认前不改业务代码
source 协议遗留 TODO:手套箱 source 的 key、枚举值、HMI 旧事件是否补 source=1,均无数据协议原文佐证;用户 2026-10-19 指示暂不拍板,Gerrit 合入前需产品/数据方确认
Q1 初始/重连/恢复时已 PRESSED 是否立即响应方案 A(当前建议,安全优先)=只建基线,须松开重按;方案 B=首个有效 PRESSED 直接响应。用户已于 2026-10-19 发起与产品讨论,尚无结论;未决前三态边沿仅为推荐方案
前序 PRD / 测试用例表当前账号无读权限(M 目录 README 开放问题节有占位与补扒方法)
台架兼容性待确认;当前 mach 台架已实证手套箱入口 + 密码页可调出(2026-10-19/20,入口显隐靠 LOCK_TYPE_CONFIG=POWER 注入 + force-stop;密码页 exported=false 需 root 直拉;注意 wrong_times≥5 残留会变扫码页)——配方见 /home/zbc/下载/test/车机JIRA/.claude/skills/car-signal-mock-test/references/场景-手套箱入口与密码页.md
节点开发&提测 2026-10-20~10-22;代码合入 DDL 2026-10-23

11. 证据清单

文件行号说明
/home/zbc/下载/test/车机Feature/Meego 5458412/docs/技术方案-手套箱物理按键.md全文方案主体(需求结论/§4 文件 diff/§5 对照矩阵/§8 风险/§10 D1~D8/§11 Q1)
.../Meego 5458412/scan/手套箱物理按键-代码扫描.md全文代码证据(信号实证/软按键流程/常驻入口选择/埋点现状/改与不改清单)
.../Meego 5458412/research/方案红队审查.md全文4 项必须修正(三态边沿/主线程串行/写前复查/source 与并发)
.../Meego 5458412/test/自测用例-手套箱物理按键.md全文E/G/F/R 测试矩阵全表
.../Meego 5458412/README.md24-92需求速查、开放问题、节点排期
平台 .../support-lib/src/mi/car/config/Body.java1841-1848, 6948-6953GLOVE_BOX_BUTTON_STATUS=0x61401781;枚举 ERROR/NOT_PRESSED/PRESSED/NO_INFO
平台 .../aidlproperty/MiVehicleProperty.aidl1614-1619AIDL 映射 SYSTEM_GLOVE_BOX_BUTTON_STATUS=1631590273
平台 .../support-lib/src/mi/car/config/Driving.java10876-10885PowerStatus:OFF=0/AWAKE=1/ACC=2/RUN=3/START=4,证 >=ACC 错误
平台 .../support-lib/src/mi/car/config/Peripheral.java572-610GLOVE_BOX(0x407)/LOCK_TYPE_CONFIG(0x409)/UNAVL_REASON(0x40a)
W:app/.../MainThreadStartTask.java62, 66, 76, 80-117主线程初始化 GlobalCarPropertyManager/VehiclePermanentListener;异步段先例 ChildSeatSignalSync(:111)
W:app/src/main/AndroidManifest.xml1615-1619BootCompleteReceiver 覆盖开机
W:base/settingsVehicleLib/.../VehiclePermanentListener.java69, 95-120, 274-317, 362-394CopyOnWrite 回调表;prepared 重注册(:103-115)/released(:118-120);注册集合(:274-303);add 回调立即 prepared(:305-313);分发(:393);离线队列(:106-114)
W:base/settingsVehicleLib/.../GlobalCarPropertyManager.kt40-59add/removePropertyCallback 无 prepared 重注册
W:base/settingsVehicleLib/.../CarConfigManager.kt139-146getGloveBoxLockType,默认 MANUAL
W:base/settingsVehicleLib/.../vehicle/CarPropertyCacheManager.java197-223注册同步回放缓存(:222 onChangeEvent)
W:base/settingsVehicleLib/.../vehicle/VehiclePropertyUtil.java55-70, 173-182null→0 陷阱;status==STATUS_AVAILABLE 检查
W:settingsPage/VehicleBodyControl/.../glovebox/GloveBoxController.kt99-102, 115-123, 166-188, 196-302软按键监听集/点击分支/可用性驱动/密码与账号异步回调/统一写入+埋点/原因映射
W:.../glovebox/GloveBoxNavigationHandler.kt62-86, 94-107, 114-131MIS 先例:POWER 检查、拉验证页前 CLOSE_SYSTEM_DIALOGS(:104-107)、GlobalCarPropertyManager 写开箱(:125-131)
W:.../glovebox/GloveBoxAccountVerifyUtils.kt45-57车主验证 P 挡约束(:50-55)
W:settingsPage/VehicleBodyControl/src/main/AndroidManifest.xml24-27, 30-38PublishService keep_alive=false;密码页 singleInstance
W:.../glovebox/GloveBoxPasswordDialog.kt59-62onNewIntent 重建 Fragment
W:base/settingsBaseUi/.../password/PinPasswordCheckUtils.kt57-70, 146-159单回调槽 mCallback(:58)被后请求覆盖(:147);结果广播回调(:64-70)
W:base/settingsBaseLib/.../track/TrackConstants.java532-558VehicleControlKey.KEY_SOURCE(:534)/KEY_GLOVE_BOX_OPEN_TYPE(:558) 已存在
W:base/settingsBaseLib/.../track/VehicleControlReporter.kt38-42, 104-108, 143-153, 489-505SOURCE_SETTINGS/OTHER 不可借用;type=1/2 密码维度;source 上报先例;reportOpenGloveBox 现态
W:settingsPage/VehicleBodyControl/.../VehicleControlSettingsFragment.java168-172非 POWER 隐藏手套箱入口
W:.../vehicle/VehicleBodyPropertyMap.kt42-49软按键 allowClickWhenDisabled(不可用也可点以弹原因)
W:src/test/.../glovebox/GloveBoxControllerTest.kt107-123现有断言恰两个监听属性,物理信号不得塞进 Controller
W:settingsPage/VehicleBodyControl/build.gradle57-89sourceSets;glovebox 仅 src/main 一份(find 实证)
/home/zbc/下载/test/车机JIRA/.claude/skills/car-signal-mock-test/references/场景-手套箱入口与密码页.md全文mach 台架入口/密码页调出配方与坑(wrong_times 残留等)

篇间导航