调试工具台 BLE 页签怎么读
0.6.0 把蓝牙层重写成了扫描调度、建链、链路事务、独占、在场几个明确的部分,调试工具台的 ble 页签直接订阅这些部分的快照和事件。页签上的每个字都对应蓝牙层的一个决定,这一页逐项解释它们的含义,以及看到异常时该去查什么。
怎么打开
设置页里的开关,打开后停在屏幕底部
- 设置 → 打开 Show Debug Console,底部出现可拖拽的调试工具台。
- 工具台顶部有三个页签:
logs(结构化日志)、device control(写入期望值与设备回报的对照)、ble(本页讲的这个)。 ble页签分上下两半:上半是状态区,每行一个主题,随蓝牙层实时刷新(约 80 毫秒合并一次,计时每秒走一格);下半是事件列表,按时间顺序追加。
颜色的含义
状态区每行的颜色表示这一项的当前状态:绿正常可用,蓝正在进行,黄需要留意,红出了问题,灰空闲或没有数据。事件列表用三个记号:· 普通信息,! 警告,✕ 错误。
状态区逐行
下面是一台 SecureLink 设备连接中的典型画面,后文按行解释
蓝牙
| 开 | 系统蓝牙可用且 App 有权限。 |
| 关或无权限 | 系统蓝牙关闭、权限被拒或设备不支持。此时所有链路已被清空,事件列表里会有 adapter-state 与 disconnected(蓝牙不可用)。 |
扫描
整个 App 同一时间只有一个系统扫描,各业务只是向调度器登记需求,调度器把需求合并到这一个扫描上。这一行回答"系统扫描现在在不在跑、为谁跑"。
| 原生扫描运行 N 秒 | 系统扫描已启动并持续了 N 秒。后面若带"建链期间暂停中",表示为了让连接顺利,扫描在建链时被暂停,连上或失败后恢复。 |
| N 项需求(发起者…) | 此刻在册的需求数与发起者名字。常见发起者:device-list 设备列表在场判定,auto-connect 控制页自动重连,ota-reconnect OTA 重启后重连,pairing 配对流程,scan-screen 添加设备页。没有需求时扫描会在 2 秒后停止。 |
| 等扫描额度,N 秒后启动 | 有需求但 Android 的启动额度用完,正在等。见下一行。 |
| 原生扫描 stopped | 没有需求或还没启动。若带"上次系统停止 status N",是上一次系统主动停止扫描时给的状态码,6 表示限频。 |
| 调度器未启动 | 蓝牙层还没初始化,通常只在 App 刚启动的一瞬间看到。 |
扫描额度(只在 Android 显示)
Android 规定 30 秒内启动扫描不能超过 5 次,超过就把扫描静默停掉。蓝牙层自己记账,不去撞这条线。
| 30 秒内已启动 N/5 | 最近 30 秒内启动过 N 次。到 4 变黄提醒接近上限。 |
| N 秒后才能再启动 | 额度已满,红色,倒计时到最早一次启动出窗口(多留 0.5 秒余量)。此时的需求都在排队,不是丢了。 |
为什么额度会用完
每次原生扫描启动都算一次:页面切换导致需求起停、建链期间暂停后恢复、系统停止后重启,都会消耗额度。0.6.0 之前多个业务各自起停扫描是撞限频的主因,现在合并到一个扫描上,正常使用不该再看到额度用完;看到的话,事件列表里数一下 native-started 是谁触发的。
建链
建链是"从一项扫描需求出发,按发现顺序逐台连接,直到调用方认证通过"的过程。同一时间只有一次建链在进行,新的建链会取代旧的。
| 发起者 | 谁在建链:auto-connect 控制页、ota-reconnect OTA、pairing 配网后首连。 |
| 需求种类 | saved-device 找一台已保存设备(按认证身份或本地名匹配);discriminator 按二维码里的 discriminator 找待配对设备;locator 按系统连接标识找回同一台(只在一次配网会话内部用);commissionable 可配对候选列表;presence 只要求扫描在跑,不找具体设备。 |
| 阶段 | 等候选:扫描中还没发现符合需求的设备。建链中:正在连接某个候选。已建链,等调用方裁定:链路建好了,等会话层做 AUTH 或 REJOIN,认证通过就接受,被拒就换下一台。 |
| 排队 N,已拒 M | 已发现但还没尝试的候选数,以及本次建链里被调用方拒绝过的候选数。已拒大于 0 说明附近有一台长得像但凭据对不上的设备。 |
| 第 K 次连接 | 当前候选的连接尝试次数。连接失败按 1、2、4 秒退避,最多重试 3 次。 |
| 剩 N 秒 | 到截止时间还剩多久。控制页自动重连的预算是扫描加建链共约 25 秒,OTA 重连按设备报的重启时间算。到期就放弃并释放需求。 |
| 没有进行中的建链 | 空闲。已连接时也是这个状态,建链在接受链路的一刻就结束了。 |
链路
蓝牙层只维护一条链路,状态机止于"已连接",之后认识协议的事(AUTH、订阅、读状态)都在会话层。
| 无链路(store: …) | 没有连接。括号里是 BLE store 的连接状态,正常应为 disconnected;若两者不一致,说明有一次断开事件还没处理完。 |
| 连接中 地址 | 已向系统发起连接,等系统回连接成功,10 秒上限。 |
| 发现中 地址,mtu / services | 系统连接成功后的两步:协商 MTU、发现服务,各 10 秒上限。逗号后面是当前在哪一步。 |
| 已连接 地址 N 秒,单次写入 M B | 链路可用,N 是已连接时长,M 是协商出的单次写入长度(ATT MTU 减 3)。SecureLink 设备通常是 244 B;显示 20 B 说明 MTU 协商没成功,帧会被拆得很碎。 |
| 断开中 地址 | App 已发起断开,等系统的断开事件,5 秒上限。 |
事务(有链路时显示)
同一条链路上的读写严格排队,每个事务有上限时间。这一行回答"链路现在被谁占着、后面排了几个、是不是在超时"。
| 标签 进行 N 秒 / 上限 M 秒 | 正在跑的事务是谁,跑了多久,上限多少。上限默认 10 秒;历史拉取 120 秒;OTA 控制帧 10 秒、数据帧 5 秒;网页控制页发起的调用按它自己的预算(读写 8 秒)。 |
| 空闲 | 没有事务在跑。 |
| 排队 N | 后面还有 N 个事务等链路。持续大于 0 说明某个事务占用时间太长,或调用方发得太密。 |
| 连续超时 N | 连续超时的事务数,任一事务完成即归零。到 2 蓝牙层就主动断链并标为"链路超时",交给自动重连找回。 |
常见事务标签:SecureLink 的 OWNER_AUTH、PASE、GET_STATE、SET_STATE、HISTORY_INFO、HISTORY_QUERY;ShimLink 的控制命令名(如设置工作模式);旧设备明文数据点的 dp-read、dp-write;OTA 的 ota-control、ota-data。
上次断开(有过断开时显示)
格式是"地址 原因(原因码名),可重连"。原因由蓝牙层分类,会话层据此决定要不要自动重连。
| remote-terminated | 对端断开:设备主动断的,或链路层被对端结束。Android 常见原因名 Remote User Terminated Connection;设备重启、进入配网、固件复位都会这样。可重连。 |
| link-timeout | 链路超时:设备走出范围、没电,或连续两个事务超时被蓝牙层主动断开。原因名多为 Connection Timeout。可重连。 |
| connection-failed | 建链失败:连接从没真正建立。可重连。 |
| app-requested | App 自己调了断开,例如页面离开、换设备、配对流程让出链路。不可重连,灰色。 |
| adapter-unavailable | 蓝牙被关闭或权限被拒。不可重连,蓝牙恢复后由业务重新发起。 |
原因码名来自平台:Android 是 HCI 错误码的规范名,iOS 是 CBError 的名字;表里没有的码会显示原始数字并按对端断开处理。
独占(有持有时显示)
配对流程和 OTA 会把一台设备"持有"起来,持有期间自动重连和连接后的状态同步都让路。格式是"持有者 持有 记录或地址,持续 N 秒",多个持有用分号隔开。持有者只有两种:pairing 和 ota。看到这一行而设备页又连不上,原因就在这里,不必再查别的。
在场
蓝牙层只记事实:每台已保存设备最近一次被扫描到的时间、地址和信号强度。格式是"记录 ID 前 14 位… N 秒前 RSSI"。设备列表据此判定"在范围内",窗口 5 秒,超过就变成不在范围内;这里显示的是原始事实,不做判定。信号强度 −40 到 −60 dBm 是近距离,−80 以下基本连不上。
事件列表
每行:时间(时:分:秒.毫秒)、记号、文字、方括号里的发起者或事务标签
- 全部 / 异常:异常只显示警告和错误,排查时先看异常。
- N 条 · 跟随 / 已暂停:默认跟随最新,向上滚动查看历史时自动暂停,滚回底部恢复。
- 清空(右侧垃圾桶):只清事件列表,状态区的扫描、链路、建链快照保留。事件最多保留 300 条,更早的自动丢弃;需要完整记录请导出日志。
- 事件按来源分六类,下面逐类列全。文字里的"地址"是系统连接标识(Android 是 MAC,iOS 是 UUID),"N 秒"在 10 秒内显示一位小数。
扫描调度
| 事件 | 页签上的文字 | 严重度 | 怎么读 |
|---|---|---|---|
need-registered | 登记扫描需求 [发起者] | info | 某个业务开始需要扫描。发起者写在方括号里。它不代表原生扫描已经开始,原生扫描要看下一条。 |
need-released | 释放扫描需求 [发起者] | info | 该业务不再需要扫描。最后一项需求释放后原生扫描还会多跑 2 秒再停,避免页面切换时反复起停。 |
native-started | 原生扫描开始,N 项需求 | info | 系统扫描真的启动了,N 是此刻合并进来的需求数。Android 上每次启动都计入 30 秒额度。 |
native-stopped | 原生扫描停止:原因[,status N] | info warn | 原因有五种:没有需求了、建链期间暂停、连续运行接近 30 分钟主动重启、管理器销毁,以及系统停止。只有系统停止是 warn,并附带 Android 的 status;status 6 表示系统判定 30 秒内启动过多。 |
start-delayed | 扫描额度不足,N 秒后再启动 | warn | Android 上 30 秒内已启动 5 次,蓝牙层主动等额度恢复,不去撞系统限频。等待期间不是故障,看倒计时即可。 |
start-failed | 原生扫描启动失败:错误 | error | 系统拒绝启动扫描。常见于蓝牙刚打开、定位权限缺失或系统蓝牙栈异常。先看蓝牙行与适配器事件。 |
throttled | 系统限频(30 秒内启动过多),按额度重排 | warn | 系统已经把扫描停了并回报限频。蓝牙层把这次也计入额度并重新排期,随后会出现 start-delayed 或 restart-scheduled。 |
restart-scheduled | N 秒后重启扫描(接近 30 分钟 / 系统停止后) | info | 两种重启:Android 会把超过 30 分钟的无过滤扫描降级,蓝牙层在 28 分钟时主动重启一次;或者系统停止后按额度择时重启。 |
restart-skipped-background | App 不在前台,扫描不重启,回到前台再恢复 | warn | 系统停止扫描时 App 在后台,蓝牙层不在后台重启,回到前台后按在册需求恢复。设备列表在后台显示不更新属正常。 |
连接管理
| 事件 | 页签上的文字 | 严重度 | 怎么读 |
|---|---|---|---|
connecting | 开始建链 地址 | info | 向系统发起连接。默认 10 秒内没建立就超时取消。 |
discovering | 地址 链路已建立,MTU 协商中 / 服务发现中 | info | 系统连接已成功,正在协商 MTU 或发现服务,每一步各 10 秒上限。 |
connected | 地址 可用:N 个服务,单次写入 M B | info | 链路进入可用状态。M 是协商出的单次写入长度(ATT MTU 减 3);显示"未知"表示这台设备或平台没有报出 MTU。 |
step-timeout | 地址 MTU 协商 / 服务发现超时(N 秒),释放链路 | error | 连接建立了但设备在这一步没有回应。多为设备固件卡住或链路质量差;蓝牙层会断开并释放,由上层决定是否重试。 |
connect-failed | 地址 建链失败:错误 | error | 系统连接本身失败。错误文本来自原生库,常见"Connection failed"或超时。建链(acquireLink)会按 1、2、4 秒退避重试,看后面的 link-attempt 次数。 |
abandoned | 地址 的链路在调用方放弃后才建立,已丢弃 | warn | 调用方已经超时放弃,Android 却在设备下次广播时连上了。蓝牙层主动断掉这条迟到的链路,不会留下一条没人用的连接。 |
disconnecting | 断开 地址 | info | App 主动发起断开。5 秒内没收到系统的断开事件会出现 disconnect-timeout。 |
disconnect-timeout | 地址 断开超时,系统仍持有链路 / 已无此链路 | warn error | 等断开事件超时。"已无此链路"说明系统其实已经断了只是事件没来,是 warn;"仍持有链路"说明系统还连着,是 error,后续建链可能被这条残留链路挡住。 |
disconnected | 地址 已断开:原因(原因码名)[,可重连] | info warn error | 原因五种:对端断开、链路超时、建链失败、App 发起、蓝牙不可用。括号里是 Android 的 HCI 原因名或 iOS 的 CBError 名,例如 Remote User Terminated Connection、Connection Timeout。"可重连"表示会话层的自动重连可以去找回设备;App 发起和蓝牙不可用不可重连。App 发起是 info,蓝牙不可用是 error,其余是 warn。 |
link-timeout-drop | 地址 连续 N 个事务超时,主动断链 | error | 同一条链路连续两个事务超时,说明设备已经不回应了,蓝牙层主动断开并按"链路超时"上报,让自动重连去处理。OTA 这类独占方可以关闭这条规则。 |
链路事务
| 事件 | 页签上的文字 | 严重度 | 怎么读 |
|---|---|---|---|
transaction-started | 事务开始,上限 N 秒,排队 M [标签] | info | 一个事务拿到了链路。标签是事务名,见下方标签表;M 是它后面还排着几个。 |
transaction-completed | 事务完成 / 失败,用时 N 秒 [标签] | info | 事务结束并释放链路。"失败"指设备答了但答的是错误,这也算一次完整往返,连续超时计数归零。 |
transaction-timeout | 事务超时(N 秒),连续第 K 次,链路让给下一个事务 [标签] | warn | 设备在上限内没有回应。事务被取消、链路让给下一个;K 到 2 就会触发 link-timeout-drop。 |
transaction-aborted | 调用方放弃事务,用时 N 秒 [标签] | info | 调用方先于超时放弃,典型是网页控制页的调用到了它自己的 8 秒预算。不是设备的问题。 |
transaction-link-lost | 链路断开,事务作废,排队 M 个一并作废 [标签] | warn | 事务进行中链路断了,它和后面排队的一起失败。配合前后的 disconnected 事件看断开原因。 |
建链
| 事件 | 页签上的文字 | 严重度 | 怎么读 |
|---|---|---|---|
acquire-started | 开始建链(需求种类 需求)[发起者] | info | 某个业务开始找设备并建链。需求种类见"建链"一行的说明。 |
candidate-queued | 候选 地址 入队,排队 N | info | 扫描到一台符合需求的设备,排进候选队列。只收登记之后的广播,重启前的旧地址不会被当成候选。 |
link-reused | 复用已连着的 地址 | info | 要找的设备本来就连着(已连接的设备不广播),直接用这条链路,不等广播。 |
link-attempt | 地址 已建链,第 N 次连接成功,等调用方裁定 | info | 链路建好了,等调用方认证后决定接受还是换下一台。N 大于 1 表示前面几次连接失败后退避重试成功。 |
candidate-rejected | 调用方拒绝 地址,换下一个(还有 N 个) | warn | 调用方认证后判定这不是要找的设备(通常是设备拒绝了保存的凭据),断开它去连下一个候选。两台同型号设备靠得近时会看到这条。 |
link-accepted | 地址 被接受,建链完成 | info | 调用方认证通过,本次建链结束,扫描需求释放,链路交给会话层。 |
acquire-cancelled | 调用方放弃建链,链路 地址 留给它处理 | info | 调用方在裁定前放弃,比如页面离开。链路不会被蓝牙层动,要断由调用方断。 |
acquire-failed | 建链结束:到截止时间 / 建链失败 / 扫描启动失败 / 调用方取消 / 被新的建链取代 | info warn | 本次建链没有拿到链路。到截止时间说明期限内没有候选或都连不上;调用方取消和被取代是正常流程,是 info;其余是 warn。 |
独占
| 事件 | 页签上的文字 | 严重度 | 怎么读 |
|---|---|---|---|
exclusive-acquired | 持有者 持有 记录/地址(合并 N 次) | info | 配对流程或 OTA 拿到了这台设备的独占。同一持有者重复申请只加计数,N 是当前计数。 |
exclusive-refused | 申请者 申请 记录/地址 被拒,持有者 持有中 | warn | 另一个业务想用这台设备但它正被别人独占。界面会提示"设备正在升级固件 / 正在配对",这条事件告诉你是谁挡住了谁。 |
exclusive-released | 持有者 释放 记录/地址 | info | 独占结束,自动重连和状态同步可以继续。 |
适配器
| 事件 | 页签上的文字 | 严重度 | 怎么读 |
|---|---|---|---|
adapter-state | 蓝牙适配器:状态 | info error | 系统蓝牙状态变化:on 正常;off、unauthorized(无权限)、unsupported 是 error;resetting、unknown 是过渡状态。变为不可用时所有链路立即清空并按"蓝牙不可用"上报。 |
几种常见画面怎么读
按"先看状态区,再筛异常事件"的顺序
控制页一直"正在连接"
- 建链行停在等候选且倒计时在走:扫描里没有符合需求的设备。看在场行有没有这台设备的记录 ID;没有就是设备没在广播(没电、被别的手机连着、还在重启),有就是身份不匹配,去看日志里的
Auto-connect timed out without finding the saved device。 - 建链行停在建链中且"第 K 次连接"在增加:设备在广播但连不上,事件里看
connect-failed的错误文本。 - 建链行是已建链,等调用方裁定很久:链路有了,卡在认证。看事务行是不是
OWNER_AUTH或 REJOIN 在超时,以及 logs 页签里会话层的认证日志。 - 独占行有内容:设备被 OTA 或配对持有,自动重连在让路,等它结束。
扫描时有时无
- 扫描额度行红色倒计时,事件里有
throttled或start-delayed:Android 限频。数一下之前的native-started是谁频繁触发的。 - 事件里有
native-stopped:系统停止,status N而 App 在后台:正常,回前台会restart-scheduled。 - 事件里定期出现
restart-scheduled(接近 30 分钟):正常,这是避开 Android 对长时间扫描的降级。
连上了但操作没反应
- 事务行"排队 N"持续大于 0:链路被某个长事务占着,看是谁的标签;历史拉取和 OTA 数据帧是合理的长事务。
- 事件里连续出现
transaction-timeout,然后link-timeout-drop:设备不再回应,蓝牙层主动断链,自动重连接手。若设备本身是好的,怀疑固件在这条命令上卡住。 - 事件里是
transaction-aborted:调用方自己放弃了,多半是网页控制页的 8 秒预算到了,看设备是不是回得太慢。
两台同型号设备互相干扰
- 建链行"已拒 1",事件里
candidate-rejected后紧接link-attempt另一个地址:第一台拒绝了保存的凭据,自动换到第二台。这是 0.6.0 的预期行为,凭据不会被误标失效。 - OTA 重连时看到同样的序列:设备重启后换了地址,旧地址的设备还在广播,同样自动换台。
设备页提示"设备正在升级固件 / 正在配对"
- 事件里有
exclusive-refused,写明申请者与持有者。等exclusive-released出现后再操作。