AET 是运行在Aether Engine虚拟机(Windows / Linux Guest)里的增强工具(Guest Additions),用于把 Guest 和宿主侧的 HarmonyOS 能力打通,并提供更像“原生系统功能”的集成体验(文件互通、碰一碰/分享联动、分布式相机、诊断与自动修复等)。
- Aether Engine(仅一句话):Aether Engine 是宿主侧的 HarmonyOS 虚拟机 App(负责启动 QEMU、提供共享目录与系统能力)。AET 是它的配套 Guest 工具。
- Guest ↔ Host 能力桥接:Guest 内的 AET 通过统一协议请求 Host(HarmonyOS App)能力,并拿到结果/数据。
- 稳定在线与诊断:AET 常驻(Agent)维持在线心跳,UI 展示状态并引导修复(共享目录未挂载/驱动缺失/权限不足等)。
- 统一交付体验(安装器):一个
AetherEnhancedToolsSetup.exe完成:- VirtIO 必要驱动(共享目录 + vioserial)
- AET(Agent + UI)
- QEMU Guest Agent(QGA,可选但推荐)
- 跨平台与多架构:
- 当前优先:Windows 11 ARM64 / Linux ARM64
- 未来扩展:Windows x64 / Linux x64
-
Guest 侧(你这个 .NET 解决方案要做的)
- AetherEnhancedTools.Agent(常驻服务):负责在线/心跳、桥接调用、后台任务、对 UI 提供本机接口
- AetherEnhancedTools.UI(Avalonia):负责可视化、用户操作入口、诊断与修复向导
- AetherEnhancedTools.Core(共享库):协议、模型、日志、配置、跨平台工具
-
通信通道(关键)
- 共享目录(Linux:virtio-9p;Windows:virtio-fs/viofs;tag=
hostshare):Guest 能看到一个“共享目录挂载点”(具体路径/盘符取决于 Guest 系统与驱动)。只要这个目录里能看到.aether_bridge/req与.aether_bridge/res,就算对接成功。 - Aether Bridge(文件型 RPC):在共享目录里用
.aether_bridge/做“写请求文件→等响应文件”的 RPC
- 共享目录(Linux:virtio-9p;Windows:virtio-fs/viofs;tag=
重要:AET Phase 1 选择“文件型 RPC”,避免长连接/端口/权限策略导致的不稳定;Host 侧可以严格控制权限边界(例如 Host 不把 QMP 暴露给 Guest)。
补充约定(Host↔Guest 对齐):
- 共享根目录包含两个关键入口:
.aether_bridge/:内部协议目录(RPC +host_input状态流),不建议作为用户文件入口nearby-huaweis/:用户可见目录(“附近的华为”入口,适合做快捷方式/盘符映射)
- 详见:
docs/shared-folder-layout.md
你目前负责的 AetherEnhancedTools.sln 当前包含 5 个项目(都是 .NET 8):
-
AetherEnhancedTools.Core(Class Library)- 职责:跨平台“核心逻辑”,被 Agent 与 UI 共用
- 建议内容:
- Aether Bridge 客户端:写
req/*.json、等待res/*.json、timeout/重试、原子写(tmp→rename) - 协议模型:hello/heartbeat/status、统一错误码与日志结构
- 挂载点探测:hostshare 是否可用、
.aether_bridge是否存在 - 配置系统:JSON 配置、版本信息、feature flags
- Aether Bridge 客户端:写
-
AetherEnhancedTools.Agent(Worker Service)- 职责:Guest 内“常驻 Agent”
- 建议内容:
- 启动即
aet.hello,循环aet.heartbeat(保持在线 TTL) - 维护本机状态(驱动/挂载/QGA 服务/网络等),暴露给 UI
- 未来:订阅/消费
evt/(Host→Guest 事件),执行后台任务(文件同步/虚拟相机/剪贴板等)
- 启动即
- 部署形态:
- Windows:最终做 Windows Service(或开机自启)
- Linux:systemd service(或用户态 daemon)
-
AetherEnhancedTools.UI(Avalonia App)- 职责:给用户看的界面(Fluent 风格)
- 建议界面模块:
- Dashboard:在线状态、版本、挂载点、最近一次错误与修复建议
- Files:文件传输/“带来带走”辅助入口
- Devices/Camera:分布式相机、设备列表等能力入口
- Settings:开机自启、日志级别、实验功能开关
当前仓库已包含
AetherEnhancedTools.Setup(安装器/GUI)。另外guest_aet/windows_setup/aether_enhanced_tools_setup.cpp仍保留为 Windows Guest 侧的“引导/驱动安装”逻辑参考。
现在仓库里已新增 AetherEnhancedTools.Setup(Avalonia GUI 安装器),并提供脚本把 UI+Agent 发布产物打包进一个 Setup.exe:
- 说明文档:
docs/windows-installer.md - 生成内置 payload:
tools/installer/build_aet_bundle.ps1
协议版本:aether.bridge.v1
位置:共享目录内:<mount>/.aether_bridge/
目录结构:
req/:Guest → Host 请求(*.json)res/:Host → Guest 响应(<requestId>.json)evt/:预留(Host→Guest 事件)blob/:预留(大数据/文件载荷:相机帧等)host_input/:Host → Guest 高频输入状态流(多指/笔压),不走req/res(详见:docs/host-input-bridge.md)
请求文件规则(必须遵守):
- 写
req/<id>.json.tmp→rename为req/<id>.json(避免 Host 读到半截文件)
最小握手(必须):
aet.hello:启动后先发一次(版本/OS/实例 ID)aet.heartbeat:每 4 秒一次(Host TTL 常见为 ~12 秒)aet.getStatus:调试查询在线状态
目标:在你本机先把 aet.hello + aet.heartbeat 的文件往返跑通,确认 .aether_bridge/req/res 协议无误。
- 准备一个“模拟共享目录”(随便找个空目录):
- 例如:
E:\temp\aet_mount
- 启动 Mock Host(它会轮询
req/并写回res/):
powershell -ExecutionPolicy Bypass -File tools/mock_host_bridge.ps1 -MountPath E:\temp\aet_mount -CreateDirs- 启动 Agent(两种方式任选其一):
- 方式 A:环境变量(推荐):
set AETHER_BRIDGE_MOUNT=E:\temp\aet_mount
dotnet run --project AetherEnhancedTools.Agent- 方式 B:写配置:在
AetherEnhancedTools.Agent/appsettings.json里设置:AetherBridge:MountPath
- 观察结果:
- Mock Host 窗口会打印:
handled aet.hello (...)- 然后每隔 ~4 秒:
handled aet.heartbeat (...)
常见问题:
- 看不到 heartbeat:Agent 默认把 heartbeat 记在 Debug 日志;但 Mock Host 端会持续打印,所以以 Mock Host 为准。
- 想保留响应文件方便看内容:把
AetherEnhancedTools.Agent/appsettings.json里的DeleteResponseAfterRead设为false。
这两类能力都是 Guest(AET) 发起 RPC → Host(App) 执行系统能力 → 文件落到共享目录 的模式:
- 带来(Host → Shared → Guest)
bridge.mediaPickToShared:宿主弹文件选择器,把选中的文件复制到共享目录的.aether_bridge/blob/,并返回relativePathbridge.collabServiceImportToShared:宿主走协同/碰一碰等能力,把收到的文件落到.aether_bridge/blob/,返回files[]
- 带走(Guest → Shared → Host → 外部设备)
files.take:Guest 先把要分享的文件复制到共享目录(比如.aether_bridge/blob/或accepted-files/),再传items[].relativePath给宿主;宿主用 ShareKit “碰一碰分享”把这些文件带走
重要约束(和宿主一致):
- 需要 AET 在线:宿主会用 TTL 判断 AET 是否在线;未在线时会对部分方法返回
PERMISSION_DENIED - 所有路径都是相对共享目录:
relativePath必须在共享目录内,且不能包含..
我们提供了:
tools/mock_host_bridge.ps1:模拟宿主轮询req/并写res/(含 bring/take 方法)AetherEnhancedTools.BridgeCli:用 同款 schema 发起这些方法(方便在 PC 上先跑通)
- 启动 Mock Host:
powershell -ExecutionPolicy Bypass -File tools/mock_host_bridge.ps1 -MountPath E:\temp\aet_mount -CreateDirs- 带来(mediaPickToShared):把一个文件丢进 mock inbox,再调用 bring:
- 把文件放到:
E:\temp\aet_mount\_mock_inbox\
dotnet run --project AetherEnhancedTools.BridgeCli -- --mount E:\temp\aet_mount bring- 带走(files.take):准备一个共享目录内的文件,然后调用 take:
dotnet run --project AetherEnhancedTools.BridgeCli -- --mount E:\temp\aet_mount take --item ".aether_bridge/blob/yourfile.txt|title"Mock Host 会把“带走”的文件复制到:E:\temp\aet_mount\_mock_taken\(用于在 PC 上模拟“分享成功”)。
内容说明:
-
aet_minimal_windows.cpp- Windows Guest 最小 AET 客户端示例:发
aet.hello+aet.heartbeat - 运行示例(Guest 内):
aet_minimal_windows.exe --mount <MOUNT>
- Windows Guest 最小 AET 客户端示例:发
-
aet_minimal_linux.py- Linux Guest 最小 AET 示例 + 相机流 demo(
camera.stream.start) - 可选把帧喂给
v4l2loopback(用 ffmpeg)
- Linux Guest 最小 AET 示例 + 相机流 demo(
-
aet_hdc_connect.py- Guest 内扫描局域网 HDC 端口并执行
hdc tconn,方便调试/部署
- Guest 内扫描局域网 HDC 端口并执行
-
windows_setup/aether_enhanced_tools_setup.cpp- Windows Guest “总安装器/Bootstrapper”骨架:
- 提权 → 解压 payload →
pnputil装vioser.inf+(vio9p.inf或viofs.inf) - 静默装 AET(MSI 优先)
- 静默装 QGA(MSI)
- 提权 → 解压 payload →
- Windows Guest “总安装器/Bootstrapper”骨架:
目标交付:AetherEnhancedToolsSetup.exe
推荐安装顺序:
- VirtIO(先装):共享目录驱动(Windows 推荐
viofs+ WinFsp;Linux 用 9p)+ vioserial(QGA 需要) - AET(再装):Agent + UI
- QGA(最后装):qemu-guest-agent(可选,但建议默认装)
Payload 组织建议:
payload/virtio/:virtio-win 解压后的驱动树(不要改动签名文件)payload/winfsp/:WinFsp 安装包(winfsp-*.msi,Windows 使用 virtio-fs/viofs 共享目录时必须)payload/aet/:你的 AET MSI/EXEpayload/qga/:QGA MSI
注意:
- 驱动/服务安装需要管理员权限(安装器必须提权)
- AET 是“产品集成层工具”:更关心用户体验与能力整合(文件/设备/相机/提示/修复)
- QGA 是“标准 Guest Agent”:更适合做 VM 管理类能力(执行命令、查询 Guest 状态、关机/重启等)
当前已知状态(对接提醒):
- Host 侧已有 QMP(
qmp.sock)用于控制/查询 QEMU - 但还需要在 QEMU 启动参数中补齐 guest-agent virtio-serial 通道,Host 才能通过 QMP 的
guest-*系列命令与 QGA 协作