Air 系列应用交流/AirShark(from WireShark)|AirShark · 鸿蒙 PC 适配全记录

AirShark(from WireShark)|AirShark · 鸿蒙 PC 适配全记录

【Air 系列 · 鸿蒙 PC 适配全记录】43 / 56

■ 应用:AirShark(from WireShark)(AirShark)
■ 定位:Wireshark 移植,网络抓包与协议分析
■ 上游:Wireshark 4.7.3-dev | 路线:Qt6 6.11.1+QPA | 版本:1.5.0
■ 开源: https://gitcode.com/Andy88/Harmony-Wireshark
■ 市场状态:已上架 AGC 应用页: https://appgallery.huawei.com/app/6917613942089866532
■ 官网(免费下载): https://www.shunidc.cn/

————————————————————
开源鸿蒙 PC 社区: https://harmonypc.csdn.net/

PC 社区项目申请: https://atomgit.com/OpenHarmonyPCDeveloper

适配开源地址:https://gitcode.com/Andy88/Harmony-Wireshark

环境搭建文章:https://blog.csdn.net/weixin_52908342/article/details/161343743

▍一、为什么要适配 AirShark

Wireshark 是网络抓包与协议分析领域的事实标准:从链路层到应用层的数千个协议解析器(dissector)、十六进制字节窗、过滤器语法与专业的检查工作流,使它成为排查网络问题的最后手段。这类深度工具一旦缺席,一个平台在开发者眼里的完成度就要打折扣。鸿蒙工程 AirShark 承接的就是 Wireshark 4.7.3-dev(master 快照)到 HarmonyOS 的全栈原生移植,遵循上游 GPL-3.0-or-later 授权。

这个工程有几个先决的硬事实。其一,Wireshark master 分支只剩 Qt 一种 GUI,find_package(Qt6 6.2 REQUIRED) 没有 Qt5 路径,而它的 Qt 界面约 15 万行,重写不现实——PORTING.md 选型三问把这步锁死在 Qt 交叉编译上。其二,鸿蒙应用没有 root,也没有 AF_PACKET,上游依赖独立进程 dumpcap 的抓包模型整体失效。其三,工程包名 com.airshark.app,版本 1.4.0,deviceTypes 覆盖 tablet、2in1 与 phone,SDK 6.1.0(23),module.json5 注册了 type 为 vpn 的 AirVpnAbility 扩展能力,并声明 ohos.permission.INTERNET 与 ohos.permission.KEEP_BACKGROUND_RUNNING 两项权限——权限挂给 VPN 扩展而非主 Ability,本身就说明了抓包架构的形态。

最终工程给出的答案是一套双层组合:GUI 侧把 Wireshark 的 ui/qt 整体改造成 libwireshark_gui.so,经自建 Qt 6.2.4 交叉栈上屏;抓包侧用 VpnExtensionAbility 建 TUN 隧道截获全设备 IP 包,在扩展进程内写成 pcap 交给 GUI 解析。文件分析与实时抓包两条主线,对应了 Wireshark 最常用的两种工作方式。

▍二、先划清边界:不把编译通过当成适配完成

把 Wireshark 装进鸿蒙,最省事的说法是"核心库编译通过"。但 PORTING.md 第 3 节"系统能力鸿沟与对策"一开始就承认了差距:无 fork/exec、无 root、沙箱禁插件目录扫描、应用 fopen 不识 content URI——每一条都打在上游的关键路径上。工程的做法是为每一层指定明确的替代物,并区分"已实证"与"编译面"两种状态:

