5 min read

247GB 的 Codebase,一個 AI,和一堆踩過的坑

Table of Contents

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:

  1. 核心服務層 — SDK 和預建 service
  2. Framework 擴展 — 系統服務擴展、AIDL interface
  3. 平台整合 — 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 mainuser rootsocket 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(像 selectsoong_config_variable)不是 JSON。Regex-based parser 可以處理 80% 的情況,剩下的 edge cases 需要特殊處理。

最終工具清單

類別工具數解決什麼問題
變更追蹤5「哪些 AOSP 檔案被我們改過?」
依賴分析3「這個模組的 build 依賴鏈是什麼?」
SELinux2「這個 domain 能存取什麼?」
系統服務2「哪些 service 跑在 system_server?」
Init.rc4「開機流程長什麼樣?」

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(),跟 ActivityManagerPackageManager 完全一致。不要發明自己的 IPC 方式。


數字說話

指標第一版重構後
工具數516
檔案數1(890 行)12(各 50-150 行)
Magic numbers10+0
JSDoc 覆蓋率0%100%
可配置性硬編碼環境變量
日誌分級日誌到 stderr

最大的改善不是數字,是心態:第一版每次要改東西都怕搞壞其他功能;重構後每個模組可以獨立測試,改起來不會心驚膽跳。


如果你也想試

不是教學,是我踩完坑之後會給同事的建議:

  1. 別一開始就寫 MCP server。 先用 Claude Code 原生工具做幾輪分析,等你發現自己重複做同樣的查詢三次以上,再考慮自動化。

  2. 文檔不是副產品,是核心產出。 Claude 分析的結果如果沒寫進文件,下次 session 就蒸發了。每次分析都產出 markdown,這些文件的價值會隨時間複利成長。

  3. 分層處理。 247GB 的 codebase,你不可能一次看完。按照「核心服務 → Framework 擴展 → 平台整合」的順序,每層吃透再往下走。

  4. 假設都要驗證。 我以為 grep 就夠了、以為 Android.bp 是 JSON、以為 SELinux policy 都在同一個地方——全錯。每個假設都在實作中被打臉。

  5. 先能動,再漂亮。 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:三大流派的技術對決