乐于分享
好东西不私藏

AOSP 整机源码 Harness 工程探索

AOSP 整机源码 Harness 工程探索

我们在一棵纯 AOSP 17(android-17.0.0_r1,SDK 37)整机源码树上,围绕 Claude Code 搭建了一套四层 harness 工程,让 coding agent 能够在上千个 git project、千万行量级的 repo 工程里稳定地导航、编译、部署、验证,目标设备是 Cuttlefish 虚拟机(aosp_cf_x86_64_phone)。本文先分析 coding agent 在整机源码树上应用的困难,再梳理 Anthropic 官方博客给出的大库通用要点,接着盘点网络上已有的同类方案,最后介绍我们的四层解决方案——每层解决什么问题、如何协同运转,以及一路探索踩过的坑。


一、问题:为什么 coding agent 在整机源码树上"开箱不可用"

Claude Code 这类 agent 不给代码库建索引(不做 RAG),而是用 agentic search 现场导航——grep、读文件、跟引用,像一个新来的工程师翻代码。这个设计有一个巨大的好处和一个巨大的代价:

  • 好处:永不过期。 它永远读的是 live 代码,不会像向量索引那样"返回两周前已改名的函数、或引用一个已删除的模块,却不告诉你它过期了"。
  • 代价:上下文窗口是唯一稀缺资源。 导航的每一步(grep 结果、读过的文件)都在消耗上下文;导航质量完全取决于你把代码库"布置"得多好。

AOSP 整机源码树把这个矛盾推到极端,有三个放大器:

不搭 harness,直接在整机树上用 coding agent 会反复撞上这些墙(均为实际遇到或验证过的):

痛点
现象
导航失效
全树 grep 一次就吞光上下文;文本匹配跳到错误的同名符号
上下文盲区
每个新会话都不知道"当前在做哪个 feature、哪些仓能动、有哪些硬约束"
流程知识丢失
每次都要重新教它怎么编译、产物在哪、push 哪些文件
"编过 = 改对"幻觉
编译成功就认为功能正确,会话心满意足地结束,设备一跑就崩
危险操作无门禁
adb push/reboot、repo sync 这类动设备/动树的操作只靠模型自觉
知识污染
上下文文档混进 gerrit project 的提交
隐性经验反复付学费
"改了这个类布局必须连某个 so 一起重编"这类血泪知识,不固化下来每次重新踩

核心论断:模型不是瓶颈,环境才是。 社区先行者 utzcoz 用 Claude Code 做成 4 个 AOSP 级项目后的结论也是如此:这类工作 coding agent 开箱做不好,能做成靠的是围绕 agent 搭的 harness engineering——"harness 诚实,产出就诚实"。


二、官方参照:Anthropic《How Claude Code works in large codebases》的要点

上一节的困境不是 AOSP 独有的。Anthropic 官方博客《How Claude Code works in large codebases》归纳了 Claude Code 在大型代码库(百万行 monorepo、几十年遗留系统、几十个仓的分布式架构)落地成功的共性模式——它不是为 AOSP 写的,但几乎每一条都能对上整机树的处境,是我们方案的通用理论底座。这里先把它的要点提炼出来;后文第四节起的四层,本质就是把这些通用原则一条条落到整机树上的具体形态。

2.1 Claude Code 怎么在大库里导航:agentic search,而非 RAG

博客把第一节我们已经点到的机制说得更透:

  • agentic search:像工程师一样遍历文件系统、读文件、用 grep 精确定位、跟着引用跨库跳转;本地运行、不需要建立/维护/上传任何索引
  • RAG 在大规模下会失效:embedding 管线追不上活跃的工程团队——开发者查询时,索引反映的是几周/几天/几小时前的代码,于是返回一个两周前已改名的函数、或引用一个上个 sprint 已删除的模块,却完全不提示它已过期
  • 代价与甜区:agentic search 反过来要求足够的起始上下文才知道去哪找;导航质量取决于代码库被"布置"得多好(用 CLAUDE.md + skills 分层)。若向一个十亿行的库问一个模糊 pattern,会在开工前就撞上上下文窗口墙。在代码库布置上投入的团队,效果明显更好。

2.2 harness 与模型同等重要:五个扩展点 + 两项能力

博客点名一个最常见的误解——以为 Claude Code 的能力只由所用模型决定。实际上围绕模型的生态(harness)比模型本身更决定表现。harness 由五个扩展点构成,外加两项能力,且叠加有顺序——每一层都建立在前一层之上

组件
是什么
何时加载
最适合
常见误用
CLAUDE.md
自动读取的上下文文件
每个会话
项目约定、代码库知识(根=全局、子目录=局部)
把该进 skill 的可复用经验塞进来
hooks
关键时刻运行的脚本
事件触发
自动化一致行为、捕获会话经验(自我改进)
用 prompt 去做本应自动跑的事
skills
针对特定任务打包的指令
按需、相关时
跨会话/项目的可复用专长(渐进式披露、可按 path scope)
全塞进 CLAUDE.md
plugins
打包 skills/hooks/MCP
配好后常驻可用
把一套可用配置分发到全组织
让好做法停留在部落知识
LSP
语言服务器的实时代码智能
配好后常驻可用
符号级导航、类型语言里自动查错
以为它自动就有
MCP servers
连接外部工具与数据
配好后常驻可用
让 Claude 够到本来够不到的内部工具
基础没跑通就先建 MCP
subagents
独立上下文的隔离实例
被调用时
把探索与编辑分离
、并行
在同一会话里既探索又编辑

其中几条博客特别强调的:hooks 最有价值的用法不是防错,而是让配置自我改进(stop hook 会话末反思→提议改 CLAUDE.md);skills 可 path-scoped,只在相关目录激活;LSP 是多语言大库里最高杠杆的投资之一(没有它,Claude 对文本 pattern-match,会落到错误的同名符号);subagents 的典型用法是只读子代理测绘子系统、写进文件,主代理再带全貌编辑

2.3 三个配置模式

博客从成功部署里提炼出三个反复出现的模式:

  1. 让大库对 Claude 可读:CLAUDE.md 精简且分层(根只放指针 + 关键坑);在子目录而非仓根初始化(Claude 会自动向上加载沿途每个 CLAUDE.md,根上下文不丢);按子目录 scope test/lint 命令(跑全套会超时、烧上下文);用 .ignore / 版本化的 permissions.deny 排除生成物、构建产物、三方码;目录结构不给力时写一份轻量 codebase map;跑 LSP 让按符号而非字符串搜
  2. 随模型演进主动维护 CLAUDE.md:为旧模型缺陷写的规则会拖累新模型(如"每次重构拆成单文件改动"会阻止新模型做它本已擅长的协调跨文件编辑);为补模型/工具缺陷写的 skill/hook 一旦缺陷消失就成负担。每 3–6 个月、或模型换代后感觉见顶时做一次配置重审。
  3. 指派 owner:技术配置本身不驱动采纳;铺开最快的组织在放开前就有专人/小队把工具接进工作流,出现 agent manager(PM/工程混合角色)或至少一个 DRI,并尽早对齐治理(谁管 skill/plugin、避免重复造轮子、AI 代码走同样的 review)。

2.4 适用边界

博客最后划了适用范围:Claude Code 面向常规软件工程环境——工程师是主要贡献者、用 Git、标准目录结构。非常规设置(游戏引擎的大二进制资产、非常规版本控制、非工程师贡献代码)需要额外的配置工作。

这些都是通用结论;而整机树把每一条的难度都放大了(第一节的三个放大器)。后文第四节起,就是我们把这套通用原则逐条落到 AOSP 整机树上的具体形态——并在两处(子目录初始化、plugin 分发)因 repo 工程的现实做了有意背离(见第四节末)。


三、他山之石:网络上已有的类似方案

动手自建之前,我们先调研了社区在"AOSP + coding agent"这个方向上已有的探索(调研时间 2026-07)。有代表性的四个方案,恰好各占一个生态位:

