手套箱 03 · 开箱主流程源码精讲

基线声明

  • W(主锚点,行号以此为准):/home/zbc/car/fuben4_micarsettings/MiCarSettings-5458412,origin/dev @ 930be9145。
  • 出货对照:/home/zbc/car/pack_a17_cn_20260923 快照,GloveBoxController.kt 与 W 逐字节一致(diff 无输出,见第 7 节)。
  • 平台源码:/home/zbc/pangu/xcd_xring_a17_fermi/vendor/micar(属性常量定义)。
  • 主类:settingsPage/VehicleBodyControl/src/main/java/com/android/car/settings/miauto/vehicle/glovebox/GloveBoxController.kt,全文 341 行。

本篇回答一个问题:用户点击「打开手套箱」之后,每一行代码做了什么。 页面拓扑与门控全景见 02-页面结构与门控.md,本篇只贴代码与日志。


1. 类骨架:一个 Controller,两个 Tab

GloveBoxController(GloveBoxController.kt:54-341)继承 BaseVehicleButtonIconToggleGroupPropController,用 2 列 ButtonIconTogglePreference 布局:

Tab 索引常量定义用途点击后入口
0TAB_INDEX_GLOVE_BOX_SWITCH(GloveBoxController.kt:73)手套箱开关showGloveBoxSwitchClick(tab)(:119)
1TAB_INDEX_GLOVE_BOX_PASSWORD_SET(:76)密码设置入口startActivity(GloveBoxSettingsDialogActivity)(:130-132)

生命周期钩子只有三个(:140-158):

  • onCreateInternal()(:140-148):put 双列配置 PREFERENCE_TAB_ITEM_COLUMN_SIZE(:142 与 :146 重复 put 两次,历史遗留的无效重复)、设置 assistView 标题(:145)、registerReceiver()(:147,见 2.8)。
  • onStartInternal()(:150-153)调 setGloveBoxPwdSettingEntryVisibility():未登录账号时隐藏「密码设置」Tab(:86-96,AccountUtils.isUserLogin 判断在 :88)。
  • onDestroyInternal()(:155-158)注销账号广播接收器。

2. 逐段拆解

2.1 getPropertyIdSet():只订阅两个属性

override fun getPropertyIdSet() = ArraySet<Int>().apply {
    add(MiCarPropertyIds.DrivingCtrl.GLOVE_BOX)
    add(Driving.CAR_MODE_STATUS)
}

(照抄 GloveBoxController.kt:99-102)

  • MiCarPropertyIds.DrivingCtrl.GLOVE_BOX 是 Peripheral.GLOVE_BOX 的别名(MiCarPropertyIds.java:1485);平台定义在 Peripheral.java:576-580:0x407 | MI_CAR | GLOBAL | INT32 | PERIPHERAL,即完整 ID 0x6140b407(行尾注释明示),值枚举 CommonParams.OpenClose。
  • Driving.CAR_MODE_STATUS 用于驾驶模式(代客)联动,见 2.3。
  • 不订阅 Peripheral.GLOVE_BOX_UNAVL_REASON(0x6140b40a,Peripheral.java:606-610):不可用原因只在点击不可用按钮时即时读取(见 2.5),该设计沿用自参考 change 165854(见其第 3 节)。

2.2 initLocalVehicleControls():双 Tab 与「disabled 也可点击」

override fun initLocalVehicleControls() {
    super.initLocalVehicleControls()
    mSupportedCtrls.clear()
 
    mSupportedCtrls.add(VehicleBodyPropertyMap.createGloveBoxSwitchCtrl()
        .withOnClickListener { tab: Tab<*> ->
            MLog.d("%s #onTabClicked() on tab: %s", implClassName, tab)
            if (tab.isAvailable) {
                showGloveBoxSwitchClick(tab)
            } else {
                showGloveBoxSwitchUnavailableNotify()
            }
        }
    )
 
    mSupportedCtrls.add(VehicleBodyPropertyMap.createGloveBoxPasswordSetCtrl()
        .withOnClickListener { tab: Tab<*> ->
            MLog.d("%s #onTabClicked() on tab: %s", implClassName, tab)
            if (tab.isAvailable) {
                context.startActivity(
                    Intent(context, GloveBoxSettingsDialogActivity::class.java)
                )
            } else {
                MiCarToastUtils.showToast(R.string.glove_box_fail_valet_mode)
            }
        }
    )
}

