再看开源的chromium,确实比较复杂。源码十几G,不禁让人好奇,chromium有什么特点?为什么平时感觉就是显示一个网页和几句HTML?为什么需要这么多代码?乍一看,从目录结构上看,chromium包括这些东西:base,公共代码,基本组件,包括字符串、文件、线程、消息队列等工具类的集合。cc是Chromiumcompositor的缩写,负责渲染和合成。chrome,Chromium浏览器shell实现。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,V8JavaScript引擎库。看起来还好吗?但实际上,里面的每一次扩展,都是一本厚厚的参考书的容量。比如net,看似只是一个网络库,但它包含了主机解析、cookies、网络变化检测、SSL、资源缓存、ftp、HTTP、OCSP实现、代理(SOCKS和HTTP)配置、解析、脚本获取(包括各种不同系统下的实现),QUIC,socketpool,SPDY,WebSockets……每一项都是一本书。v8层看似功能单一,只是实现了js,但是包含了字节码解析器,JIT编译器,多代GC,inspector(调试支持),memoryandCPUprofiler(性能统计),WebAssembly支持,两种post-mortemdiagnosticssupport,启动快照,代码缓存,代码热点分析……就里面的每一项来说,都是另外一本书,编译原理和优化方向还是很难坑。Skia,看起来只是一个图形库,用点来画各种图。但是,它包含了十几种矢量绘图、文本绘制、GPU加速、矢量指令录制和回放(以及线程安全支持)、各种图片格式编解码、pdf生成(这是一个隐藏很深的功能,但是它很有意思,Skia支持将矢量图绘制成pdf),GPU渲染优化(上面的部分功能需要用GPU渲染)...里面的每一项都是一本书。另外值得一提的是,skia是被谷歌收购的。不知道谷歌是觉得自己没有力气去做,还是太费功夫了。总之,谷歌选择了直接购买别人的代码来完成这些功能。ui,好像只是一套UI框架。但是chromium需要一套适配全平台的ui库,还必须支持gpu加速。但是很遗憾里面并没有实现richedit。ui库的设计,如果做的深入,其实可以说又是一个浏览器。等一下,以上这些,看起来只是浏览器的外层。我们最关心的网页布局呢?这不就是浏览器的核心吗!是的,神奇的是chromium把排版引擎blink放在了third_party之下,在架构上真的把它当成了第三方库。按照谷歌员工的说法,这是一个历史原因……好吧,让我们认为这是理所当然的吧。但是,这个第三方库却成为了最复杂的第三方库,功能也是最重要的。Blink的工作包括:实现Web平台规范(例如HTML标准),包括DOM、CSS和WebIDL,使用V8运行JavaScript,从底层网络堆栈请求资源,构建DOM树,计算样式和布局请求,以及chrome合成器(上面提到的cc层)和绘制图形。这很容易说。看看现在的HTML和CSS规范,所有的细节加起来……差不多有几万页。除了chromiumlayoutgroup、firefoxdevelopers等,我想很少有人会仔细阅读并一一执行这些规范。光是看目录和文字说明都让人头疼,更别说完全体会了。往往在简单显示的背后:grid\flex是一个庞大而复杂的计算,还需要充分考虑如何优化性能,如何在滚动时更快地显示……另外,排版还需要支持来自各种奇怪的文字全世界。例如,阿拉伯语是从右向左书写的,规则极其复杂。相比之下,像汉字这样的方块字的排版就如同弟弟一般。还有各种奇怪的unicode字符。如何处理这些字符和语言,并用上千页的html和css布局规则正确显示……这是一件极其烧脑的事情。让我们跳出排版这个大泥坑,看看外面的其他东西。这时候,你会发现……外面的泥坑好像变大了。随便说几个,比如:多进程框架。好吧,你需要更多的进程来渲染更多的网页,这样它才能在不影响其他网页的情况下崩溃。注意,chromium将渲染和排版放在了渲染进程中,但是绘制到窗口才是主要进程。这里少不了各种跨进程通信和同步。对于代码编写和调试来说,是对编程能力的考验。webrtc。网络视频相关。另一个收购的图书馆。关于webrtc,你要知道它可以实现多人实时语音、降噪、网络传输视频、摄像头抓拍、音频算法实现(比如fft)、视频算法实现(比如h264协议格式)、Socket,thread,lock等基础库(是的,webrtc也自己造了一套轮子)。另一个笨重的组件。密码管理、下载管理、分机管理。一套调度整个多进程框架和blink的核心层。在Chromium中,它被称为内容层,负责处理所有繁琐的细节。例如,各种系统和平台的鼠标和键盘消息分发,历史堆栈(向前和向后),页面缓存。沙盒机制。负责隔离和减少子进程的权限。在沙箱的实现中,在不同的系统中做了很多hook操作。与Chrome相关的外壳和应用程序。比如我们常见的标题栏,url栏,webui比如设置页,历史页。是的,其实chrome这个词的本义就是这个。Clound_Print,与谷歌云打印相关,提供谷歌浏览器页面预览打印列表。Courgetter是Google提供的二进制文件比较核心算法,用于比较不同版本的二进制差异。为了方便升级,谷歌制定了一套升级策略和算法。出色的syzygy优化。是的,谷歌也认为chrome太大,加载太慢。因此他们开发了一个工具链来优化重新排列PE二进制文件的算法,以实现优化程序。Chrome浏览器经过Syzygy优化后,程序冷启动的分页流量优化了80%,加载图片的工作集优化了40%。简单来说,谷歌为了优化启动性能,从编译器开始对exe和dll进行操作。Media是Chrome的多媒体模块,支持音频播放、录音等功能。这里使用了ffmpeg。但是在ffmpeg之外,为了配合blink,又包裹了厚厚的一层来处理渲染管线。此外,MSEAPI也花了不少功夫。迅捷着色器。一个非常有趣的模块,使用纯软件代码,完全实现了opengl接口。您可以在没有硬件加速的机器上运行opengl。同样是一个巨大的图书馆,也被收购了。似乎谷歌在图形方面不擅长很多工程?我还是不想觉得应该交给更专业的团队。gn,gyp,忍者。为了更方便的管理和编译,chromium滚动了三组轮子。类似makefile,cmake,然后在底层调用ninja,然后到vs或者clang去负责具体的编译。还有很多其他的点,以后想到了再补充。总之,以上任何一点要落实到位,都是一个团队的工作量,可以写进书里。然而,Chromium已经实现了所有这些,并且仍在添加新功能。看到这里,大家应该明白为什么他们强如微软,而放弃维护自己的浏览器内核了。因为需要投入的人力财力实在是太恐怖了。仅Chromium团队就有数千名开发人员。如果每个员工的年薪是100万元,持续投入十年,支出将是数十亿,还不算周边的测试、产品、UI。最关键的是,就算微软愿意投入十亿,也能保证和chromium一样的功能吗?就算能实现同样的功能,又不是另外一套chromium,能不能做出其他的优势呢?所以最后微软也放弃了,索性从开源的chromium改过来,把微软需要的功能集成到chromium中。所以,Chromium的霸权就是这么来的。它看似开源免费,但实际上将所有的开发者和反对者紧紧地捆绑在自己的周围。好的,现在开始咆哮。由于Chromium已经统治了浏览器世界,它似乎是开源的,任何人都可以使用它来修改它。然而,与它的前辈相比,我认为Chromium在“道德”方面“差”了很多。最让我困扰的是,当Chromium无休止地往里面塞功能的时候,它很少考虑别人是否可以轻易地删除它们。chromium代码号称模块化,高内聚低耦合,但是如果要砍掉一些不需要的东西,不好意思,没有宏观调控,手动删除代码。又有多少人能有精力一点一点去掉这些繁琐的功能呢?这导致了一个问题。需要某一部分铬的人必须被迫进入谷歌认为你需要的一堆东西。相比之下,为什么我说它比chromium的前辈差很多呢?其实我指的是webkit。webkit最让人佩服的地方在于,虽然它专注于实现内核,但它的大部分功能都是“可拆卸的”。有些宏可以关闭。即使像svg这样的小排版功能也有可以关闭的宏。还有chromium,如果我需要排版,音视频,但不需要多进程?如果我需要音频和视频但不需要webrtc怎么办?抱歉,Google没有考虑到这一点。要带就全带,不带就自己砍码。当你努力几周,破解完代码后,谷歌会告诉你,我已经更新了2或3个版本,你要更新代码吗?哦?新版chromium的架构变化很大?哭了。。。这就造成了一堆基于chromium的开发框架,electron,cef,nwjs,大小都在100M以上。因为从chromium的框架设计来看,很难排除那些极其庞大复杂的细节。这些功能对于谷歌作为浏览器来说当然是必不可少的。不过回到这个问题,“浏览器内核”真的需要这么复杂吗?浏览器确实需要如此复杂;但是,作为浏览器核心提供给一些SDK给其他人使用,是否也需要这么复杂?我们用electron写了一套客户端供销管理系统。需要带上几十兆的webrtc、webgl、多媒体播放、天城文支持吗?最后打破这个疑惑的是多年后我进入了QQ浏览器的移动端群(其实就是x5内核,微信上大家吐槽最多的那个)。当年的x5内核其实就是基于webkit修改的。从chromium回到webkit,顿时有种豁然开朗的感觉。回到问题的开头,从浏览器内核的角度来看,其实并没有那么复杂。只要做好网络、排版、渲染,足以应对大部分使用场景。这让我想起了浏览器的早期,群雄割据的时代,浏览器内核很小。浏览器从几百K到几M不等,我记得早些年移动设备上运行的浏览器对css的支持不是很好,但是很小,有的只有几百K。不过,后来集团的结构有所调整。x5内核为了跟上时代,从webkit换回了chromium(也是因为被骂的太多了,当时x5叫移动IE6,做过微信相关开发的应该深有体会)理解)。讨厌铬的我当时有一个大胆的想法。排版引擎blink(即chromium中webkit的继承者)再次从chromium中剥离出来,加上一些外围设施和组件,再次成为一个完整的独立浏览器内核。当然我还是有自知之明的。它只是一个浏览器内核,不可能实现和chromium一样的功能。但是实现排版、渲染、网络、视频,差不多就够了。其实我不想做浏览器,我想专注于内核,做一个可以嵌入第三方应用的内核。作为一个内核,你实际上并不需要上面提到的所有功能。比如网络层,大部分人不需要网络变化检测、ftp、OCSP实现、代理配置、解析、脚本获取、QUIC、socket池、SPDY等,大部分人只需要一个可以拉取服务器的http实现资源。我把十多M的chromiumnet库换成了300k的curl,还可以。缺少的功能可以通过插件的形式进行补充。我打算把一些与排版和渲染无关的功能做成插件。比如音视频、webgl、webrtc、多进程等。目前这个项目已经进行了5年。开源在github上,提供了C接口,方便其他语言调用。整个编译是一个1-20m左右的dll(取决于编译选项),甚至还包含了electron的精简实现:https://github.com/weolar/miniblink49。
