据报道称“浏览器内核有上千万行代码”,浏览器内核真的很复杂吗?

  • 据报道称“浏览器内核有上千万行代码”,浏览器内核真的很复杂吗?已关闭评论
  • A+
所属分类:今日新闻

据报道称“浏览器内核有上千万行代码”,浏览器内核真的很复杂吗?龙泉寺扫地僧,首席浏览器架构吹牛师,全球最小chromium内核--miniblink作者
阅读原文

这会儿正好在 rebuild chromium,机器卡到不行。看到这个问题有感来回答一下。

其他童鞋对于“浏览器内核真的很复杂”这个复杂的一面,已经回答的很的多了,但我想从“复杂”和“没那么复杂”两个方面都来讲讲,给大家提供一些别的思路和参考。

(如果觉得前文太长,也可以直接跳到最后看吐槽)

先说复杂。其他回答基本都是用 chromium 来举例的。我们来看 chromium,这货确实相当相当的复杂。源码拉下来就有十多 G。我们不禁好奇,chromium 到底有哪些玩意,为啥平时感觉只是显示个网页、几句 HTML 而已,怎么会需要这么多代码。

第一眼从目录结构上,chromium 包含这些东西:

  • base,通用代码,基础组件,包含字符串、文件、线程、消息队列等工具类集合。
  • cc,Chromium compositor 的缩写,负责渲染合成。
  • chrome,Chromium 浏览器外壳实现。
  • content,多进程沙盒浏览器的核心代码,管理进程架构和线程架构。
  • gpu,OpenGL 封装代码,包含 CommandBuffer 和 OpenGL 兼容性支持等。
  • net,网络栈实现。
  • ipc,进程间消息通信实现。
  • media,多媒体封装代码,包含了媒体内容捕获和播放的组件集合。
  • mojo,类似于 Android 的 AIDL,提供了跨语言(C++ / Java / JavaScript)跨平台的进程间对象(Object)通信机制;。
  • skia,图形库,这里存放的是 Chromium 对 skia 的 配置和扩展代码,另有 third_party/skia 目录存放原生的 skia 代码。
  • third_party,网页排版引擎。第三方库
  • ui,UI 框架。
  • v8,V8 JavaScript 引擎库。

看起来还好吧?但实际上,这里面每一个展开来讲,都是一本厚厚的工具书的容量。

比如 net,看起来只是个网络库,然而里面包含主机解析,cookies,网络改变探测,SSL,资源缓存,ftp,HTTP, OCSP 实现,代理 (SOCKS 和 HTTP) 配置,解析,脚本获取(包括各种不同系统下实现),QUIC,socket 池,SPDY,WebSockets……里面每一项展开来讲,又是一本书。

v8 层,看起来功能很单一,只是实现一下 js 嘛,但里面包括字节码解析器,JIT 编译器,多代 GC,inspector (调试支持),内存和 CPU 的 profiler(性能统计),WebAssembly 支持,两种 post-mortem diagnostics 的支持,启动快照,代码缓存、代码热点分析……里面每一项展开来讲,又是一本书,还是难坑的编译原理和优化方向。

Skia,看起来只是个图形库嘛,用点画出各种图。然而里面包括十几种矢量的绘制,文字绘制、GPU 加速、矢量的指令录制以及回放(还要能支持线程安全)、各种图像格式的编解码、PDF 的生成(这个是个隐藏的很深的功能,但很有趣。Skia 支持把矢量图绘制成 pdf)、GPU 渲染优化(既以上部分功能需要用 gpu 来渲染)……里面每项展开来讲,又是一本书。另外值得一提的是,skia 是谷歌收购的。不知道谷歌是觉得自己没实力做,还是太费功夫。总之谷歌选择了直接买别人的代码来完成这些功能。

ui,看起来只是一套 UI 框架嘛。然而 chromium 需要一套全平台适配的 ui 库,还要能支持 gpu 加速。不过可惜的是里面没实现 richedit。ui 库的设计,深入来做,其实可以说又是个浏览器了。

等等,以上这些,看起来只是浏览器的外层。我们最关心的网页排版呢?这个难道不是浏览器的核心嘛。是的,chromium 奇特的把排版引擎 blink 放到了 third_party 下,而且真的当成了一个第三方库一样对待。据谷歌的员工说,这是历史原因……好吧姑且信了。然而这个第三方库,成了当之无愧的最复杂,功能最重要的第三方库。

