《深入理解Android》一2.3 WebKit架构概览

本文涉及的产品
全局流量管理 GTM,标准版 1个月
云解析 DNS,旗舰版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介:

本节书摘来自华章出版社《深入理解Android》一书中的第2章,第2.3节,作者孟德国 王耀龙 周金利 黎欢,更多章节内容可以访问云栖社区“华章计算机”公众号查看

2.3 WebKit架构概览

我们从浏览器的发展历程和现状分析中可以看出,WebKit是一个功能完备、性能优良、相对轻巧、使用广泛的排版内核,是诸多操作系统上开发浏览器的不二之选。本书集中论述Android 4.2平台上的WebKit移植版本,本节将从组成架构、工作流程和设计风格三个方面对Android WebKit做初步介绍,为读者简单梳理其庞大代码的整体样貌,也是对后续章节的引导。

2.3.1 整体组成架构

Android系统中的WebKit如图2-14所示既是一个Native的动态库也是Framework的一部分,从结构上大致可以划分为7个较为独立的组成部分:
WTF:Web Template Framework,公共基础库;
JS Engine: JavaScript引擎,负责JS脚本的执行,Android采用V8而非JavaScript Core;
WebCore:核心所在,负责HTML/CSS解析、排版和显示以及JS的DOM绑定;
Chromium-Net:Chrome浏览器源码中抽取的网络库;
Skia:Android和Chrome共同使用的图形库,负责底层的图形文字绘制工作;
WebKit:封装所有C++层代码,提供与Java层交互的接口;
Framework:对以上Native层代码的Java层封装,对外提供Framework层的WebKit API。

image

WebCore如图2-15所示是WebKit中最大最复杂的部分,也是排版引擎核心所在,其内部结构可大致进一步细分为如下若干子系统,每个子系统包含大小不一功能上彼此关联的若干模块:
Page:提供对外的总入口以及页面相关的Chrome、Setting、History等模块;
Document:解析html/xml/svg,生成DOM树的子系统;
CSS:负责CSS的解析和匹配;
Render:实现Layout和Render过程的子系统;
Graphics:封装底层图形库,对上提供一套平台无关的绘制接口;
Loader: 负责网络IO、Form Submission、Memory Cache等;
Script: 提供JS执行入口以及从C++对象到JS对象转换的Binding和Bridge;
Extension Modules:实现非DOM的HTML 5扩展JS功能模块,如Worker、WebSocket、WebStorage、FileAPI等,可能需要相应的Custom Binding代码;
Plugin:用于加载NPAPI插件,需要Bridge模块完成和JS引擎的互动;
Interaction: Editing、Accessibility等相对较独立的与交互、命令有关的模块。

image

下面重点介绍WebKit渲染主线上的一些关键概念和核心对象,理解了这些对象就等于抓住了主要节点,纲举目张事半功倍,读者可以从源码层面一一对照阅读分析。
Page模块如图2-16所示,Page类(位于Source/WebCore/page/Page.h)代表整个页面,一个Page对象包含一个作为MainFrame 的Frame对象(Source/WebCore/page/Frame.h)。每个Frame表示某URI对应的主文档资源在一个WebKit页面中加载后的可以呈现出可视化结果的一帧,因此对应一个FrameLoader类(Source/WebCore/loader/FrameLoader)、一个文档模型Document类(Source/WebCore/dom/Document.h)和一个视图FrameView类(Source/WebCore/page/FrameView.h)。Frame可以拥有子Frame,Frame之间可能构成一棵FrameTree,对应于网页中的iframe或frameset标签。和Page对象相关联的对象主要还有Setting对象(Source/WebCore/page/Setting.h)和Chrome对象(Source/WebCore/page/Chrome.h),分别表示页面设置和内容以外的外框。

image

