247GB 的 Android 系統原始碼。散落在 vendor/、device/、framework/ 的客製化。
每次要改東西,光是找到「這個功能在哪裡實作」就要花半天。資深工程師離職,帶走的是腦內索引。新人進來,花三個月才能獨立作業。
我決定試試讓 Claude Code 當我的 codebase navigator。結果?有用,但不是你想的那種方式。
別急著開工,先承認你不知道自己要什麼
「用 AI 優化 AOSP 架構」——我一開始就是帶著這個模糊到不行的目標開始的。
第一個教訓:Claude 不會幫你釐清一個模糊的問題,它只會幫你更有效率地解決一個清楚的問題。
你說「優化架構」,它會給你一堆看起來合理的方向。但哪個方向對你的專案有意義,只有你知道。
所以我花了一整天,把「優化架構」拆成四個可執行的問題:
| 問題 | 為什麼重要 |
|---|---|
| 開機流程有哪些 service 可以延後? | 開機時間直接影響用戶體驗 |
| 有沒有功能重疊的 service 可以合併? | 記憶體和維護成本 |
| 客製化的入口點能不能統一? | 每次 AOSP 升級都是一場災難 |
| 架構知識怎麼留在組織裡? | 人會離職,文件不會 |
但在做這四件事之前,還有一個更根本的前提:你得先知道現狀是什麼。
Claude Code 的甜蜜點和邊界
用 Claude Code 分析 AOSP 之前,先搞清楚它的能力邊界。這不是客氣,是避免你浪費時間。
適合交給它的:
- 單一模組的結構分析——讀 Android.bp、trace 依賴、解釋 SELinux policy
- 用 Explore agent 做開放式搜索——「這個功能在哪裡實作」
- 把分析結果整理成文檔
不要期待它做的:
- 記住 247GB codebase 的全貌(context window 就那麼大)
- 跨 session 保持狀態(每次都是新的一天)
- 理解你組織內的潛規則(「這個 service 是三年前 A 同事為了趕 deadline 硬加的」)
一句話:Claude Code 是一個強大的即時分析器,不是長期記憶庫。
要讓它持續有用,你需要一個策略——而那個策略不是 prompt engineering,是文檔化。
文檔驅動的分析流程
我的策略很土:每次 Claude 分析完一個模組,就把結論寫成文件。下次新 session 只需要讀文件,就能恢復 context。
docs/
├── Architecture_Overview.md # 整體架構(Claude 的起點)
├── Module_Analysis/ # 各模組分析
└── Optimization_Backlog.md # 待辦清單
然後分層處理,不要妄想一次看懂整個 AOSP:
- 核心服務層 — SDK 和預建 service
- Framework 擴展 — 系統服務擴展、AIDL interface
- 平台整合 — HAL、SELinux、init.rc
每一層分析完,文檔更新一次。新的 Claude session 讀完文檔就能接手。
聽起來很基本?對,但 90% 的人(包括一開始的我)都會跳過這步,直接開始問 Claude 問題,然後抱怨「它不記得上次說的」。
MCP:從「先別急」到「真的該做了」
第一輪分析我完全用 Claude Code 原生工具——Bash、Grep、Read。效果不錯,但我注意到一個 pattern:
同樣的查詢我做了十幾次。
「這個模組依賴誰?」→ 手動 grep Android.bp → 找 static_libs → 再 grep 下一層。 「這個 SELinux domain 有什麼權限?」→ 找 .te 檔案 → 手動過濾 allow rules。 「開機時哪些 service 啟動?」→ grep init.rc → 追蹤 import chain。
每次都是 3-5 步的重複操作。這就是 MCP 該出場的時機。
MCP(Model Context Protocol)的本質就是:把重複的多步查詢封裝成一個 API call。
如果你還不確定什麼操作會重複,別急著寫 MCP server。先手動做幾輪,記錄下來,pattern 自然會浮現。
16 個工具,從 890 行到模組化架構
第一版:能動就好(然後後悔)
第一版 MCP server 就是一個 890 行的 TypeScript 檔案。Magic numbers 到處飛、路徑硬編碼、全局變量管 cache、零日誌。
能動嗎?能動。能維護嗎?一週後我自己都看不懂。
重構後的結構
src/
├── index.ts # 請求分發,不做邏輯
├── config.ts # 常量集中管理
├── types.ts # TypeScript 類型
├── cache/
│ └── dependency-cache.ts # Singleton cache
├── parsers/
│ └── blueprint-parser.ts # Android.bp 解析
├── tools/
│ ├── changes.ts # 變更追蹤
│ ├── dependencies.ts # 依賴分析
│ ├── initrc.ts # Init.rc 分析
│ ├── sepolicy.ts # SELinux 查詢
│ └── services.ts # 系統服務
└── utils/
├── exec.ts # 命令執行
└── logger.ts # 分級日誌
12 個檔案,每個 50-150 行,各自可以獨立測試。
被打臉的假設
重構過程中有幾個假設被現實打臉:
假設 1:「grep init.rc 就夠了」
不夠。Init.rc 的 service block 是多行的,而且 import 可以用 wildcard 路徑。你 grep 到 service zygote 那行,但下面的 class main、user root、socket zygote stream 660 全都屬於同一個 service。需要寫 parser,不是 grep。
假設 2:「SELinux policy 在 system/sepolicy 就好」
OEM 的 sepolicy 散落在 vendor/、device/、甚至 system/sepolicy/private/ 和 public/ 裡。要查完整的 allow rules,得遍歷所有路徑。
假設 3:「Android.bp 就是 JSON」
不是。看起來像,但有些 syntax(像 select 和 soong_config_variable)不是 JSON。Regex-based parser 可以處理 80% 的情況,剩下的 edge cases 需要特殊處理。
最終工具清單
| 類別 | 工具數 | 解決什麼問題 |
|---|---|---|
| 變更追蹤 | 5 | 「哪些 AOSP 檔案被我們改過?」 |
| 依賴分析 | 3 | 「這個模組的 build 依賴鏈是什麼?」 |
| SELinux | 2 | 「這個 domain 能存取什麼?」 |
| 系統服務 | 2 | 「哪些 service 跑在 system_server?」 |
| Init.rc | 4 | 「開機流程長什麼樣?」 |
Init.rc 分析:開機優化的起手式
如果你要優化 Android 開機時間,init.rc 是第一個要看的地方。但 AOSP 的 init.rc 是一個分散式的系統——主檔案 import 設備特定的 rc,設備又 import vendor 的 rc,層層嵌套。
MCP server 裡的 init.rc 工具讓我可以直接問:
「boot trigger 觸發了哪些東西?」
on boot
- system/core/rootdir/init.rc:1104
- device/amlogic/bluebell_wv4/init.amlogic.board.rc:31
- device/amlogic/common/initscripts/audio.rc:1
- device/amlogic/common/initscripts/bluetooth.rc:4
「zygote service 的完整配置是什麼?」
Service: zygote
Executable: /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server
Source: system/core/rootdir/init.zygote64.rc
Properties:
class: main
user: root
Sockets:
- zygote stream 660 root system
- usap_pool_primary stream 660 root system
On Restart:
- restart audioserver
- restart cameraserver
- restart media
這種查詢如果手動做,每次要 grep → 追蹤 import → 解析 multi-line block,至少 5 分鐘。MCP 一秒。
Framework Extension 的設計模式
分析過程中的一個副產物:我搞清楚了 AOSP 中 Framework Extension 的標準模式。如果你需要在 system_server 中加自訂服務,這個模式值得參考。
CustomSystemService (AIDL Stub)
├── Monitor modules # 讀取系統狀態
├── Policy Engine # 決策邏輯
├── Action modules # 執行動作
└── Callback Manager # 管理 listener
Build 配置的關鍵:interface library 用 sdk_version: "system_current",service implementation 用 sdk_version: "system_server_current"。搞反了會編不過但不會告訴你為什麼。
App 端用標準的 Manager pattern 存取——context.getSystemService(),跟 ActivityManager、PackageManager 完全一致。不要發明自己的 IPC 方式。
數字說話
| 指標 | 第一版 | 重構後 |
|---|---|---|
| 工具數 | 5 | 16 |
| 檔案數 | 1(890 行) | 12(各 50-150 行) |
| Magic numbers | 10+ | 0 |
| JSDoc 覆蓋率 | 0% | 100% |
| 可配置性 | 硬編碼 | 環境變量 |
| 日誌 | 無 | 分級日誌到 stderr |
最大的改善不是數字,是心態:第一版每次要改東西都怕搞壞其他功能;重構後每個模組可以獨立測試,改起來不會心驚膽跳。
如果你也想試
不是教學,是我踩完坑之後會給同事的建議:
-
別一開始就寫 MCP server。 先用 Claude Code 原生工具做幾輪分析,等你發現自己重複做同樣的查詢三次以上,再考慮自動化。
-
文檔不是副產品,是核心產出。 Claude 分析的結果如果沒寫進文件,下次 session 就蒸發了。每次分析都產出 markdown,這些文件的價值會隨時間複利成長。
-
分層處理。 247GB 的 codebase,你不可能一次看完。按照「核心服務 → Framework 擴展 → 平台整合」的順序,每層吃透再往下走。
-
假設都要驗證。 我以為 grep 就夠了、以為 Android.bp 是 JSON、以為 SELinux policy 都在同一個地方——全錯。每個假設都在實作中被打臉。
-
先能動,再漂亮。 890 行的第一版醜到不行,但它讓我驗證了「MCP 對 AOSP 分析有用」這個假設。確認有用之後再重構,不要在確認價值之前就追求完美架構。
結語
Claude Code + MCP 不會讓你「不用理解 AOSP 就能改 AOSP」——那是幻想。
它做的是把「理解 AOSP」這件事的門檻降低了一個量級。以前要花半天的依賴追蹤、SELinux policy 分析、init.rc 解析,現在幾秒鐘。
省下來的時間不是讓你偷懶,是讓你把認知資源花在真正需要判斷力的地方——架構決策。
參考資源
這是「AI Agent 架構實戰」系列的 Bonus 篇。上一篇:Cursor 的 $29B 秘密:被刪除的 Shadow Workspace 技術解密。下一篇:2026 AI Agent Memory Wars:三大流派的技術對決