DiPECS v0.2 — 端到端处理管道打通¶
日期: 2026-05-05 基线: v0.1 (aios-spec 宪法层 + aios-core 核心逻辑 + collector 采集骨架) 主题: 从单纯采集升级为完整的「采集 → 脱敏 → 聚合 → 模拟推理 → 校验 → 执行」管道
一、架构变更总览¶
v0.1 的 daemon 只有一条采集循环,sanitizer / policy / executor 存在但未被调用。v0.2 将它们全部串入管道。
v0.1: [采集线程] → bus.push() → (丢进虚空)
v0.2: ┌─ Task 1 (采集) ────────────────────────┐
│ ProcReader / BinderProbe / SysCollector│
│ │ raw_events_tx (mpsc) │
└─────────┼───────────────────────────────┘
│
┌─────────▼───────────────────────────────┐
│ Task 2 (处理管道) │
│ │
│ raw_events_rx → PrivacyAirGap.sanitize │
│ → WindowAggregator (10s) │
│ → MockCloudProxy │
│ → PolicyEngine.evaluate │
│ → ActionExecutor.execute │
└─────────────────────────────────────────┘
二、新增模块¶
2.1 aios-agent — Mock CloudProxy (crates/aios-agent/)¶
新增文件: src/lib.rs (207 行)
首次实现 agent 层。当前阶段为 Mock,后续替换为真实 HTTPS 通信 (reqwest + rustls)。
API¶
pub struct MockCloudProxy;
impl MockCloudProxy {
pub fn evaluate(context: &StructuredContext) -> IntentBatch;
}
模拟决策规则¶
| 检测信号 | 生成意图 | 推荐动作 | 置信度 |
|---|---|---|---|
| 通知含 FileMention | OpenApp(source_app) | PreWarmProcess | 0.70 |
| ActivityLaunch 检测 | SwitchToApp(target) | PreWarmProcess + KeepAlive | 0.85 |
| 文件活动 (任意) | HandleFile(ext_category) | PrefetchFile | 0.75 |
| 屏幕亮起 | Idle | KeepAlive(foreground) | 0.60 |
| 电量 < 20% | Idle | ReleaseMemory | 0.80 |
| 空窗口 | Idle | NoOp | 0.50 |
方法细节¶
evaluate(context: &StructuredContext) -> IntentBatch (crates/aios-agent/src/lib.rs:35)
接收一个 10s 时间窗口的结构化上下文,返回模拟的 IntentBatch。内部调用 generate_intents() 进行信号匹配和意图生成。所有意图的风险等级与模型标识 (mock-cloud-proxy-v0.1) 为固定值,方便在日志中区分 mock 与真实云端返回。
generate_intents(context: &StructuredContext) -> Vec<Intent> (crates/aios-agent/src/lib.rs:43)
遍历窗口内的 SanitizedEvent 序列,累计六大信号位 (has_file_mention, has_activity_launch, launched_apps, has_screen_on, is_low_battery, notified_apps)。文件活动事件(FileActivity)直接为每个扩展名类别生成独立的 HandleFile 意图。事件遍历完成后,按信号位优先级依次生成意图,始终兜底一条 Idle + NoOp 用于证明链路通畅。
2.2 aios-action — ActionExecutor 骨架 (crates/aios-action/)¶
新增文件: src/lib.rs (85 行)
实现 aios_spec::traits::ActionExecutor trait。当前为骨架,所有操作通过 tracing 记录,后续对接真实 syscall。
实现细节¶
pub struct DefaultActionExecutor;
impl ActionExecutor for DefaultActionExecutor {
fn execute(&self, action: &SuggestedAction) -> ActionResult;
}
execute(&self, action: &SuggestedAction) -> ActionResult (crates/aios-action/src/lib.rs:22)
以 Instant::now() 标记开始时间,按 action.action_type 分发到五个分支:
PreWarmProcess— 要求target非空,缺失时返回success: false。占位日志记录目标 app 和紧迫度。PrefetchFile— 占位日志,不要求 target 必填。KeepAlive— 不强制 target,无目标时静默跳过(仍返回 success)。ReleaseMemory— 占位日志。NoOp— 直接返回成功,日志级别为debug。
每条结果包含 latency_us(微秒级计时),确保即使骨架阶段也有可度量的耗时统计。
2.3 aios-core — WindowAggregator (crates/aios-core/src/context_builder.rs)¶
新增文件: src/context_builder.rs (171 行)
将 SanitizedEvent 按固定时间窗口 (默认 10s) 聚合为 StructuredContext,这是发送给 LLM 前的最后一步。
API¶
pub struct WindowAggregator {
buffer: Vec<SanitizedEvent>,
window_secs: u64,
window_start_ms: i64,
}
impl WindowAggregator {
pub fn new(window_secs: u64, now_ms: i64) -> Self;
pub fn push(&mut self, event: SanitizedEvent);
pub fn len(&self) -> usize;
pub fn is_empty(&self) -> bool;
pub fn is_expired(&self, now_ms: i64) -> bool;
pub fn close(&mut self, now_ms: i64) -> Option<StructuredContext>;
}
方法细节¶
new(window_secs: u64, now_ms: i64) -> Self (crates/aios-core/src/context_builder.rs:25)
以当前时间作为窗口起点,初始化空缓冲区。
push(&mut self, event: SanitizedEvent) (crates/aios-core/src/context_builder.rs:35)
追加单个脱敏事件到当前窗口。不做任何过滤——所有事件均被保留,由 LLM 端按上下文窗口做统计推断。
close(&mut self, now_ms: i64) -> Option<StructuredContext> (crates/aios-core/src/context_builder.rs:52)
关闭当前窗口:取走全部事件(std::mem::take),调用 build_summary() 生成摘要,构建 StructuredContext 并重置窗口起点。空窗口返回 None。
build_summary(events: &[SanitizedEvent]) -> ContextSummary (crates/aios-core/src/context_builder.rs:91)
从事件序列构建聚合摘要: - foreground_apps — 从 ProcessResource 和 InterAppInteraction 事件的 package_name / source_package 提取,去重 - notified_apps — 从 Notification 事件的 source_package 提取,去重 - all_semantic_hints — 从 Notification 事件的 semantic_hints 汇总,去重 - file_activity — 从 FileActivity 的 extension_category 计数 (HashMap<ExtensionCategory, u32>) - latest_system_status — 取窗口内最后一条 SystemStatus 事件的快照 - source_tier — 若窗口内存在任一条 Daemon 级事件则升为 Daemon,否则 PublicApi
三、重构的模块¶
3.1 daemon 主循环 (crates/aios-daemon/src/main.rs)¶
变更: 165 行 → 264 行 (重构, 后从 aios-collector 迁移至 aios-daemon — 见 3.3)
从单一采集循环重构为 2-task tokio 管道:
采集任务 (task 1)¶
原主循环的采集逻辑完整迁移至独立的 async block (crates/aios-daemon/src/main.rs)。行为不变:每 100ms 扫描 /proc 差分 + Binder eBPF 轮询,每 30s 采集系统状态。事件通过 raw_events_tx.send() 推送到处理管道。退出信号通过 broadcast::Receiver::try_recv() 非阻塞轮询。
处理管道 (task 2)¶
运行在主 task 上 (crates/aios-daemon/src/main.rs)。核心循环使用 tokio::select! 等待三路事件:
- shutdown_rx.recv() — 优雅退出
- bus.raw_events_rx.recv() — 接收原始事件 →
sanitizer.sanitize()→window.push() - tokio::time::sleep — 窗口到期的 deadline 定时器触发窗口关闭
窗口关闭后调用 process_window() (crates/aios-daemon/src/main.rs),执行 DecisionRouter::evaluate() → PolicyEngine::evaluate_batch() → executor.execute_batch() 完整链路。所有步骤均通过 tracing::info!/tracing::warn!/tracing::debug! 打点。
3.2 aios-spec 微调¶
| 文件 | 变更 | 原因 |
|---|---|---|
src/lib.rs | traits 模块新增 pub use executor::ActionResult | aios-action 实现 ActionExecutor 需要 ActionResult 类型 |
src/event.rs | ExtensionCategory derive 增加 Hash | context_builder 需要 HashMap<ExtensionCategory, u32> 做文件活动计数 |
3.3 依赖层级重排 — 恢复计划架构¶
问题: v0.2 初始合并时,aios-collector 直接依赖 aios-agent 以使用 MockCloudProxy,违反了 CLAUDE.md 规定的「上层依赖下层」单向层级:
aios-cli / aios-agent (业务逻辑 / LLM 代理)
↓
aios-collector (平台适配)
↓
aios-action (资源生命周期)
↓
aios-core (动作总线、隐私、策略)
↓
aios-spec (数据类型 & traits)
修正 (5 处变更):
| 文件 | 变更 | 说明 |
|---|---|---|
crates/aios-collector/Cargo.toml | 移除 aios-agent 依赖 + [[bin]] 节 | collector 回归纯库角色 |
crates/aios-daemon/Cargo.toml | 新增 aios-collector, aios-core, aios-action, aios-agent, tokio, tracing-subscriber, anyhow, libc 依赖 + [[bin]] 节 | daemon 独立为运行时宿主 |
crates/aios-daemon/src/main.rs | 新建 (从旧 dipecsd 入口迁移, 264 行) | daemon 二进制归属 aios-daemon |
crates/aios-collector/src/main.rs | 删除 | — |
docs/src/design/crates-map.md | 更新 daemon 二进制路径 → crates/aios-daemon/src/main.rs | 文档与代码一致 |
修正后依赖方向正确: aios-spec → collector/core/action/agent → aios-daemon。
验证: cargo tree -p aios-collector | grep -E "aios-agent|aios-cli" 无输出。
四、测试覆盖¶
v0.1 遗留测试 (5 个)¶
文件: crates/aios-core/tests/privacy_airgap_test.rs (141 行)
| 测试 | 描述 | 验证点 |
|---|---|---|
test_notification_file_detection | 飞书收到 PDF 文件通知 | 脱敏后正确检出 SemanticHint::FileMention,原文不可访问 |
test_notification_image_detection | 微信收到照片 | 脱敏后正确检出 SemanticHint::ImageMention |
test_fs_classification | 下载 report.pdf | /Download/report.pdf → ExtensionCategory::Document |
test_binder_notification_detection | Binder 通知事务 | enqueueNotificationWithTag → InteractionType::NotifyPost |
test_prefixed_variable_warning_suppression | 编译期验证 | 确保 _ 前缀变量不触发 clippy 警告 |
v0.2 新增测试 (58 个)¶
MockCloudProxy (crates/aios-agent/tests/mock_cloud_proxy_test.rs, 9 个)¶
| 测试 | 验证点 |
|---|---|
test_empty_window_returns_idle | 空窗口 → Idle + NoOp 兜底 |
test_file_mention_triggers_open_app | 通知含 FileMention → OpenApp + PreWarmProcess |
test_activity_launch_triggers_switch_to_app | ActivityLaunch → SwitchToApp + 双动作 |
test_file_activity_generates_handle_file | FileActivity(Document) → HandleFile + PrefetchFile |
test_multiple_file_activities_generate_multiple_intents | 3 类文件活动 → 3 条独立 HandleFile 意图 |
test_screen_on_triggers_keepalive | 屏幕 Interactive → Idle + KeepAlive |
test_low_battery_triggers_release_memory | 电量 < 20% → Idle + ReleaseMemory |
test_normal_battery_no_release | 电量 85% → 不触发 ReleaseMemory |
test_combined_signals_all_detected | 5 种信号同时存在 → 全部检出 |
DefaultActionExecutor (crates/aios-action/tests/action_executor_test.rs, 14 个)¶
| 测试 | 验证点 |
|---|---|
test_prewarm_with_target_succeeds | PreWarmProcess + target → success=true |
test_prewarm_without_target_fails | PreWarmProcess 缺 target → success=false |
test_prefetch_file_succeeds / test_prefetch_file_no_target_succeeds | PrefetchFile 有无 target 均成功 |
test_keep_alive_*_succeeds (2 个) | KeepAlive 有无 target 均成功 (静默跳过) |
test_release_memory_*_succeeds (2 个) | ReleaseMemory 始终成功 |
test_noop_succeeds | NoOp → success=true |
test_execute_batch_* (2 个) | 批量执行返回正确数量和顺序 |
test_result_contains_action_name | ActionResult.action_type 字段正确 |
test_result_preserves_target | ActionResult.target 字段保留 |
test_latency_is_microseconds | 骨架执行耗时 < 1ms |
WindowAggregator (crates/aios-core/tests/context_builder_test.rs, 17 个)¶
| 测试 | 验证点 |
|---|---|
test_new_window_is_empty | 新窗口 is_empty=true, len=0 |
test_push_increases_length | push → len 递增 |
test_window_not_expired_before_deadline | 窗口到期前 is_expired=false |
test_window_expired_after_deadline / at_exact | 窗口到期后 / 精确边界 is_expired=true |
test_close_empty_window_returns_none | 空窗口 close → None |
test_close_non_empty_returns_context | 非空窗口 close → StructuredContext (含正确时间戳) |
test_close_resets_buffer | close 后窗口变空, len=0 |
test_close_updates_window_start | close 后新窗口起点刷新 |
test_summary_foreground_apps | Process + InterApp → foreground_apps 聚合去重 |
test_summary_notified_apps | Notification → notified_apps 聚合去重 |
test_summary_semantic_hints | 多通知 → all_semantic_hints 聚合去重 |
test_summary_file_activity_counts | 文件活动 → file_activity 计数 (HashMap) |
test_summary_latest_system_status | 多条 SystemStatus → 取最新值 |
test_summary_source_tier_daemon_wins | PublicApi + Daemon 共存 → Daemon |
test_summary_source_tier_public_api_only | 仅 PublicApi → PublicApi |
test_multiple_windows_cycle | 两个连续窗口正确隔离 |
PolicyEngine (crates/aios-core/tests/policy_engine_test.rs, 11 个)¶
| 测试 | 验证点 |
|---|---|
test_low_risk_approved_by_default | Low Risk → approved=true |
test_medium_risk_rejected_by_default | Medium Risk > max(Low) → rejected |
test_high_risk_rejected_by_default | High Risk → rejected |
test_medium_risk_approved_with_relaxed_config | 配置放宽到 Medium → approved |
test_low_confidence_rejected | confidence < 0.3 → rejected |
test_confidence_at_boundary_approved | confidence = 0.3 → approved (精确边界) |
test_deferred_urgency_filtered | Deferred 紧迫度 → 动作被过滤 |
test_blocked_action_filtered | 黑名单 ReleaseMemory → 动作被过滤 |
test_max_actions_per_batch_enforced | 3 动作 + max=2 → 截断为 2 |
test_evaluate_batch_mixed_results | 3 意图 (ok/high-risk/low-conf) → 混合决策正确 |
test_approved_intent_preserves_actions | 通过的意图保留全部动作 |
ActionBus (crates/aios-core/tests/action_bus_test.rs, 7 个)¶
| 测试 | 验证点 |
|---|---|
test_push_raw_event_succeeds / _received | 原始事件发送和接收 |
test_push_intent_succeeds / _received | 意图批次发送和接收 |
test_channel_closed_after_rx_dropped | rx drop 后 send 返回 Err |
test_intent_channel_closed_after_rx_dropped | intent_rx drop 后 intent_tx.send 失败 |
test_action_bus_default_creates | ActionBus::default() 通道可用 |
五、编译与测试验证¶
全量检查 (一键命令)¶
# 格式检查
cargo fmt --all -- --check
# Clippy 严格模式 (warnings as errors)
cargo clippy --workspace --all-targets -- -D warnings
# 全量测试 (当前: 63 passed; 0 failed)
cargo test --workspace
# 类型检查
cargo check --workspace --all-targets
CI 等效命令 (推荐在提交前执行)¶
测试分布总览¶
crates/aios-agent/tests/mock_cloud_proxy_test.rs | 9 tests (意图生成 6 种信号 + 组合)
crates/aios-action/tests/action_executor_test.rs | 14 tests (5 种动作 + batch + 字段)
crates/aios-core/tests/privacy_airgap_test.rs | 5 tests (脱敏 v0.1 遗留)
crates/aios-core/tests/context_builder_test.rs | 17 tests (窗口生命周期 + 聚合)
crates/aios-core/tests/policy_engine_test.rs | 11 tests (风险/置信度/动作过滤)
crates/aios-core/tests/action_bus_test.rs | 7 tests (事件/意图通道)
────────────────────────────────────────────────────────────────
Total | 63 tests; 0 failed
快速确认一切正常的步骤¶
- 编译:
cargo check --workspace→ 无 error - 格式:
cargo fmt --all -- --check→ 无输出 (表示格式正确) - Lint:
cargo clippy --workspace --all-targets -- -D warnings→ 无 warning - 测试:
cargo test --workspace→63 passed; 0 failed - 交叉编译 (可选):
source scripts/setup-env.sh && cargo android-release→ 编译成功 - 依赖审计 (可选):
cargo deny check→ 0 个许可/安全违规
预期输出: 以上 6 步全部零错误 / 零警告 / 测试全绿。
六、依赖变更¶
| 变更 | 位置 | 说明 |
|---|---|---|
aios-agent workspace dep (新增) | Cargo.toml | agent crate 进入 workspace |
aios-action workspace dep (新增) | Cargo.toml | action crate 进入 workspace |
aios-collector, aios-core, aios-action (新增) | crates/aios-agent/Cargo.toml | agent 依赖下层所有 crate (符合层级) |
tokio, tracing-subscriber, anyhow, libc (新增) | crates/aios-daemon/Cargo.toml | daemon 二进制需要 |
aios-agent | crates/aios-collector/Cargo.toml | 修正反向依赖 (见 3.3 节) |
aios-spec + tracing + uuid (保留) | crates/aios-agent/Cargo.toml | MockCloudProxy 实现 |
aios-spec + tracing + libc | crates/aios-action/Cargo.toml | ActionExecutor 骨架 (libc 预留给后续 syscall) |
所有依赖均来自 workspace,无新增外部 crate。
七、已知缺口 (后续版本)¶
v0.2 测试状态: 6 个测试文件, 63 个测试, 全部通过。覆盖 MockCloudProxy / ActionExecutor / WindowAggregator / PolicyEngine / ActionBus / PrivacyAirGap。
| 模块 | 状态 | 计划 |
|---|---|---|
aios-agent CloudProxy (HTTPS) | Mock 已就绪 | 替换为 reqwest + rustls 真实 LLM 通信 |
aios-action ActionExecutor (syscall) | 骨架已就绪 | 对接 /proc/pid/oom_score_adj, posix_fadvise, process_madvise |
FanotifyMonitor | 未实现 | FsAccessEvent 类型已有,采集器待写 |
NotificationBridge (Kotlin → Rust) | 未实现 | 需要 JNI bridge + NotificationListenerService |
| GoldenTrace 录制与回放 | TraceEngine 已有,未接入主循环 | 需在 process_window 中集成录制 |
| Android 交叉编译 | 配置就绪 (.cargo/config.toml) | 真机/模拟器上跑 dipecsd --no-daemon --verbose |
八、文件变更清单¶
Cargo.lock (同步)
Cargo.toml | 2 + (aios-agent, aios-action workspace dep)
crates/aios-daemon/Cargo.toml | 8 + (依赖 + [[bin]])
crates/aios-agent/src/lib.rs | 212 +++ (MockCloudProxy 重写)
crates/aios-daemon/src/main.rs | 264 +++ (daemon 二进制, 从 collector 迁移)
crates/aios-agent/tests/mock_cloud_proxy_test.rs | 300 +++ (新增: 9 个测试)
crates/aios-core/src/context_builder.rs | 171 +++ (WindowAggregator 新增)
crates/aios-core/src/lib.rs | 1 + (pub mod context_builder)
crates/aios-core/tests/context_builder_test.rs | 271 +++ (新增: 17 个测试)
crates/aios-core/tests/policy_engine_test.rs | 228 +++ (新增: 11 个测试)
crates/aios-core/tests/action_bus_test.rs | 112 +++ (新增: 7 个测试)
crates/aios-action/Cargo.toml | 3 + (依赖)
crates/aios-action/src/lib.rs | 92 +++ (DefaultActionExecutor 重写)
crates/aios-action/tests/action_executor_test.rs | 155 +++ (新增: 14 个测试)
crates/aios-collector/Cargo.toml | 1 - (移除 aios-agent 依赖 / [[bin]])
crates/aios-collector/src/main.rs | 0 - (删除, 迁移至 aios-agent)
crates/aios-spec/src/event.rs | 2 +- (ExtensionCategory +Hash)
crates/aios-spec/src/lib.rs | 2 +- (导出 ActionResult)
CLAUDE.md | 2 +- (daemon 二进制路径更新)
─────────────────────────────────────────────────────────────────
19 files, 63 tests, all passing