手套箱知识库 · 总索引
小米智能座舱 MiCarSettings ·「车辆控制」页 →「手套箱」(软按键开箱 + 密码手套箱 + 物理按键扩展)全解
基线声明
- 主锚 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(pack_a17_cn_20260923 快照,判包新旧/行号对照用)- 平台源码:
/home/zbc/pangu/xcd_xring_a17_fermi/vendor/micar(MiVehicleService / support-lib,属性与枚举定义权威源)- ⚠️ 手套箱模块全部 Kotlin(.kt),但入口 Fragment 是
VehicleControlSettingsFragment.java、属性写通道是VehicleControlManager.java、埋点常量在TrackConstants.java—— 检索必须同时覆盖.java与.kt,纯单语 grep 会漏一半- 需求:Meego 5458412(手套箱物理按键);目标车型 Mann 28A/E4(feynman)+ Modena L 27C/E4U3(fermi),均 A17;开发提测 2026-10-20~10-22,合入 DDL 2026-10-23
- 建立日期:2026-10-19(01~07 篇全部为带 file:line 证据的源码实证篇)
1. 这个功能是什么(30 秒版)
设置 → 车辆控制 →「手套箱」:CarUiTabLayout 两个并排图标 Tab——左「打开手套箱」,右「手套箱密码设置」。
- 开箱(软按键):点击后向车控属性
Peripheral.GLOVE_BOX(0x6140B407)写入OPEN(1),手套箱电动弹开。只有”开”没有”关”的下发——关箱是用户手动物理合上的;已开状态再点只弹「请手动关闭」Toast。 - 密码手套箱:可选开启 4 位数字 PIN。设密码后开箱必须先输对密码;输错 5 次锁定,锁定后必须做**车主账号验证(扫二维码)**才能开。
- 对外能力:语音助手(「打开手套箱」)/手机 App 远程开箱,走 MIS 总线,由
GloveBoxModulePublishService发布、GloveBoxNavigationHandler受理(响应码 1001 成功 / 1002 需密码 / 1003 不支持 / 1004 达上限)。 - 物理按键(本库新增主题,Meego 5458412):车侧新增物理按键,CAN 信号
GlvBoxBtnSts(0x2:Psd按下)经平台属性Body.GLOVE_BOX_BUTTON_STATUS(0x61401781)上报;Settings 侧常驻监听,只在NOT_PRESSED→PRESSED边沿触发,复用软按键同一条开箱流(门控→密码→写属性→埋点),前置条件 ACC/Run 电源挡位,依旧只开不关。交付边界仅 HMI(MiCarSettings):按键采集/卡滞 20s/电释放锁 = SC12 他组,密码协作 = SC49。
五个容易被忽视的设计点,也是历史问题的全部来源:
- 不是按车型写死显隐,而是按配置字动态显隐:车控配置
GLOVE_BOX_LOCK_TYPE_CONFIG == POWER(2)(电动手套箱)时入口才存在,否则整组从页面移除(VehicleControlSettingsFragment.java:168-172,读取默认 MANUAL,CarConfigManager.kt:139-146)。 - 密码存在 Settings.Global 而非 SharedPreferences:
glove_box_password/glove_box_password_salt/glove_box_password_wrong_times三键,SHA-256(时间戳盐+密码)哈希,跟车存储、恢复出厂即清;每次改密换盐,旧哈希自动失效。 - 账号验证不是跳页面,而是 ContentProvider call:
contentResolver.call("content://mi.car.account", "confirm", scene="glovebox_verify", style="qr_code"),且默认要求 P 挡(忘记密码分支唯一例外,传isNeedCheckGear=false跳过)。 - 写完即报语义:
openGloveBox先setVehicleProperty(GLOVE_BOX, OPEN)紧接上报埋点,不等车控回执(GloveBoxController.kt:222-229;SET 丢ThreadPoolUtils.ASYNC,VehicleControlManager.java:128-130)——埋点语义是「意图已受理」,不是「手套箱已开」。 - 可用性事实标准 = 属性状态 + 原因属性双件套:Tab 可用性看
GLOVE_BOX属性的STATUS_AVAILABLE(VehiclePropertyUtil.isPropertyAvailable,:173-182),不可用原因由GLOVE_BOX_UNAVL_REASON(0=Idle / 1=NotDisArmed / 2=AntyPlay)解释并弹对应 Toast;物理按键侧GlvBoxDcdFcnAvl/GlvBoxDcdDiRsn两个 CAN 信号在 vendor/micar 全树 grep 为零,映射实现不可见,列为底层确认项(01 篇)。
2. 文档导航
| 篇目 | 适合谁 | 一句话内容 |
|---|---|---|
| 01-需求与信号契约 | 所有人 · 物理按键起点 | Meego 5458412 需求边界、三个 CAN 信号(GlvBoxBtnSts / GlvBoxDcdFcnAvl / GlvBoxDcdDiRsn)与五个平台属性的取值契约、可用性事实标准、三个底层确认项 |
| 02-页面结构与门控 | 新手 | 挂载链(XML key → Fragment 移除机制 → Controller → 双 Tab 注册)+ 三道门控(配置字 POWER / 属性 STATUS_AVAILABLE / 账号与代客)+ Tab 三态语义表 |
| 03-开箱主流程源码精讲 | 进阶 · 核心篇 | GloveBoxController.kt 逐段精讲:双 Tab 初始化 / 属性回调 / 三分支决策(已开 Toast、无密码直开、锁定扫码、弹密码框)/ 原因 Toast / openGloveBox 写完即报 / 账号广播注册 |
| 04-密码与账号验证体系 | 进阶 | Settings.Global 三键与 SHA-256+盐、四事件同页分流、Dialog→Fragment→Tools→CheckUtils 四层架构、5 次锁定与扫码解锁、MIS 语音入口、台架 root 直拉命令 |
| 05-埋点体系 | 数据/测试 | 54662 开箱(CLICK)/ 54663 忘记密码(EXECUTE)/ 54664 密码操作(EXECUTE)字段语义全表;写完即报口径边界(MIS 不上报 54662);物理按键 source 扩展铁律 |
| 06-属性通道与台架mock | 测试/自测 | 三层属性通道(SettingsCarPropertyManager / CarPropertyCacheManager / VehicleControlManager)+ 常驻监听 VehiclePermanentListener;SET 超时校验与台架回滚假象;lshal mock 操作手册与手套箱配方 |
| 07-物理按键扩展设计 | 开发 · 方案 | D1~D8 架构决策、NOT_PRESSED→PRESSED 边沿状态机全转换表、五级门控+写前复查、并发语义(后请求覆盖前请求)、6 文件改动清单、E/G/F/R 测试矩阵 |
| 08-速查卡 | 所有人 | 一页纸速查:propId/枚举、Settings.Global 三键、台架命令、日志签名、常见假象表 |
📦 旧系列已归档:
archive/下的01-功能与页面结构.md、02-开箱业务流与密码生命周期.md、03-源码精讲.md、04-信号链路与属性.md、05-MIS语音远程与对外暴露.md、06-演进历史与问题单.md、07-埋点与测试.md为旧系列(fuben31_micarsettings 基线,2026-10-20 建),保留作历史参考与 MIS/演进史细节补充;本目录 00~08 为新系列(W=origin/dev@930be9145 基线重建),门控/流程/埋点/台架结论以新系列为准;引用旧系列行号时注意基线差异。
3. 人类学习路线
flowchart LR A["01 需求与信号契约<br/>做什么、信号与属性是什么"] --> B["02 页面结构与门控<br/>入口在哪、谁能看见"] B --> C["03 开箱主流程源码精讲<br/>点了以后发生什么(核心)"] C --> D["04 密码与账号验证<br/>PIN 怎么存/验/锁/解"] C --> E["05 埋点体系<br/>数据口径与 source 扩展"] F["06 属性通道与台架 mock"] -.自测/注入.-> C G["07 物理按键扩展设计"] -.开发前必读.-> A G -.复用同一条开箱流.-> C H["08 速查卡(旧)"] -.贯穿.-> B
- 只想了解功能/排查「不显示、置灰、不可用 Toast」:02 + 01 §可用性
- 分析「点不开、密码不弹、锁定、扫码失败」:03 + 04
- 分析「语音/远程开箱」:04 §MIS 入口 + 05 §口径边界(MIS 不上报 54662)
- 做物理按键开发/评审:01 → 07,改码前必读 03(委托点)与 05(埋点铁律)
- 台架自测:06 配方先行,mach 已实证入口+密码页(2026-10-19/20)
4. 速览:四条链路一张图
flowchart TD subgraph UI["① 设置页软按键(本仓)"] A1["车辆控制页 双Tab"] --> A2{"点击开箱 Tab"} A2 -->|"已开(mIsSelected)"| A3["Toast 请手动关闭"] A2 -->|"无密码"| A4["openGloveBox 写 GLOVE_BOX=OPEN<br/>写完即报 54662 type=1"] A2 -->|"有密码"| A5["GloveBoxPasswordDialog 4位PIN"] A5 -->|"正确"| A6["openGloveBox type=2"] A5 -->|"错5次"| A7["账号扫码验证<br/>content://mi.car.account"] A7 -->|"通过"| A6 end subgraph PHY["② 物理按键(Meego 5458412,新增)"] P1["车侧按键"] -->|"CAN GlvBoxBtnSts 0x2:Psd"| P2["属性 GLOVE_BOX_BUTTON_STATUS<br/>0x61401781"] P2 -->|"常驻监听 NOT_PRESSED→PRESSED 边沿"| P3{"五级门控<br/>电源ACC/Run·配置字·可用性·代客·密码"} P3 -->|"通过,复用软按键开箱流"| A4 end subgraph MIS["③ 语音/远程(MIS 总线)"] B1["语音助手/手机App"] --> B2["GloveBoxNavigationHandler"] B2 -->|"无密码直开"| B3["直写属性 回1001<br/>不上报54662"] B2 -->|"有密码"| B4["拉起密码页 回1002"] B2 -->|"已锁定"| B5["拉起账号验证 回1004"] B2 -->|"非POWER配置"| B6["回1003 不支持"] end subgraph VHAL["④ 信号层(平台 vendor/micar)"] C1["GLOVE_BOX 0x6140B407 RW<br/>只写 OPEN=1"] C2["GLOVE_BOX_LOCK_TYPE_CONFIG 0x409 RO<br/>MANUAL=1/POWER=2 入口门控"] C3["GLOVE_BOX_UNAVL_REASON 0x40A RO<br/>0/1/2 原因Toast"] end A4 --> C1 A6 --> C1 B3 --> C1 A1 -.显隐.- C2 A2 -.不可用Toast.- C3
5. AI 使用指引
| 你要干什么 | 必读 |
|---|---|
| 分析「入口不显示 / 置灰 / 不可用 Toast」类问题 | 02(三道门控链)+ 01 §可用性事实标准;台架复核按 06 配方(mock 0x409=2 + force-stop) |
| 分析「点击无反应 / 弹错 Toast / 开箱流程」类问题 | 03(三分支决策 + 写完即报)+ 06(属性通道与回滚假象) |
| 分析「密码 / 锁定 / 扫码验证 / wrong_times 残留」类问题 | 04(含台架 root 直拉与清零命令) |
| 埋点口径核对 / 数据对不上 / 54662 缺数 | 05(写完即报语义;MIS 路径不上报 54662 是边界不是 bug) |
| 台架自测 / mock 注入 / 判「onDataVerifyFailed」 | 06(判定只信 App 日志;vehicled 不持久 SET 回滚是假象,vehicle_mock_data 1 解法) |
| 物理按键开发 / 方案评审 / 改码 | 01 + 07;改码落点前必读 03(Controller 委托点)与 05(source 不可变捕获铁律);软按键零回归约束在 07 §并发与 §对照矩阵 |
| 判断出货包是否带某修复 | 出货对照 pack_a17_cn_20260923 快照 diff(02/03 篇方法);gerrit MERGED 不可信,只对 origin 实例 + grep 实证 |
三条纪律:
- 本库所有 file:line 均以 W(fuben4 @ origin/dev 930be9145) 为基线;在出货快照或其他分支核对时行号可能漂移,以符号定位为准(±3 内算吻合)。
- 引用任何 file:line 前必须先用 Read 打开该文件核实符号确实存在;没读过的文件只写路径不带行号。本篇 §5 与证据清单所列条目均已抽查或标注核实出处。
- 台架现象判定只信 App 日志;
onDataVerifyFailed在台架大概率是 vehicled 不持久 SET 的回滚假象(06 篇实证),不要当成 App bug 修。
6. 关键数字一页纸
6.1 propId 表(平台 Peripheral.java / Body.java / Driving.java,javap+源码双实证)
| 语义 | 常量 | propId(hex / dec) | 权限 | 取值枚举 |
|---|---|---|---|---|
| 开箱执行属性 | Peripheral.GLOVE_BOX | 0x6140B407 / 1631630343 | READ_WRITE | OpenClose{ CLOSE=0, OPEN=1 },App 只写 OPEN |
| 电机命令(监测) | Peripheral.GLOVE_BOX_MOTOR_CMD | 0x6140B408 / 1631630344 | READ | GloveBoxMotorCmd{ IDLE=0, CLOCKWISE=1, COUNTER_CLOCKWISE=2, BREAK=3 } |
| 锁类型配置字(入口门控) | Peripheral.GLOVE_BOX_LOCK_TYPE_CONFIG | 0x6140B409 / 1631630345 | READ | { MANUAL=1, POWER=2 },POWER 才显示入口 |
| 不可用原因(Toast) | Peripheral.GLOVE_BOX_UNAVL_REASON | 0x6140B40A / 1631630346 | READ | GloveBoxUnavlReason{ IDLE=0, NOT_DIS_ARMED=1, ANTY_PLAY=2 } |
| 物理按键状态(新增) | Body.GLOVE_BOX_BUTTON_STATUS | 0x61401781 / 1631590273 | READ | GloveBoxButtonStatus{ ERROR=0, NOT_PRESSED=1, PRESSED=2, NO_INFO=3 },唯一触发沿 1→2 |
| 电源挡位(物理按键前置) | Driving.POWER_MODE | 0x61407207 | READ | PowerStatus{ OFF=0, AWAKE=1, ACC=2, RUN=3, START=4(Deprecated) } —— 前置判 `==ACC |
| 车辆模式(代客门控) | Driving.CAR_MODE_STATUS | 0x6140720B | READ | CarModeStatus.NORMAL=0,非 NORMAL 密码入口置灰 |
源码锚点:Peripheral.java:576 / 586 / 596 / 606(短 ID 0x407~0x40a);Body.java:1844(0x781);Driving.java:2426(POWER_MODE=0x207)、:10876-10885(PowerStatus 枚举)。五属性全部 GLOBAL + ON_CHANGE + initialValue=0(01 篇)。
6.2 存储三键与密码常量(Settings.Global,跟车存储,恢复出厂即清)
| key / 常量 | 值 / 含义 |
|---|---|
glove_box_password | SHA-256(salt + 密码) 哈希;被哈希串是 IntArray 串如 "[1, 2, 3, 4]" |
glove_box_password_salt | 时间戳盐(System.currentTimeMillis),改密换盐 |
glove_box_password_wrong_times | 错误次数;上限 PWD_WRONG_MAX_TIMES=5 触发锁定 |
| 密码长度 / 延迟 | PWD_MAX_LENGTH=4,DELAY_TIMES=200L |
| 四事件 | INPUT_EVENT_CHECK_PWD=0 / SET_PWD=1 / CHANGE_PWD=2 / CHANGE_PWD_VERIFIED=3 |
锚点:PinPasswordTools.kt:50-68(常量区,本篇抽查);哈希实现 PinPasswordEncryptor.kt:52-64,93-100(04 篇)。
6.3 埋点三事件(OneTrack,APP_ID 31000401514,PROJECT_ID xiaomiev-cockpit-intl)
| 事件 | ID | 类型 | 关键字段 | 调用点 |
|---|---|---|---|---|
TIP_OPEN_GLOVE_BOX | 1147.1.0.1.54662 | CLICK | type:1=无密码 / 2=验证后;tab_instance_id | GloveBoxController.openGloveBox 唯一上报点(写完即报) |
TIP_GLOVE_BOX_FORGOT_PASSWORD_SUCCESS | 1147.0.0.0.54663 | EXECUTE | — | Controller + DialogActivity 双调用点(两条业务路径非重复) |
TIP_GLOVE_BOX_PASSWORD_OPERATION | 1147.0.0.0.54664 | EXECUTE | type:1=设置 / 2=关闭 / 3=修改 | 密码操作三处 |
KEY_SOURCE="source" 常量已存在(TrackConstants.java:533-534)但手套箱协议未定;物理按键扩展铁律:source 不可变捕获穿透异步回调、最终开箱点只报一次、禁 type=3(05 篇)。锚点:VehicleControlReporter.kt:106-108(openType 常量)、reportOpenGloveBox 约 :494-503(本篇抽查)。
6.4 日志签名三条(排障先认这三行)
| 签名 | 出处 | 含义 |
|---|---|---|
>>> Done set propVal: 1 to propId: 0x6140b407 | VehicleControlManager.java:135(setIntPropertyBySync) | 开箱属性已写入(异步线程),不代表手套箱已开 |
onDelayGetProp / onDataVerifyFailed propId: 0x6140b407 | SettingsCarPropertyManager.kt:193-203(handlePropertyTimeout) | SET 超时校验未等到回值——台架 vehicled 不持久 SET 的回滚假象,06 篇 mach 实测;解法 settings put --user 0 GLOBAL vehicle_mock_data 1 |
reportOpenGloveBox type= | VehicleControlReporter.kt 约 :497 | 埋点已上报(紧随写属性,不等回执) |
附:属性回调签名 onPropertyChanged: gloveBoxStatus=(GloveBoxController.kt:175,本篇抽查)。
6.5 台架命令四条(06 篇全录,mach 实证)
# ① mock 配置字 POWER(2) 让入口显示(十进制 propId,间隔≥0.25s,值要变化)
lshal debug android.hardware.automotive.vehicle@2.0::IVehicle/default --mock_from_car 1631630345 -a 0 --stat 0 -i 2
am force-stop com.android.car.settings # 重进车辆控制页生效
# ② vehicled 持久 SET(消除回滚假象;重启不清,用完必须显式归 0)
settings put --user 0 GLOBAL vehicle_mock_data 1
# ③ 密码页 root 直拉(--ei param_event_id:0=验证 1=设置 2=修改 3=已验证后修改)
am start -n com.android.car.settings/.miauto.vehicle.glovebox.GloveBoxPasswordDialog --ei param_event_id 0
# ④ 清锁定残留
settings put global glove_box_password_wrong_times 0 && am force-stop com.android.car.settingsroot 判别:adb shell "id | grep -o 'context=[^ ]*'" 须 su:s0;通道判法:dumpsys -l | grep -i vehicle 有 IVehicle/micar 为 AIDL,否则 HIDL 用 lshal(06 篇)。
7. 关联知识库
- 00-能量回收-README.md —— 同风格车设知识库;属性 mock、台架自测、「写完即报/下发覆盖」时序认知与本库互通
- 00-蜂窝网络-README.md —— 「平台受理/执行分离恒 true」认知同样适用于本功能:写属性成功 ≠ 执行完成
- 05-车辆接口层与IPC.md —— CarProperty 读写 / binder 链路底层,本功能
setVehicleProperty的通道基石(车技车设根目录)
8. 基线与纪律
- 主锚:
/home/zbc/car/fuben4_micarsettings/MiCarSettings-5458412@origin/dev930be9145e06a0a390d5982b6d713dc381004f7c;出货对照/home/zbc/car/pack_a17_cn_20260923;平台/home/zbc/pangu/xcd_xring_a17_fermi/vendor/micar。 - 行号以 W 为准;出货快照与平台树的行号仅对照不锚定。跨分支核对时以符号(函数名/常量名)定位,±3 行内漂移视为吻合。
- kt/java 双语检索:手套箱模块 .kt,入口 Fragment / 属性通道 / 埋点常量 .java;grep 必须
-include='*.kt' -include='*.java'双罩。 - file:line 纪律:引用前先 Read 核实;没读过的文件写路径不带行号或标【未核实】。禁止编造代码内容,引代码照抄原文。
- 出货判定纪律:判包新旧看 committer 时间 + 预置快照 diff;Gerrit 「MERGED」标签不可信,只对 origin 实例 + grep 实证(02/03 篇 diff 方法)。
- 性能/台架判定纪律:只信 App 日志;
onDataVerifyFailed台架回滚假象已实证(06 篇);mock 后必须复位(配置字归原值 +vehicle_mock_data 0)。
证据清单
| 文件 | 行号区间 | 说明 | 核实 |
|---|---|---|---|
vendor/micar/.../mi/car/config/Peripheral.java | :576 / :586 / :596 / :606 | 四个手套箱属性短 ID(0x407~0x40a) | 本篇抽查 |
vendor/micar/.../mi/car/config/Body.java | :1844 | GLOVE_BOX_BUTTON_STATUS = 0x781 | 本篇抽查 |
vendor/micar/.../mi/car/config/Driving.java | :2426, :10876-10885 | POWER_MODE=0x207;PowerStatus OFF/AWAKE/ACC/RUN/START=0/1/2/3/4 | 本篇抽查 |
W .../glovebox/GloveBoxController.kt | :99-102, :173-186, :222-229, :261-278 | 监听 2 属性;可用性/代客门控;openGloveBox 写完即报;三分支决策 | 本篇抽查 |
W VehicleControlSettingsFragment.java | :168-172 | POWER != getGloveBoxLockType() 即整组移除 | 本篇抽查 |
W .../common/password/PinPasswordTools.kt | :50-68 | 事件常量 0~3、PWD_WRONG_MAX_TIMES=5、PWD_MAX_LENGTH=4、DELAY_TIMES=200L | 本篇抽查 |
W VehicleControlManager.java | :128-136 | setIntProperty 丢 ThreadPoolUtils.ASYNC;>>> Done set propVal 日志 :135 | 本篇抽查 |
W SettingsCarPropertyManager.kt | :193-203 | handlePropertyTimeout / onDelayGetProp / onDataVerifyFailed(回滚假象源头) | 本篇抽查 |
W VehicleControlReporter.kt | :106-108, 约:494-503 | openType 常量 1/2;reportOpenGloveBox(54662,CLICK) | 本篇抽查 |
W TrackConstants.java | :533-534 | KEY_SOURCE="source" 已存在 | 本篇抽查 |
W CarConfigManager.kt | :139-146 | getGloveBoxLockType 读取与默认 MANUAL | 01/02 篇核实 |
W VehiclePropertyUtil.java | :173-182 | isPropertyAvailable = status==STATUS_AVAILABLE;mock 注入点 :165-170 | 01/02/07 篇核实 |
W .../glovebox/GloveBoxAccountVerifyUtils.kt + AccountVerifyHelper.kt | :45-57; :121-159 | P 挡前置闸;content://mi.car.account call 扫码(scene=glovebox_verify) | 03/04 篇核实 |
W .../glovebox/GloveBoxNavigationHandler.kt | :45-54, :104-107, :125-131 | MIS 响应码 1001-1004;CLOSE_SYSTEM_DIALOGS;直写属性不上报 54662 | 04/05/07 篇核实 |
W VehiclePermanentListener.java | :103-115, :305-313 | 常驻监听 prepared 重注册与分发(物理按键宿主) | 06/07 篇核实 |
W CarPropertyCacheManager.java | :197-228 | callbackByCache 注册即回放(:222 同步 onChangeEvent) | 06 篇核实 |
W VehicleBodyPropertyMap.kt | :42-63 | 双 Tab 工厂;withAllowClickWhenDisabled(true)(置灰可点击前提) | 02/03 篇核实 |
W PinPasswordEncryptor.kt | :52-64, :93-100 | SHA-256(salt+pwd),salt=currentTimeMillis | 04 篇核实 |