层次 原项目实现 鸿蒙侧当前方案
抓包通道 dumpcap 独立进程 + AF_PACKET(root) VpnExtensionAbility 建 TUN + 扩展进程内用户态转发中继
GUI 主窗 Qt Widgets 桌面主窗口 XComponent TEXTURE + 自建 libqohos6 QPA
菜单栏 QMenuBar 原生渲染 ArkTS 顶栏:getMenubarJson 导出 + activateMenuAction 回注
协议解析 epan/wiretap/wsutil + 运行时插件目录 同源交叉编译,ENABLE_PLUGINS=OFF 内置 dissectors
文件打开 本地路径 fopen 系统 Picker → 拷入沙箱 → POSIX 路径进 core
实时刷新 dumpcap 管道推送新包 live_capture.pcap 轮询打开 + 1.2s cf_reload 增量
品牌资源 鲨鱼鳍图标、About 致谢、启动轮播 P12/P13 去上游化:播放/循环图标、qrc 置空、轮播数据剔除

边界还包括被明确关闭的能力:libpcap(无 root 抓包不可行)、libgcrypt(部分解密 dissector 暂缺)、Lua 与全部可选外部库按 M1 最小集 ENABLE_*=OFF。这些不是遗漏,而是依赖矩阵里逐项登记过的取舍。

▍三、鸿蒙版的整体架构

README.md 给出的架构总图是 Air 双层架构的 Qt 变体:ArkTS 壳负责 splash、XComponent、系统 Picker、rawfile 数据部署与 VPN 扩展拉起;libsharkbridge.so 是只链 ace_napi/native_window/hilog/dl 的薄 NAPI 桥;重型核心集中在 libshark_core.so——宿主线程、环境变量前置、Qt 事件循环与 VPN pcap 写线程都在这里;最深层是 Qt 6.2.4 OHOS 交叉栈、ohos QPA、Wireshark 本体四个库与复用自 AirGimp 的 glib 2.80.4。

text
ArkTS 壳(XComponent SURFACE + splash + Picker + VPN 抓包扩展)
│ NAPI:libsharkbridge.so(薄壳:拓扑序 dlopen + QPA 预绑定 + 事件注入)
▼
libshark_core.so(Qt 宿主线程 + env 前置 + VPN pcap 写线程)
├── Qt 6.2.4 OHOS 交叉栈(自建)+ ohos QPA(AirKrita 蓝本 Qt6 移植)
├── libwireshark_gui.so(ui/qt 改造为 SHARED 库,入口 airshark_wireshark_main)
└── glib 2.80.4(复用 AirGimp)+ gcrypt/cares/pcre2 + libwireshark/wiretap/wsutil


仓库主要目录如下(真实 ls 结果):

text
AirShark/
├── AppScope/app.json5 # 包名与版本
├── PORTING.md # 选型、依赖矩阵、补丁登记(P/D/Q 三系)、风险册
├── CONTINUE.md # 断点续作指南(脚本幂等)
├── README.md # 架构总图、里程碑状态、构建入口
├── signature/ # 自建 CA 调试签名脚本
├── native/
│ ├── deps/ install/ # 依赖与安装前缀(glib 栈等)
│ ├── qt6/ qt_platform_ohos/ # Qt 6.2.4 源码与 ohos QPA
│ ├── src/ patches/ # wireshark 源码树与权威补丁副本
│ ├── tools/ core/
│ └── scripts/ # build_deps/core/qt6/qpa/gui/deploy 等全链脚本
└── entry/src/main/
├── module.json5 # 权限、vpn 扩展、设备类型
├── ets/
│ ├── pages/Index.ets # ArkTS 顶栏菜单 + XComponent + pcap 入口
│ ├── vpn/AirVpnAbility.ets # VpnExtensionAbility:TUN 建立与转发中继启动
│ ├── managers/ImmersiveManager.ets
│ └── utils/DownloadDirs.ets # 下载目录与 live_capture.pcap 路径
├── resources/rawfile/wireshark-data/ # epan 运行时数据(manuf/services/dtds 等)
└── cpp/
├── napi_init.cpp # NAPI 桥与 TSFN 通道
└── vpn_relay.cpp # 用户态转发中继(读 TUN 写 pcap + 真实转发)


▍四、核心适配过程

### 1. 无 GUI 核心先行,验证通道收敛到 HAP 内