(照抄 GloveBoxController.kt:111-138)

关键设计在控件工厂里——VehicleBodyPropertyMap.kt:42-50(W 已读核实):

fun createGloveBoxSwitchCtrl(): VehicleQuickCtrl<*> {
    return VehicleQuickCtrl<Any?>(
        MiCarPropertyIds.DrivingCtrl.GLOVE_BOX,
        R.drawable.ic_glove_box_switch, R.string.glove_box_switch
    )
        .withDefault(CommonParams.OpenClose.OPEN)
        .withAllowClickWhenDisabled(true)
        .withTabFlag(TabKeyMapHelper.TAB_FLAG_GLOVE_BOX_SWITCH)
}

(照抄 VehicleBodyPropertyMap.kt:42-50)

withAllowClickWhenDisabled(true)(:48)是整条不可用提示链成立的前提:按钮置灰时点击事件依然送达,于是 :118-122 的二分流才有机会执行——可用走业务(2.4),不可用走原因 Toast(2.5)。密码设置入口同理(VehicleBodyPropertyMap.kt:55-63,:61 同样允许),其不可用时统一弹 glove_box_fail_valet_mode(GloveBoxController.kt:134)。两个控件共用 GLOVE_BOX 属性做 Tab 状态源,默认值不同:开关 Tab 默认 OPEN(:47),密码 Tab 默认 false(:60)。

2.3 onHandlePropertyChange():属性回调如何刷 UI

override fun onHandlePropertyChange(
    propertyValue: MiCarPropertyValue<*>?,
    shouldUpdateUI: Boolean
) {
    if (preference.buttons.isEmpty()) return
 
    // 更新手套箱开关状态
    val gloveBoxStatus = getProperty(MiCarPropertyIds.DrivingCtrl.GLOVE_BOX)
    val gloveBoxSwitchTab: Tab<*>? = preference.buttons[TAB_INDEX_GLOVE_BOX_SWITCH]
    MLog.tag(TAG).d("onPropertyChanged: gloveBoxStatus=$gloveBoxStatus")
    gloveBoxSwitchTab?.isAvailable = VehiclePropertyUtil.isPropertyAvailable(gloveBoxStatus)
    gloveBoxSwitchTab?.mIsSelected = VehiclePropertyUtil
        .getIntPropertyValue(gloveBoxStatus) == CommonParams.OpenClose.OPEN
    // ... 后半段(:180-186):代客模式下密码设置入口置灰,isAvailable = !isValetMode && carMode == NORMAL
    refreshUi()
}

(截取照抄 GloveBoxController.kt:166-188,省略 :180-186 密码入口段)

两个工具函数的实际语义(VehiclePropertyUtil.java,W 已读核实):isPropertyAvailable(:173-182)——null → false、命中 mock unavailable → false、否则要求 status == STATUS_AVAILABLE,所以属性超时/丢失时 Tab 置灰但仍可点击(配合 2.2);getIntPropertyValue(:55-71)——null → 0,Number 取 intValue,Boolean 映射 Sts_On/Sts_Off。mIsSelected 即「箱体当前为 OPEN」= 属性值等于 CommonParams.OpenClose.OPEN(:177-178)。密码入口可用条件(:185)是双重判断:!isValetMode && carMode == NORMAL。

2.4 showGloveBoxSwitchClick():三分支决策

这是点击「打开手套箱」后真正的业务分发点(:261-278):

private fun showGloveBoxSwitchClick(tab: Tab<*>) {
    if (tab.mIsSelected) {
        MiCarToastUtils.showToast(R.string.glove_box_close_notice)
    } else {
        if (GloveBoxPasswordTools.getLocalPwd().isNullOrEmpty()) {
            // 未设置密码
            MLog.tag(TAG).d("no password, open glove box")
            openGloveBox()
        } else if (GloveBoxPasswordTools.isPwdLimit()) {
            MLog.tag(TAG).d("open password is limit")
            showAccountVerifyPage()
        } else {
            MLog.d("open password page ${this::class.java.name}")
            // 打开密码输入页面
            showPasswordCheckDialog()
        }
    }
}

