手套箱 07 · 埋点与测试
本篇回答:数据上报了什么、单测覆盖什么、台架怎么自测。 基线:
fuben31_micarsettings/MiCarSettings@ dev
1. 埋点事件清单
常量:base/settingsBaseLib/src/main/java/com/android/micar/settings/track/TrackConstants.java:308-313(TIP)+ :536-538(参数 key);
封装:VehicleControlReporter.kt:104-115(TrackValues)+ :489-534(report 方法)。
| 事件 | 事件 ID | 类型 | 参数 | 时机 | 调用点 |
|---|---|---|---|---|---|
TIP_OPEN_GLOVE_BOX | 1147.1.0.1.54662 | CLICK | type:1=无密码直开 / 2=验证后开;+ tab_instance_id=VEHICLE_CONTROL | 实际下发 GLOVE_BOX=OPEN 时 | GloveBoxController.kt:237(openGloveBox() 内) |
TIP_GLOVE_BOX_FORGOT_PASSWORD_SUCCESS | 1147.0.0.0.54663 | EXECUTE | 仅 tab_instance_id | 锁定→车主账号验证通过 | GloveBoxController.kt:248;GloveBoxSettingsDialogActivity.kt:262 |
TIP_GLOVE_BOX_PASSWORD_OPERATION | 1147.0.0.0.54664 | EXECUTE | type:1=设置成功 / 2=关闭成功 / 3=修改成功;+ tab_instance_id | 三个密码操作各自成功回调 | GloveBoxSettingsDialogActivity.kt:160/179/130 |
TrackValues 枚举(VehicleControlReporter.kt:104-115):
GLOVE_BOX_OPEN_NO_PASSWORD = 1 // 开箱 type:无密码
GLOVE_BOX_OPEN_WITH_PASSWORD = 2 // 开箱 type:密码/账号验证后
GLOVE_BOX_PWD_SET = 1 // 密码操作 type:设置
GLOVE_BOX_PWD_CLEAR = 2 // 密码操作 type:关闭
GLOVE_BOX_PWD_CHANGE = 3 // 密码操作 type:修改埋点挂接示意:
flowchart LR A[点击开箱] --> B{分支} B -->|无密码直开| C["openGloveBox(NO_PASSWORD)<br/>→ 54662 type=1"] B -->|密码/账号验证通过| D["openGloveBox(WITH_PASSWORD)<br/>→ 54662 type=2"] E[锁定→账号验证通过] --> F["54663<br/>+ 54662 type=2"] G[设置密码成功] --> H["54664 type=1"] I[关闭密码成功] --> J["54664 type=2"] K[修改密码成功] --> L["54664 type=3"]
注意:MIS 语音/远程开箱复用
GloveBoxController.openGloveBox吗?——不复用,GloveBoxNavigationHandler.openGloveBox()(:125-131)是自己直接写属性, 语音/远程开箱不会产生 54662 埋点(埋点只挂在 Controller 路径)。做数据分析时注意口径。
2. 单元测试覆盖
settingsPage/VehicleBodyControl/src/test/java/com/android/car/settings/miauto/vehicle/glovebox/GloveBoxControllerTest.kt(124 行),
继承 BaseVehicleToggleGroupTest<GloveBoxController>,JUnit5 + Mockito + Truth。
| 用例 | 覆盖点 |
|---|---|
testButtonGroupSignal(参数化) | TG-01/02:注入 OPEN/CLOSE,断言选中态跟信号走 |
signalUnavailable_groupDisabled | TG-03:信号不可用 → 按钮组置灰 |
clickDisabledToggle_noPropertyWritten | TG-05:不可用下点击不写属性(Mockito never()) |
signalOpen_gloveBoxSwitchSelected | TG-04:OPEN → selectedToggleIndex ≥ 0 |
signalClose_gloveBoxSwitchNotSelected | TG-05:CLOSE 未选中(@Disabled,TODO 待基类精确断言) |
timeout_uiRestoresPreviousSelection | TG-06:写属性超时 → UI 回滚原选中 |
getPropertyIdSet_containsCarModeStatus | TG-07:订阅集含 CAR_MODE_STATUS |
getPropertyIdSet_containsGloveBoxPropId | 订阅集含 GLOVE_BOX |
getPropertyIdSet_containsTwoPropIds | 订阅集 size == 2 |
Mock 策略:基类统一提供 context/fragmentController/carPropertyManager(Mockito mock);
injectSignalValue / injectUnavailableSignal / injectTimeout 三个 helper 模拟信号推送/
信号不可用/写超时回滚;TestReflectionHelper 反射调 protected 方法;
参数化用自定义注解 @VehiclePropertyValues(@VehicleProp(propId=GLOVE_BOX, intValues=[OPEN,CLOSE]))。
未覆盖(改这些区域时自己补验证):密码弹窗(Fragment/Dialog)、账号验证、
MIS Handler、mLoginReceiver、GloveBoxSettingsDialogActivity。
3. 台架 mock 配方
按 car-signal-mock-test skill 的通用打法,手套箱台架自测需要这些信号/数据:
3.1 让入口显示出来(前置)
| 目的 | mock | 说明 |
|---|---|---|
| 入口显示 | 0x6140b409 = 2 | GLOVE_BOX_LOCK_TYPE_CONFIG=POWER;台架默认 1(MANUAL)时入口隐藏 |
| 按钮可用 | 0x6140b407 = 0 | GLOVE_BOX=CLOSE |
| 无不可用原因 | 0x6140b40a = 0 | UNAVL_REASON=IDLE |
| Tab1 可用 | 登录账号 + 非代客 + CAR_MODE_STATUS=NORMAL | 代客: settings put secure judge_user_guest 0 |
3.2 分支用例矩阵
| # | 前置 | 操作 | 期望 |
|---|---|---|---|
| 1 | 无密码 | 点开箱 | 直接下发 OPEN;埋点 54662 type=1 |
| 2 | 已是 OPEN | 点开箱 | Toast「请手动关闭手套箱」 |
| 3 | UNAVL_REASON=1 | 点开箱 | Toast「请解锁车辆后重试」 |
| 4 | UNAVL_REASON=2 | 点开箱 | Toast「操作过于频繁」 |
| 5 | 无密码 | Tab1 → 点 Switch | 弹密码框(SET 模式,无「忘记密码」)→ 两次一致 → Toast「设置成功」,Switch ON,出现「修改密码」;埋点 54664 type=1 |
| 6 | 有密码 | 点开箱 | 弹密码框(CHECK 模式,有「忘记密码」)→ 输对 → 开箱;埋点 54662 type=2 |
| 7 | 有密码 | 开箱时连错 4 次 | 每次「密码错误」提示;settings get global glove_box_password_wrong_times 递增 |
| 8 | 有密码 | 开箱时第 5 次错 | 自动拉账号验证页(qr_code);P 挡才拉起 |
| 9 | 有密码 | 非 P 挡触发锁定验证 | Toast「请驻车后重试」 |
| 10 | 有密码 | 密码框点「忘记密码」 | 账号验证(不查 P 挡)→ 通过后进 SET 重设 |
| 11 | 有密码 | Tab1 → 点 Switch | CHECK+close 流程 → 输对 → Toast「清除成功」,Switch OFF;埋点 54664 type=2 |
| 12 | 有密码 | Tab1 → 修改密码 | 验旧 → 两次新 → Toast「修改成功」;埋点 54664 type=3 |
| 13 | 代客模式 | 看 Tab1 / 点 Tab1 | 置灰;点击 Toast「请在用户模式下使用该功能」 |
| 14 | 未登录账号 | 看 Tab1 | 隐藏;登录广播后实时出现 |
| 15 | 语音「打开手套箱」(无密码) | MIS | 直接开,响应 1001 |
| 16 | 语音开箱(有密码) | MIS | 弹密码框 + 控制中心收起,响应 1002 |
| 17 | 配置字=MANUAL | 语音开箱 | 响应 1003,入口隐藏 |
3.3 密码数据的 adb 观察
# 查看密码哈希(非空=已设密码)
adb shell settings get global glove_box_password
# 查看错误次数
adb shell settings get global glove_box_password_wrong_times
# 查看盐(时间戳)
adb shell settings get global glove_box_password_salt
# 手动重置密码(模拟未设密码态)
adb shell settings put global glove_box_password ""
adb shell settings put global glove_box_password_wrong_times 0
# 手动制造锁定态
adb shell settings put global glove_box_password_wrong_times 5⚠️ 台架判定以 App 日志与 UI 为准;vehicled 侧不持久回滚是假象(通用踩坑)。
4. 日志观测点
| TAG/关键字 | 内容 |
|---|---|
GloveBoxController / GloveBox | Controller 分发与状态 |
getGloveBoxLockType | CarConfigManager 配置字读取(MLog.d) |
PinPassword | 通用框架输入/校验 |
glovebox_verify | 账号验证 scene(账号侧日志) |
CARSIGNAL 中 6140b407 / 6140b409 / 6140b40a | 车端原始信号流(04 篇 §7 排障表) |