WebKit将资源请求分成两类,分别交由主资源MainResourceLoader和子资源SubResourceLoader来处理。MainResourceLoader负责的是能够载入到Frame的HTML文档,SubResourceLoader对应的则是其余的JavaScript/CSS/Image等资源。ResourceLoader将请求和应答交由ResourceHandle类处理,ResourceHandle负责将网络和IO工作交给更底层的平台相关的对象去处理。Android 4.x系统中WebKit已经开始使用Chromium-Net网络库,网络模块单独移出,网络调用接口也直接上移至ResourceLoaderAndroid中。
Load过程都有各自的请求发起者,WebKit还根据请求对象生存期的不同,将Loader类拆分成不同类型。Page和Frame对应于页面标签和暴露给Shell层的WebView,它们请求URL加载,由FrameLoader负责处理。CachedResource类代表那些能够被缓存的资源,如JS/CSS/Image等,它们可以静态的持续存在,并和Cache模块关联,因此其加载由一个全局静态生存期的Loader类来负责。Frame对象load了某个URL之后,会根据其页面HTML生成对应的Document对象,Document对象的加载请求和应答则是通过DocumentLoader来转发完成。
Loader模块核心类的生存期和调用关系如图2-17所示。
文档对象模型(Document Object Model,DOM)是页面文档在浏览引擎内部的模型表示,Page/Frame/FrameView/WebView则相当于是页面的视图表示,Browser端JavaScript定义的事件方法等脚本则可看成是控制器,三者构成了类MVC的架构。WebKit中文档被Document类对象表示,HTML文档则是继承于Document类的HTMLDocument。文档节点由Node类对象表示,HTML页面元素是HTMLElement类,各种HTML标签元素对应的类都继承于HTMLElement。HTMLElement类和Document类中包含了DOM模型大部分接口内容。构成了浏览器端JavaScript的根对象是Window,在WebKit中对应的实现类则是DOMWindow。图2-18描绘了一些核心DOM对象的类型继承体系。
image

image

WebKit中Render树节点也以一系列具有继承体系的类来表示,其基本类型是RenderObject,具备CSS盒子模型的类型是RenderBoxModelObject,以Inline方式和Block方式排版的Render对象类型分别是RenderInline和RenderBox。为了处理CSS动画、页面内Video、定位方式和包含Z-Index元素的排版渲染,WebKit又引入了RenderLayer类。一个RenderLayer代表一个渲染中的分层,RenderLayer也构成一棵树。每个RenderObject都隶属于某个RenderLayer,通常具有共同坐标系的Render节点属于同一个RenderLayer。图2-19描绘了RenderObject部分重要派生类的继承结构。

image

2.3.2 核心工作流程

介绍完Android WebKit内部的架构组成和重点模块的关键对象之后,本节将根据2.1.2节中介绍的排版引擎工作原理来简单说明WebCore排版引擎各阶段工作的流程入口函数,读者可据此分析源码,顺藤摸瓜,一览究竟。
图2-20从整体上勾勒出了WebCore部分的工作流程图,可以看出其中包括HTML Parser、CSS Parser、Render树创建Attachment、Render树排版Layout和Render树绘制Painting这几个核心过程。
网络IO:加载一个URL的流程,在Framework中从WebView的loadUrl开始,在WebCore中则从FrameLoader::loadURL开始。

image

页面解析:HTML文本由DocumentWriter::addData方法传入,调用HTML DocumentParser类来解析页面。后者使用HTMLTokenizer类做词法分析,获取Token,再交由HTMLTreeBuilder去构建DOM树。
DOM树和Render树创建:建树过程从HTMLTreeBuilder::constructTreeFromTok-en开始,然后调用HTMLContructionSite类的insert类函数,依次把根据Token类型创建的HTMLElement对象加入到DOM树。而Render树的创建过程则以Element::attach方法开始,通过RenderObject::createObject静态方法创建,同时会计算出Element的CSSStyle。
布局排版:排版流程以一系列类的layout方法完成,以FrameView::layout方法为布局起始点,调用Render树根节点的layout,递归触发Render树节点的layout过程。FrameView::layout可以被布局timer或者Shell层的WebViewCore::layout方法触发。
绘制显示:在Android WebKit中,Render树的内容排版后要经过Paint和Draw两个阶段才能显示给最终用户,paint阶段是指把RenderObject的内容画到Bitmap上的过程,Draw阶段则使Bitmap内容最终显示出来,这两者分别在WebCore线程和UI线程中完成。Paint阶段和排版类似,以一系列类的paint方法完成,从FrameView::paint开始,调用RenderLayer树根节点的paintLayer,再依次递归调用Render树Object的paint方法绘制节点的内容。Draw阶段则由WebView类的draw或者drawGL方法触发。
脚本执行:WebKit中JS引擎的封装类为ScriptController,脚本执行的入口函数为ScriptController::evaluate方法。
事件处理:WebKit中的UI事件从Framework层传入给WebViewCore类,主要有keyEvent、mouseEvent、dragEvent和touchEvent等。事件处理的入口类是EventHandler,各种事件一般经EventHandler分发给DOM元素依次处理,按照冒泡事件消息传递的方法递归寻找EventHandler,最终被DefaultEventHandler吸收。

2.3.3 代码设计风格

WebKit开源项目在目前看来虽然体量很大,但是可读性很好,这与该项目从一开始就有着清晰的架构设计和良好的代码风格分不开。相比较而言,更加庞大的Gecko内核因种种原因则设计相对复杂,架构比较臃肿。正因如此苹果公司在开发自有Safari浏览器时,才抛弃了同样是开源的老牌Gecko而选择了不够完善但设计精巧的KHTML,即WebKit的前身。

  1. 代码风格
    下面简单说明WebKit中常用的一些代码技巧和风格,读者在阅读源码和本书的同时可加以留意。