(照抄 GloveBoxController.kt:261-278)

分支条件动作代码行
已打开tab.mIsSelected == trueToast「请手动关闭手套箱」,不发开箱指令:262-263
无密码getLocalPwd().isNullOrEmpty()直接 openGloveBox()(默认 openType=1):265-268
错误达上限isPwdLimit() == trueshowAccountVerifyPage() 走车主验证:269-271
有密码未达上限elseshowPasswordCheckDialog() 弹密码输入:272-275

协作接口(本篇只画接口,细节归 04 篇):

  • GloveBoxPasswordTools.getLocalPwd():Settings.Global 里的密码哈希,无密码为 null(GloveBoxPasswordTools.kt:110,委托 PinPasswordTools,配置见 :24-41)。
  • GloveBoxPasswordTools.isPwdLimit():错误次数是否达上限(GloveBoxPasswordTools.kt:135-139)。
  • showPasswordCheckDialog()(:196-203)调 GloveBoxPasswordCheckUtils.goToCheckPassword(context, INPUT_EVENT_CHECK_PWD) { if (it) openGloveBox(GLOVE_BOX_OPEN_WITH_PASSWORD) };签名在 GloveBoxPasswordCheckUtils.kt:50-58,拉起 GloveBoxPasswordDialog 用广播回结果。

2.5 showGloveBoxSwitchUnavailableNotify():不可用原因 → Toast

private fun showGloveBoxSwitchUnavailableNotify() {
    val reason = getIntProperty(Peripheral.GLOVE_BOX_UNAVL_REASON)
    MLog.tag(TAG).i("showGloveBoxSwitchUnavailableNotify: reason=$reason")
    val strRes = when (reason) {
        Peripheral.GloveBoxUnavlReason.NOT_DIS_ARMED -> R.string.glove_box_fail_need_unlock
        Peripheral.GloveBoxUnavlReason.ANTY_PLAY -> R.string.glove_box_fail_anty_play
        else -> {
            if (AccountUtils.isValetMode(context)) R.string.glove_box_fail_valet_mode
            else Resources.ID_NULL
        }
    }
    if (strRes != Resources.ID_NULL) {
        MiCarToastUtils.showToast(strRes)
    }
}

(照抄 GloveBoxController.kt:288-302)

注意三点:

  1. 触发时读原因(:289),不依赖订阅缓存——与 2.1 的「不订阅 UNAVL_REASON」呼应。
  2. else 分支(:294-297):只有代客模式才弹 glove_box_fail_valet_mode;其它一切未知 reason(含 IDLE、信号丢失)映射为 Resources.ID_NULL,静默不弹。枚举 IDLE=0x0 / NOT_DIS_ARMED=0x1 / ANTY_PLAY=0x2 见平台 Peripheral.java:1426-1430。这是 165854 留下的已知语义,不是「信号丢失必有提示」。
  3. strRes != Resources.ID_NULL 才 showToast(:299-301)。完整映射表见第 4 节。

2.6 openGloveBox():写完即报,不等回执

/** 发送开箱车辆属性指令 */
private fun openGloveBox(openType: Int = TrackValues.GLOVE_BOX_OPEN_NO_PASSWORD) {
    MLog.tag(TAG).d("openGloveBox openType=$openType")
    setVehicleProperty(
        MiCarPropertyIds.DrivingCtrl.GLOVE_BOX,
        CommonParams.OpenClose.OPEN
    )
    reportGloveBoxOpenTrack(openType)
}

(照抄 GloveBoxController.kt:221-229)

默认 openType=1(无密码开箱),常量 GLOVE_BOX_OPEN_NO_PASSWORD = 1、GLOVE_BOX_OPEN_WITH_PASSWORD = 2 在 VehicleControlReporter.kt:106/:108。

setVehicleProperty(propId, value) 两参版本来自基类 CarPropertyMgrPreferenceController.java:606-615(INVALID_PROP_ID 直接 false,否则 setCarProperty(propertyId, propVal))。此后链路:

  • SettingsCarPropertyManager.setCarProperty(:429-487)::436 先回调 reportOneTrackWhenSetProperty;Int 分支 :446-449 默认 isSync=false 走异步;:483 startTimeOutMonitor 启动回读校验超时监视。
  • VehicleControlManager.setIntProperty(:128-130):丢进 ThreadPoolUtils.ASYNC,主线程立即返回;异步线程里 setIntPropertyBySync(:132-141)下发 vehicled,成功后打 :135 的 >>> Done set propVal: %d to propId: %s, aId: %d。

