# 星爱野 1.0.3 APK 整改清单

## 结论先说

当前交付的二进制补丁版在你的设备上仍然闪退，因此**当前 APK 不可视为修复完成版**。前面完成的是 DEX/Smali 静态修改、APK 回编、对齐和签名；这些步骤只能证明安装包能生成并通过结构/签名检查，不能证明它能在 Android 上正常启动或稳定运行。

原 APK SHA-256：`608F2C5E52C437CD17609F76A8CF4B04881748573AAB846F34901108FECC4446`

最近候选 APK SHA-256：`F9E4C9B453B45F69FC464ACAF16A93DDB5ECAFBFD6577D9173C035C0DAEB6315`

最近候选使用临时 Android Debug 签名。它和原 APK 的签名证书不同；这会影响覆盖安装，若程序内部检查签名也可能影响运行。先前两版尝试直接改 Kotlin 协程生成的 Smali，留下了容易出错的分支和字段访问方式。后续应以原始 Kotlin/Java 项目重建，不应继续叠加 Smali 热补丁。

## 已从 APK 静态确认的问题

| 优先级 | 代码位置 | 已确认行为 | 应达到的行为 |
|---|---|---|---|
| P0 | `TunnelService.connect()` | `addAllowedApplication()` 失败时原路径继续建 VPN，结果可能覆盖全部应用 | 游戏包白名单配置失败时，明确报告失败并停止建隧道；不得静默放开全设备流量 |
| P0 | `TunnelService.startMonitor()` | 每秒检查 Native 统计和运行状态；单轮异常会触发全隧道 teardown | 区分暂态读取异常和 Native 线程退出；连续异常达到门限后才重建，并记录每次原因 |
| P0 | `TunnelService.connect()` / `scheduleReconnect()` | Native 刚报告启动成功就清零重连计数，短启短退会反复回到早期退避 | 运行稳定一段时间后再清零计数；手动停止/重新开始才明确重置会话计数 |
| P1 | `SettingsStore.autoReconnect()` 与 `TunnelService` | 设置值存在存取实现，但当前服务重连决策未读取它 | 服务每次重连前读取设置；关闭时不自动重连，开启时按退避策略重试 |
| P1 | `Socks5Config.yaml()` | TCP/UDP 读写超时均配置为 3600000 ms | 先用实战日志确认闲置流和活跃流的行为，再确定独立、可配置的超时；不要凭端口数猜测并盲改 |
| P1 | ConnectLog/Native 日志 | 现有日志可以记录连接步骤，但还不足以区分设备崩溃、VPN service teardown、代理 EOF | 为连接尝试、Native 启停、健康失败、TUN 关闭记录同一 session/attempt ID 和时间戳 |

## 必须先定位闪退

当前没有设备的 `FATAL EXCEPTION` 堆栈或崩溃日志，所以还不能把闪退归因到某一行代码。整改时第一步应在设备上采集一次启动日志，并保留异常前后约 30 秒：

```text
adb logcat -c
adb shell monkey -p com.xay.radar 1
adb logcat -d -v threadtime > launch-crash.log
```

优先检查 `FATAL EXCEPTION`、`VerifyError`、`IllegalAccessError`、`NoSuchMethodError`、`UnsatisfiedLinkError`、`SecurityException`，以及 `TunnelService`、`NativeTunnel` 的首个异常。只有首个异常堆栈能确定启动闪退根因；其后的异常通常只是连锁结果。

同时核对设备安装包的签名/版本，以及 APK 内的 `classes3.dex`、Native ABI 和 Android 系统版本。Debug 签名与原证书不同，若设备覆盖安装失败，应先确认是不是签名冲突；如果安装完成但启动即退出，还要检查应用内部是否校验签名。

## 推荐源码改造

### 1. 连接建立改为显式失败结果

将 VPN 白名单设置封装为一个可测试函数。成功时记录实际允许的 package；失败时返回带原因的连接失败结果，更新 UI 状态并清理已经创建的临时资源。不要在 `connect()` 中继续走 `establish()`，也不要用未捕获异常跨越协程边界。

包名应来自配置并在启动前验证。若产品支持多个游戏包名，逐个验证后建立明确的 allowlist；无有效包时显示明确错误并退出本次连接。

### 2. 健康检查使用状态机和连续失败门限

把以下状态分开观测：

- `NativeTunnel.isRunning()`：Native 工作线程是否存活。
- `NativeTunnel.stats()`：JNI 统计读取是否成功。
- TUN FD：文件描述符是否仍有效。
- SOCKS 控制连接：代理端是否可达。
- UDP/TCP 流：独立流是否结束或超时。

暂时读不到 stats 不应等价于 Native 已退出。建议计数器只在健康检查成功时清零；连续失败达到门限并再次确认 Native 不存活后才 teardown。若只是单条业务流失败，应只回收该流。

### 3. 让重连计数有清晰生命周期

- 每次启动失败或健康检查确认故障时递增 attempt。
- Native 初次启动成功时不要清零。
- 隧道连续稳定运行一个明确窗口后才清零。
- 用户主动停止时取消定时重连并清理 attempt。
- 使用有上限的指数退避和总重试预算；耗尽后进入可见错误状态。

### 4. 把 `autoReconnect` 接到服务层

设置界面写入 DataStore 后，重连决策必须读取同一个 key。关闭时，Native 退出后显示断开/错误状态并停止自动启动；开启时，才进入退避重连。为“设置关闭、连接失败、网络切换、用户手动停止”分别加单元或集成测试。

### 5. 日志要能对齐手机和服务器

每轮连接生成 attempt/session ID，日志至少记录：UTC 时间、状态迁移、失败类型、Native start/exit、TUN 建立/关闭、当前连接节点、健康检查连续失败次数、重连序号和等待时间。密码/token 不写日志。

服务端也按同一时间窗口记录 UDP/TCP 关联创建/关闭、EOF 原因和账户/session ID。只有客户端 teardown 时间与服务器批量 EOF 对齐，才能判定客户端是断线触发方。

## 验收清单

1. 原 APK 安装后能启动；改版在同设备、同 Android 版本完成启动和进入主界面。
2. 白名单有效时仅目标游戏进入 VPN；包不存在或白名单失败时，连接显示失败且其他应用不被接管。
3. 单次 stats 读取异常不 teardown；连续异常达到门限后只发生一次受控恢复。
4. 重复短启短退时重连计数持续累计，不会每次成功返回第一档退避。
5. 连续稳定运行到设定窗口后，计数才复位。
6. `autoReconnect=false/true` 两种状态分别验证；手动停止之后没有遗留后台重连任务。
7. Wi‑Fi/蜂窝切换、后台/前台切换、游戏大厅/对局切换分别运行并导出日志。
8. 至少进行一局实机对局并复测大厅返回；检查网络重连提示、键位状态、雷达队伍分类和坐标漂移。
9. 使用项目正式签名证书构建；覆盖安装、卸载重装、升级路径分别验证。

## 本次候选包状态

- 静态修复：白名单 fail-open、健康检查连续门限、重连计数清零时机。
- 未修复：`autoReconnect` 服务层接入、TCP/UDP 超时调整。
- 已完成：apktool 回编、zipalign、临时 Debug v2/v3 签名、签名检查、最终 APK 反解检查。
- 未完成：设备崩溃堆栈分析、设备启动验证、完整对局与长时间稳定性验证。

因此当前候选 APK 仅适合定位问题的测试包，不能标记为已修好的发布版本。正式修复需要原始 Android Studio 项目（Kotlin/Java、Gradle、Native 源码和资源）以及一次启动闪退的 logcat 堆栈。