方案
形态
一句话定位
Lightrion AOSP RAG
托管 MCP 服务(SaaS)
对公开 AOSP 各版本做语义检索,agent 即插即查
utzcoz《Using Claude Code on AOSP-scale projects》
方法论(博客)
4 个已交付 AOSP 级项目沉淀的 harness engineering 十模式
hyperb1iss/hyperdroid-skill
Claude Code 插件
Android 通用领域技能包(adb/fastboot/构建/LineageOS)+ crash 分析 agent
jonaschen/Android-Software
分层 skill 知识包
L1 路由 → L2 子系统专家,防幻觉路径与跨域错配

Lightrion AOSP RAG:托管的 AOSP 语义检索

一个商业 MCP 服务:把 AOSP 13–17 各发布版预先建好索引,暴露 search_code / get_chunk / get_file / list_versions / diff_versions 五个工具,任何 MCP 客户端加一个 bearer token 就能用自然语言检索 AOSP 源码,还能按 minor release 钉住版本、跨版本 diff。

  • 优点:零本地成本——不需要本地源码树、不需要自己建索引;多版本覆盖 + 跨版本 diff 是独有能力("这个函数在 15→17 之间改了什么"一问即得);接入是标准 MCP,五分钟配完。
  • 局限:它索引的是公开 AOSP 发布版,而整机开发的工作对象是自己的本地树——你刚改过的代码、本地 feature 分支、树上的任何 delta 它都不知道。这正是 Anthropic 官方博客点名的 RAG 死穴("返回已改名的函数却不告诉你它过期了")在 fork 场景下的极端形态。此外代码问题出网查询有保密性顾虑;且它只覆盖"读与查"这一层,编译、部署、验证、护栏全不涉及。
  • 我们的取舍:不能作为本地树的主导航(live 树必须 agentic search + LSP),但作为"查上游基线/跨版本差异"的补充通道有真实价值。

utzcoz 十模式:被四个交付项目验证过的方法论

作者用 Claude Code 做成并发布了 4 个 AOSP 级项目(ARM64→x86_64 二进制翻译器、AOSP 14 多窗口补丁集、Chromium WebXR 移植、64 章 AOSP 内核书),沉淀出十条 harness engineering 模式,分三组:跨会话保存状态(CLAUDE.md 行为契约、handoff 交接文档)、验证(模拟器基座、verify 脚本只编码一次、红条 TDD、读截图判对错)、输出可信(结论带源码路径行号、冷启动对抗 review)。

  • 优点:唯一经过"真的交付了东西"检验的完整方法论;对"编过 = 改对"幻觉、"似是而非 ≠ 正确"这两个 agent 根性问题给出了系统解法;多条模式可直接照抄(CLAUDE.md 只写 agent 默认会犯的错、verify 脚本单入口确定性输出)。
  • 局限:它是方法论而非可安装工件,每个项目都要自己重新落地;其项目形态是"单仓 fork + 模拟器",没有处理 repo 千仓工程特有的问题——上下文文件会污染 gerrit project、上下文如何随 feature 分支切换;对代码智能层(LSP/compdb)也没有展开。
  • 我们的取舍:十模式是本文方案在理念层的最大来源——CLAUDE.md 行为契约、verify 确定性脚本、"harness 诚实产出就诚实"都直接进入了设计;repo 工程特有的部分(第六、七节)则是我们补上的。

hyperdroid-skill:插件化的 Android 通用技能包

LineageOS 社区开发者的 Claude Code 插件(MIT):四个按触发词自动激活的 skill(android 设备/adb、android-fastboot 刷机/分区/防砖、android-build Gradle+AOSP 构建、lineageos repo/Gerrit 工作流)加一个受限工具的 crash-analyzer 子代理(自主收集 logcat/tombstone/ANR 后给诊断)。

  • 优点工程骨架是四家里最值得抄的——单仓分发多 skill + agent(plugin.json/marketplace 一键装)、渐进式披露(SKILL.md 速查 + references/ 深度页按需加载)、触发词自动激活、受限工具 + 固定工作流的子代理模板、仓库自校验 Makefile(CI 强制每个 skill 结构合规)。
  • 局限:内容是参考手册级的通用知识(adb/fastboot/构建命令速查),视角偏三方 ROM 玩机而非整机平台开发;不绑定任何具体源码树——不知道你的 feature、你的编译产物、你的验证脚本;对树内导航、上下文经济、gerrit 污染等核心矛盾不涉及。
  • 我们的取舍:抄骨架、自己填肉——渐进式披露和触发激活的思想直接体现在我们的 path-scoped skill 设计里(paths glob 替代触发词,粒度更准)。

Android-Software:分层专家路由的知识包

面向 Android Software Owner / BSP 工程师的分层 skill 集(Beta,对 Android 15 验证):所有任务先过 L1 路由器(意图 → 已验证的 AOSP 路径映射),再加载对应的 L2 子系统专家(build/SELinux/HAL/framework/init/内核 GKI/bootloader/ATF/pKVM 等 12 个),每个专家带子系统知识、禁止动作和工具链;另有 hindsight notes 机制沉淀跨会话经验。

  • 优点:直击 agent 在 AOSP 上的三大失败模式(幻觉路径、跨域错配——把 bootloader 问题路由给 init、版本知识漂移);"MMU 式按需加载"与我们的上下文经济诉求同源;子系统覆盖面最广(连 LK/ATF/pKVM 这类 vendor 层都有路由位);没有本地源码也能回答问题。
  • 局限:本质是静态知识包——与"你这棵树"零绑定,答案来自预写的知识而非现场读码,版本演进要人工维护(对 A15 验证,用在 17 上就有漂移窗口,恰是它自己要解决的问题);无 symbol 级导航;无编译→部署→验证闭环;单人 Beta 项目,成熟度有限。
  • 我们的取舍:分层按需加载的思想与我们"索引粒度注入、详情按需 Read"殊途同归;但我们把"知识从哪来"反过来了——不预写知识,让 agent 现场读真代码,harness 只负责把它引到对的地方。

四方案对照与我们的位置

用整机树内开发需要的四类能力——代码智能、上下文、流程、护栏与验证,这也正是下文我们方案的四层框架——给它们做覆盖度体检(● 深度覆盖 ◐ 部分/通用级 ○ 基本不涉及):

方案
① 代码智能
② 上下文
③ 流程
④ 护栏与验证
Lightrion AOSP RAG
◐ 仅上游版本,不含本地改动
utzcoz 十模式
○ 未展开
◐ CLAUDE.md 契约 + handoff
◐ 脚本化约定
● verify/红条 TDD/对抗 review
hyperdroid-skill
◐ 通用命令速查
◐ crash-analyzer
Android-Software
○ 防幻觉路径 ≠ symbol 导航
◐ 分层按需加载
◐ 子系统流程知识
本文方案
● 本树 compdb + clangd
● 随 feature 分支注入
● path-scoped skill
● 硬门禁 + verify 闭环

结论一目了然:四个方案分别解决了检索、方法论、通用领域知识、知识路由,但没有一个解决"这一棵树"的问题——本地 fork 的 symbol 级实时导航、repo/gerrit 布局下不污染上游的上下文组织、随 feature 分支自动切换的工作状态、绑定本树目标设备的确定性验证环。这块空白,就是下文四层 harness 的主体;而各家的长处(utzcoz 的验证纪律、hyperdroid 的渐进披露骨架、Android-Software 的按需分层思想)都被吸收进了对应层的设计。


四、方案总览:四层 Harness

4.1 一个业务前提与五个术语

展开四层之前,先厘清本方案赖以成立的一个业务前提和几个反复出现的术语——它们决定了这套 harness 为什么可行、四层各自靠什么落地。