「写完即报」语义由此成立:openGloveBox 里 setVehicleProperty(:224-227)只是把写请求排进线程池,主线程下一行就执行 reportGloveBoxOpenTrack(openType)(:228)。埋点不等平台回执、不等回读确认、不关心 vehicled 是否受理——所以实测日志里 reportOpenGloveBox type=1 打在 Done set propVal 之前(见第 3 节)。

2.7 reportGloveBoxOpenTrack():埋点收口

private fun reportGloveBoxOpenTrack(openType: Int) {
    try {
        VehicleControlReporter.reportOpenGloveBox(openType)
    } catch (e: Exception) {
        MLog.tag(TAG).i("reportGloveBoxOpenTrack error: ${e.message}")
    }
}

(照抄 GloveBoxController.kt:235-241)

VehicleControlReporter.reportOpenGloveBox(VehicleControlReporter.kt:495-505)::497 先打 reportOpenGloveBox type=$type 日志,再 TrackEvent.create(Event.CLICK, TIP_OPEN_GLOVE_BOX) 携带 KEY_GLOVE_BOX_OPEN_TYPE=type 与车辆控制 Tab 的 instanceId 上报。try/catch 保证埋点 SDK 异常绝不影响开箱主链。

2.8 账号广播注册(含 API 33 导出标志)

onCreateInternal 调 registerReceiver()(:147),实现:

private fun registerReceiver() {
    if (mLoginReceiver == null) {
        mLoginReceiver = object : BroadcastReceiver() {
            override fun onReceive(context: Context?, intent: Intent?) {
                setGloveBoxPwdSettingEntryVisibility()
            }
        }
    }
    val intentFilter = IntentFilter().apply {
        addAction(CarSettingsJump.UserAccount.USER_DATA_CHANGED)
        addAction(CarSettingsJump.UserAccount.LOGIN_ACCOUNTS_POST_CHANGED)
    }
 
    // AI(claude) auto generated at 2026-08-24 BEGIN
    // 用途: API 33+ 动态注册广播接收器必须声明导出标志
    if (Build.VERSION.SDK_INT >= 33) {
        BaseApplication.getGlobalApp().applicationContext.registerReceiver(
            mLoginReceiver, intentFilter,
            CarSettingsJump.UserAccount.USER_PERMISSION, null,
            0x2 /* RECEIVER_EXPORTED */
        )
    } else {
        BaseApplication.getGlobalApp().applicationContext.registerReceiver(
            mLoginReceiver, intentFilter,
            CarSettingsJump.UserAccount.USER_PERMISSION, null
        )
    }
}

(照抄 GloveBoxController.kt:305-332)

  • 监听两个 action:USER_DATA_CHANGED / LOGIN_ACCOUNTS_POST_CHANGED(:314-315),收到即重算密码入口可见性(:309)。
  • API 33+ 走五参 registerReceiver 并显式传 0x2 (RECEIVER_EXPORTED)(:320-325);33 以下走四参带权限版本(:326-331)。广播带 USER_PERMISSION 签名权限,导出无外部滥用面。配对的 unregisterReceiver() 在 :335-340,置空 mLoginReceiver 防重复注销。与出货快照的关系见第 7 节。

3. 「写完即报」实证:2026-10-19 mach 台架日志逐行对照

2026-10-19 mach 台架(无密码车辆)实测点击「打开手套箱」的日志序列,逐行锚定代码:

