手套箱 08 · 速查卡
一页纸速查,所有人用:排查/开发/台架自测手套箱问题前先把这页过一遍。细节推导过程见各专篇,本篇只给结论与命令。
基线声明:
- 主锚点(W)=
/home/zbc/car/fuben4_micarsettings/MiCarSettings-5458412,origin/dev@930be9145。本篇行号以此为准。- 出货对照=
/home/zbc/car/pack_a17_cn_20260923(快照);平台源码=/home/zbc/pangu/xcd_xring_a17_fermi/vendor/micar。- 仓内别名:
MiCarPropertyIds.DrivingCtrl.GLOVE_BOX=Peripheral.GLOVE_BOX,GLOVE_BOX_TYPE=Peripheral.GLOVE_BOX_LOCK_TYPE_CONFIG(MiCarPropertyIds.java:1485/:1487)。
0. 30 秒心智模型
flowchart TD A["点击开箱 Tab"] --> B{"已开?<br/>(GLOVE_BOX==OPEN)"} B -->|是| T1["Toast 请手动关闭"] B -->|否| C{"有密码?"} C -->|无| O["写 GLOVE_BOX=OPEN<br/>+ 埋点 54662 type=1"] C -->|有| D{"错误达 5 次?"} D -->|否| P["弹 4 位 PIN 框"] -->|验证通过| O2["写 OPEN + 54662 type=2"] D -->|是| AV["账号扫码验证<br/>content://mi.car.account"] -->|通过| O3["清零错误次数<br/>写 OPEN + 54662 type=2 + 54663"] P -->|错满 5 次| AV E["入口显隐"] -.只看.- F["配置字 0x6140b409==2(POWER)"] G["MIS 语音/远程"] --> H["GloveBoxNavigationHandler<br/>直写属性,不报 54662"]
一句话:写属性即开箱意图受理,不等回执;关箱只能手动物理合上,App 无「关」路径。
1. propId / 枚举一页纸表
| 属性 | hex | dec | 权限(注解) | 枚举值 | 平台出处 |
|---|---|---|---|---|---|
Peripheral.GLOVE_BOX | 0x6140b407 | 1631630343 | VENDOR_EXTENSION | OpenClose:CLOSE=0 / OPEN=1 | Peripheral.java:572-580 |
Peripheral.GLOVE_BOX_MOTOR_CMD | 0x6140b408 | 1631630344 | CAR_INFO | GloveBoxMotorCmd:IDLE=0 / CLOCKWISE=1 / COUNTER_CLOCKWISE=2 / BREAK=3 | Peripheral.java:582-590, 枚举 :1414-1419 |
Peripheral.GLOVE_BOX_LOCK_TYPE_CONFIG | 0x6140b409 | 1631630345 | CAR_INFO | GloveBoxLockTypeConfig:MANUAL=1 / POWER=2 | Peripheral.java:592-600, 枚举 :1421-1424 |
Peripheral.GLOVE_BOX_UNAVL_REASON | 0x6140b40a | 1631630346 | CAR_INFO | GloveBoxUnavlReason:IDLE=0 / NOT_DIS_ARMED=1 / ANTY_PLAY=2 | Peripheral.java:602-610, 枚举 :1426-1430 |
Body.GLOVE_BOX_BUTTON_STATUS(物理按键) | 0x61401781 | 1631590273 | CONTROL_CAR_FEATURES | GloveBoxButtonStatus:ERROR=0 / NOT_PRESSED=1 / PRESSED=2 / NO_INFO=3 | Body.java:1841-1848, 枚举 :6948-6953 |
Driving.POWER_MODE(门控用) | 0x61407207 | 1631613447 | CAR_DRIVING_STATE | PowerStatus:OFF=0 / AWAKE=1 / ACC=2 / RUN=3(ON=3、START=4 已 @Deprecated) | Driving.java:2423-2430, 枚举 :10876-10885 |
判读要点:
- GLOVE_BOX 只写 1(OPEN):业务上只有开箱没有关箱,写 0 无意义(
openGloveBox固定写CommonParams.OpenClose.OPEN,GloveBoxController.kt:222-229)。 - LOCK_TYPE_CONFIG 是入口总闸:非 POWER 整组移除(
VehicleControlSettingsFragment.java:168-172),读取默认 MANUAL(CarConfigManager.kt:139-146)。 - UNAVL_REASON 只在不可用时才有意义:1=未解锁(未解防)、2=防玩;0(IDLE)与未知值不弹 Toast(见 §5)。
- 可用性事实标准 = 属性
status == STATUS_AVAILABLE,不是值本身(VehiclePropertyUtil.java:173-182)。 - 物理按键唯一触发沿 = NOT_PRESSED(1) → PRESSED(2);电源判 ACC/Run 用
==ACC || ==RUN,禁止>=ACC(deprecated 的 START=4 会漏过)。 - dec 值换算已逐个数验算:
hex → dec对照见上表,与 01 篇一致。
2. Settings.Global 三键与清零命令
存储三键(定义于 GloveBoxPasswordTools.kt:33-38,跟车存储,恢复出厂自动清除):
| key | 内容 | 说明 |
|---|---|---|
glove_box_password | SHA-256 哈希 | 非空 = 已设密码;哈希输入是 "[1, 2, 3, 4]" 形式的 IntArray 串(PinPasswordEncryptor.kt:93-100) |
glove_box_password_salt | 时间戳盐 | System.currentTimeMillis,改密即换盐(PinPasswordEncryptor.kt:52-64) |
glove_box_password_wrong_times | 连续错误次数 | ≥5 锁定转账号验证(PWD_WRONG_MAX_TIMES=5,PinPasswordTools.kt:62) |
密码常量一页纸:PIN 4 位(PinPasswordTools.kt:65),验证延迟 200ms(:68),事件 ID 0=CHECK_PWD 验证 / 1=SET_PWD 设置 / 2=CHANGE_PWD 修改 / 3=CHANGE_PWD_VERIFIED 已验证后修改(:50-59,即 param_event_id 取值 :44)。
# 查状态
adb shell settings get global glove_box_password # null/空 = 未设密码
adb shell settings get global glove_box_password_wrong_times # >=5 = 锁定中
# 清零锁定(台架高频):清键 + 杀进程,两步缺一不可
adb shell settings put global glove_box_password_wrong_times 0
adb shell am force-stop com.android.car.settings
# 清密码(恢复「无密码直开」)
adb shell settings put global glove_box_password ""
adb shell am force-stop com.android.car.settings⚠️ wrong_times 残留坑:不清零就直接测「无密码开箱」,会被锁定分支拦去扫码页,误判为「代码改坏了」。
3. 台架命令速查
3.1 root 与通道判法
adb root && adb remount # reboot 会掉 root
# 每批 mock 前必查:必须是 su:s0(u:r:shell:s0 会被 avc 拒)
adb shell "id | grep -o 'context=[^ ]*'"
# AIDL(fermi 等新车机):能看到 IVehicle/micar
adb shell dumpsys -l | grep -i vehicle
# 看不到则是 HIDL(mach/ampere 等老车机):
adb shell lshal | grep -i vehicle3.2 mock 注入与复位
# AIDL 注入(fermi 实证):
adb shell dumpsys android.hardware.automotive.vehicle.IVehicle/micar \
--mock_from_car <dec_propId> -a 0 --stat 0 -i <val>
# HIDL 注入(mach/ampere 实证):
adb shell lshal debug android.hardware.automotive.vehicle@2.0::IVehicle/default \
--mock_from_car <dec_propId> -a 0 --stat 0 -i <val>注入铁律(06 篇实证):
- 每批间隔 ≥0.25s;值必须翻转才触发 ON_CHANGE 回调(同值重注无效)。
- 配置字走
CarConfigManager进程级静态缓存,mock 新值后必须am force-stop com.android.car.settings再开页,否则读到旧值(日志hit cached pId)。 vehicle_mock_data(底层持久化 SET 开关)按需开:
adb shell settings put --user 0 GLOBAL vehicle_mock_data 1 # 开:UI 不被台架 vehicled 回滚
adb shell settings put --user 0 GLOBAL vehicle_mock_data 0 # 复位铁律:重启不清,必须显式归 0- 复位三件套:注回基值 +
vehicle_mock_data归 0 + force-stop。
手套箱入口最小配方(2026-10-19 mach 实证入口出现):
# LOCK_TYPE_CONFIG(dec 1631630345) 1→2(MANUAL→POWER)
adb shell lshal debug android.hardware.automotive.vehicle@2.0::IVehicle/default \
--mock_from_car 1631630345 -a 0 --stat 0 -i 2
adb shell am force-stop com.android.car.settings
# 重进:车辆控制页 → 出现「手套箱」组
# 恢复:同命令 -i 13.3 密码页 root 直拉(跳过开箱主流程)
adb shell am start -n com.android.car.settings/.miauto.vehicle.glovebox.GloveBoxPasswordDialog \
--ei param_event_id 0 --ez param_is_close_pwd false -f 0x10000000param_event_id 取值 0/1/2/3 同 §2 事件表;该 Activity 是 singleInstance(模块 AndroidManifest.xml:31-34),重复拉起走 onNewIntent(GloveBoxPasswordDialog.kt:59-64)。
3.4 logcat 取证 grep 模式
adb logcat | grep -aE "GloveBox|6140b40|onDataVerifyFailed|reportOpenGloveBox|showAccountVerifyPage"
# bugreport 场景:
grep -aE "GloveBox|6140b40" bugreport-*.txt4. 日志签名表
正常开箱五连(2026-10-19 mach 台架无密码车实测,逐行锚定,详见 03-开箱主流程源码精讲.md):
| # | 日志签名 | 出处 |
|---|---|---|
| 1 | #onTabClicked() on tab: Tab[打开手套箱, false, true] | GloveBoxController.kt:117 |
| 2 | no password, open glove box | GloveBoxController.kt:267 |
| 3 | openGloveBox openType=1 | GloveBoxController.kt:223 |
| 4 | reportOpenGloveBox type=1(先于 #5,写完即报) | VehicleControlReporter.kt:497 |
| 5 | >>> Done set propVal: 1 to propId: 0x6140b407, aId: ... | VehicleControlManager.java:135 |
其他关键签名:
| 场景 | 日志签名 | 出处 | 判读 |
|---|---|---|---|
| 台架回滚假象 | onDelayGetProp propId: 0x6140b407 + onDataVerifyFailed ... propVal: 1 | SettingsCarPropertyManager.kt:195/:199-201 | 台架 vehicled 不持久 SET 的回读校验失败,≠开箱失败;解法 vehicle_mock_data 1,判定只信 App 日志 |
| 不可用 Toast 分流 | showGloveBoxSwitchUnavailableNotify: reason=N | GloveBoxController.kt:290 | N=1 未解锁 / 2 防玩 / 其它看代客 |
| 达上限转扫码 | showAccountVerifyPage: pwd limit reached | GloveBoxController.kt:211 | 随后应见账号验证拉起 |
| MIS 受理 | onAction: specId=... → sendResponse: specId=..., code=100X | GloveBoxNavigationHandler.kt:63/:144 | 1001 成功 / 1002 需密码 / 1003 不支持 / 1004 达上限(:45-54) |
| 密码验证拉起 | goToCheckPassword: event=N, isClosePwd=... | PinPasswordCheckUtils.kt:139 | event 取值同 §2 |
5. 常见假象与误判表
| 误判 | 真相 | 证据 |
|---|---|---|
「onDataVerifyFailed = 开箱失败」 | 台架 vehicled 不持久 SET 的回滚假象;实车以 MCU 执行为准 | SettingsCarPropertyManager.kt:193-203 |
| 「锁定解不掉,代码坏了」 | wrong_times 残留;settings put global glove_box_password_wrong_times 0 + force-stop | §2 命令 |
| 「未登录账号没有密码设置入口 = bug」 | 设计如此:Tab1(密码设置)显隐只跟账号登录态 | GloveBoxController.kt:86-96 |
| 「点了没 Toast = 点击没响应」 | reason 非 1/2 且非代客时走 Resources.ID_NULL 静默分支,现状如此 | GloveBoxController.kt:294-301 |
| 「mock 了值页面没变」 | 同值重注不触发 ON_CHANGE;或 CarConfigManager 静态缓存未清(缺 force-stop) | CarPropertyCacheManager.java:192-193(ON_CHANGE 注册) |
| 「置灰还能点是 bug」 | 故意:两 Tab 都 withAllowClickWhenDisabled(true),留点击弹原因 Toast | VehicleBodyPropertyMap.kt:48/:61 |
| 「语音开箱也该有 54662 埋点」 | MIS 路径直写属性不过 Controller,不报 54662,是口径边界 | GloveBoxNavigationHandler.kt:125-131 |
「电源判断 >=ACC 就行」 | 不行:START=4(deprecated)会被漏过/误纳,必须 ==ACC || ==RUN | Driving.java:10876-10885 |
| 「远程能关手套箱」 | 不能,信号链只有写 OPEN;关箱=手动物理合上 | GloveBoxController.kt:222-229 |
| 「密码存在 SP/私有文件」 | 存 Settings.Global 三键,跟车存储,恢复出厂即清 | GloveBoxPasswordTools.kt:33-38 |
| 「GloveBoxButton 还在用」 | 旧自定义 View,全仓零引用(死代码),别对着它改 | GloveBoxButton.kt(本仓 grep 无引用) |
6. 文件清单
手套箱目录 settingsPage/VehicleBodyControl/.../miauto/vehicle/glovebox/(10 文件):
| 文件 | 一句话角色 |
|---|---|
GloveBoxController.kt | 双 Tab 宿主:订阅 GLOVE_BOX+CAR_MODE_STATUS(:99-102),三分支分发 :261-278,统一开箱点 :222-229,原因 Toast :288-302 |
GloveBoxSettingsDialogActivity.kt | 密码管理弹窗:handleSwitchChange() 三态(达上限/未设/已设):145-186 |
GloveBoxPasswordDialog.kt | 密码框宿主 Activity,singleInstance + 冲突弹窗,onNewIntent :59-64 |
GloveBoxPasswordFragment.kt | 薄壳,继承 BasePinPasswordFragment(:22),只注入手套箱配置 |
GloveBoxPasswordTools.kt | 委托 PinPasswordTools,注入三键与广播 Action(:33-38) |
GloveBoxPasswordCheckUtils.kt | 委托 PinPasswordCheckUtils,goToCheckPassword() :50-58 |
GloveBoxAccountVerifyUtils.kt | 车主验证入口 + P 挡前置闸(:45-57,忘记密码路径传 false 免 P 挡) |
GloveBoxNavigationHandler.kt | MIS 语音/远程受理,响应码 1001-1004(:45-54),发 CLOSE_SYSTEM_DIALOGS(:104-107) |
GloveBoxModulePublishService.kt | MIS 静态发布服务(模块 AndroidManifest.xml:9-28,keep_alive=false) |
GloveBoxButton.kt | 死代码(旧自定义 View,无引用) |
通用密码框架 base/settingsBaseUi/.../common/password/(与升降顶等共用,改前 grep 影响面):
| 文件 | 一句话角色 |
|---|---|
PinPasswordTools.kt | PIN 核心:输入/验证/存储/5 次锁定,事件常量 :50-59 |
PinPasswordEncryptor.kt | SHA-256 + 时间戳盐,IntArray 串格式 :93-100 |
PinPasswordCheckUtils.kt | 拉起密码弹窗 + LocalBroadcast 单回调槽(mCallback :58,覆盖赋值 :147) |
BasePinPasswordFragment.kt | 密码页框架:忘记密码入口 :264(免 P 挡)、达上限 :319(查 P 挡) |
(同目录另有 PinPasswordConfig.kt 参数化配置、PinAccountVerifyUtils.kt 账号验证框架,合计 6 文件。)
属性通道 5 文件(base/settingsVehicleLib/.../,分层详解见 06-属性通道与台架mock.md):
| 文件 | 一句话角色 |
|---|---|
GlobalCarPropertyManager.kt | L0 入口单例(:16),getCarManager() :32 |
SettingsCarPropertyManager.kt | L1 页面级:setCarProperty :430-487,SET 超时校验 :193-203(回滚假象发源地) |
CarPropertyCacheManager.java | L2 缓存回放:注册即同步回调缓存值 callbackByCache :197-228 |
VehicleControlManager.java | L3 写入:setIntProperty 丢 ASYNC 线程池 :128-130,>>> Done set 日志 :135 |
CarConfigManager.kt | 配置字静态缓存:getGloveBoxLockType() :139-146(默认 MANUAL,mock 后必须 force-stop) |
常驻监听宿主 VehiclePermanentListener.java:onPropertyManagerPrepared 重注册 + 回放离线队列 :103-115(物理按键常驻监听的挂点,方案见 07-物理按键扩展设计.md)。
7. 相关链接
需求与方案(飞书 wiki):
- Meego 5458412 需求文档:https://mi.feishu.cn/wiki/GaoUwNTrUi3aPfkKHhdcI9sEnqb
- FD&FR 评审:https://mi.feishu.cn/wiki/I4pZwnIHoivmcwk2ZYDcRtecnhh
- SSC REQ003(物理按键交互):https://mi.feishu.cn/wiki/FaKhw7wZjiFUvukG6sDcmPL1nje
- 既有技术方案:https://mi.feishu.cn/wiki/B2DRwjrt5ihlqykZk87co3aOnbh
参考 change(Gerrit):
- 161208:软按键开箱+密码流程主参考(Meego 2350608,MERGED)
- 165854:不可用原因 Toast 映射(N801PROB-34263,MERGED)
- 368053:开箱埋点引入(Meego 3860784,PS14 MERGED)
本地路径:
- M 目录(一手资料):
/home/zbc/下载/test/车机Feature/Meego 5458412/(docs/kb/research/test 子目录) - 台架自测场景:
/home/zbc/下载/test/车机JIRA/.claude/skills/car-signal-mock-test/references/场景-手套箱入口与密码页.md - 台架方法论总库:同 skill 下
KNOWLEDGE.md/LESSONS.md
本库篇目:01 需求与信号契约 · 02 页面结构与门控 · 03 开箱主流程源码精讲 · 04 密码与账号验证体系 · 05 埋点体系 · 06 属性通道与台架mock · 07 物理按键扩展设计
8. 证据清单
| 文件 | 行号区间 | 说明 |
|---|---|---|
vendor/micar/.../support-lib/src/mi/car/config/Peripheral.java | 572-610, 1414-1430 | 四个手套箱属性定义(0x407~0x40a)与三个枚举类 |
同目录 Body.java | 1841-1848, 6948-6953 | 物理按键属性 GLOVE_BOX_BUTTON_STATUS 与 GloveBoxButtonStatus 枚举 |
同目录 Driving.java | 2423-2430, 10876-10885 | POWER_MODE=0x61407207 与 PowerStatus(START=4 deprecated) |
W:.../miauto/vehicle/MiCarPropertyIds.java(settingsBaseLib) | 1485, 1487 | 仓内别名 GLOVE_BOX / GLOVE_BOX_TYPE |
W:.../glovebox/GloveBoxController.kt | 86-102, 117, 166-188, 210-229, 261-302, 305-332 | 订阅集/三分支/统一开箱点/原因 Toast/账号广播 |
W:.../glovebox/GloveBoxNavigationHandler.kt | 45-54, 62-86, 104-131, 144 | MIS 响应码/受理/直写属性/关控制中心 |
W:.../glovebox/GloveBoxPasswordTools.kt | 33-38, 110-139 | Settings.Global 三键定义与锁定判断 |
W:.../glovebox/GloveBoxPasswordCheckUtils.kt | 25-58 | 委托通用框架的拉起入口 |
W:.../glovebox/GloveBoxAccountVerifyUtils.kt | 45-57 | 车主验证 + P 挡闸 |
W:.../glovebox/GloveBoxPasswordDialog.kt | 59-64 | singleInstance 下 onNewIntent 重载 Fragment |
W:.../glovebox/GloveBoxSettingsDialogActivity.kt | 145-186, 193-199, 260-262 | 密码管理三态与忘记密码埋点调用点 |
W:.../glovebox/GloveBoxModulePublishService.kt | 全文(21 行) | MIS 静态发布,注册 NavigationHandler |
W:.../glovebox/GloveBoxButton.kt | 全文 | 旧自定义 View,全仓零引用(死代码判定) |
W:VehicleBodyControl/src/main/AndroidManifest.xml | 9-34 | MIS 发布服务(keep_alive=false)与密码弹窗 singleInstance |
W:base/.../common/password/PinPasswordTools.kt | 44-71 | param_event_id、事件 0-3、5 次/4 位/200ms 常量 |
W:base/.../common/password/PinPasswordEncryptor.kt | 52-64, 93-100 | SHA-256+盐与 IntArray 串格式 |
W:base/.../common/password/PinPasswordCheckUtils.kt | 54-58, 132-163 | 单回调槽与 goToCheckPassword |
W:base/.../common/password/BasePinPasswordFragment.kt | 264, 319 | 忘记密码(免 P 挡)与达上限(查 P 挡)两个验证拉起点 |
W:base/.../track/VehicleControlReporter.kt | 38-42, 104-114, 495-505, 510-514 | source 常量、手套箱埋点常量与上报函数 |
W:base/.../track/TrackConstants.java | 309-313, 532-536 | 54662/54663/54664 事件 ID 与 KEY_SOURCE |
W:base/.../track/SettingsTrack.kt | 12-16 | OneTrack APP_ID=31000401514 / PROJECT_ID |
W:base/.../miauto/vehicle/SettingsCarPropertyManager.kt | 193-203, 430-487 | SET 超时校验(回滚假象)与 setCarProperty 主流程 |
W:base/.../miauto/vehicle/VehicleControlManager.java | 128-141 | 异步写入与 >>> Done set 日志 |
W:base/.../miauto/vehicle/CarPropertyCacheManager.java | 187-228 | 首注册远端 + 缓存同步回放(ON_CHANGE) |
W:base/.../miauto/vehicle/VehiclePropertyUtil.java | 165-182 | isPropertyAvailable = status==STATUS_AVAILABLE |
W:base/.../miauto/CarConfigManager.kt | 139-146 | getGloveBoxLockType 静态缓存(默认 MANUAL) |
W:base/.../miauto/VehiclePermanentListener.java | 103-115 | prepared 重注册 + 离线队列回放 |
W:base/.../miauto/vehicle/VehicleControlSettingsFragment.java | 168-172 | 非 POWER 整组移除门控 |
W:base/.../miauto/vehicle/VehicleBodyPropertyMap.kt | 42-63 | 双 Tab 工厂,withAllowClickWhenDisabled(true) |
W:base/.../utils/AccountVerifyHelper.kt(settingsBaseLib) | 14, 64-76, 121-159 | content://mi.car.account、scene=glovebox_verify、qr_code |
| 台架命令与回滚假象实证 | 见 06-属性通道与台架mock.md §4-§5 | AIDL/HIDL 注入、vehicle_mock_data、2026-10-19 mach 实测 |