业务前提:一个专项 = 一个 feature = 一个本地分支 = 3–8 个单仓。 真实的手机厂商以专项的形式推进 OS 特性开发(一个专项就是一次成体系的特性迭代)。我们把一个专项对应成一个 feature,并约定 一个 feature 独占一个 repo 本地分支repo start <feature> --all),该 feature 的全部改动只在这个分支上进行——这样 harness 才有一个稳定的"当前在做什么"的锚点。一个 feature 通常只触及 3–8 个 git 单仓(例如"新增一个系统服务 + 一个边栏应用",落在 frameworks/baseframeworks/native、新建 app 仓、build/makesystem/sepolicy 上)。正是"涉及仓有限、且随分支固定"这个业务事实,让后文所有"随 feature 组织、随分支自动切换、按仓精简"的机制得以成立。

五个术语(四层各自的关键落地物,正文表格里会直接用到):

  • LSP(Language Server Protocol,语言服务器协议):编辑器/agent 与语言服务器之间的标准协议,把"跳到定义、查找所有引用、按符号导航、类型报错"这类代码智能能力暴露出来。它让 agent 按 symbol(符号) 而非文本字符串检索——同名函数在不同文件/语言里能被精确区分,不会 pattern-match 到错误的符号。C++ 侧我们用 clangd 作为语言服务器,喂给它一份 compdbcompile_commands.json,编译命令数据库)即可(第①层,详见第五节)。
  • SessionStart hook:Claude Code 在会话启动 / 恢复 / 清屏 / 压缩时触发的钩子脚本,它的 stdout 会被 Claude Code 注入为会话上下文。我们用它在每次会话"睁眼"时,按当前分支自动把"这个 feature 在做什么、涉及哪些仓、验证跑哪个脚本"喂给 agent(第②层,详见第六节)。
  • path-scoped skill:skill 是按需加载的打包指令;带 paths glob 的 skill 只在 agent 读到匹配路径的代码时才激活。我们用它承载"改到这片代码怎么编译 / push / 验证"这类过程性知识——不读到就零上下文占用(第③层,详见第七节)。
  • permissions.ask 硬门禁:Claude Code 的权限机制,把匹配到的危险命令(adb push/rebootcvd start/stoprepo syncm clean 等)变成执行前的系统级弹窗确认,不依赖模型记性(第④层护栏,详见第八节)。
  • features/<分支>/verify-*.sh 确定性脚本:每个 feature 自带的验证脚本,就是这个 feature 的"测试"——输出只有确定性的 PASS/FAIL,用来斩断"编过 = 改对"的幻觉(第④层验证,详见第八节)。

4.2 四层总览

我们把「导航、上下文、流程、护栏与验证」四件事做成工程化的基础设施,让 agent 在这棵树上的每次会话都站在同一套地基上:

解决什么
落地物
① 代码智能
按 symbol 而非文本导航
树根 .clangd → feature 精简 compdb(C++);Java/Kotlin 明确不配 LSP
② 上下文
每个会话自动知道"在哪、做什么、什么不能碰"
根 CLAUDE.md(固定 bootstrap + 硬约束)+ SessionStart hook 按分支注入 features/<分支>/_index.md
③ 流程
动到哪片代码就知道怎么编译/push/验证
树根 .claude/skills/ 若干 path-scoped skill
④ 护栏与验证
防误操作设备、斩断"编过=改对"
permissions.ask
 硬门禁 + features/<分支>/verify-*.sh 确定性脚本

与官方博客扩展点框架的对应关系(博客要点见第二节):博客把 harness 拆成五个扩展点(CLAUDE.md、hooks、skills、plugins、MCP servers)外加两项能力(LSP、subagents),并强调叠加有顺序——每一层都建立在前一层之上。我们这张"四类能力"表是同一套东西按"解决什么问题"重排的:① 代码智能 = LSP;② 上下文 = CLAUDE.md + hooks(SessionStart 动态注入);③ 流程 = skills(path-scoped);④ 护栏 = hooks(permissions/校验)+ verify 脚本。博客说的叠加顺序在我们的探索历程(第十节)里也如实复现:先用 CLAUDE.md 定行为契约、再用 hook 注入上下文、再用 skill 承载流程、最后补护栏与验证——每一战都踩在上一战的地基上。五个扩展点里我们只暂缓了两个(plugins 与 MCP servers),另有两处对博客通用建议的有意背离,理由见本节末。

四层全部落在树根的游离文件上。这里有一个 repo 工程的关键事实:源码树根不是 git 仓(树根只有 .repo/,没有 .git/),所以放在树根的文件不被任何 gerrit project 跟踪,soong/kati 也不会把纯 markdown 目录当模块编进整机——这是整套方案"不污染上游"的地基。

<AOSP_ROOT>/# repo 工程根(非 git 仓)├── CLAUDE.md# ② 固定 bootstrap + 硬约束(不随 feature 变)├── .clangd# ① 指向 feature 精简 compdb(绝对路径)├── compile_commands.json# ① 根符号链├── gen-compdb-clangd.sh# ① compdb 两段式刷新脚本├── .claude/ │ ├── settings.json# ② hooks 注册 + ④ permissions 门禁│ ├── hooks/load-feature.sh# ② 按分支注入 feature 上下文│ ├── hooks/check-branch-drift.sh# ② 会话中途切分支告警│ ├── rules/compdb-freshness.md# ① compdb 时效提醒(path-scoped rule)│ └── skills/build-*/SKILL.md# ③ path-scoped 编译/验证 skill└── features/# ② 独立 git 仓(不在 manifest,repo/gerrit/soong 全不可见)    └── dev-sidebar/# 目录名 = repo 分支名 = feature 名        ├── _index.md# 启动注入的索引(几百 token)        ├── frameworks-base.md# 单仓约定(只写 feature 特有内容)        ├── check-branch.sh# 涉及仓分支一致性检查        └── verify-sidebar.sh# ④ 确定性验证脚本

📦 可跑 Demo:本节这棵目录树的最小可运行复刻见同级 aosp-harness-demo/——四层落地物一应俱全,关键脚本都带 --demo,不需要真实 AOSP 树,./run-demo.sh 即可一键演示四层如何协同。下文五~八节每节开头的「▶ Demo」标注,就指向它对应的文件。

对博客扩展点的三点取舍(都是被 repo/整机树的现实逼出来的,不是遗漏):

  • 背离一:博客建议"在子目录而非仓根初始化"(让 agent scope 到与任务相关的部分,Claude 会自动向上加载沿途每个 CLAUDE.md,根上下文不丢)。我们反其道必须从树根启动——envsetup / lunch / m / adb 全都要求树根 cwd,repo 树也没有子目录级 git 仓的天然边界可供 scope。子目录上下文不会被"向上加载"自动带进来的代价,我们用 SessionStart hook 的索引注入(第六节)+ path-scoped skill(第七节)显式补回。
  • 背离二:博客把 plugins 当作"分发可复用配置、防止好做法停留在部落知识"的手段(打包 skills/hooks/MCP,marketplace 一键装)。我们刻意不把这套 harness 做成 plugin——它的价值恰恰在于是一组树根游离文件(见上),做成 plugin 会脱离"树根非 git 仓"这个不污染上游的地基。跨机分发改由 features/ 独立 git 仓推私有 remote 实现(第九节)。
  • 暂缓一:MCP servers。博客点名一个常见错误——"基础还没跑通就先建 MCP 连接"。我们目前只在"查上游基线 / 跨版本 diff"这类读侧场景把 Lightrion 这类 MCP 当补充通道(第三节);"把结构化检索暴露成 agent 可直接调用的工具"是后续可演进项,而非当前地基。

下文以一个真实工作中的 feature 为例(记作 dev-sidebar):在 AOSP 17 上新增一个系统服务 + 一个常驻边栏应用,涉及 frameworks/baseframeworks/native、新建 app 仓、build/makesystem/sepolicy 五个仓。


五、第①层 代码智能:让导航按 symbol,而不是按文本

▶ Demoaosp-harness-demo 里对应 .clangdgen-compdb-clangd.sh(带 --demo 演示两段式过滤)、.claude/rules/compdb-freshness.md