#日志行出处说明
1... #onTabClicked() on tab: Tab[打开手套箱, false, true]GloveBoxController.kt:117withOnClickListener 首行无条件打。Tab 三元组:mIsSelected=false(未开)、isAvailable=true → 进 :119 showGloveBoxSwitchClick
2no password, open glove boxGloveBoxController.kt:267:265 GloveBoxPasswordTools.getLocalPwd().isNullOrEmpty() 为 true(GloveBoxPasswordTools.kt:110),:262 的 mIsSelected 判断已为 false
3openGloveBox openType=1GloveBoxController.kt:223默认参数 GLOVE_BOX_OPEN_NO_PASSWORD=1(:222;常量 VehicleControlReporter.kt:106)
4reportOpenGloveBox type=1VehicleControlReporter.kt:497由 :228 → :237 触发。先于 #5:setVehicleProperty 只把写请求丢进 ThreadPoolUtils.ASYNC(VehicleControlManager.java:128-130),主线程立刻走到埋点
5>>> Done set propVal: 1 to propId: 0x6140b407, aId: ...VehicleControlManager.java:135异步线程内 setIntPropertyBySync(:132-141)下发成功。0x6140b407 = Peripheral.GLOVE_BOX(Peripheral.java:576-580),propVal=1 = CommonParams.OpenClose.OPEN
6onDataVerifyFailed propId: 0x6140b407, ..., propVal: 1(回读 v=0)SettingsCarPropertyManager.kt:199-201setCarProperty 在 :483 起的超时监视到期,handlePropertyTimeout(:193-203)发现 set 值 1 与缓存回读值 0 不等(:198),回调 onDataVerifyFailed

第 6 行是台架 vehicled 不持久 SET 的回滚假象:台架 vehicled 对 GLOVE_BOX 写请求受理后不持久(随后回滚为 0),App 侧回读校验必然失败。它不表示开箱失败,实车链路以 MCU 执行为准;mock 与台架判定边界详见 06-属性通道与台架mock.md。

一句话总结:UI 层认为「写到 vehicled 的 Binder 接口」即完成,埋点同刻上报;属性真实状态完全依赖后续 onHandlePropertyChange 回读刷新,两者解耦。

4. 不可用原因映射表

showGloveBoxSwitchUnavailableNotify(:288-302)全量分支:

reason(Peripheral.GLOVE_BOX_UNAVL_REASON 回读值)枚举值(Peripheral.java:1426-1430)代码行Toast 资源文案(zh-rCN)
NOT_DIS_ARMED0x1:292R.string.glove_box_fail_need_unlock「请解锁车辆后重试」
ANTY_PLAY0x2:293R.string.glove_box_fail_anty_play「操作过于频繁,请稍后再试」
其它 + 代客模式任意:294-295R.string.glove_box_fail_valet_mode代客模式不可用提示
其它 + 非代客(含 IDLE=0x0、未知值、信号丢失)—:296Resources.ID_NULL静默,不弹 Toast(:299 拦截)

文案出处见 参考change-165854.md 第 1 节(该 change 首次建立此映射并沿用至今,中文文案为其 commit 中字符串证据)。

5. 错误达上限 → 车主验证:本篇只画入口与回调

showGloveBoxSwitchClick 第二分支(:269-271)进入 showAccountVerifyPage(:210-219):

private fun showAccountVerifyPage() {
    MLog.tag(TAG).i("showAccountVerifyPage: pwd limit reached")
    GloveBoxAccountVerifyUtils.openVerifyPage {
        if (it) {
            GloveBoxPasswordTools.setPwdWrongTimes(0)
            openGloveBox(TrackValues.GLOVE_BOX_OPEN_WITH_PASSWORD)
            reportGloveBoxForgotPasswordTrack()
        }
    }
}

(照抄 GloveBoxController.kt:210-219)

入口侧 GloveBoxAccountVerifyUtils.openVerifyPage(GloveBoxAccountVerifyUtils.kt:45-57)有一个手套箱特有的前置闸:默认检查 P 挡——getIntProperty(Driving.GEAR, ...) != Gear.PARK 时(:50-51)弹 glove_box_fail_pwd_limit 并返回 false(:53-54),验证页不起;P 挡才委托通用 PinAccountVerifyUtils.openVerifyPage(:56)。

验证通过(it == true)回调里按固定顺序做三件事:setPwdWrongTimes(0) 清零错误计数(:214 → GloveBoxPasswordTools.kt:126-129);openGloveBox(GLOVE_BOX_OPEN_WITH_PASSWORD) 以 openType=2 开箱并埋点(:215);reportGloveBoxForgotPasswordTrack() 上报忘记密码验证成功事件(:216 → :246-252 → VehicleControlReporter.kt:510-519,Event.EXECUTE)。