内存管理:WebKit C++代码中内存管理最基本的模式是引用计数,RefCounted模板类定义了ref()和unref()计数加减方法,很多类都继承了该模板类。为了避免不正确或者遗漏的计数使用,又进一步引入了RefPtr和PassRefPtr两个智能指针模板类,它们重载了赋值操作符,自动完成有关计数加减的工作。WebCore中需要传递赋值的共享对象大多使用了智能指针代替指针持有,基本没有了内存泄露的可能。关于智能指针更详细的介绍参见第3章。
代码自动生成:WebKit中的DOM在C++有关模块中实现,同时需要把DOM接口暴露给JavaScript执行引擎。从C++对象到JS对象的Binding实现,WebKit采用了代码自动生成方法,使用Perl脚本根据DOM对象的IDL(Interface Description Language)接口描述文件完成code generator的工作,以机器代替手工编写了大量的Wrap代码。此外,CSS和HTML解析过程也或多或少地采用了机器代码生成的技巧,使得CSS属性值和HTML标签属性的自定义添加变得相当容易,只需修改相应的.in配置文件即可。IDL代码自动生成的细节参见第9章,HTML和CSS相关代码自动生成参见第5章。
代码编写风格:WebKit代码书写十分规范,包括缩进、空格、换行和括号的使用,变量的骆驼命名法(CamelCase),成员和静态成员的前缀区分,条件和分支判断,指针和引用,乃至头文件注释名字空间等都有涉及。代码阅读起来整齐优雅,根据命名大致能猜出含义,读者可参考网络上的官方coding style文档(https://www.webkit.org/coding/coding-style.html)。此外,代码文件的组织分布也有其规则,各模块文件层次有序地按目录结构分隔,平台有关的文件代码基本位于Source/WebCore/platform目录或Source/WebKit目录下对应平台名的子目录中。

  1. 设计模式
    设计模式是软件架构中针对普遍存在、反复出现的需求问题而提出的可复用的解决方案。这里给出一些WebKit中出现的设计模式例子,其具体实现方案与GOF经典设计模式可能会有所差异,但面对的问题域基本是一致的,读者可据此更快速地领会其代码设计意图和工作原理。

单例:单例模式是为了确保某个类仅有一个实例并提供全局访问。WebKit中Loader模块负责管理CachedResource的Memory Cache就是一个典型的单例模式,可缓存资源的管理器理所当然有且只有一个全局访问。
工厂方法:工厂方法模式也是一种创建型设计模式,用于解决在不指定对象具体类型的情况下创建对象的问题,WebKit中Parser模块最终创建实际的HTMLElement所面临的情况正与此类似。HTMLTreeBuilder类和HTMLConstructionSite类将HTML标签名传入工厂类HTMLElementFactory的createElement接口,由它来决定实际创建哪个类型的HTMLElement对象。
观察者模式:观察者模式让对象管理自己的观察者对象,发布事件消息或通知状态改变。WebKit中有很多名称的末尾为Client的类,如FrameLoaderClient、CachedResourceClient等,可以将它们看成是一种观察者类,被观察者如FrameLoader、CachedResource向其 Client观察者类通知自身的状态改变。
组合模式:组合模式通常用于将具有树状结构的对象组织成一个组合对象,WebKit中存在多个重要的树状数据结构,如DOM树、Render树、RenderLayer树等,它们的基类如ContainerNode、RenderObject、RenderLayer都有一套Children和Parent的管理方法,也可以视为组合模式的一个具体例子。
代理模式:代理模式使用一个代理类替原始类完成具体的操作,WebKit中Audio/Video有关元素的实现用到了该模式。HTMLMediaElement类包含一个MediaPlayer类对象来完成具体的多媒体播放功能,而MediaPlayer类则通过MediaPlayerPrivate类来实现实际真正的操作,这里MediaPlayerPrivate就可以看作MediaPlayer的Proxy。
命令模式:命令模式将动作及其参数封装起来用面向对象的设计来表示,WebKit中DOM模块的Event类和Editing模块的Command类都可以看作典型的命令模式实现。
责任链模式:责任链模式可以将命令对象在一系列处理对象中传递,处理对象自行决定如何处理命令或将不能处理的命令传递给链条中的下一个处理对象。WebKit对DOM事件处理的实现与该模式有关,Event对象(作为命令对象)在DOM树(作为处理对象)中按照一定规则(如冒泡)传递并寻找其Event Handler/Listener。

相关文章
|
4月前
|
安全 Android开发 iOS开发
深入探索Android与iOS的差异:从系统架构到用户体验
在当今的智能手机市场中,Android和iOS无疑是最受欢迎的两大操作系统。本文旨在探讨这两个平台之间的主要差异,包括它们的系统架构、开发环境、安全性、以及用户体验等方面。通过对比分析,我们可以更好地理解为何不同的用户群体可能会偏好其中一个平台,以及这些偏好背后的技术原因。
|
4月前
|
Android开发 Swift iOS开发
深入探索iOS与Android操作系统的架构差异及其对应用开发的影响
在当今数字化时代,移动设备已经成为我们日常生活和工作不可或缺的一部分。其中,iOS和Android作为全球最流行的两大移动操作系统,各自拥有独特的系统架构和设计理念。本文将深入探讨iOS与Android的系统架构差异,并分析这些差异如何影响应用开发者的开发策略和用户体验设计。通过对两者的比较,我们可以更好地理解它们各自的优势和局限性,从而为开发者提供有价值的见解,帮助他们在这两个平台上开发出更高效、更符合用户需求的应用。
|
1月前
|
Android开发 开发者 Kotlin
Android实战经验之Kotlin中快速实现MVI架构
MVI架构通过单向数据流和不可变状态,提供了一种清晰、可预测的状态管理方式。在Kotlin中实现MVI架构,不仅提高了代码的可维护性和可测试性,还能更好地应对复杂的UI交互和状态管理。通过本文的介绍,希望开发者能够掌握MVI架构的核心思想,并在实际项目中灵活应用。
57 8
|
3月前
|
网络协议 Linux Android开发
深入探索Android系统架构与性能优化
本文旨在为读者提供一个全面的视角,以理解Android系统的架构及其关键组件。我们将探讨Android的发展历程、核心特性以及如何通过有效的策略来提升应用的性能和用户体验。本文不包含常规的技术细节,而是聚焦于系统架构层面的深入分析,以及针对开发者的实际优化建议。
141 21
|
3月前
|
存储 Linux API
深入探索Android系统架构:从内核到应用层的全面解析
本文旨在为读者提供一份详尽的Android系统架构分析,从底层的Linux内核到顶层的应用程序框架。我们将探讨Android系统的模块化设计、各层之间的交互机制以及它们如何共同协作以支持丰富多样的应用生态。通过本篇文章,开发者和爱好者可以更深入理解Android平台的工作原理,从而优化开发流程和提升应用性能。
|
3月前
|
安全 Android开发 iOS开发
深入探索iOS与Android系统架构差异及其对开发者的影响
本文旨在通过对比分析iOS和Android两大移动操作系统的系统架构,探讨它们在设计理念、技术实现及开发者生态方面的差异。不同于常规摘要仅概述内容要点,本摘要将简要触及核心议题,为读者提供对两大平台架构特点的宏观理解,铺垫
|
4月前
|
IDE 安全 Android开发
深入探索Android与iOS操作系统的架构差异
本文旨在对比分析Android和iOS两大主流移动操作系统在架构设计上的根本差异。通过详细解读两者的系统架构、开发环境、以及安全性等方面,揭示它们各自的特点及优势,为开发者选择合适的平台提供参考。
|
3月前
|
开发工具 Android开发 iOS开发
Android与iOS生态差异深度剖析:技术架构、开发体验与市场影响####
本文旨在深入探讨Android与iOS两大移动操作系统在技术架构、开发环境及市场表现上的核心差异,为开发者和技术爱好者提供全面的视角。通过对比分析,揭示两者如何塑造了当今多样化的移动应用生态,并对未来发展趋势进行了展望。 ####
|
4月前
|
安全 Linux Android开发
深入探索Android与iOS的系统架构:一场技术较量
在当今数字化时代,智能手机操作系统的选择成为了用户和开发者关注的焦点。本文将深入探讨Android与iOS两大主流操作系统的系统架构,分析它们各自的优势与局限性,并对比两者在用户体验、开发生态和安全性方面的差异。通过本文的技术剖析,读者将对这两个平台的核心技术有更深入的理解。
|
4月前
|
安全 Java Linux
深入解析Android系统架构及其对开发者的意义####
【10月更文挑战第21天】 本文旨在为读者揭开Android操作系统架构的神秘面纱,探讨其如何塑造现代移动应用开发格局。通过剖析Linux内核、硬件抽象层、运行时环境及应用程序框架等关键组件,揭示Android平台的强大功能与灵活性。文章强调了理解Android架构对于开发者优化应用性能、提升用户体验的重要性,并展望了未来技术趋势下Android的发展方向。 ####
121 0

热门文章

最新文章