mirror of
https://gitee.com/xmz7891/ykxmz.git
synced 2026-10-18 12:30:44 +00:00
阶段1 网络加速 - 发现隧道在跑 QUIC(ExecStart 丢了 --protocol http2), 实测 QUIC 可用率 48% vs HTTP/2 80%+,是重大性能回退。 恢复后公网延迟从 4141ms 降到 690ms(快 6 倍),可用率 92%。 - 优选 IP 结论:无效。hosts 覆盖确实生效了(日志里连的就是指定 IP), 但落点仍是 lax —— 运营商把所有 Cloudflare anycast 都路由到美西。 已清掉这段无效配置。 - BBR 不可用:设备是自定义内核 6.4.0-rc4-jsbsbxjxh66, 没编 tcp_bbr 模块也没配置项。改用 cubic + 调优: TCP 缓冲 4MB、tcp_fastopen=3、tcp_slow_start_after_idle=0 (长轮询场景关键)、tcp_tw_reuse=1。 阶段2 官网重做 - 拆出独立模块 relay/landing.py(relay.py 已两千多行, 再塞 HTML 没法看) - 信息结构参考成熟产品站:吸顶导航 / Hero / 九宫格功能 / 三步上手 / 下载 / FAQ / 页脚 - 保持白色简洁:底白、浅灰面板、细边框、大量留白 - logo 用内联 SVG(ICO 放 img 里实测是破图) - 管理入口从官网移除(管理不对外开放) 过程中被自己的测试抓到两个 bug: - 模块叫 site.py 会和 Python 标准库重名,import site 拿到的是标准库 - _logo() 里把 % 格式化和字符串拼接混用,直接抛 TypeError
178 lines
7.5 KiB
Python
178 lines
7.5 KiB
Python
# -*- coding: utf-8 -*-
|
||
'''防回归:抓"定义了但从没被调用"的方法。
|
||
|
||
为什么值得单独一个测试:
|
||
1.7.0 交付后用户装上发现**一片白屏**。根因是
|
||
private void initTabs() { ... } // 定义在第 937 行
|
||
而 onCreate 里只调了 buildControlPanel(),**从头到尾没人调 initTabs()**。
|
||
结果 tabDefs 为 null -> selectTab() 直接 return -> 内容区空白。
|
||
|
||
这种错误编译能过、别的测试也能过,只有真机跑起来才看得见,
|
||
所以必须静态查出来。
|
||
|
||
判定方法:
|
||
统计方法名在文件里出现的次数(定义那一处也算)。
|
||
只出现 1 次 = 只有定义没调用。
|
||
|
||
分两档:
|
||
* **硬性失败**:关键路径上的方法(initTabs / 三个面板 / selectTab)。
|
||
这些漏了就是白屏或功能全无,必须拦住。
|
||
* **仅报告**:其它可疑方法。有些确实是历史遗留的死代码
|
||
(下面的 KNOWN_DEAD 记录了已确认的),有些是接口回调
|
||
(由框架调用,本文件里当然只有定义)。
|
||
报告出来供清理,但不拦构建 —— 免得噪音太大没人看。
|
||
'''
|
||
from __future__ import annotations
|
||
|
||
import re
|
||
import sys
|
||
from pathlib import Path
|
||
|
||
ROOT = Path(__file__).resolve().parent.parent
|
||
MAIN = (ROOT / "android" / "src" / "com" / "lanremote" / "watch"
|
||
/ "MainActivity.java")
|
||
|
||
# 框架/接口回调:由 Android 或 RemoteClient 调用,本文件里只有定义是正常的
|
||
WHITELIST = {
|
||
"onCreate", "onDestroy", "onResume", "onPause", "onStart", "onStop",
|
||
"onRestart", "onNewIntent", "onSaveInstanceState", "onRestoreInstanceState",
|
||
"onBackPressed", "onKeyDown", "onKeyUp", "onWindowFocusChanged",
|
||
"onRequestPermissionsResult", "onActivityResult", "onOptionsItemSelected",
|
||
"onCreateOptionsMenu", "onPrepareOptionsMenu", "onConfigurationChanged",
|
||
"onTouchEvent", "onClick", "onLongClick", "onTouch", "onAnimationUpdate",
|
||
"onAnimationStart", "onAnimationEnd", "onAnimationCancel", "onAnimationRepeat",
|
||
"onPreDraw", "onGlobalLayout", "onScrollChanged", "onItemClick",
|
||
"onItemSelected", "onNothingSelected", "onFocusChange", "onEditorAction",
|
||
"run", "call", "get", "set", "equals", "hashCode", "toString",
|
||
"uncaughtException", "afterTextChanged", "beforeTextChanged",
|
||
"onTextChanged", "onProgressChanged", "onStartTrackingTouch",
|
||
"onStopTrackingTouch", "onDateSet", "onTimeSet", "onDismiss",
|
||
"onCancel", "onShow", "onKey", "onCreateDialog", "onPrepareDialog",
|
||
"onReceive", "onServiceConnected", "onServiceDisconnected",
|
||
"onBind", "onCreateView", "onViewCreated", "onDestroyView",
|
||
"onAttach", "onDetach", "onActivityCreated", "onOptionsMenuClosed",
|
||
"onContextItemSelected", "onCreateContextMenu", "handleMessage",
|
||
"onChildViewAdded", "onChildViewRemoved", "onGlobalFocusChanged",
|
||
"onLayoutChange", "onScrollStateChanged", "onScrolled",
|
||
"onPageStarted", "onPageFinished", "shouldOverrideUrlLoading",
|
||
"onReceivedError", "onDownloadStart", "onChildDraw",
|
||
# RemoteClient.Listener 的实现
|
||
"onDisconnected", "onEvent", "onFrame", "onProgress", "onLog",
|
||
}
|
||
|
||
# 已确认的历史遗留死代码:早期版本的实现,后来换成了别的写法,
|
||
# 函数留着但没人调。不影响功能,列出来是为了有朝一日清掉。
|
||
KNOWN_DEAD = {
|
||
"buildFeatureTab": "旧的分页构建方式,已被 renderGroups() 取代",
|
||
"pickFolder": "已被 pickFile() 取代",
|
||
"pickClipHistory": "功能已移到服务端注册表",
|
||
"confirmWallpaper": "功能已移到服务端注册表",
|
||
"confirmMonitor": "功能已移到服务端注册表",
|
||
"sendMedia": "已被 media() 取代",
|
||
"promptRun": "已被 runFeature() 取代",
|
||
"showInfo": "已被 feature_run 的 info 取代",
|
||
"findSavedToken": "旧的重连逻辑,已被 RelayTransport 取代",
|
||
"glassBackground": "旧的美化辅助函数,样式改成 glass() 后没人用了",
|
||
"sp": "旧的字号辅助,已被 dp() 取代",
|
||
}
|
||
|
||
# 关键路径:这些漏了就是白屏 / 功能全无,必须硬性拦住
|
||
CRITICAL = ("buildConnectPanel", "buildControlPanel", "initTabs",
|
||
"buildMirrorPanel", "buildLanPanel")
|
||
|
||
passed = 0
|
||
failed = 0
|
||
|
||
|
||
def check(name, ok, detail=""):
|
||
global passed, failed
|
||
if ok:
|
||
passed += 1
|
||
print(" [PASS] " + name)
|
||
else:
|
||
failed += 1
|
||
print(" [FAIL] " + name + " " + str(detail))
|
||
|
||
|
||
def defined_methods(text: str) -> list[str]:
|
||
pattern = re.compile(
|
||
r"(?:private|public|protected|static|final|\s)+"
|
||
r"[\w<>\[\],.\s]+\s+(\w+)\s*\([^)]*\)\s*(?:throws [\w.,\s]+)?\{")
|
||
names = []
|
||
for match in pattern.finditer(text):
|
||
name = match.group(1)
|
||
if name in ("if", "for", "while", "switch", "catch", "synchronized",
|
||
"try", "return", "new"):
|
||
continue
|
||
names.append(name)
|
||
return names
|
||
|
||
|
||
def main() -> int:
|
||
check("MainActivity.java 在", MAIN.is_file())
|
||
if not MAIN.is_file():
|
||
return 1
|
||
text = MAIN.read_text(encoding="utf-8")
|
||
|
||
print()
|
||
print("一、关键路径必须被调用(漏了就是白屏)")
|
||
# initTabs 专项:白屏的根因就是它
|
||
init_def = len(re.findall(r"private void initTabs\s*\(", text))
|
||
init_use = len(re.findall(r"\binitTabs\s*\(\s*\)", text))
|
||
check("initTabs() 有定义", init_def >= 1, f"定义 {init_def} 处")
|
||
check("initTabs() 被调用(否则连上后一片白屏)",
|
||
init_use >= 2, f"出现 {init_use} 次(1 次是定义,>1 才算被调用)")
|
||
check("initTabs() 紧跟 buildControlPanel()",
|
||
re.search(r"buildControlPanel\(\);\s*(?://[^\n]*\n\s*)*initTabs\(\);",
|
||
text) is not None,
|
||
"必须在 buildControlPanel() 之后立刻调用")
|
||
|
||
for method in CRITICAL:
|
||
n = len(re.findall(r"\b" + method + r"\s*\(", text))
|
||
check(f"{method}() 被调用", n > 1, f"出现 {n} 次")
|
||
|
||
print()
|
||
print("二、分页定义完整性")
|
||
tab_names = re.findall(r'new TabDef\("([^"]+)"', text)
|
||
check("定义了 10 个分页", len(tab_names) == 10, f"实际 {len(tab_names)} 个")
|
||
print(f" 分页: {' '.join(tab_names)}")
|
||
check("selectTab 有定义", "private void selectTab(" in text)
|
||
check("selectTab 被调用", len(re.findall(r"\bselectTab\s*\(", text)) > 1)
|
||
|
||
print()
|
||
print("三、未调用方法扫描")
|
||
names = defined_methods(text)
|
||
orphans = []
|
||
for name in sorted(set(names)):
|
||
if name in WHITELIST or name in KNOWN_DEAD:
|
||
continue
|
||
n = len(re.findall(r"\b" + re.escape(name) + r"\s*\(", text))
|
||
if n <= 1:
|
||
orphans.append((name, n))
|
||
|
||
check("没有**未知**的未调用方法", not orphans,
|
||
"\n ".join(f"{n}({c} 次)" for n, c in orphans)
|
||
if orphans else "")
|
||
if orphans:
|
||
print()
|
||
print(" 未知的未调用方法(可能是漏接的事件处理,也可能是新的死代码):")
|
||
for name, cnt in orphans:
|
||
print(f" {name} (出现 {cnt} 次)")
|
||
|
||
if KNOWN_DEAD:
|
||
print()
|
||
print(f" 已知死代码 {len(KNOWN_DEAD)} 个(不影响功能,待清理):")
|
||
for name, why in sorted(KNOWN_DEAD.items()):
|
||
still = len(re.findall(r"\b" + re.escape(name) + r"\s*\(", text))
|
||
mark = "" if still else " [已删除]"
|
||
print(f" {name}: {why}{mark}")
|
||
|
||
print()
|
||
print("=" * 58)
|
||
print(f"通过 {passed} 项,失败 {failed} 项")
|
||
return 0 if failed == 0 else 1
|
||
|
||
|
||
if __name__ == "__main__":
|
||
sys.exit(main())
|