扫码验证页内部(Intent action、confirm_scene=glovebox_verify、结果广播)归 04 篇,本篇不展开。

6. 开箱主流程时序图

sequenceDiagram
    autonumber
    actor 用户
    participant Ctrl as "GloveBoxController"
    participant Pwd as "PasswordTools / PasswordCheckUtils"
    participant Acct as "GloveBoxAccountVerifyUtils"
    participant Base as "CarPropertyMgr... / SettingsCarPropertyManager"
    participant VCM as "VehicleControlManager(异步)"
    participant Rpt as "VehicleControlReporter"
    participant VHAL as "vehicled / VHAL"

    用户->>Ctrl: 点击「打开手套箱」
    Note over Ctrl: isAvailable=false 时走<br/>showGloveBoxSwitchUnavailableNotify(:121)
    Ctrl->>Ctrl: showGloveBoxSwitchClick(tab)(:261)
    alt 已打开
        Ctrl->>用户: Toast 请手动关闭(:263)
    else 无密码
        Ctrl->>Pwd: getLocalPwd()=null(:265)
        Ctrl->>Ctrl: openGloveBox(openType=1)(:268)
    else 错误达上限
        Ctrl->>Acct: showAccountVerifyPage()(:271)
        Acct-->>Ctrl: 回调 true(P挡闸 :50-55)
        Ctrl->>Pwd: setPwdWrongTimes(0)(:214)
        Ctrl->>Ctrl: openGloveBox(openType=2)(:215)
        Ctrl->>Rpt: reportGloveBoxForgotPasswordSuccess()(:216)
    else 有密码
        Ctrl->>Pwd: goToCheckPassword(CHECK_PWD)(:275)
        Pwd-->>Ctrl: 回调 true
        Ctrl->>Ctrl: openGloveBox(openType=2)(:201)
    end
    Ctrl->>Base: setVehicleProperty(GLOVE_BOX, OPEN)(:224)
    Base->>VCM: setCarProperty→setIntProperty 入ASYNC线程(:128-130)<br/>同时 startTimeOutMonitor(:483)
    Ctrl->>Rpt: reportGloveBoxOpenTrack(openType)(:228)
    Note over Ctrl,Rpt: 写完即报:埋点日志先于 Done
    VCM->>VHAL: setIntProperty 下发(:134)
    VCM->>VCM: Done set propVal: 1 to 0x6140b407(:135)
    VHAL-->>Base: 属性回读 / 超时
    alt 回读 != set值(台架不持久假象)
        Base->>Ctrl: onDataVerifyFailed(propVal=1)(:199-201)
    else 正常回读 OPEN
        Base->>Ctrl: onHandlePropertyChange(:166)
        Ctrl->>用户: Tab 刷新 mIsSelected=true(:177-178)
    end

7. dev 与出货快照差异表

对比对象:W(dev @ 930be9145)vs pack_a17_cn_20260923,同路径 GloveBoxController.kt。

区段dev(W)出货快照差异
全文341 行341 行diff 无任何输出,两版逐字节一致
registerReceiver()(:305-332)含 API 33+ RECEIVER_EXPORTED(0x2)五参分支(:320-325)+ 四参带权限分支(:326-331)同左无差异。出货版已包含 API33 导出标志适配,注释 AI(claude) auto generated at 2026-08-24(:318)同样存在

结论:本篇所有行号对 dev 与 0923 出货包同样适用,不存在「出货版缺 RECEIVER_EXPORTED」的分叉。

8. 证据清单

