AndroidChromium源码编译全攻略:从解压到APK生成与最小定制
2026/9/17 3:55:44 网站建设 项目流程

简介:这份Android Chromium浏览器源码面向Android应用开发者与浏览器内核研究者,是剖析Chrome在移动端运行机制的一手材料。压缩包为rar格式,大小约30.91MB,轻量易下载;目前已有673人学习。通过阅读源码,可重点研习V8引擎的JIT编译与垃圾回收、Blink渲染引擎的HTML/CSS解析与绘制流程、多进程架构下的IPC通信、HTTP/2网络请求与缓存策略,以及Chromium与Android系统的深度集成方式。此外,预加载、预渲染、内存池等性能优化手段和安全沙盒机制也完整呈现,能帮助开发者掌握从页面加载到渲染绘制的完整链路,为开发高性能、高稳定性的移动应用提供直接参考。

1. AndroidChromium 源码是什么,为什么值得花时间解压它

一个叫android应用源码---浏览器源码(AndroidChromium).rar的压缩包,解压之后的体积通常会让人怀疑自己是不是装错了东西。它不是一个能用 Android Studio 直接打开的普通 App 工程,而是 Chromium 项目针对 Android 平台维护的完整移植版源码树:浏览器 UI、渲染引擎、网络栈、GPU 进程、安全沙箱、V8 JavaScript 引擎全部都在里面。这意味着两件事:第一,它的构建方式与绝大多数 Android 应用完全不同,入口是 GN 加 Ninja,而不是 Gradle;第二,你能在这套源码里看到的不只是一个“浏览器 App”,而是一种多进程架构在产品代码里的落地形态。如果你正在做 Web 内核封装、系统 WebView 定制,或者想研究 Android 平台上 Java 与 C++ 的 JNI 协作,这套源码比任何二次封装的开源浏览器都更值得花时间读进去。

2. AndroidChromium 源码的准备:从压缩包到可编译目录

2.1 先看清压缩包里的工程是哪种形态

拿到压缩包后第一件事不是写代码,而是确认它的形态。Chromium 源码体积太大,打包者在打包时通常会做两类处理:一类是包含.gclient配置文件但没拉全依赖的仓库根目录,这类解压后还需要走一次完整的gclient sync;另一类是已经 sync 完毕、只把src/目录压缩起来的快照,这类省去了最耗时的代码同步,但编译所需工具链仍然要单独准备。

区分方式很简单:在解压目录下执行ls -la,如果能看到src/目录而且里面已经有BUILD.gn,说明依赖基本在;如果只有.gclient和若干脚本,说明它只是仓库骨架。我一般会把这两类包当成不同流程处理:前者重点调gclient,后者重点跑 hooks。无论哪种,都不要试图用 Android Studio 的 “Open an existing project” 直接打开,这里没有settings.gradle,它认识不了这套构建组织方式。

2.2 Chromium for Android 源码目录地图

面向 Android 平台看这个源码树,最先要记住的不是全部目录,而是下面这七块核心区域。它们各自管一件事,修改时定位问题也用得上。

