34 · 忘记网络与删除后的列表时序(竞态窗口解剖)
核心文件:
view/MiCarWifiEntryDetailFragment.kt(删除入口)、wifitrackerlib/StandardWifiEntry.java(forget 实现)、WifiPickerTracker.java(配置/状态双广播处理) 代码基线:fuben_micarsettings @ dev,f3 flavor 关联:三个历史 case 的机制底座——2901(删除残留 3.67s)、131987(列表清空 ~1s)、2782(海外删网延迟)
0. 一句话总纲
忘记网络没有任何乐观移除——App 调完 forget(null) 立即返回列表页,条目何时消失完全取决于”框架两路广播(binder 往返)× 库的多波重算 × 扫描缓存窗口”何时收敛。删除已连接网络时存在两个竞态窗口,谁先到决定用户看到的中间态。
1. 入口与 forget 实现
// 详情页负按钮「删除网络」→ confirmDeleteAp 确认框
detailWifiEntryData?.forget(null) // MiCarWifiEntryDetailFragment.kt:157
fragmentHost.goBack() // :158 立即返回,不等 forget 结果// f3dif StandardWifiEntry#forget:640-649
public synchronized void forget(@Nullable ForgetCallback callback) {
if (canForget()) { // canForget = getWifiConfiguration() != null (:636-638)
mForgetCallback = callback;
mWifiManager.forget(mTargetWifiConfig.networkId, new ForgetActionListener(this)); // :646
}
}- 回调传
null:App 层不用 ForgetCallback 刷新列表。 ForgetActionListener(WifiEntry.java:1505-1525)弱引用,成功/失败只回调——不做任何本地缓存摘除。WifiManager.forget(netId)异步 binder:框架删配置→断开当前连接(若是本网)→发广播[待验证:广播顺序以 logcat 为准]。
唯一 UI 入口:已保存条目右侧详情按钮(仅 isSaved 且已 provisioned 显示)→ 详情页删除。没有长按忘网路径(已检索确认)。
2. 完整时序:从点删除到列表恢复
sequenceDiagram participant U as 用户 participant D as 详情页 participant F as WifiService participant T as WifiPickerTracker(worker) participant L as 列表UI U->>D: 删除网络 → 确认 D->>F: WifiManager.forget(netId) D->>L: goBack()(UI 立即返回,显示旧状态) Note over L: 列表fragment view重建<br/>tracker onStart→handleOnStart 重拉 F->>F: 删config→断链 F-->>T: 波1: CONFIGURED_NETWORKS_CHANGED T->>T: 重拉配置,updateConfig→isSaved=false T->>L: onWifiEntriesChanged(重建#1) F-->>T: 波2: NETWORK_STATE_CHANGED / onLost T->>T: connectedState→DISCONNECTED T->>L: onWifiEntriesChanged(重建#2) Note over L: 条目按新状态落入可用组<br/>(前提:扫描仍可达) F-->>T: 波3: 下一轮 SCAN_RESULTS(≤10s) T->>L: onWifiEntriesChanged(重建#3,信号格刷新)
代码调用链(对照上图,波 1 展开):
MiCarWifiEntryDetailFragment#confirmDeleteAp:157
→ StandardWifiEntry#forget:641-646 → WifiManager.forget(netId) [binder 异步]
→ [框架广播 CONFIGURED_NETWORKS_CHANGED]
→ BaseWifiTracker$mBroadcastReceiver#onReceive:177
→ WifiPickerTracker#handleConfiguredNetworksChangedAction:377 → processConfiguredNetworksChanged:385-393
→ updateWifiConfigurationsInternal:1353(binder 重拉 getConfiguredNetworks)
→ updateWifiConfigurations:1291-1350(config 缓存 clear+重建;被忘 netId 已不在)
→ StandardWifiEntry#updateConfig(null→emptyList):1054-1088 → mMatchingWifiConfigs.clear()
→ isSaved 变 false(共享网络无 config 的 entry 直接删缓存 :1331-1337,仅跨用户)
→ conditionallyUpdateScanResults(false,false):389(不 poll 新扫描、5min 容错窗不清旧扫描)
→ updateWifiEntries:610 → notifyOnWifiEntriesChanged:790/1554(main post)
→ MiWifiTrackerUtils:51 → MiCarBaseWifiEntryController#updateState:96 → 子类 removeAll+重建波 2:NETWORK_STATE_CHANGED → handleNetworkStateChangedAction:397-434 → onPrimaryWifiInfoChanged:1152(WifiInfo 不再匹配 → mNetworkInfo=null :1154-1159 → connectedState 回 DISCONNECTED);另有 NetworkCallback.onLost → handleNetworkLost:471-482 → clearConnectionInfo(true)(:1255-1286 清 mNetwork/mNetworkInfo/mNetworkCapabilities/mWifiInfoLevel)。
3. 两个竞态窗口(谁先到,中间态不同)
| 窗口 | 前提 | 用户看到 |
|---|---|---|
| A:config-changed 先到 | isSaved=false 但 connectedState 仍 CONNECTED → 仍算进 activeWifiEntries(:620-621 只摘 DISCONNECTED),connectedWifiEntry 还是它(:776-787) | 已保存组仍显示”已连接”高亮卡,等断链波到达才落回普通条目 |
| B:network-state 先到 | DISCONNECTED 但 isSaved 仍 true(配置广播未到)→ 进 mWifiEntries;可用组跳过它(只计 mStartIndex),已保存组当普通 saved 显示 | ”已连接卡 → 短暂未高亮已保存条目 → 消失/落入可用组” |
4. 无乐观移除的机制事实
- App 层:
forget(null)后立即 goBack,不先摘条目; - tracker 层:entry 从缓存消失只有两条路——①
updateWifiConfigurations的跨用户 removeIf(:1329-1337,单用户不触发);②updateStandardWifiEntryScans的removeIf(level==UNREACHABLE)(:938-939)。普通 forget 走的是”属性翻转”:isSaved→false + connectedState→DISCONNECTED,条目对象在扫描仍可达期间继续存在,只是换组。
5. 三个历史 case 在本机制的落点
| Case | 现象 | 机制落点 |
|---|---|---|
| MANNPROB-2901 | 删网络后条目残留 3.67s | 无乐观移除 + 等 CONFIGURED_NETWORKS_CHANGED 的 binder 往返(多波) |
| N801PROB-131987 | 删已连接 AP 后列表清空 ~0.8-0.9s | forget 触发断连 → 瞬间 scan 数据为空 → updateStandardWifiEntryScans 全置 UNREACHABLE 清缓存 → getWifiEntries 空 → App 当时无”空列表保留上一帧”防护 → 整表白屏(现已由 guardTransientEmpty 兜住) |
| MIICOSBUG-2782(海外 27B) | 删网后列表刷新延迟 ~1s | 第一次 CONFIGURED_NETWORKS_CHANGED( |
共同根因模式:App/tracker 双层都假设”广播最终会来”,但没有对”多久来、来几波、中间态长什么样”做任何控制——这就是删除类体验问题的结构性来源。
6. 恢复条件:被忘 AP 何时回到”可用组”
- 要求它的扫描结果仍可达:
updateScanResultInfo维持mScanResultLevel; - 扫描缓存窗口 =
mMaxScanAgeMillis=15s(MiWifiTrackerUtils.kt:29)+ 失败容错 5min(ScanResultUpdater.java:36); - 若 AP 已出范围/扫描过期 → 条目直接从列表消失(不会留在”可用”)。
7. 修改密码的三个入口(共用 WifiPasswordDialog)
- 详情页「修改密码」(仅加密网;开放网禁用):带原 networkId connect(MiCarWifiEntryDetailFragment:100-129);
- 列表点击认证失败的已保存网(3405 修复):shouldEditBeforeConnect → 直弹带错误提示(MiCarBaseWifiEntryController:218-223);
- 连接无配置加密网:NO_CONFIG 回调 → 弹密码框(:324-329)。
[待验证]:①框架侧 forget 后三路事件(CONFIGURED/NETWORK_STATE/onLost)的确切顺序与间隔;②两个竞态窗口在实车上的实际时长。