里程碑 M1 先落 headless 路径:wsutil→wiretap→epan→tshark 交叉编译,用源码树自带的 tsni_req.pcapng 验证解析。计划中的验证方式是 hdc shell 直推二进制,实施中确认了鸿蒙对原生二进制强制签名(补丁登记 D6,连显式 loader 调用都拒绝),验证通道因此收敛为"一切经 HAP 内 dlopen"。这个决定后来塑造了整个工程的部署形态:所有库进 entry/libs/arm64-v8a 模块通道,数据文件进 rawfile 经沙箱部署。

### 2. Qt 6.2.4 自建栈与 QPA 的 Qt6 移植

上游强制 Qt6,工程从源码构建了 qtbase/qtsvg/qttools 6.2.4:先编 macOS host 工具(moc/rcc/lrelease,QT_HOST_PATH 同版本组合),再交叉目标栈。补丁登记的 Q 系记录了这类构建的真实门槛:Q1 给 QtBuild.cmake 加 OHOS mkspec 分支映射 linux-clang-libc++,否则 qplatformdefs.h 无处解析;Q2 在 qthread_unix.cpp 扩展 !defined(__MUSL__) 守卫绕开 pthread_cancel 家族;Q5 处理源码构建不安装 *Private cmake 包的问题,消费侧手动补版本化 private/qpa include。ohos QPA 以 AirKrita 的 Qt5 版为蓝本移植到 Qt6,字体走 QFreeTypeFontDatabase,EGL blit 上屏路径同源复用。

### 3. GUI 整体 SHARED 化与捕获动作接管

P4 把 ui/qt/main.cpp 的 main 在 AIRSHARK_AS_LIB 守卫下改名为 airshark_wireshark_main,CMake 侧由 add_executable 改产出 libwireshark_gui.so(命名避让 epan 的 libwireshark.so)。P5 解决的是更根本的问题:没有 dumpcap 时构造函数会禁用全部捕获动作——工程把"开始捕获"的 triggered 信号改接 VPN 流(请求经桥 TSFN 到 ArkTS 拉起/停止 AirVpnAbility),加 1.2s reload_timer 做增量 cf_reload,再加 1.5s 保活断言自愈外部禁用。用户在界面上点鲨鱼鳍(现在是播放三角)走的是这条改接后的链路。

### 4. VPN 抓包链路:TUN、防回环与转发中继

M8 记录了 2026-08-16 的全链路实证:UI 按钮 → core 请求 → 桥 TSFN → ArkTS startVpnExtensionAbility → AirVpnAbility.ets 建 TUN(v4 10.111.111.2/32 加 v6 fd00:abcd:1::2/128,默认路由全接管,MTU 1400)→ 扩展进程内 bridge.vpnStartCapture(tunFd, pcapPath, forward) → vpn_relay.cpp 读 TUN 逐包写 pcap(LINKTYPE_RAW)→ UI 轮询到 live_capture.pcap 后 openCaptureFile 打开,1.2s cf_reload 实时增量显示。链路上的两个关键设计写在 AirVpnAbility.ets 头注释里:其一是 protectProcessNet 防回环——不调用它,转发中继的 socket 会再次进 TUN 形成风暴,失败则降级为仅捕获;其二是 pcap 落共享 el2/base 沙箱,因为 M14 实测扩展进程的 SELinux 域对 Download URI 无写权限(EACCES),UI 进程与扩展进程同包名共享该目录。转发中继对 UDP/TCP 做真实转发使抓包期间网络可用(M15 起),ICMP 无 raw socket 只记录不转发。

### 5. 菜单 ArkTS 化与去上游化

