Chromium架构之启动

总结一下Chromium浏览器从wWinMain到浏览器循环开始的这段逻辑。 wWinMain Win32程序的入口都是wWinMain,Chromium浏览器也不例外。 初始化Crashpad 一开始就调用SignalInitializeCrashReporting去初始化Crashpad崩溃报告系统。这里会创建一个ChromeCrashReporterClient的对象,用来处理crash相关的逻辑。初始化完成之后就会启动一个crashpad-handler的进程。其他浏览器进程崩溃后,这个crashpad-handler进程就会为它们生成dump。 fast... Read More | Share it now!

Profile-guided optimization

传统的C++代码编译链接器生成可执行文件,并没有考虑到代码实际执行的情况。比如代码中一个switch表达式,某条分支的逻辑在实际环境中执行的次数占绝大数,而编译链接器无从得知这些信息,也就没办法做出优化。Profile... Read More | Share it now!

创建新的Chromium extension api

不同编程语言的开发效率是不一样的,比如c++可以实现一些很底层的功能,但是开发速度比较慢,对开发者的要求也很高。而javascript开发速度很快,编程的抽象层次很高,无法调用一些系统底层的api。于是我们想到可以把c++与javascript结合起来,c++给javascript提供一些底层的api接口,javascript调用c++的接口并专注于业务开发,这样岂不两全其美。 事实上真有这样做的,比如Chromium浏览器,浏览器本身是用c++编写的,提供了很多extension... Read More | Share it now!

Chrome extension的类型

Chrome中的extension概念跟我们一般想的不一样,除了一般的extension,比如广告过过滤extension是属于extension,其实Chrome中的theme也是属于extension。另外随着extension系统的发展,类型的定义也会发生改变。 Extension类型的定义 我们可以在代码extensions\common\manifest.h中查看Manifest::Type的定义: 此外我们可也以从代码extensions\common\api\management.json中可以看到ExtensionType的定义: 这两处对于extension类型的定义有些差异,management.json定义渐渐废弃,以manifest.h中的定义为准。 Extension类型的判断 判断一个extension类型是看extensions\common\extension.h中的判断逻辑: Extension最后还是调用Manifest中的逻辑: 在Manifest构造函数中: 可以看到extension类型的判断逻辑: theme 类型为Manifest::Type::TYPE_THEME的extension就是一个theme(主题),它可以改变浏览器的外观。theme通常不会包含有html和js等代码。具体可以看看这里的介绍https://developer.chrome.com/extensions/themes。 shared_module shared_module类型很少见。 app app包含三种类型,platform_app、hosted_app、legacy_packaged_app。2016年Chrome宣布将不再支持app类型了。app与extension最大的差别是app可以具有独立于浏览器的窗口界面。app相比extension可以获取到更多的权限,能够实现更加强大的功能。 extension 我们在Chrome网上应用店里面下载到扩展程序都是属于extension,这也是最常见的,如下图: ... Read More | Share it now!

Chrome的差量升级Courgette

Windows客户端做程序的升级是一件比较复杂的事情。不像移动端,有专门的移动商店用来安装和更新程序,Windows客户端程序升级需要自己制作安装包,放到服务器上供用户下载,后续还需要提供升级服务。由于用户操作不可预知性和用户环境的复杂,安装跟升级都会发生各种异常而失败。迄今为止Windows上也没有一个好的程序安装、升级、卸载框架,这不得不说是Windows开发的悲哀。 而且目前程序的安装包越来越大了,动辄几十兆,用户下载安装包需要很长的时间,这也是导致安装升级成功率低的一个原因。所以,安装升级包越小越好。对于这个问题,有两个解决思路: 程序功能模块化,把代码编译到不同的dll里面。如果某个模块有修改,就只需要升级相应的dll就行了。 找出旧版本和要升级的新版本文件的差异,把差异文件发给客户端。客户端根据旧版本和差异文件还原出新版本。 对于第一种方案,优点是实现起来比较简单,我之前的老东家360很多产品就是用的这种方案。这个方案的缺点也很多: 把功能模块化,这个升级粒度依然有点大,有些dll可能只是修改了几行代码就需要升级这个几兆的dll文件。 如果底层模块的接口改了,那么调用它的上层模块都需要修改,这就导致升级会涉及到很多文件。 如果模块代码划分不清或者有一些隐式的逻辑依赖,这种dll升级可能引入难以觉察的bug,甚至会导致程序崩溃。 第二种方案已经有了bsdiff了。但是对于Widnows客户端程序,依然存在很大的挑战。因为C++这种需要编译的代码,充满了内部地址引用,一些指令直接包含其他指令的地址或者位移,几行代码的修改就会导致许多地址值的改变,结果导致最终生成的二进制文件差异很大。 Google的Chrome开发团队特地为C++这种需要代码编译的程序开发了一种叫做Courgette的差异算法。原理是先把可执行的二进制程序进行反汇编,找到那些内部的地址指针,把它们替换成一个符号,然后再用常规的办法生成差异文件。 下面是常规的bsdiff升级: 这个是Courgette升级: 不得不佩服,这是个绝妙的思路。没有对C++、编译器、汇编、PE文件格式深厚了解的人,是无法设计出如此精妙的方案。 Chrome团队还有一个数据的对比: Full... Read More | Share it now!

Chromium UI框架view

如果把widget当作画板,那么view就相当于铺在画板上的画纸。widget上面不会画什么东西,我们的界面元素都是画在view上,然后view又盖在widget上面。 在non_client_view.h的注视里面可以看到以下的内容: 可以看到最底层是Widget,然后RootView盖在Widget上面。RootView包含了NonClientView,而NonClientView又包含NonClientFrameView和ClientView。View不仅可以显示元素,而且可以当作容器包含其他的View。所有的View形成了一个树状的层次结构,低底层的根是RootView。 RootView附着在一个Widget上面,Widget从操作系统里面接受事件,转换成与View兼容的事件,然后再传递给RootView。RootView则按照树状层次结构一层层的传递事件。 听起来还是很抽象,我们可以实际动手试一试,我们利用views::PrintViewHierarchy(this)打印出RootView的View... Read More | Share it now!

Chromium预置搜索引擎

Chromium是Google主导一个开源浏览器项目,而Google是以搜索引擎起家的,因此Chromium里面搜索是个很重要的功能,给它增加了很多特性。我写篇博客介绍一下Chromium里面的搜索功能。 预置的搜索引擎 在浏览器的地址栏里面输入chrome://settings/searchEngines就可以管理搜索引擎。里面有一些预置的搜索引擎,你可以删除它们也可以添加一些你自定义的搜索引擎:如下图所示: 预置的搜索引擎是由Chromium代码prepopulated_engines.json定义的,这个文件的注释值得一读。文件其实就是包含了json格式的一些数据,在编译的时候会动态生成prepopulated_engine.h/cc文件。值得注意的是:每次修改过prepopulated_engines.json文件里面的数据都需要自增int_variables.kCurrentDataVersion的值,否则你的修改可能不会生效。原因是浏览器运行之后会把预置搜索引擎的数据保存在Web... Read More | Share it now!

Chromium UI框架widget

很早之前就想把Chromium的UI框架总结一遍。知道一个事物并向别人描述清楚并非是一件容易的事情,而且它又是如此的复杂,我没有把握把Chromium的UI框架给别人讲清楚,只有尽力而为。 我准备分三部分来讲Chromium的UI框架。首先是Widget,它是View的宿主,也是连接操作系统原生的UI系统的枢纽,同时还与CC(Chrome... Read More | Share it now!