blink 的工作包括:

  • 实现 web 平台的规范(例如,HTML 标准),包括 DOM,CSS 和 Web IDL
  • 配合 V8 运行 JavaScript
  • 从底层网络堆栈请求资源
  • 构建 DOM 树
  • 计算样式和布局
  • 请求 chrome compositor(上文提到的 cc 层)并绘制图形。

说起来简单。看一下现在的 HTML、CSS 规范,各种细节加起来……有快上万页。除了 chromium layout 组、firefox 的工作人员,我想没几个人会去仔细阅读并一个个的实现这些规范吧。光是看目录和文字描述,就头大了,更别说要完整的实现出来。往往一个简单的 display:girdflex 背后就是庞大复杂的计算,而且还要充分考虑性能上如何优化,滚动时如何更快的展示…

另外排版还需要支持世界各国的奇奇怪怪的文字。例如从右往左写、规则复杂无比阿拉伯文,天城文。相比之下,汉字这种方块字的排版简直就是弟弟。还有各种奇怪的 unicode 字符。

【转】奇怪的 unicode 字符

据报道称“浏览器内核有上千万行代码”,浏览器内核真的很复杂吗?

怎么能处理好这些字符和语言,并配合几千页的 html、css 排版规则正确显示出来……这是个极度烧脑的事情。

我们再从排版这个大泥坑里跳出来看看外面别的东西。这时候你会发现……原来外面的泥坑好像更大。

随便说几个,比如:

  • 多进程框架。嗯,你需要更多的进程来渲染更多的网页,这样才能崩溃了也不影响其他网页。注意,chromium 把渲染排版放在渲染线程,但绘制到窗口又是主进程。这里面少不了各种跨进程通信、同步。对于代码的编写以及调试,是个很考验编程功底的事情。
  • webrtc。网络视频相关。又是一个被收购的库。关于 webrtc,你需要知道它能实现多人实时语音、降噪、网络传输视频、摄像头的捕获,音频算法实现(比如 fft),视频算法实现(比如 h264 协议格式), Socket、线程、锁等基础库(是的,webrtc 也造了套自己的轮子)。又是个庞大的组件。
  • 密码管理、下载管理、扩展管理。
  • 一套调度整个多进程框架以及 blink 的核心层。在 chromium 被称之为 content 层。负责处理了一切繁琐的细节,例如各种系统、平台的鼠标键盘消息派发,历史栈(前进后退),页面缓存。
  • 沙箱机制。负责隔离以及降低子进程的权限。沙箱的实现上,在不同系统做了诸多 hook 操作。
  • chrome 相关的外壳及应用。例如我们常见的标题栏、url 栏,webui 如设置页、历史记录页。对,其实 chrome 单词的原意就是这个。
  • Clound_Print,谷歌云打印相关,提供谷歌浏览器页面预览打印清单。
  • Courgetter,谷歌提供的二进制文件对比核心算法,在谷歌浏览器中用于比较不同版本的二进制差异。谷歌为了方便升级,搞了套升级策略和算法。
  • 神奇的 syzygy 优化。是的,谷歌也嫌 chrome 太大了,加载太慢了。于是他们开发的一套优化重排布 PE 二进制文件来达到优化程序的工具链。Chrome 浏览器应用了 Syzygy 优化之后,程序冷启动的页面调度(paging traffic)优化了 80%,加载的 Image 的 Working Set 优化了 40%。简单的说,谷歌从编译器上对 exe、dll 开始做手脚了。
  • Media Chrome 的多媒体模块,支持音频播放和录音等功能。这里用到了 ffmpeg。但在 ffmpeg 外,为了和 blink 配合,又是包裹了厚厚的一层,用来处理好渲染管线。另外 MSE API 也花了不少功夫。
  • swiftshader。很有趣的一个模块,用纯软件的代码,完整实现了 opengl 的接口。可以在没有硬件加速的机器上跑起 opengl。也是个庞大的库,而且也是被收购的。看起来谷歌对图形学方面的很多工程似乎不擅长?还是不想觉得应该交给更专业的团队去做。
  • gn、gyp。chromium 为了更方便的管理编译,自己撸了两套轮子。类似 makefile、cmake。

其他的点还有很多很多,以后想到了再补充。总之,以上随意一个点,要正确的实现,都是一个团队的工作量,都可以写成一本书。然而 chromium 把他们全部实现了,而且还在不停的加入新的功能。