entry/src/main/ets/pages/Index.ets 的头注释写明了菜单方案:native 侧隐藏 QMenuBar,菜单树经 bridge.getMenubarJson() 导出(品牌、版权、广告条目已在 native 过滤,label 剥离助记符),ArkTS 顶栏按 separator 分组渲染,叶子项经 activateMenuAction(objectName) 触发 QAction;XComponent 用 TEXTURE 类型,让 ArkUI 系统弹层可以浮在 native 画面之上。去上游化分两支:P12 运行时摘除"帮助"菜单整树、用应用级事件过滤器隐藏 20 多个 .ui 对话框的 Help 键(hide 而非 removeButton,避免悬空指针)、窗口标题回退改 AirShark;P13 处理资源——鲨鱼鳍图标换成蓝色播放三角与绿色环形箭头(16/24 两套 @2x,qrc 文件名不变零代码改动)、about.qrc 置空保留符号壳、启动轮播与 Donate 数据不编入。二进制审计记载 Gerald Combs、GPL 全文、SharkFest 轮播、created-by Wireshark 均 0 命中。

▍五、适配中遇到的几个难点

### 难点一:NDK sysroot 的 libz.so 是个桩库

现象:wiretap 打开 pcap 报 "out of swap space",file_fdopen 走进 ENOMEM 分支。根因在 D7 的记录里:NDK sysroot 的 libz.so 只有 8 KB,95 个导出符号全是同一条 ret 指令——它只是链接期桩。打进 HAP 后,应用库目录的查找优先级遮蔽了系统真库,inflateInit2 返回 -93M 的乱码值。解法是部署脚本 deploy_shark.sh 绝不拷贝 libz.so 并以 rm -f 兜底,运行时交给系统镜像真库解析。这条坑的隐蔽之处在于静态检查全绿,只有设备上的分层埋点(P6 给 wiretap 加的 fw_probe)才把它暴露出来。

### 难点二:交叉工具链的两个静默欺骗

D1 与 D2 是 autotools 依赖构建的陷阱:DevEco toolchains 的 diff 恒返回 0,PATH 被劫持后 config.status 的 unchanged 判定被骗,config.h 永不生成;lld 自报版本不含 "GNU ld",libtool 交叉探测失败后把 archive_cmds 清空,.so 实体不生成只剩悬空符号链接。前者解法是构建前把 PATH 前置为系统目录,后者做了一个 ohos-ld shim,-v 时回 GNU ld 身份、其余转发 ld.lld。两个问题都不报错,只能靠构建产物缺失反推。

### 难点三:musl 缺 pthread_cancel 家族

同一个缺口打了两处:libgpg-error 的 src/posix-lock.c 直接编译失败(D3,sed 补弱符号声明,走非 pthread 锁路径),Qt 的 qthread_unix.cpp 有三处守卫加一处 setTerminationEnabled 需要 !defined(__MUSL__) 扩展(Q2)。PORTING.md 风险册把这类差异列为 R4 常态——epan 里 strerror_r 的 GNU 语义、backtrace 等 glibc 专用 API 都按"编译期暴露、__OHOS__ 打补丁"处理。

### 难点四:VPN 授权弹窗是隐私安全层

D8 记载:系统 VPN 授权弹窗被标记为隐私/特殊层(RSSurfaceRenderNode "marked as privacy or special layer"),截图呈现纯白或纯黑,视觉自动化完全无法定位按钮,只能靠布局树或用户手点;且每次 startVpnExtensionAbility 都会弹授权,无人操作约 20-25 秒自动取消而 promise 恒 pending 无日志。对依赖真机自动化回归的工程,这等于给 VPN 链路的验证环节加了一个人工必经点,也是把授权时序设计进交互流程(而非后台静默重试)的直接原因。

### 难点五:hvigor 与 entry/libs 的打包陷阱

R5/R6 与 D4/D5 记录了部署面的三件事:hvigor 闭包打包会丢运行时 dlopen 的库,所以 Qt/wireshark/glib 全走 entry/libs/arm64-v8a 模块通道;hvigor 对该目录内容变化不敏感,改库后必须 touch module.json5 强制重打包;NDK llvm-strip --strip-unneeded 会抹掉 glib 栈小库的动态符号名导致设备 reloc 失败,glib 栈只做 elf_edit 原位编辑不做 strip,配置里 strip:false 与 compressNativeLibs:false 双保险。

▍六、编译、安装与启动