文件(绝对路径)行号区间一句话说明
/home/zbc/car/fuben4_micarsettings/MiCarSettings-5458412/settingsPage/VehicleBodyControl/src/main/java/com/android/car/settings/miauto/vehicle/glovebox/GloveBoxController.kt:54-341(全文已读)主类:双 Tab、三分支开箱、原因 Toast、埋点、账号广播注册
同上(出货)/home/zbc/car/pack_a17_cn_20260923/settingsPage/VehicleBodyControl/src/main/java/com/android/car/settings/miauto/vehicle/glovebox/GloveBoxController.kt全文与 dev diff 完全一致
/home/zbc/car/fuben4_micarsettings/MiCarSettings-5458412/settingsPage/VehicleBodyControl/src/main/java/com/android/car/settings/miauto/vehicle/VehicleBodyPropertyMap.kt:42-50, :55-63createGloveBoxSwitchCtrl / createGloveBoxPasswordSetCtrl,withAllowClickWhenDisabled(true) 在 :48/:61
/home/zbc/car/fuben4_micarsettings/MiCarSettings-5458412/base/settingsVehicleLib/src/main/java/com/android/car/settings/miauto/vehicle/VehiclePropertyUtil.java:173-182, :55-71isPropertyAvailable(状态可用判定)、getIntPropertyValue(null→0)
/home/zbc/car/fuben4_micarsettings/MiCarSettings-5458412/base/settingsVehicleLib/src/main/java/com/android/car/settings/miauto/common/CarPropertyMgrPreferenceController.java:606-615两参 setVehicleProperty,委托 setCarProperty
/home/zbc/car/fuben4_micarsettings/MiCarSettings-5458412/base/settingsVehicleLib/src/main/java/com/android/car/settings/miauto/vehicle/SettingsCarPropertyManager.kt:429-487, :193-203setCarProperty(isSync=false 异步 + :483 超时监视);handlePropertyTimeout/onDataVerifyFailed 回读校验日志 :199-201
/home/zbc/car/fuben4_micarsettings/MiCarSettings-5458412/base/settingsVehicleLib/src/main/java/com/android/car/settings/miauto/vehicle/VehicleControlManager.java:128-141setIntProperty 丢 ThreadPoolUtils.ASYNC;>>> Done set propVal 日志 :135
/home/zbc/car/fuben4_micarsettings/MiCarSettings-5458412/base/settingsBaseLib/src/main/java/com/android/micar/settings/track/VehicleControlReporter.kt:106, :108, :495-505, :510-519openType 常量 1/2;reportOpenGloveBox(:497 日志);reportGloveBoxForgotPasswordSuccess
/home/zbc/car/fuben4_micarsettings/MiCarSettings-5458412/base/settingsBaseLib/src/main/java/com/android/car/settings/miauto/vehicle/MiCarPropertyIds.java:1485DrivingCtrl.GLOVE_BOX = Peripheral.GLOVE_BOX
/home/zbc/pangu/xcd_xring_a17_fermi/vendor/micar/packages/services/MiVehicleService/support-lib/src/mi/car/config/Peripheral.java:576-580, :606-610, :1426-1430GLOVE_BOX=0x6140b407、GLOVE_BOX_UNAVL_REASON=0x6140b40a、GloveBoxUnavlReason IDLE/NOT_DIS_ARMED/ANTY_PLAY
/home/zbc/car/fuben4_micarsettings/MiCarSettings-5458412/settingsPage/VehicleBodyControl/src/main/java/com/android/car/settings/miauto/vehicle/glovebox/GloveBoxPasswordTools.kt:24-41, :110, :126-129, :135-139密码工具委托 PinPasswordTools;getLocalPwd/setPwdWrongTimes/isPwdLimit
/home/zbc/car/fuben4_micarsettings/MiCarSettings-5458412/settingsPage/VehicleBodyControl/src/main/java/com/android/car/settings/miauto/vehicle/glovebox/GloveBoxPasswordCheckUtils.kt:50-58goToCheckPassword 接口签名
/home/zbc/car/fuben4_micarsettings/MiCarSettings-5458412/settingsPage/VehicleBodyControl/src/main/java/com/android/car/settings/miauto/vehicle/glovebox/GloveBoxAccountVerifyUtils.kt:45-57openVerifyPage 的 P 挡前置闸
/home/zbc/下载/test/车机Feature/Meego 5458412/kb/参考change-161208.md全文开箱主流程与密码链的来源演进(Meego 2350608)
/home/zbc/下载/test/车机Feature/Meego 5458412/kb/参考change-165854.md全文不可用原因 → Toast 映射与中英文案出处
2026-10-19 mach 台架实测日志序列任务给定,逐行见第 3 节「写完即报」与台架回滚假象的实证(截图佐证:Meego 5458412/test/screenshots/打开手套箱点击后-mach-20261019.png)