前言
尽管Chromium 是一个开源项目,但其架构和内容异常复杂。直接深入研究就像看天书一样,尤其对于那些对C++代码不太熟悉的前端程序员来说。然而,借助我们在大学里学到的一些C++知识和通用的程序调试技巧,我们有机会从程序的启动阶段开始,逐步、有条不紊地理解Chromium 的整体结构。这包括深入了解其实现原理,如多进程架构 、网络解析 、以及blink排版布局引擎 等等。通过这样的学习过程,我们能够真正理解从输入URL到页面展示的整体流程 。在着手这些内容之前,我们首先需要学习如何使用visual studio 2022。
Chromium 编译
在之前的文章里(在Mac上编译属于你自己的Chromium),我介绍了如何在Mac编译Chromium。为了方便,这次我们选择在Windows上进行编译。编译方法在网上已经有比较全的攻略了,经过本人实验可行。具体可参考以下几篇文章(至少预留
100G的编译空间):
- win10 下载 Chromium 源码并编译(版本 103.0.5060.66)
 - windows下载,编译,运行chromium源码遇到的问题
 - 编译chromium时下载gn.exe时出错的解决方案
 - Chromium Windows 编译官方文档
 
我们以第一篇为主,主要为以下几步:
- 安装 Visual Studio 2022 Professional
 - 安装 Windows 11 SDK
 - 安装 depot_tools
 - depot_tools 初始化(
gclient) - 拉取代码(
fetch --no-history chromium) - 同步第三方依赖(
gclient sync) - 编译调试版浏览器
 - 编译正式版浏览器
 - 程序的断点调试
 
注意事项
在执行任何命令之前,如
gclient,记得先设置cmd的代理:
            
            
              shell
              
              
            
          
          set HTTP_PROXY=http://127.0.0.1:8888 // 改为你的代理地址
set HTTPS_PROXY=http://127.0.0.1:8888
        同时需要设置
NO_AUTH_BOTO_CONFIG,否则可能导致gn.exe下载失败
- 随便找个地方创建一个文本文件,比如 C:\boto.cfg,写入以下文本内容:(注意端口号换成你的代理端口)
 
            
            
              text
              
              
            
          
          [Boto]
proxy=127.0.0.1
proxy_port=1080
        - 设置环境变量,把这个文件添加到系统环境变量中:
 

拉取代码这一步,可不必按照
第一篇,而是参考第二篇文章:
            
            
              shell
              
              
            
          
           fetch chromium   //下载代码
 fetch --no-history chromium   //只下载最新版本
        其他步骤如
"编译配置"等,结合第一、二篇文章处理即可,最后编译完成后可以得到如下界面:(编译大概需要10小时)



Visual Studio 2022 调试指南
以管理员身份运行开始菜单 Visual Studio 2022 文件夹的 "x64 Native Tools Command Prompt for VS 2022" 程序:

执行以下命令(如果要调试多进程则把--single-process删除):
            
            
              shell
              
              
            
          
          devenv /DEBUGEXE D:\src\chromium\src\out\Default\chrome.exe --single-process
        功能界面
使用快捷键ctrl + o打开源码目录,选择源码文件,我这里以Chromium在Windows上的入口启动文件chromium\src\chrome\app\chrome_exe_main_win.cc为例。
断点
我们在401行处打上断点(鼠标点击行标左边空白区域即可)。此函数位于main函数中,是Chromium启动关键路径中的重要一环。

单击启动(或按F5):

程序会在我们设置的断点处暂停:

局部变量
左下角这部分是函数运行时局部变量的值,除了基础的布尔值和数字之外,还包括指针地址等,具有一定的参考性,但是我们在前期不必过多关注这块儿内容。

调用堆栈
右下角的区域是函数执行时的调用堆栈,箭头所指部分为当前正在执行的代码行,也就是我们打断点的地方。

我们可以也可以切换左下角的选项卡,查看我们标记的所有断点:

进/线程树
刚启动的时候是看不到并行堆栈的,也就是所有线程组成的线程树。我们需要点击调用堆栈中的查看所有线程按钮:

此时就会弹出线程树窗口,我们可以通过这颗树,更好的分析程序启动后所拉起的所有进/线程,对程序有更好的把控和分析。其中通过箭头来表示父子进/线程关系。

其中每一个框都是一个线程从开始创建后执行过的关键函数的调用栈,且Chromium中的函数名都非常语义化,这很有利于我们之后的分析。
可以根据个人喜好把窗口放到你喜欢的位置。
Tips: 在Chromium windows实现中:
- 通过
 CreateThread函数创建线程。- 通过
 CreateProcess或者ShellExecuteEx函数创建子进程。
多进程调试
Chromium是多进程架构,但是visual studio 2022默认只能调试程序的主进程,无法调试主进程创建的子进程,这时候可以通过插件来实现这部分功能,主要步骤如下:
- 安装 Visual Studio 扩展 Microsoft Child Process Debugging Power Tool 2022(安装时记得退出Visual Studio)
 - 配置插件:
 

将Enable child process debugging打上勾并保存即可:
 3. 重新启动调试,查看当前运行的进程ID:

或者打开一个单独的窗口查看:


这些进程都叫相同的名字chrome.exe,不好分辨,但我们可以一直调试下去,最终可以打开Chromium的任务管理器查看Chromium中启动的进程,与我们在进程tab中的id进行比较,就可以找到对应的渲染进程 、GPU进程 、插件进程 、网络进程等。

调试技巧
基础技能

:点击后执行到下一个断点处。
:点击后结束调试。
: 快速定位到当前正在执行的语句。
:进入当前函数调用栈。
:逐语句,不进入函数,一条代码一条代码的执行。
:跳出当前函数调用栈。
关键路径分析
先凭直觉每隔一大段距离找到一个你认为是关键函数调用的地方打一个断点,多打几个,然后从头执行。因为每一次断点执行,线程树中都会多很多的函数调用,这些调用在不同的线程中,形成不同的调用栈。我们可以从根出发,分析这其中的关键路径。
线程树调用堆栈分析
通过分析前后两个断点之间拉起的线程、进程,对线程中的堆栈函数进行分析,找出关键函数并跳转,打上断点。假如我们通过跳着打断点,最终捕捉到了线程栈中渲染进程 、Gpu进程 、以及其他辅助进程的启动过程:

在Chromium浏览器的源代码中,
content目录下有一些主要的入口点,其中包括RendererMain、GpuMain和UtilityMain。这些入口点负责启动Chromium浏览器的不同组件。以下是它们的简要描述:
- RendererMain: - 位于
 content/renderer/目录。 - 负责启动渲染进程。 - 渲染进程负责处理网页内容、JavaScript 执行等,每个标签页通常对应一个渲染进程。- GpuMain: - 位于
 content/gpu/目录。 - 负责启动GPU进程。 - GPU进程处理与图形渲染相关的任务,包括加速绘图、WebGL等。- UtilityMain: - 位于
 content/utility/目录。 - 负责启动一些辅助进程,通常用于处理一些特殊任务,如插件进程等。
那么我们就可以分别对这三个进程打断点,如:


由于Chromium是多进程,且启动后,就进入各种子进程的创建过程中,那么我们刚才打的这三个断点就很利于我们分析Chromium主子进程的启动过程。
ChatGPT
- 不懂的地方可以交给GPT来分析,如 :
chromium中有很多看不懂的C++语法,皆可扔给GPT,让他帮你解答。 - 结合你自己的疑惑给他提问,如 :
chromium源代码的main函数在哪儿,也就是启动的入口函数在哪儿? 

他的回答很具有参考意义,虽然在Windows平台上实际的main函数在chromium\src\chrome\app\chrome_exe_main_win.cc的wWinMain中,但也十分接近我们想要的结果了。
因此,结合GPT发挥自己的想象力!
最后
诚以此文献给所有对Chromium饱有热情的同学,希望通过此文能够帮助大家更好的学习如何调试Chromium,让阅读Chromium源码不再是那么遥不可及。