这一层要做的事,一句话就是给 agent 配好 LSP——让它像 IDE 里的工程师那样按 symbol 导航,而不是对文本做 pattern-match。LSP 被 Anthropic 官方博客点名为多语言大库里"最高杠杆的投资之一":没有它,agent 在命名相似的代码里会落到错误的 symbol(整机树里 onTransact 这类同名符号成海,是最大的导航陷阱)。下面按"AOSP 提供了什么机制 → 我们怎么用 → Claude Code 侧怎么配 → 配好后 agent 怎么查代码 → 好处"讲清 C++ 侧的落地;Java/Kotlin 侧论证后刻意不配(见 5.2)。

5.1 C++:clangd + 两段式 compdb

① AOSP 为 LSP 准备好的机制。 clangd(C/C++ 的语言服务器)要工作,只需喂它一份准确的 compile_commands.json(compdb,编译命令数据库——记录每个源文件用哪些 flag 编译)。AOSP 内建了生成它的机制:让 soong 在分析阶段顺带吐出全树 compdb(几分钟,不需要真编译);树内还自带一份与构建工具链同版本的 clangd(prebuilts/clang/host/linux-x86/clang-*/bin/clangd)。

SOONG_GEN_COMPDB=1 m nothing# → out/soong/development/ide/compdb/compile_commands.json

② 我们怎么用:两段式精简。 全树 compdb 对 clangd 太重(本树实测 113,371 条 / 1.97GB)。脚本 gen-compdb-clangd.sh 把它做成两段——soong 全树库只作过滤源,再按当前 feature 涉及的仓过滤出精简库;soong 版每文件已去重(同一 .cpp 的 shared/static/arch 变体只留一条),过滤后即净(用 ninja -t compdb 从构建图导出也行,但不去重,全树会膨胀到几十万条):

③ Claude Code 侧要做的配置。 让 agent 用上这套,只需四件事:

  • 树根放一个 .clangd,把 CompilationDatabase 指向精简库的绝对路径,并开后台索引:
# 树根 .clangdCompileFlags:CompilationDatabase:<AOSP_ROOT>/out/soong/development/ide/compdb-feature/Index:Background:Build
  • Claude Code 通过 LSP(plugin 层) 把 clangd 挂进来(博客原话:"LSP is accessed through the plugin layer"),agent 便获得符号级能力;
  • 让它拉起的是树内 prebuilt clangd(与生成 compdb 的工具链同版本,避免 flag 兼容噪音)——用 ~/.local/bin/clangd 的 shim 按 $PWD 分树分发,多树共存时防串台(见第十节踩坑二);
  • 树根启动 Claude Code,让 workspace root 与 .clangd、compdb 的绝对路径对齐。

④ 配好之后 agent 怎么查代码。 不再靠全树 grep 猜同名符号,而是走 LSP 的符号级能力——跳到定义(go-to-definition)、查所有引用(find-all-references)、列工程符号、hover 看类型签名。例如追一个 binder 调用,能从接口方法直接跳到具体实现,而不必在几十个同名 onTransact 里逐个排除;clangd 后台已建好索引(Index.Background: Build),preamble 秒级、AST 完整;只改函数体不用重生成 compdb——clangd 实时读源文件内容。

⑤ 好处。

  • 精准:按 symbol 区分同名符号,不落到错误符号——这是整机树最大的导航陷阱;
  • 省上下文:LSP 直接返回定义/引用的确切位置,把"过滤"放在 agent 读文件之前,不用打开一堆文件人工判断哪个才对(正是博客强调的 context 经济性);
  • :秒级 preamble + 完整 AST + 后台增量索引;
  • 永不过期:读的是 live 源文件,与 agentic search 同源的好处。

⑥ 两条属于"配置"一部分的实测坑。

  • 一律不要给 AOSP 的 clangd 加 --query-driver。社区常见的这个参数在 AOSP 上是反作用:clangd 会"裸跑"驱动探测系统 include(不带 compdb 里的 -nostdlibinc/-target 全套参数),把宿主机 glibc 头以 -isystem 注入,与 bionic 头混装后爆出上百个 __GLIBC_USE is not defined 之类的错误。AOSP 的 compdb 命令本身已带全套 bionic -isystem,什么都不需要补。
  • compdb 有时效:改了 Android.bp/Android.mkrepo sync、新增源文件后要重跑刷新脚本(只改函数体不用)——这条提醒本身也固化成了一条 path-scoped rule(读到构建文件时自动注入),不靠人记。

一个值得知道的上游坑:AOSP 曾有一个"省内存"的临时 commit(b790b9cb8,2025-03,soong 核心作者所写),在每个 cc 模块构建动作结束就把 compiler 字段置 nil;而 compdb 生成器按设计在所有模块之后才遍历——遍历时七万多个 cc 模块的 compiler 全是 nil,收集到 0 条,SOONG_GEN_COMPDB=1 m nothing 静默产出一个空 []。更新的 AOSP 基线已移除该 commit,但若你的基线恰好落在这个窗口,标准命令会"成功地什么都不生成"。检查方法:grep 'c.compiler = nil' build/soong/cc/cc.go;绕行方案是 ninja -t compdb 从 ninja 构建图提取,或给 cc.go 打三行补丁条件保留 compiler。

5.2 Java/Kotlin:论证之后,刻意不配

Java 侧我们完整走了一遍 aidegen + jdtls(Eclipse JDT 语言服务器)路线,最终结论是不配,且放弃本身是重要的探索成果:

  1. 命脉工具已弃用:aidegen 自己打印 "AIDEGen is no longer supported",官方引导到 Android Studio for Platform——那是 GUI IDE,对 agent 毫无帮助。
  2. 架构性不匹配:agent 的 LSP 以进程启动目录为 workspace root,而编译/adb 都要求从树根启动;jdtls 是 workspace 模型,会从根 URI 遍历整棵树找工程——实测空转吃约 2GB 内存、documentSymbol 反复 internal error;同一时刻 clangd 对 .cpp 秒回。
  3. 无法收窄:官方 jdtls 插件是薄封装,不暴露限制扫描范围的配置。

这一战沉淀出后续所有工具选型的判据

能靠"精确文件清单"喂的 LSP(clangd 读 compdb,不遍历树)就配;要靠"遍历大树 workspace"、且工具链已弃用的就不配。

Java/Kotlin 导航改用 Grep 搜符号 + Read,跨 Java↔JNI↔native 追踪时用 JNI 注册名(如 android_view_*)作 Grep 锚点。不硬配不是偷懒,是止损——后文"踩坑精选"里还有它写坏源码树的实证。


六、第②层 上下文:每个会话睁眼就知道"在哪、做什么、什么不能碰"

▶ Demoaosp-harness-demo 里对应 CLAUDE.md.claude/settings.json.claude/hooks/{load-feature,check-branch-drift}.shfeatures/dev-sidebar/{_index,frameworks-base}.md 与 check-branch.sh(demo 用树根 CURRENT_FEATURE 模拟"锚定仓当前分支")。

这一层做的事一句话说清:在 Claude Code 的 SessionStart hook 里执行一个 shell 脚本,把「当前 feature 对应的上下文」注入到会话里。 于是 agent 每次启动"睁眼"就知道自己在做哪个 feature、能动哪些仓、什么不能碰——无需人工每次交代。

承接 4.1 的前提(一个 feature = 一个 repo 本地分支 = 3–8 个单仓),本层要解决的是:让 agent 一启动就知道当前 feature 是什么、涉及哪些仓、每个仓的约定在哪。四条需求:按 feature 组织、随分支自动切换、不污染 gerrit、大单仓省上下文。下文先给出方案的具体构成与端到端流程(6.1),再解释为什么非得这么设计——那个 git 语义层面的死结与破局(6.2),最后讲几个关键设计决策(6.3)。

6.1 方案概览:由哪些文件构成、启动时怎么跑

先看具体由哪些东西构成(都放在树根,不进任何 gerrit 仓):

  • features/ —— 一个放在树根的独立 git 仓:每个 feature 一个子目录,目录名就等于该 feature 的 repo 分支名。以 dev-sidebar 为例:
features/ └── dev-sidebar/# 目录名 = 分支名 = feature 名    ├── _index.md# 启动时注入的"索引"(几百 token)    ├── frameworks-base.md# 单仓约定(只在 agent 动到该仓时按需 Read)    ├── check-branch.sh# 涉及仓分支一致性检查    └── verify-sidebar.sh# 确定性验证脚本
  • _index.md —— 会话启动时喂给 agent 的"第一屏":内容极简——feature 目标一句话、涉及哪几个仓、每个仓的约定文件在哪、验证脚本入口。例如:
# feature: dev-sidebar目标:新增系统服务 SidebarService + 常驻边栏应用 SidebarApp 涉及仓:frameworks/base、frameworks/native、packages/apps/SidebarApp、build/make、system/sepolicy 单仓约定(动到再 Read):frameworks-base.md 验证入口:./features/dev-sidebar/verify-sidebar.sh
  • .claude/hooks/load-feature.sh —— 注册在 SessionStart 上的脚本:负责"读当前分支 → 选中对应 feature 目录 → 把它的 _index.md 打印到 stdout"。Claude Code 会把 SessionStart hook 的 stdout 自动当作会话上下文注入

启动时就跑这么一条链(工程师在树根敲 claude 那一刻):

一步步拆开:

  1. Claude Code 启动,先加载树根 CLAUDE.md(固定 bootstrap + 硬约束,见 6.3)。
  2. 触发 SessionStart hook load-feature.sh:它从 stdin 的 JSON 里拿到 cwd,再到锚定仓读当前 git 分支名(比如读出 dev-sidebar)。
  3. 脚本把 features/dev-sidebar/_index.md 打印到 stdout,这几百 token 被注入为会话上下文。
  4. 同一时刻,permissions.ask 护栏生效、clangd + feature 精简 compdb 就绪。
  5. 于是 agent "睁眼"第一屏就知道:在做 dev-sidebar、只该动那几个仓、验证跑哪个脚本——全程无需人工交代

hook 脚本的核心不过十几行(拿 cwd → 读分支 → cat 索引)。几个容易踩的细节都已加固:

  • SessionStart 不写 matcher = 四种触发源全覆盖(startup / resume / clear / compact)。初版只覆盖 startup+compact,/clear 之后 feature 上下文会静默消失。
  • 每条 prompt 跑一次分支漂移检测(UserPromptSubmit hook check-branch-drift.sh):比对当前分支与注入时的快照,会话中途 repo checkout 切了分支会收到一次告警,提示先读新分支索引再动手;没切则零输出、零打扰。
  • 锚定仓做成链:feature 不一定碰 frameworks/base,按 base → native → 下一候选的顺序找到第一个能读出分支的仓。

博客视角的一个补白:官方博客认为 hooks 最有价值的用法并不是"拦住 agent 做错事",而是让配置自我改进——用 stop hook 在会话结束、上下文还热的时候反思本次教训并提议更新 CLAUDE.md;用 start hook 动态加载团队/模块上下文,让每个人无需手动配置就拿到对的地基。我们当前的两个 hook(SessionStart 索引注入、UserPromptSubmit 分支漂移检测)已经落地了"动态加载"这一半,但还都停在"注入 + 防错"这一侧;"会话末反思 hook"已列入演进方向(第十一节),是把这套 harness 从"静态地基"推向"自我改进闭环"的下一步。

6.2 命门矛盾与破局:为什么 features/ 是"树根上的独立 git 仓"

上面这套结构里最不显然的一步,是"为什么 features/ 要单独做成一个放在树根的 git 仓,而不是就放进 frameworks/base 里、让它跟着分支走"。因为这里藏着一个 git 语义层面的死结:

即:「随分支变」与「不进 gerrit」在同一个 project 仓内不可兼得,必须把"随分支"这件事从 git 跟踪机制里拿出来,改由 hook 在会话启动时按当前分支动态注入(这正是 6.1 那条链)。方案推演走了五版:

版本
方案
结局
v1
feature 目录与源码树同级,在 feature 目录启动
✗ CLAUDE.md 只沿 cwd 树向上加载,同级源码树的上下文完全加载不到
v2
features/
 放树内、独立 git 仓
✓ 部分成立,但深层单仓的约定仍进不来
v3
根 CLAUDE.md 随分支切换
根不是 git 仓、"分支"是 per-project 的——要么建瘦仓手动同步(两套分支),要么 hook 动态注入
v4
SessionStart hook 按分支注入
✓ 单一分支源、自动跟随、零手动同步
v5
大单仓约定也进 features/索引粒度注入
✓ 启动只注入几百 token 的索引,详情按需 Read

最终形态 = v4 + v5。

6.3 三个设计决策

为什么注入用"索引粒度"? 先说清什么叫索引粒度:像一本书的目录——只列"讲了什么、在第几页"这类指针,而不是把每一章正文都抄给你。落到本方案,就是启动时只注入 _index.md 里那几行指针(feature 目标 + 涉及仓清单 + 各约定文件的路径 + 验证入口),而把每个仓的完整约定全文灌进会话。为什么这么设计:frameworks/base 这类单仓的约定若全量注入会每个会话常驻、挤占上下文;改成只注入索引、agent 真动到某仓时再顺着路径 Read 对应的 frameworks-base.md——用"一个 feature 涉及的单仓有限、且不会全被碰到"这个业务事实,换来上下文经济性。

为什么硬约束放根 CLAUDE.md 而不是全靠 hook? 因为子代理不吃 hook 注入的内容,但会加载 CLAUDE.md。"改 public API 必须跑 m update-api,否则 checkapi 挂构建"这种不知道会出事故的规则,必须让派出去的子代理也看见。同时遵守一条纪律:CLAUDE.md 只写 agent 默认会犯的错,不写文档。本树的硬约束一共六条:

硬约束
防的是什么
不向任何 gerrit project 提交 harness/上下文文件
知识污染上游
禁配 Java LSP / 禁生成 Eclipse 工程文件
吃内存 + 写坏树(见踩坑精选)
改 public/System API 后必须 m update-api
checkapi 挂构建
新增系统服务必须同步 system/sepolicy
服务起不来(avc denied)
push framework.jar/services.jar 后注意 ART 缓存
dexpreopt/boot image 校验不一致拖慢甚至起不来
不手改 out/ 下任何生成物
增量构建被破坏

为什么编译约定也要写进 CLAUDE.md? 有两个 agent 默认必错的点:envsetup 必须用 bash(工具默认 shell 可能是 zsh),且 source 后不能接 pipe(函数会进子 shell);一切编译必须后台跑 + 轮询日志(agent 的前台命令有超时上限,而单编模块十几分钟起步)。

bash -c'source build/envsetup.sh >/dev/null 2>&1 \   && lunch aosp_cf_x86_64_phone-trunk_staging-userdebug >/dev/null 2>&1 \   && m services' > /tmp/build.log 2>&1 &# 后台 + 日志轮询,# 看到 build completed successfully 才算完

(顺带一个 Android 17 的新变化:lunch 目标是三段式 product-release-variant,release 段如 trunk_staging,可从 out/soong.log 的 TARGET_RELEASE= 反查。)


七、第③层 流程:动到哪片代码,就知道怎么编译验证