README.md 的构建入口把全链路收敛成一个幂等脚本,顺序是依赖 → 无 GUI 核心 → Qt6(先 host 后 OHOS)→ QPA → GUI 库 → 部署 → HAP:

bash
zsh native/scripts/build_all.sh # 全链路(deps 已完成会自动跳过)



源码准备(wireshark-master 快照与 Qt 6.2.4 tarball 落位 native/)见 CONTINUE.md。ArkTS 与 HAP 段:

bash
export JAVA_HOME=/Applications/DevEco-Studio.app/Contents/jbr/Contents/Home
export DEVECO_SDK_HOME=/Applications/DevEco-Studio.app/Contents/sdk

hvigorw --mode module -p module=entry assembleHap --no-daemon


产物位于 entry/build/default/outputs/default/entry-default-signed.hap。安装与启动:

bash
hdc install -r entry/build/default/outputs/default/entry-default-signed.hap
hdc shell aa start -a EntryAbility -b com.airshark.app


签名说明按 README.md 原文:signature/generate_debug_sign.py 自建 CA,仅覆盖模拟器;真机需要华为签发的 profile(AGC/DevEco 自动签名)。触发实时抓包时,系统会弹 VPN 授权(见难点四的交互特性)。

▍七、当前功能边界

按 README.md 状态表(2026-08-15)与 PORTING.md 补丁登记、里程碑记录综合,当前工程已覆盖:

- M0 至 M4 全部完成:ArkTS 壳与 HAP、无 GUI 核心(tshark 链)、Qt 6.2.4 交叉栈、ohos QPA 与 libshark_core 编译面、Wireshark Qt GUI 的 SHARED 库化;
- VPN 实时抓包全链路 M8 实证(2026-08-16):TUN 建立、防回环保护、pcap 写入、UI 轮询增量显示,且抓包期间网络经转发中继可用;
- 文件分析链路:系统 Picker → 沙箱 → openCaptureFile 打开 pcap;
- 去上游化在 MateBook 真机实证(菜单无帮助项、已启用协议对话框无帮助按钮);
- epan 运行时数据经 rawfile 部署、extension 域的写权限与共享沙箱方案。

尚未覆盖或有明确待办:README 状态表中 M5(上屏/交互验证)与 M6(抓包列表/详情/字节窗交互回归)仍标记为进行中——补丁登记虽已出现 MateBook 真机实证条目,完整的交互回归尚未在文档中闭环;ICMP 只记录不转发(无 raw socket 属系统约束);libgcrypt 关闭导致部分解密 dissector 缺失,依赖矩阵标为后补;Lua、SMI、MaxMindDB 等可选库维持最小集关闭。

因此,当前版本更准确的定位是"编译链路与抓包链路已经打通、GUI 交互验证仍在推进中的移植中间态":实时抓包与文件分析两条核心链路有实证记录,而成熟度评级应当留给交互回归完成之后。

▍八、总结

AirShark 移植的难点分布很能说明 Wireshark 这类工程的特征:真正的麻烦不在 15 万行 Qt UI(SHARED 化范式在姊妹工程里已经成熟),而在系统底座——桩库级的 libz、静默失败的工具链、musl 的线程模型、隐私安全层里的授权弹窗。这份 PORTING.md 用 P/D/Q 三系补丁编号把这些坑逐条登记并给出解法,使后来者不必重新踩一遍;VPN 抓包方案则在没有 root 的约束下,用 VpnExtensionAbility 加用户态转发中继给出了 PCAPdroid 式的完整替代。

后续重心按里程碑表推进:M5/M6 的上屏与交互回归收尾,抓包列表、协议详情与字节窗逐项过真机;libgcrypt 与解密类 dissector 按依赖矩阵补齐;中文字体、DPI 与键盘的 M7 打磨随交互验证展开。抓包期间的网络可用性与 ICMP 语义,则受系统 raw socket 约束,边界已在代码注释中写明。
楼主 8 天前
想参与讨论?登录 或 30 秒注册。