看到这里,大家应该明白为啥强如微软,也放弃维护他们自己的浏览器内核了。因为需要投入的人力财力实在是太恐怖了。chromium 团队,光是开发人员,都已经上千了。假如每个人员年薪是 100w 人民币,持续投入十年,这个支出就是几十亿,这还不算周边的测试、产品、UI。最关键的是,就算微软愿意投入十亿,能保证做到 chromium 相同的功能吗?就算能做到相同的功能,还不是另外一套 chromium 吗?能做出其他优势吗?所以最后微软也放弃了,干脆直接从开源的 chromium 上改起,把微软需要的功能融入 chromium。

所以,chromium 的霸权就是这么来的。看似开源免费,实则把所有开发者和对手,紧紧的捆绑在自己周围。

好了,现在吐槽开始了。

chromium 称霸浏览器界以来,看起来开源,谁都可以拿去改。然而比起它的前辈,我觉得从“道德”上,chromium 要“差”很多。最让我受不了的一点是,chromium 在无尽的往里面塞功能的时候,很少想过是否别人可以轻易的移除它们。chromium 代码号称模块化、高内聚低耦合,然而如果你想砍掉一些不需要的东西,对不起,没有宏控制,手动注释代码吧。有几个人能有精力一点点的去掉里面这些繁琐的功能呢?这就导致一个问题,需要 chromium 某一部分功能的人,必须被强塞进一堆谷歌认为你需要的东西。

对比之下,为啥我说比起 chromium 的前辈要差很多呢,其实我指的正是 webkit。webkit 最让人欣赏的一点就是它在专注实现内核的同时,大部分功能都是可“拆卸”的。有宏可以关闭。甚至连 svg 这种排版上的小功能都有宏可以关闭。而 chromium,如果我需要排版、音视频,但不需要多进程呢?对不起,谷歌没这考虑。要带就全都带上吧。

这也就造成现在基于 chromium 的一堆开发框架,如 electron、cef、nwjs,全都动不动 100 多 M 的大小。因为从 chromium 的框架设计上,就很难把那些极其庞大复杂的细节功能排除掉。这些功能对于谷歌作为一个浏览器来说,当然是必要的。然而回到本问题,“浏览器内核”真的需要这么复杂吗?浏览器需要这么复杂,这是真的;然而作为一个浏览器内核提供给一些 sdk 给别人用,也需要这么复杂吗?我们用 electron 写一套进供销管理系统的客户端,你会需要带上十几 M 的 webrtc、webgl、多媒体播放、天城文支持吗?

最后打破这个疑问的,是我很多年后进入了 QQ 浏览器的移动端组(其实就是 x5 内核,微信上被大家吐槽最多的那个)。当年的 x5 内核其实是基于 webkit 改造的。从 chromium 回到 webkit,我突然有种豁然开郎的感觉。从浏览器内核的角度,只要做好网络、排版、渲染,就足以应付大部分使用场景了。

然而后来组里架构调整,x5 内核为了跟上时代,也从 webkit 跳回了 chromium(也是被骂了太多了,当时 x5 号称移动端 IE6)。对 chromium 深恶痛绝的我,当时有了一个大胆的想法。把排版引擎 blink(也就是 webkit 在 chromium 里的继承者)重新从 chromium 里剥离出来,再补上一些周边的设施、组件,再次成为一个完整独立的浏览器内核。

当然我还是有自知之明的。一个浏览器内核而已,不可能实现 chromium 同样的功能。但能把排版、渲染、网络、视频实现,就差不多了。其实我也不是想做个浏览器,而是想专注内核这块,做一个提供给第三方 app 嵌入的内核。

作为一个内核,其实不需要上面讲的所有那一大堆功能。比如,网络层,大部分人不需要什么网络改变探测,ftp,OCSP 实现,代理配置、解析、脚本获取,QUIC,socket 池,SPDY 什么的。大部分人仅仅需要一个 http 的实现,可以拉取到服务器资源。我用 300k 的 curl 代替了十余 M 的 chromium net 库,并工作良好。少了的功能可以用插件形式补上嘛。一些和排版渲染无关的功能,我都打算做成插件。例如音视频、webgl、webrtc、多进程等。

目前这个项目已经撸了 5 年了,放在 github 上,提供 C 接口方便其他语言调用。整个编译出来就是一个 1-20m 左右的 dll(视编译选项而定),甚至还包含了一个 electron 的精简实现:

weolar/miniblink49

欢迎围观。

阅读原文
weinxin
我的微信
这是我的微信扫一扫