目录主要职责什么时候需要动它
base/文件、线程、字符串、内存等基础设施需要替换系统调用或加全局日志时
net/网络栈:HTTP/2、QUIC、代理、Cookie 管理调整网络协议行为或截获请求时
content/public浏览器进程与渲染进程之间的核心接口把内核能力暴露给上层封装时
chrome/android浏览器 UI 的 Java 与 Native 实现改界面、改入口、加浏览器功能时
content/public/androidAndroid 侧 JNI 入口与辅助工具需要从 Java 调原生能力时
components/*/android各类功能模块的 Android 分支单独换下载、书签、自动填充模块时
android_webview/以系统 WebView 形态封装整个内核要做 WebView 而不仅是浏览器时

这些目录的层级关系是:base垫底,netcontent在它上面,chrome又依赖content。Android 专用代码不会单独游离在整个框架之外,而是以android目录或*_java目标的形式插进对应模块,阅读时要有“同一个模块同时存在 Java、C++、JNI 三部分”的心理预期。

2.3 depot_tools 是这套源码的构建入口

depot_tools是 Chromium 体系的工具集,对外最重要的三个可执行文件是gclientgnninjagclient负责管理多个 git 仓库之间的依赖关系,gn负责生成构建描述,ninja负责真正执行编译。AndroidChromium 源码里不会自带 depot_tools,需要单独克隆。

cd androidchromium git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git export PATH="$PWD/depot_tools:$PATH" export DEPOT_TOOLS_UPDATE=0 # 若压缩包带 .gclient,只做依赖同步; # 若 src 已在包内,这一行也会补充遗漏的嵌套仓库 gclient sync --nohooks

这段命令里真正值得解释的是环境变量和--nohooksDEPOT_TOOLS_UPDATE=0会让 depot_tools 停掉自动更新;没有这一行,每执行一次工具都会先尝试把自身切到最新版本,而新版工具对 Python 和系统库的要求可能与你当前环境冲突,这是很常见的“昨天还能跑,今天莫名其妙报错”的原因。gclient sync根据根目录下的.gclient文件,把 Chromium 依赖的几百个仓库同步到各自固定 revision;--nohooks表示“只拉代码,不执行后续的下载和脚本操作”,这样可以把同步失败与 hooks 失败分隔开,排错时少一半干扰。

2.4 系统依赖与 hooks:真正耗时的长尾

代码同步完成只是第一步。Chromium for Android 编译需要 Clang 工具链、Android NDK、sysroot,以及若干辅助包,这些由 DEPS 文件定义、在 hooks 阶段被拉取。直接把这一步跳过的后果是gn gen报一堆“missing xxx”错误,而且错误信息不直观。

build/install-build-deps-android.sh # 安装系统级编译依赖,需要 sudo gclient runhooks # 下载 LLVM、sysroot 等构建工具链

install-build-deps-android.sh是 Chromium 官方提供的脚本,会自动识别发行版并安装编译需要的系统库;如果你在一个新容器里构建,它比手工逐条apt install可靠得多。gclient runhooks幂等,中断后重跑就行,不需要回滚之前同步的仓库。这里有一个容易被忽略的点:runhooks下载的内容量和代码本身一样大,建议在磁盘余量充足的分区上执行,通常预留 80 GB 以上再动手。磁盘满导致的ERR_FILE_NOT_FOUND很容易被误判成网络问题,实际上只要删掉部分缓存再重试即可。

3. AndroidChromium 的源码架构:从 content 层读到 chrome/android 层

3.1 一条清晰的分层线

AndroidChromium 不是“界面层 + WebView 外壳”的传统浏览器 App,而是把浏览器内核和 UI 放在同一个进程模型里分层管理。从源码目录角度看,最典型的一条链是base -> net -> content -> chromecontent层负责多进程、页面渲染、资源加载这些核心能力;chrome层负责地址栏、书签、设置这些浏览器产品功能。你改变页面加载逻辑,动content;改标签页交互,动chrome

这条分界线在标识符上也很直观:content暴露给上层的是WebContentsBrowserContextNavigationHandle这些偏底层的概念;chrome层面出现的是ChromeTabbedActivityTabModelOmnibox这类偏产品化的概念。阅读源码时如果看到一个类不知道属于哪层,先看它的 import 里有没有org.chromium.chrome,再决定改的时候要遵循哪一层的接口约束。

3.2 Android 特有目录:Java UI、Native 服务与 JNI 桥

Android 平台的特殊性在于:UI 必须是 Java,渲染内核几乎全是 C++。AndroidChromium 的处理方式是把 Java 层做薄,Native 层做厚,二者通过 JNI 搭桥。这里有一张基于常见版本整理的目录对照表,能帮你在 grep 代码时不至于找错地方。

目录内部角色常见文件或目标
chrome/android/java/src/org/chromium/chrome/browser/浏览器 UI 主线程与各组件入口ChromeTabbedActivity.java
chrome/browser/android/浏览器侧 Native 状态与 JNI 反向回调*_jni_headers生成物
content/public/android/content 内核暴露给 Java 的接口ContentMain.javaWebContents.java
content/browser/android/浏览器进程中 content 层的原生实现Binder、进程通信相关源码
components/下载、书签、自动填充、安全检测等业务模块各组件自己的android/
android_webview/把内核封装成系统 WebView APIAwBrowserContext.java

JNI 桥在这套工程里不是零散存在的,而是用@NativeMethodsgenerate_jni工具自动生成既有声明又有实现的绑定代码。修改 Java 层新增一个 native 方法时,通常只需要在 Java 文件里写带@NativeMethods的接口,构建系统会生成对应的 C++ 头文件。这与直接手写JNI_OnLoad和在jni.h里登记函数完全不同,习惯普通 Android JNI 方式的人一开始会找不到“注册函数”,这是正常现象。

3.3 从入口 Activity 反推一条调用链

无论是排查启动问题还是改启动流程,都要先找到入口。Chromium 的 Android 入口类历次重构后位置略有变化,最快的方式不是记路径,而是在源码里用一次 grep 定位。

grep -rn "class ChromeTabbedActivity" --include="*.java" chrome/ | head -5 find chrome/ -name "*ChromeTabbedActivity*" -type f 2>/dev/null

第一条命令用文件名和类名双重匹配,能在几秒内定位到当前版本的真实路径;第二条命令把可能存在的构造相关文件也带出来。定位到文件之后,从onCreate往后的调用链大致是:ChromeTabbedActivity创建TabModelSelectorTabModelSelector维护多个Tab,每个Tab里持有WebContents,而WebContents才是真正对应到渲染进程的容器。看到这条链你就会明白,想在 AndroidChromium 里“打开一个网页”并不是简单地 setContentView 加 WebView,而是要在 Java 层准备好 tab,再把 URL 通过WebContents下发到渲染进程。

3.4 用 gn ls 建立组件地图

阅读大型源码时,最怕的是不知道哪些东西“可以编译”。Chromium 里所有可构建产物都叫 target,分布在各个目录的BUILD.gn文件中。用gn ls可以列出指定目录下的 target,这是比看文档实时得多的摸排方式。

gn ls out/Release | grep -E "chrome_public|chrome_apk" | head -20

out/Release是上一章生成过的构建目录,gn ls会读取该目录的构建配置,列出实际上能被 Ninja 识别的目标。grep -E "chrome_public|chrome_apk"把浏览器 APK 相关目标筛出来;如果你想了解自己解压的这个压缩包有没有附带 WebView,可以把过滤词换成system_webview。这样做的价值在于:源码树里的同名目录可能有好几个 target,只有经过 GN 解析、被构建系统接受的 target 才是你在改完代码后真正会编译的那个。

4. 用 GN 配置、编译 AndroidChromium APK 的关键参数

4.1 为什么是 GN 而不是 Gradle

普通 Android 工程用 Gradle 管理依赖和构建变体,AndroidChromium 用的是 GN 加 Ninja。GN 负责在BUILD.gn文件里做依赖分析与参数解析,产出build.ninja,Ninja 再根据这份文件做增量编译。两者定位不同,GN 更接近 CMake,Ninja 更接近 Make,但它们都不负责依赖下载,依赖是gclient管的事。所以常见的错误认知“改完 JAVA_HOME 再 sync 一下就能编译”,在这里是行不通的;GN 参数、gclient 依赖、系统工具链三者分别生效。

4.2 常见 GN 参数表

编译 AndroidChromium 前,必须先建一个args.gn文件。它位于构建目录下,例如out/Release/args.gn,里面是以键值对形式写的构建参数。下面这份是我在一台 8 核 16 GB 的 Linux 机器上验证过的最小配置,适合出 Debug 包和做源码调试。

参数推荐值作用
target_os"android"声明构建平台,漏掉会走 Linux 桌面逻辑
target_cpu"arm64"真机用 arm64,模拟器可用 x64
is_debugtrue开启调试符号和关闭优化,方便断点
is_component_buildfalseAndroid 下必须保持 false,组件动态库不支持
symbol_level1符号级别,0 最小、1 可回溯、2 最全
android_channel"stable"渠道名,影响默认包名与渠道标识
fieldtrial_testing_liketrue关闭随机抽样,行为更容易复现

target_cpu很值得单独说。如果你打算在模拟器上调试,用x64会比 arm64 快很多,但 APK 不能安装到真机上;反过来,arm64 的包在模拟器上会走转译,启动慢且有些拖沓。symbol_level是一个性价比比较高的参数:2的调试体验最完整,但会让链接时间和包体明显上涨;日常验证用1,遇到 Native 崩溃再临时改成2重新编译。

4.3 生成构建目录并开始编译

参数写好后,执行gn gen生成构建描述,然后直接autoninja编译目标。这里建议用多行 args 文件而不是一长串--args,因为参数一旦变多,命令行转义很容易出错。

mkdir -p out/Release cat > out/Release/args.gn <<'EOF' target_os = "android" target_cpu = "arm64" is_debug = true is_component_build = false symbol_level = 1 android_channel = "stable" fieldtrial_testing_like = true EOF gn gen out/Release autoninja -C out/Release chrome_public_apk

gn gen out/Release做的事是解读当前目录所有BUILD.gn,结合out/Release/args.gn生成build.ninjaautoninja是 Ninja 的封装,会自动根据机器核数计算并发,比直接敲ninja更不容易压垮内存。chrome_public_apk是浏览器 APK 的构建目标,产物会出现在out/Release/apks/ChromePublic.apk。首次编译通常要跑一两个小时,这不是死机,Ninja 会持续输出编译进度;如果中间某次失败,修完参数后重新执行autoninja只会增量编译失败点之后的 target,不需要从头再来。

4.4 构建期最常见的三类失败

第一类是args.gn参数拼写或取值不合法,典型报错是ERROR at //build/config/android/config.gni。这类问题通常出在抄了网上旧版本的参数组合,比如is_component_build=true在 Android 上已经不被支持,删掉那行重新gn gen即可。

第二类是依赖缺失,报错表现为编译到某个模块时提示找不到头文件或资源文件。常见原因是gclient sync --nohooks跳过了 hooks,导致src/third_party/下部分工具链没拉全。解决方式是回到仓库根目录执行gclient runhooks,不一定要重新 sync 全部仓库。

第三类是构建过程内存不足,表现为 Ninja 在链接阶段突然中断,日志尾部能看到internal compiler error: Killed。常规缓解手段是把并发调低,例如:

autoninja -C out/Release -j2 chrome_public_apk

-j2表示只开两个并发任务。8 核机器默认并发 8,但一个 C++ 链接动作就能吃满 4 GB 内存,并发一高很容易被系统 OOM。代价是编译时间变长,不过总比重启机器重跑来得可控。

5. 拿到 AndroidChromium 构建产物后:验证、联调与最小定制

5.1 安装与确认 APK 可用

编译成功不等于 APK 能安装进所有机器。Chromium 的 Debug APK 默认使用org.chromium.chrome作为包名,这个包名在部分厂商 ROM 上可能被预装组件占用,需要先卸载旧版本再安装。

adb install -r out/Release/apks/ChromePublic.apk adb shell monkey -p org.chromium.chrome -c android.intent.category.LAUNCHER 1 adb logcat | grep cr_ | head -50

adb install -r-r表示覆盖安装,如果提示签名冲突,先adb uninstall org.chromium.chrome再装。monkey是一个不起眼但很有用的启动命令:-p org.chromium.chrome限定包名,-c android.intent.category.LAUNCHER指定启动入口,最后一个数字1表示只触达一个 Activity,不会像压力测试那样产生大量随机事件。启动后大概率能在 MainActivity 的调用链上看到标签cr_,这是 Chromium 在 Android 上统一的日志前缀,用它过滤比直接看全量 logcat 有效得多。

5.2 一条改完就能重新编译的最小定制路径

如果你只是想做一次“改源码再编译成功”的验证,不要一上来就改界面布局。最便宜的改法是替换默认搜索引擎或主页字符串。Chromium 的搜索引擎预置数据集中在components/search_engines/下,先用 grep 找到预置 URL:

grep -rn "google.com" components/search_engines/ --include="*.cc" --include="*.json" | grep -v test | head

把命中文件里的google.com替换成目标站点,重新编译chrome_public_apk,安装后触发一次搜索就能看到效果。这条路径改动范围小、编译时间短、出错了也好恢复。对比之下,直接改ChromeTabbedActivity的布局风险很高,因为它的 view 构建依赖大量模板资源和自适应逻辑,改一行 XML 可能引发整条启动链不稳定。

如果你的最终目标不是“改造一个浏览器”,而是“让自己的 App 拥有 Chromium 内核”,可以少走几步:直接构建system_webview_apk并用它替换系统 WebView,或者在此基础上封装自定义 WebView 接口。AndroidChromium 这套源码的价值并不是给你一个开箱可用的浏览器,而是让你在需要内核级能力时,不用从地址栏反推到底层。编译出一个能安装、能 grep、能改参数的 APK,后续再深入就只是时间问题了。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询