Firefox OS的奇幻漂流——全面解析新一代Open Web移动操作系统
文/薛东升FireFox OS是移动操作系统的新成员,它以Linux内核和Gecko为基础,延续了Web版的开源理念。这款新的操作系统在设计上究竟有哪些独到之处?是否能满足移动市场中多元化的用户需求?本文将从FireFox OS的底层架构为入口,从技术角度带领读者开启一段FireFox OS的探秘之旅。Firefox OS是由Mozilla主导开发的新一代开源移动操作系统。自2011年6月项...
文/薛东升
FireFox OS是移动操作系统的新成员,它以Linux内核和Gecko为基础,延续了Web版的开源理念。这款新的操作系统在设计上究竟有哪些独到之处?是否能满足移动市场中多元化的用户需求?本文将从FireFox OS的底层架构为入口,从技术角度带领读者开启一段FireFox OS的探秘之旅。
Firefox OS是由Mozilla主导开发的新一代开源移动操作系统。自2011年6月项目正式启动以来,受到越来越多的关注。在过去的几个月中,我常在不同的场合被问到一些关于Firefox OS的问题,其中最常见的主要有下面几个。
- Firefox OS上的应用是否只能在Firefox OS的设备或Mozilla的产品上才能使用?
- Firefox OS为用户提供服务时,是否会占用大量的网络流量?
- Web应用是否比原生应用性能差?
下面我们就对Firefox OS这个系统做一个全面的介绍,请大家跟随我,一起完成这段Firefox OS的探秘之旅吧。
第一站:Firefox OS概念馆
Firefox OS作为一款开放网络技术的移动操作系统,基于Linux内核及Gecko引擎技术,从一开始就完全采取开源的方式进行开发,其核心理念是用户可接触到的 应用都是基于Web的应用,这些应用使用HTML5技术和硬件设备接口,可以通过JavaScript直接访问手机的硬件设备。Firefox OS架构主要由三层组成(如图1所示),分别为Gonk、Gecko和Gaia。
[caption id="" align="aligncenter" width="502" caption="图1 Firefox OS架构图"][/caption]
与现有的平台相比,Firefox OS在技术上具有以下特点。
- Firefox OS是一个基于HTML5技术的移动操作系统,用户界面和应用完全使用Web技术实现。Firefox OS具有紧密的GPU和硬件的集成,可以支持直接使用版本和下载版本的应用程序。
- Firefox OS基于通用的硬件及公开的硬件抽象层。它的开发一开始是基于Android来启动的,从技术实现的角度看,Firefox OS基于Android的底层实现来完成其架构中的Gonk层和对应的Gecko层,它采用了类似于Android的公开硬件抽象层,且其中很多接口与 Android中的相一致。
- 由于Firefox OS是基于Web技术开发的,所以其应用开发与测试可以直接在桌面浏览器中进行。实际上,Firefox OS的平台就是为Web应用服务的。除此之外,Firefox OS还在渲染方式与JavaScript引擎性能上进行了优化与调整,例如使用新的Azure库来实现Canvas2D、增强多进程架构、提供并行渲染合 成的能力、完善Web Worker/Web Socket/Web Storage的支持。
第二站:Gonk机器工厂
Gonk 一词来源于《Star Wars》中的一个叫做Gonk Droid的机器人。Gonk层是Firefox OS的最底层,由Linux内核和用户态硬件抽象层组成,来自通用的开源项目,其中部分与Android硬件抽象层共享,也包括部分硬件厂商提供的需要授 权的代码或库,如RIL、OpenGLES、FM等。
当打开安装Firefox OS设备的电源时,主引导程序(Bootloader)开始执行,引导主系统内核的过程以通常的方式进行,最后,执行由Bootloader转交到 Linux内核。接下来进入Linux内核启动阶段,这一阶段与主流Linux系统的内核启动一致,Gonk中的Linux内核在一定程度上接近 AOSP(Android Open Source Project)的内核部分。在内核启动的最后,用户空间中的Init进程被触发,此时,只有内存虚拟盘被挂载。Ramdisk在Firefox OS系统构建的过程中被构建,包含了关键工具、其他启动脚本和可装载内存模块。许多设备通过sysfs暴露给Gecko。下面给出了Gecko中获取电池 状态的代码:
在Linux内核完成启动后,会进入Init初始化过程,这部分将挂载必要的文件系统,加载系统服务和核心进程,并在服务启动后充当服务管理器。孵化系统服 务与其他类Unix系统的Init进程非常相似,由Init阶段加载的主要进程有b2g、rild、rildproxy、dbus-daemon等。其中 b2g为主要运行环境进程,图2展示了Firefox OS用户空间中的主要进程(虚线表示被Init孵化的进程,实线表示其他通信管道)。
[caption id="" align="aligncenter" width="502" caption="图2 系统用户空间中的主要进程"][/caption]
- b2g进程是主系统进程,具有很好的运行优先级,并可以访问大多数硬件设备(如图3所示)。b2g与Modem进行通信,绘制到显示用的帧缓冲器并与 GPS、相机和其他设备进行交互。在内部,b2g运行Gecko代码(libxul.so),b2g进程可能会会孵化一些低权限的内容进程(如 Content进程),Web应用和其他一些网页内容就是在这些进行中被加载的。这些内容进程通过IPDL(一个消息传递系统)与主Gecko服务进程通 信。不同的应用采用OOP(Out-Of-Process)多进程运行模型,这是为了保证不同Web应用的独立性与安全性,它规定不同的进程有不同的权 限,例如Chrome进程有较高的权限,而Content进程权限较低。在内存的管理上,Firefox OS使用和Android相同的技术,如果一个进程在前台,它将有超过其他应用程序的内存分配优先级,而那些在后台运行的应用程序将有可能被系统关闭。
[caption id="" align="aligncenter" width="502" caption="图3 b2g进程与其他设备的交互过程"][/caption]
- rild进程是访问Modem处理器的接口。RIL是无线接口层,rild是Ril的守护进程。rild允许客户端连接到它所绑定的UNIX- domain Socket上。在Firefox OS中,rild客户端是rilproxy进程,它仅仅在rild和b2g之间充当了一个静默转发代理(dumb forwarding proxy)的角色。netd进程用于配置网络接口,wpa_supplicant是通过端点连接到Wi-Fi的标准UNIX-ish守护进程。
总的来说,我们可以认为Gonk层是一个简化过的Linux分发版本,是支撑Gecko在硬件设备上运行的基础。我们知道,Gecko同样是Firefox 浏览器在各平台上运行的核心,但与浏览器不同的是Firefox OS对Gonk有完全的控制能力,它把在其他平台上无法获得的硬件接口暴露给Gecko层,例如全部的电话堆栈(telephony
stack)和显示帧缓冲(display framebuffer)。
第三站:Gecko两栖动物乐园
Gecko层是Firefox OS的技术核心,也是整个系统的应用运行环境,这一层提供对公开标准的支持。为了确保这一支持,这一层还包括其他内容,包括网络处理、图形图像处理、排版引擎、JavaScript虚拟机和对GonkHAL的支持等。
在处理输入方面,Gecko中的大部分动作都是由输入事件触发的,这些事件包括:按下按钮和触摸屏幕等。这些输入事件起源于标准的Linux输入事件系统,由输入设备驱动对这些事件进行转发。我们在提供了一些良好特性的事件(如事件过滤器)之上,使用了一个简单抽象。
对于图像处理,在非常底层的地方,Gecko使用OpenGL ES 2.0进行绘制,绘制到一个包含硬件帧缓冲的叫做“图形上下文”的地方。它使用了图形驱动的gralloc硬件接口,映射帧缓冲到缓冲区,Gecko使用 它的图层系统将内容进行组合,绘制显示到屏幕上。Gecko绘制不同的页面区域到内存缓冲中,有时这些缓冲就是系统内存,另外一些时候,它们是映射到 Gecko地址空间的纹理,即Gecko直接绘制到VRAM(Video Random Access Memory),Gecko使用GL指令组合这些纹理到屏幕上。值得注意的是Gecko里也存在一个硬件抽象层,为了避免Gecko的硬件抽象层与 Gonk的硬件抽象层混淆,Gecko硬件层将被称为hal,而Gonk的硬件抽象层被称为HAL。hal位于Gecko的移植层,它为Gecko中的更 高层次提供了一个跨平台的C++ API,这些API是在hal内部实现的,并且只能被Gecko中的C++代码所访问。
目前,Web的通用语言是JavaScript,而主流的浏览器引擎大多是用C++开发的,Gecko也不例外,DOM Bindings就是使JavaScript可以通过DOM API调用一些由C++实现的功能(如图4所示)。
[caption id="" align="aligncenter" width="502" caption="图4 JavaScript与Gecko的交互方式"][/caption]
Gecko内部使用最多的还是基于XPConnect上的DOM Bindings,使用ScriptableHelper来帮助把XPCOM组件暴露在JavaScript上,但这种方式有一些内存管理和速度上的缺 点,并且XPIDL(XPCOM界面定义语言)与WebIDL(Web界面定义语言)在语义上有一定的不同,会使各种加速方法和处理语义问题的 Wrapper需要手工地针对不同API进行修改。
因为XPIDL的一些问题,Firefox OS里还提供一种DOM bindings的方法。由于这个问题是在法国巴黎首次讨论的,所以最早被称为“Paris Bindings”。因为这些DOM API实际上不使用XPCOM的许多功能,所以它的速度比原有的XPConnect会快许多。通过WebIDL DOM bindings可以省略掉一些虚函数的开销,还可以节省掉XPCOM处理线程安全的花费,透过新的JIT技术,从JavaScript可以调用DOM API,甚至直接调用C++的实现。未来描述DOM API的语言可能统一为WebIDL。
第四站:Gaia视觉体验中心
Gaia 层是指Firefox OS的用户界面层,当Firefox OS启动后任何可以显示在屏幕上的内容都可看成该层的一个应用。Gaia层实现了HomeScreen、ScreenLock乃至一个现代智能手机所具备 的标准应用。它由Gecko层提供实现支持,通过开放的Web接口访问潜在的操作系统功能。在介绍Gaia之前,我认为有必要描述一下Firefox OS的显示流程。Firefox OS在Gonk层和Android系统类似,但又有很多不同。首先我们来看看简易的类别图和几个简单的概念(如图5所示)。
[caption
id="" align="aligncenter" width="502" caption="图5 FireFox OS的显示流程"][/caption]
- Players是一个用来辅助IPC的Class,它有两个子代,分别代表Parent和Child。
- BasicLayerManager是用来管理Web应用的Layer,同时绘制所有的Layer。
- ShadowLayerForwarder负责把Layer的树状结构传递到Compositor端,以准备Layer的合成。
- CompositorParent是利用LayerManagerOGL把所有收集到的Layer合成出来。
在目前的Gecko引擎当中,所有的绘图动作都会作用在一个称为Layer的对象上。每一个Layer基本上就是一张点阵图,并且包含了应该怎样被显示在屏 幕上的基本信息。值得注意的是,每一个Web应用只负责把它自己的Layer内容准备好,并不会把它们合并在一起,每个Web应用最终可能是由多个 Layer的树形结构所组成(如图6所示)。
[caption id="" align="aligncenter" width="502" caption="图6 Web应用显示结构"][/caption]
最终由CompositorParent把收集起来的所有Layer叠加在一起,形成整个画面。基于此,我们大致可以把Firefox OS的显示流程分为下面几个步骤。
- 排版:Gecko引擎基于HTML和CSS把整个网页用做排版。
- 绘制:将排版后的内容绘制到各自的Layer里。
- 合成:把所有的Layer叠加在一起显示到屏幕上。Gaia层完全使用HTML、CSS和JavaScript来实现,所以本质上说,它和目前所有使用Web技术开发的页面或应用没有根本区别,不过还是有一些实现上的区别需要注意。
- Web应用最大的优势在于根据页面内的URL链接任意跳转到不同页面,强调内容的专注化、应用化,像本地应用一样专注于完成某种功能,尽可能地让用户停留在该应用内。
- 由于Firefox OS是一款针对移动端的操作系统,所以具备许多移动设备的特性,如触摸操作、屏幕较小、可定位、可摄像等。Firefox OS为此提供了许多新设备或移动相关的Web接口,帮助Web应用开发者学习和使用。
在Gaia的结构设计上,使用XULRunner作为最外层的框架(如图7所示),System App作为权限最高的应用在设备启动后被系统默认加载。System App本身包含锁屏管理、Home桌面、声音管理、窗口管理、状态栏管理、输入事件管理、电源管理,以及系统设置等,是系统的核心应用。
[caption id="" align="aligncenter" width="502" caption="图7 Gaia的结构构成"][/caption]
在Gaia层,除了System App外,其他应用都是由System App负责创建的,例如拨号盘、浏览器、游戏等,基本上遵循以下过程。
- 主屏幕从mozapps API获取应用程序的详细信息,并调用app.launch()。
- Gecko层接收到请求,发送mozChromeEvent事件和应用的详细信息到System App。
- System App接收到事件后,在DOM中为应用插入一个iframe。
- 在iframe中加载当前应用程序。
在Web应用中,最容易让人产生误解的就是应用和网络之间的关系,那么在没有网络时,我们该如何是好呢?
HTML5提供了离线缓存机制,开发者可以通过使用这些App缓存接口指定浏览器应该将哪些资源存储下来供脱机时使用,这样即便在脱机状态下,只要用户点击了刷新键,App也能读取缓存并正确地运行下去。使用缓存能为App带来以下几点好处。
- 离线浏览:用户能在离线状态下操作网页 。
- 高速访问:缓存成本地资源,读取速度更快。
- 减少对服务器的访问:浏览器只会在服务器资源有变更时才会下载文件 。
当浏览器访问一个设置了manifest属性的页面,它会检测是否已创建该页面的缓存文件,如果还未创建,那么浏览器就会载入页面并抓取所有在这份缓存声明 文件中定义的资源,并在客户端创建App缓存的第一个版本。再次访问该页,浏览器在载入页面时,会优先从客户端的App缓存中获取相关资源。此外,在遵循 HTTP缓存协议的前提下,浏览器还会送出一个触发事件给window.applicationCache这个对象, 并会去抓取服务器的缓存声明文件。
如果当前的缓存声明文件是最新的,浏览器会发送一个noupdate事件给applicationCache对象,告知其更新已结束。需要注意:如果你修改了服务器上的资源,必须及时更新缓存声明文件,这样浏览器才会知道需要抓取新的资源。
如果缓存声明文件被修改了,所有在其中罗列的文件(包括那些之前已经通过调用 applicationCache.add()方法存入缓存的文件)会根据HTTP缓存协议被再次抓取到一个临时的存储空间中。所有被抓到这个临时存储空 间的文件,浏览器都会发送一个process事件给appliCation对象(如果有错误发生,浏览器也会发送一个error事件,并停止更新)。等到所有文件被成功地下载下来,它们会自动调入真正的离线缓存,并且发送一个cached事件给appliCation对象。因为文档已被浏览器通过缓存读 取,所以新的文档暂时不会取而代之,直到页面刷新。
起航吧,新起点
HTML5是近十年来Web开发标准最巨大的飞跃。HTML5并不是仅仅用来表示Web内容,它的新使命是将Web带入一个成熟的应用平台——视频、音频、图像、动画,同电脑的交互全部标准化。在这个群雄并起的移动平台上,Firefox OS是否会为移动互联网开启一个新的局面,还需要靠未来的市场做最终评价。虽然本次Firefox OS的探秘之旅已然接近终点,但对Open Web及Firefox OS的开发者和爱好者来说,却是旅程中的一个新起点,还有更多的秘密等待大家去探索,向着新的目标,起航吧。
作者薛东升,火狐软件经理,主要负责国内火狐移动产品的研发和管理工作,包括Fennec、Firefox for Android和Firefox OS。
更多推荐
所有评论(0)