▶ Demoaosp-harness-demo 里对应 .claude/skills/build-services-jar/SKILL.mdpaths: frameworks/base/services/**)与 build-sepolicy/SKILL.mdpaths: system/sepolicy/**),配合 features/dev-sidebar/frameworks-base.md 里"一句话指回 skill"的单一事实源写法。

这一层做什么。 一句话:让 agent 一动某片代码,就自动知道这片代码"怎么编译、产物在哪、要 push 哪些文件、怎么验证"——不用人每次交代,平时也不占上下文。这类"改了这片代码该怎么走完编译到验证"的知识是过程性知识(区别于第②层"在哪、做什么"那种背景知识)。

怎么做到的。 难点在于:把它全塞进根 CLAUDE.md,会每个会话常驻、白白挤占上下文。解法是 skill 按需加载 + paths glob 按路径激活——把每一类代码的编译验证流程各写成一个 skill,并在 frontmatter 里用 paths 标注它作用的代码路径;只有当 agent 真的 Read 到匹配路径的文件时,对应 skill 才被拉进上下文,其余时间零占用。

# .claude/skills/build-services-jar/SKILL.md(frontmatter 示意)---name:build-services-jardescription:编译/部署services.jar——改frameworks/base/services下代码时用paths:-"frameworks/base/services/**"---

这里的 glob 就是文件路径的通配符匹配(和 shell 里 ls *.c 的 * 同源):* 匹配单层路径内的任意字符,** 跨目录递归匹配任意层级。所以 frameworks/base/services/** 的意思是"frameworks/base/services/ 目录下任意深度的任意文件"。skill frontmatter 里的 paths 字段就是给这个 skill 挂一组这样的路径模式;agent 每 Read 一个文件,Claude Code 就拿该文件路径逐条比对这些模式,一旦命中就把对应 skill 载入上下文,不命中就当它不存在。这就是它按"你正在动的代码落在哪个目录"来决定加载哪个 skill——比 hyperdroid 那种按关键词触发的粒度更准(路径是确定的,关键词会误触),也正是官方博客说的 skill "可 path-scoped、只在相关目录激活"。

repo 工程有个特殊决策点:skill 放哪。嵌套进 frameworks/base/.claude/skills/ 会被该 gerrit project 跟踪——又是污染问题。结论与 feature 工作流同构:集中放树根 .claude/skills/(树根不属于任何 project),用 paths glob 做作用域。前提是从树根启动 agent,而编译/adb 本来就要求树根 cwd,天然满足。

另一条重要纪律是单一事实源:初版曾在 skill 和 feature 单仓约定里把编译/push 流程写了两遍,评审时判定必然漂移。最终分工——skill 承载不随 feature 变的通用流程(编译命令、产物、push 清单、已知坑);features/ 单仓约定只写 feature 特有内容,流程一句话指回 skill。本树目前有五个这样的 skill:framework.jar、services.jar、inputflinger、边栏 app、sepolicy,每个都写明"后台编译 + 日志轮询、产物与 push 清单、快环稳环、编过≠改对指向 verify 脚本"。


八、第④层 护栏与验证:斩断"编过 = 改对"

▶ Demoaosp-harness-demo 里对应 .claude/settings.json 的 permissions.ask 门禁与 features/dev-sidebar/verify-sidebar.sh --demo(四步确定性断言、FAIL>0 非零退出)。

这一层做什么。 一句话:在 agent 干活的两个危险时刻各设一道拦截——动设备/动源码树前别让它误操作,收工宣布完成前别让它把"编译通过"当成"改动正确"。前三层帮 agent 把事做顺,这一层专门防它把事做砸或自我误判。

怎么做到的。 两道护栏,都不依赖模型的记性:一是 permissions 硬门禁permissions.ask),把危险命令变成系统级弹窗,模型上下文再长也绕不过(见 8.1);二是 确定性验证脚本(verify 脚本),把"改对了没有"编码成只输出 PASS/FAIL 的机器判定,堵死 agent 拿模糊输出自我安慰的路(见 8.2)。

8.1 permissions 硬门禁

"动设备先确认"写在文档里是软约束,模型上下文一长就可能被忽略。permissions.ask 把危险操作变成系统级弹窗,不依赖模型记性:

门禁命令
为什么要拦
adb push
 / adb reboot / adb remount …
直接改写运行中设备
cvd start
 / cvd stop / cvd resetlaunch_cvd / stop_cvd
虚拟机生命周期操作
repo sync
动整棵源码树
m clean
 / m installclean
清掉数小时的构建产物

8.2 确定性验证脚本

AOSP 没有"改完跑一下"的现成测试套,verify 脚本就是这个 feature 的测试。utzcoz 的原话:"没有这个,会话结尾 agent 会因为 build 成功就确信改动生效了。" 验证环编码成脚本、只编码一次,输出只有确定性的 PASS/FAIL——中间态会诱导 agent 把模糊输出读成成功。

以 dev-sidebar 的 verify 脚本为例,它做四步确定性断言:

  1. sys.boot_completed=1(设备真的起来了);
  2. system_server 存活;
  3. crash buffer 扫描(无新增崩溃);
  4. 新增系统服务与边栏应用存在性(service list / pm list packages 命中)。

feature 早期允许部分断言标 SKIP,随开发推进逐项转为硬断言——这本身就是一种可执行的进度表。Cuttlefish 作为目标设备在这里显出独特价值:虚拟机的"稳环"(整机镜像 + cvd stop/start)是真机没有的兜底手段,push 出诡异状态时可以低成本回到干净基线。


九、串起来:一个会话的完整生命周期

四层不是四个孤立的配置,而是按时间协同的一条流水线:

触发时机
管什么
① 代码智能
启动 / Read C++ 文件
按 symbol 而非文本导航
② 上下文
启动 + 每条 prompt
每会话自动知道"在哪、做什么、什么不能碰"
③ 流程
Read 到匹配路径
动到哪片代码就知道怎么编/push/验证
④ 护栏与验证
危险命令 / 收工前
防误操作设备、斩断"编过=改对"

换 feature 的成本约等于零repo start dev-next --all + 建 features/dev-next/ 目录 + 重启会话,hook 自动跟随新分支;skills 完全不用动(paths 是按仓的,不随 feature 变)。features/ 是独立 git 仓,feature 上下文、上游调研、verify 脚本随开发演进提交,还可以推私有 remote 跨机同步。

一句话总结这套工作流:

启动时 hook 告诉 agent"在哪、做什么",干活时路径激活 skill 告诉它"怎么编怎么验",危险动作被 permissions 拦一道,收工前 verify 脚本判定"真的改对了"——四层各管一段,缺一层闭环就断。


十、这条路是怎么探索出来的

前面九节呈现的是结果——四层各就各位、彼此咬合,读起来像是一开始就照着蓝图搭的。真实过程要曲折得多:这套 harness 不是自顶向下设计出来的架构,而是被一个个具体的失败逼出来的。每一层的定型几乎都走同一条轨迹——先撞上一个具体故障 → 挖到根因 → 才沉淀出对应的设计决策,顺序恰恰和成品的呈现顺序相反。

回头看,整个探索大致是四场"战役"加一轮自审:前两场在代码智能层,分别啃下 C++(compdb 空数组的上游坑)和 Java(论证后刻意不配 LSP)两块硬骨头;第三场在上下文层,解开"随分支 ⇔ 被跟踪 ⇔ 污染 gerrit"这个 git 语义死结;第四场把流程知识从"全塞 CLAUDE.md"改造成 path-scoped skill。四层搭齐后我们没有就此收工,而是专门做了一轮自审——"配上了"不等于"能用",回头把六个会在真实会话里咬人的缺陷逐个补掉。这段历程里最有价值的往往不是最终方案,而是为什么放弃了另一些看似更直接的方案(比如 Java LSP、把 harness 做成 plugin)。

下面这张时间线先给全局,随后的「踩坑精选」再挑几个最有代表性、且都有实证的坑展开细节。

踩坑精选(每个都有实证)

坑一:Eclipse/jdtls 残留会写坏源码树。 一次 m 在 aconfig 阶段失败——flag already declared,而 frameworks/base 零本地提交。根因:此前 Java LSP 实验中 Eclipse 把资源文件连同 .class 拷进了 services/*/bin/,其中的 .aconfig 副本被 soong 的 **/*.aconfig glob 收进同一 aconfig_declarations,导致重复声明。更隐蔽的是 frameworks/base 自带 .gitignore 忽略 .project/.classpathgit status 完全看不见这批残留;甄别要用 git ls-files --error-unmatch 逐个判断是否 tracked(AOSP 一些老仓的 Eclipse 文件是 checked-in 的,不能一刀切删)。这让"禁配 Java LSP"从性能取舍升级成了硬约束——它不只吃内存,还会污染构建。

坑二:机器级 clangd 包装脚本劫持(多树共存必踩)。clangd --check 日志里出现了另一棵树的 compdb 路径 + "Compile command inferred" + 错误的目标架构——树根 .clangd 明明配对了。根因:~/.local/bin/ 里给旧树写的 clangd 包装脚本硬编码了 --compile-commands-dir,而 CLI flag 优先级压过一切 .clangd 配置。修复:包装脚本按 $PWD 分树分发,每棵树用各自的 in-tree clangd + 各自 compdb 绝对路径;树根 .clangd 一律写绝对路径双保险。速查信号:--check 日志里 ①DB 路径不是本树 ②"inferred"字样 ③目标架构/API 级不对。

坑三:--query-driver 在 AOSP 上是反作用。(详见第五节——宿主 glibc 头污染 bionic,删掉即清零。)

元教训:harness 自身也要用工程标准对待——设计完要评审、加固、实测,而不是"配上了"就算完。三大件搭好后我们专门做了一轮"这套方案还有哪些缺陷"的自审,修掉的六个缺陷里最典型的三个:长编译撞工具超时上限(改为强制后台+轮询)、/clear 后上下文静默丢失(matcher 全覆盖 + 漂移检测)、"动设备先确认"是软约束(升级为 permissions 硬门禁)。


十一、边界与下一步

已知边界(都是明确认下的取舍,不是遗漏):

边界
说明
Java/Kotlin 无 LSP
跨 Java↔JNI↔native 追踪靠 Grep 搜符号 + JNI 注册名锚点
单树单分支
repo 树没有 git worktree 等价物,并行两个 feature 需要两棵树
hook 注入不进子代理
已用"硬约束下沉 CLAUDE.md"缓解,派发子代理时仍需转述 feature 上下文
compdb 有时效
改构建文件/repo sync 后要重跑刷新脚本(已有 rule 自动提醒)

何时重审:每 3–6 个月、或新一代模型发布后感觉规则见顶时,删过期/矛盾的规则——"为迁就某代模型缺陷写的规则,下一代模型上来就变成束缚"。另加一条我们自己的信号:依赖的工具链出现弃用声明时立即重审(aidegen 之鉴)。

可演进方向(按杠杆排序):

  1. 五段式 handoff 交接文档(What Was Done / How Verified / Files Modified / Blocker / Next)——跨会话 bug hunt 的最高杠杆,新会话读最新 handoff 即可冷启动续上;
  2. 会话末反思 hook——提议更新 CLAUDE.md,形成持续改进闭环;
  3. 冷启动 review 子代理对抗审查——作者 agent 偏 "ship it",无历史包袱的 reviewer 偏 "explain this"。
  4. 只读子代理测绘、主代理编辑——博客点名的 subagent 核心模式:整机树上"探索"极烧上下文,可先派一个只读 subagent 去测绘某个子系统(跟调用链、读 dumpsys、定位改动点),把发现写进一个文件,主代理再带着全貌下手编辑,避免探索的中间产物挤占主上下文。要与本树"hook 注入不进子代理"的边界(见上表)配套——派发时必须把 feature 上下文转述进子代理的任务描述。

结语

这套 harness 工程没有任何一处依赖"更聪明的模型":它做的全部事情,是把一位 AOSP 老工程师带新人时会做的四件事——给他一张地图(上下文)、教他怎么编译(流程)、告诉他哪些红线不能碰(护栏)、要求他改完必须验证(闭环)——翻译成了 agent 基础设施。模型每半年换代一次,而这棵树上的地基,每个会话都在复用。

参考资料

  • 本文配套可跑 Demo:yuandaimaahao/aosp-harness-demo(四层方案的最小可运行复刻,关键脚本带 --demo,无需真实 AOSP 树,./run-demo.sh 一键演示)
  • Anthropic 官方博客:How Claude Code works in large codebases(agentic search 的代价与甜区、"上下文是唯一稀缺资源"、五扩展点 CLAUDE.md/hooks/skills/plugins/MCP + LSP + subagents 及其叠加顺序、hooks 的"自我改进"用法、subagents"探索与编辑分离"、"子目录初始化"建议、plugins 分发反部落化、LSP 最高杠杆、每 3–6 个月重审)
  • utzcoz:Using Claude Code on AOSP-scale projects(harness engineering 十模式,https://utzcoz.github.io/2026/04/26/using-claude-code-on-aosp-scale-projects.html)
  • Claude Code 官方文档:hooks / skills / memory / large-codebases(SessionStart 注入机制、paths frontmatter 语义、CLAUDE.md 加载规则)
  • AOSP 树内文档:build/soong/docs/compdb.md;相关源码 build/soong/cc/compdb.gobuild/soong/cc/cc.go
  • 社区同类方案(见第三节):Lightrion AOSP RAG(https://lightrion.com/docs)、hyperb1iss/hyperdroid-skill(https://github.com/hyperb1iss/hyperdroid-skill)、jonaschen/Android-Software(https://github.com/jonaschen/Android-Software)
基本 文件 流程 错误 SQL 调试
  1. 请求信息 : 2026-07-05 10:49:38 HTTP/1.1 GET : https://www.yeyulingfeng.com/a/834206.html
  2. 运行时间 : 0.226632s [ 吞吐率:4.41req/s ] 内存消耗:4,978.62kb 文件加载:145
  3. 缓存信息 : 0 reads,0 writes
  4. 会话信息 : SESSION_ID=2643011ebe9f4c9b4fbcc6a7200e57da
  1. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/public/index.php ( 0.79 KB )
  2. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/autoload.php ( 0.17 KB )
  3. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/composer/autoload_real.php ( 2.49 KB )
  4. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/composer/platform_check.php ( 0.90 KB )
  5. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/composer/ClassLoader.php ( 14.03 KB )
  6. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/composer/autoload_static.php ( 6.05 KB )
  7. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-helper/src/helper.php ( 8.34 KB )
  8. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-validate/src/helper.php ( 2.19 KB )
  9. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/ralouphie/getallheaders/src/getallheaders.php ( 1.60 KB )
  10. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/helper.php ( 1.47 KB )
  11. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/stubs/load_stubs.php ( 0.16 KB )
  12. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Exception.php ( 1.69 KB )
  13. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-container/src/Facade.php ( 2.71 KB )
  14. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/symfony/deprecation-contracts/function.php ( 0.99 KB )
  15. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/symfony/polyfill-mbstring/bootstrap.php ( 8.26 KB )
  16. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/symfony/polyfill-mbstring/bootstrap80.php ( 9.78 KB )
  17. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/symfony/var-dumper/Resources/functions/dump.php ( 1.49 KB )
  18. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-dumper/src/helper.php ( 0.18 KB )
  19. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/symfony/var-dumper/VarDumper.php ( 4.30 KB )
  20. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/guzzlehttp/guzzle/src/functions_include.php ( 0.16 KB )
  21. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/guzzlehttp/guzzle/src/functions.php ( 5.54 KB )
  22. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/App.php ( 15.30 KB )
  23. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-container/src/Container.php ( 15.76 KB )
  24. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/psr/container/src/ContainerInterface.php ( 1.02 KB )
  25. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/provider.php ( 0.19 KB )
  26. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Http.php ( 6.04 KB )
  27. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-helper/src/helper/Str.php ( 7.29 KB )
  28. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Env.php ( 4.68 KB )
  29. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/common.php ( 0.03 KB )
  30. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/helper.php ( 18.78 KB )
  31. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Config.php ( 5.54 KB )
  32. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/alipay.php ( 3.59 KB )
  33. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/facade/Env.php ( 1.67 KB )
  34. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/app.php ( 0.95 KB )
  35. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/cache.php ( 0.78 KB )
  36. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/console.php ( 0.23 KB )
  37. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/cookie.php ( 0.56 KB )
  38. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/database.php ( 2.48 KB )
  39. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/filesystem.php ( 0.61 KB )
  40. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/lang.php ( 0.91 KB )
  41. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/log.php ( 1.35 KB )
  42. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/middleware.php ( 0.19 KB )
  43. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/route.php ( 1.89 KB )
  44. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/session.php ( 0.57 KB )
  45. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/trace.php ( 0.34 KB )
  46. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/view.php ( 0.82 KB )
  47. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/event.php ( 0.25 KB )
  48. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Event.php ( 7.67 KB )
  49. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/service.php ( 0.13 KB )
  50. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/AppService.php ( 0.26 KB )
  51. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Service.php ( 1.64 KB )
  52. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Lang.php ( 7.35 KB )
  53. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/lang/zh-cn.php ( 13.70 KB )
  54. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/initializer/Error.php ( 3.31 KB )
  55. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/initializer/RegisterService.php ( 1.33 KB )
  56. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/services.php ( 0.14 KB )
  57. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/service/PaginatorService.php ( 1.52 KB )
  58. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/service/ValidateService.php ( 0.99 KB )
  59. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/service/ModelService.php ( 2.04 KB )
  60. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-trace/src/Service.php ( 0.77 KB )
  61. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Middleware.php ( 6.72 KB )
  62. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/initializer/BootService.php ( 0.77 KB )
  63. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/Paginator.php ( 11.86 KB )
  64. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-validate/src/Validate.php ( 63.20 KB )
  65. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/Model.php ( 23.55 KB )
  66. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/model/concern/Attribute.php ( 21.05 KB )
  67. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/model/concern/AutoWriteData.php ( 4.21 KB )
  68. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/model/concern/Conversion.php ( 6.44 KB )
  69. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/model/concern/DbConnect.php ( 5.16 KB )
  70. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/model/concern/ModelEvent.php ( 2.33 KB )
  71. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/model/concern/RelationShip.php ( 28.29 KB )
  72. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-helper/src/contract/Arrayable.php ( 0.09 KB )
  73. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-helper/src/contract/Jsonable.php ( 0.13 KB )
  74. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/model/contract/Modelable.php ( 0.09 KB )
  75. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Db.php ( 2.88 KB )
  76. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/DbManager.php ( 8.52 KB )
  77. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Log.php ( 6.28 KB )
  78. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Manager.php ( 3.92 KB )
  79. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/psr/log/src/LoggerTrait.php ( 2.69 KB )
  80. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/psr/log/src/LoggerInterface.php ( 2.71 KB )
  81. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Cache.php ( 4.92 KB )
  82. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/psr/simple-cache/src/CacheInterface.php ( 4.71 KB )
  83. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-helper/src/helper/Arr.php ( 16.63 KB )
  84. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/cache/driver/File.php ( 7.84 KB )
  85. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/cache/Driver.php ( 9.03 KB )
  86. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/contract/CacheHandlerInterface.php ( 1.99 KB )
  87. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/Request.php ( 0.09 KB )
  88. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Request.php ( 55.78 KB )
  89. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/middleware.php ( 0.25 KB )
  90. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Pipeline.php ( 2.61 KB )
  91. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-trace/src/TraceDebug.php ( 3.40 KB )
  92. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/middleware/SessionInit.php ( 1.94 KB )
  93. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Session.php ( 1.80 KB )
  94. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/session/driver/File.php ( 6.27 KB )
  95. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/contract/SessionHandlerInterface.php ( 0.87 KB )
  96. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/session/Store.php ( 7.12 KB )
  97. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Route.php ( 23.73 KB )
  98. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/route/RuleName.php ( 5.75 KB )
  99. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/route/Domain.php ( 2.53 KB )
  100. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/route/RuleGroup.php ( 22.43 KB )
  101. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/route/Rule.php ( 26.95 KB )
  102. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/route/RuleItem.php ( 9.78 KB )
  103. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/route/app.php ( 3.94 KB )
  104. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/facade/Route.php ( 4.70 KB )
  105. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/route/dispatch/Controller.php ( 4.74 KB )
  106. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/route/Dispatch.php ( 10.44 KB )
  107. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/controller/Index.php ( 9.87 KB )
  108. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/BaseController.php ( 2.05 KB )
  109. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/facade/Db.php ( 0.93 KB )
  110. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/connector/Mysql.php ( 5.44 KB )
  111. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/PDOConnection.php ( 52.47 KB )
  112. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/Connection.php ( 8.39 KB )
  113. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/ConnectionInterface.php ( 4.57 KB )
  114. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/builder/Mysql.php ( 16.58 KB )
  115. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/Builder.php ( 24.06 KB )
  116. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/BaseBuilder.php ( 27.50 KB )
  117. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/Query.php ( 15.71 KB )
  118. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/BaseQuery.php ( 45.13 KB )
  119. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/TimeFieldQuery.php ( 7.43 KB )
  120. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/AggregateQuery.php ( 3.26 KB )
  121. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/ModelRelationQuery.php ( 20.07 KB )
  122. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/ParamsBind.php ( 3.66 KB )
  123. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/ResultOperation.php ( 7.01 KB )
  124. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/WhereQuery.php ( 19.37 KB )
  125. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/JoinAndViewQuery.php ( 7.11 KB )
  126. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/TableFieldInfo.php ( 2.63 KB )
  127. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/Transaction.php ( 2.77 KB )
  128. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/log/driver/File.php ( 5.96 KB )
  129. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/contract/LogHandlerInterface.php ( 0.86 KB )
  130. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/log/Channel.php ( 3.89 KB )
  131. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/event/LogRecord.php ( 1.02 KB )
  132. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-helper/src/Collection.php ( 16.47 KB )
  133. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/facade/View.php ( 1.70 KB )
  134. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/View.php ( 4.39 KB )
  135. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/controller/Es.php ( 3.30 KB )
  136. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Response.php ( 8.81 KB )
  137. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/response/View.php ( 3.29 KB )
  138. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Cookie.php ( 6.06 KB )
  139. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-view/src/Think.php ( 8.38 KB )
  140. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/contract/TemplateHandlerInterface.php ( 1.60 KB )
  141. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-template/src/Template.php ( 46.61 KB )
  142. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-template/src/template/driver/File.php ( 2.41 KB )
  143. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-template/src/template/contract/DriverInterface.php ( 0.86 KB )
  144. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/runtime/temp/c935550e3e8a3a4c27dd94e439343fdf.php ( 31.50 KB )
  145. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-trace/src/Html.php ( 4.42 KB )
  1. CONNECT:[ UseTime:0.001227s ] mysql:host=127.0.0.1;port=3306;dbname=wenku;charset=utf8mb4
  2. SHOW FULL COLUMNS FROM `fenlei` [ RunTime:0.001648s ]
  3. SELECT * FROM `fenlei` WHERE `fid` = 0 [ RunTime:0.000701s ]
  4. SELECT * FROM `fenlei` WHERE `fid` = 63 [ RunTime:0.000689s ]
  5. SHOW FULL COLUMNS FROM `set` [ RunTime:0.001360s ]
  6. SELECT * FROM `set` [ RunTime:0.000604s ]
  7. SHOW FULL COLUMNS FROM `article` [ RunTime:0.001536s ]
  8. SELECT * FROM `article` WHERE `id` = 834206 LIMIT 1 [ RunTime:0.002049s ]
  9. UPDATE `article` SET `lasttime` = 1783219778 WHERE `id` = 834206 [ RunTime:0.018362s ]
  10. SELECT * FROM `fenlei` WHERE `id` = 64 LIMIT 1 [ RunTime:0.000277s ]
  11. SELECT * FROM `article` WHERE `id` < 834206 ORDER BY `id` DESC LIMIT 1 [ RunTime:0.000470s ]
  12. SELECT * FROM `article` WHERE `id` > 834206 ORDER BY `id` ASC LIMIT 1 [ RunTime:0.000646s ]
  13. SELECT * FROM `article` WHERE `id` < 834206 ORDER BY `id` DESC LIMIT 10 [ RunTime:0.000816s ]
  14. SELECT * FROM `article` WHERE `id` < 834206 ORDER BY `id` DESC LIMIT 10,10 [ RunTime:0.003311s ]
  15. SELECT * FROM `article` WHERE `id` < 834206 ORDER BY `id` DESC LIMIT 20,10 [ RunTime:0.003952s ]
0.230546s