惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

D
Darknet – Hacking Tools, Hacker News & Cyber Security
Jina AI
Jina AI
博客园_首页
J
Java Code Geeks
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
博客园 - 司徒正美
Hugging Face - Blog
Hugging Face - Blog
S
SegmentFault 最新的问题
MyScale Blog
MyScale Blog
P
Proofpoint News Feed
L
Lohrmann on Cybersecurity
Forbes - Security
Forbes - Security
大猫的无限游戏
大猫的无限游戏
Vercel News
Vercel News
Y
Y Combinator Blog
Google DeepMind News
Google DeepMind News
The Register - Security
The Register - Security
N
News | PayPal Newsroom
S
Security Archives - TechRepublic
量子位
Cisco Talos Blog
Cisco Talos Blog
V
V2EX
C
Cisco Blogs
The Cloudflare Blog
Stack Overflow Blog
Stack Overflow Blog
L
LangChain Blog
Scott Helme
Scott Helme
S
Securelist
Security Latest
Security Latest
爱范儿
爱范儿
TaoSecurity Blog
TaoSecurity Blog
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
I
Intezer
L
LINUX DO - 最新话题
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
C
Check Point Blog
C
CXSECURITY Database RSS Feed - CXSecurity.com
美团技术团队
Know Your Adversary
Know Your Adversary
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
PCI Perspectives
PCI Perspectives
月光博客
月光博客
T
Tailwind CSS Blog
Cloudbric
Cloudbric
小众软件
小众软件
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
K
Kaspersky official blog
D
DataBreaches.Net
博客园 - 【当耐特】
有赞技术团队
有赞技术团队

博客园 - duguguiyu

『Android开发精要』推荐 深入Android【八】 —— Activity间数据传输 深入Android【七】 —— 资源文件 深入Android 【六】 —— 界面构造 深入Android 【五】 —— 任务和进程 深入Android 【四】 —— 组件调用 深入Android 【三】 —— 组件入门 深入Android 【二】 —— 架构和学习 深入Android 【一】 —— 序及开篇 Symbian手记【五】 —— Symbian的异步框架 Symbian手记【四】 —— Symbian的容器 Symbian手记【三】 —— Symbian的描述符 Symbian手记【二】 —— Symbian对象构造 Symbian手记【一】 —— Symbian命名法 分布式基础学习【二】 —— 分布式计算系统(Map/Reduce) 分布式基础学习【一】 —— 分布式文件系统 Chrome源码剖析 【四】 Chrome源码剖析【三】 Chrome源码剖析【二】
Chrome源码剖析 【五】
duguguiyu · 2008-11-05 · via 博客园 - duguguiyu

【五】 Chrome的插件模型

1. NPAPI

为了紧密的与各个开源浏览器团结起来,共同抗击IE的垄断,Chrome的插件,也遵循了NPAPI(Netscape Plugin Application Programming Interface)标准,支持这个标准的浏览器需要实现一组规定的API供插件调用,这组API形如NPN_XXX,比如NPN_GetURL,插件可以利用这些API进行二次开发。而NPAPI插件以一个Dll之类的作为物理载体(windows下dll,linux下是so...)进行提供,里面同样也实现了一组规定的API。形式包括NP_XXXNPP_XXX,NP_XXX是系统需要默认调用的方法,用于认知这个插件,比如NP_Initialize, 而NPP_XXX是用于插件完成一些实际功能,比如NPP_New。。。

所有的插件dll都需要放置在指定目录下(根据操作系统的不同而不同...),每个插件可以处理一种或多种MIME格式的数据,比如application/pdf,说明该插件可以处理pdf相关的文档。在Chrome中键入about:plugins,可以查看当前Chrome中具有的插件信息。。。

NPAPI是一个很经典的插件方案,用dll进行注入,用协定的API进行通信,用字符串描述插件能力。插件宿主(在这里就是浏览器...),会根据能力描述,动态加载插件,并负责插件调用的流程和生命周期管理。而插件中,负责真实逻辑的处理,并可以构造UI与用户交流。以此类方式实现的插件系统,往往是处理的逻辑比较固定适用范围一般(用API写死了逻辑...),但可扩展性不错(用字符串描述能力,可无限扩展...)。。。

在Chrome中nphostapi.h中,定义了所有NPAPI相关的函数指针和结构,这个文件放置在glue目录下,如果看过前面碰过的文章就知道,在WebKit内肯定也有一套相同的东西;在npapi.h/.cc中,提供了Chrome浏览器端的NPN_XXX系列函数的实现;每一个插件物理实例,用PluginLib类来表示,而每一个插件的逻辑实例,用PluginInstance类来表示。这个概念牵强附会的可以用windows中的句柄来类比,当你想操作一个内核对象,你需要获得一个内核对象的句柄,每个进程中的句柄肯定不相同,但后面的内核对象却是同一个,内核对象的生命周期通过句柄的计数来控制,有人用则或,无人用则死(当然这个类比相当的牵强,主要是想说明引用计数和逻辑与物理的关系,但一个关键性的区别在于,PluginLib与PluginInstance都是在一个进程内的,不能跨越进程边界...)。在Chrome中,PluginLib负责加载和销毁一个dll,拿到所有导出函数的函数指针,PluginInstance对这些东西进行了封装,可以更好的来调用。。。

关于NPAPI的更多细节,Chrome并没有提供任何文档,但是,各个先驱的浏览器们都提供了大量丰富的文档。比如,你可以到这里,查看firefox中的NPAPI文档,基本通用。。。

2. Chrome的多进程插件模型

Chrome的插件模型,与早先的浏览器的最大不同,是它采用了多进程的方式,每一个插件,都有一个单独的进程来承载(Shift + Esc打开Chrome进程管理器,可以看到现在已经加载的插件进程...)。当WebKit进行页面渲染的时候,发现了未知的MIME类型数据,它会告知给Browser进程,召唤它提供一个插件来解析。如果该插件还未加载,Browser会在指定目录中搜寻出具有此实力的插件(如果没有此类人才只能作罢...),并为它创建一个进程,让它负责所有的该插件相关的任务,然后建立起一个IPC通路,与它“保持通话”。这套流程一定不会太陌生,因为它与Render进程的创建大同小异换汤不换药。。。

Plugin进程与Render进程最大的区别在于,Render需要与Browser进程大量通信,因为它的HWND归Browser老大掌管着,相关所有内容都需要通信完成。但Plugin不需要与Browser频繁联系,它大部分的通信都是与Render进程发生的。如果Plugin与Render之间的通信,还需要走Browser中转一下,这就显得有些脱裤子放屁了,虽然Browser是大头,但不是冤大头,它不会干这种吃力不讨好的事情。他只是做了一回Render与Plugin间的媒婆而已。当Plugin与Browser建立好了IPC通路后,它会让Render建立一个新IPC通路,用以与Plugin通信,IPC的有名管道名,经由Browser通知给Plugin。完成名字协商后,Render与Plugin的通信关系就建立好了,它们之间就可以直接进行通信了。。。

整个通信模式,可以看这里。这是一个很标准的代理模式的应用,稍有了解的都可以跳过我后面会做的一段罗嗦的描述,一看官方文档中的图便能知晓。在Render进程端,WebPluginImplWebPlugin的一个子类,WebPlugin是供Webkit进行调用的一个接口,利用依赖倒置,实现了扩展。在Plugin进程端,实现了一个WebPluginDelegateImpl类,该类会调用PluginInstance的相关接口实现真实的插件功能。这样的话,只需要WebPluginImpl调用WebPluginDelegateImpl中的相应方法,就可以实现功能。但问题是WebPluginImpl与WebPluginDelegateImpl天各一方各处于一个进程,很显然,这里需要一个代理模式。这里沿用了COM的架构,Delegate + Stub + Proxy。WebPluginImpl调用代理WebPluginDelegateProxy,该代理会将调用转换成消息,通过IPC发送给Plugin进程,在Plugin端,通过WebPluginDelegateStub监听消息,并转换成对真实WebPluginDelegateImpl的调用,从而完成了跨进程的一个调用,反之亦然。。。

3. Chrome的可扩展性

总所周知,firefox通过三种方式进行自定义,插件、扩展和皮肤。其中,插件是使得浏览器能用,不会出现一大块一大块的无法显示的区域;扩展是使得浏览器好用,可以简单方便的进行功能的定制和个性化配置;皮肤是帮助浏览器变得好看,毕竟罗卜白菜,给有所爱。。。

与之对比,来看Chrome。Chrome有了插件,有了皮肤,但是没有扩展。这就意味着,你很难为Chrome定制一些特色的功能。目前,所有对Chrome的功能扩展,都是通过书签抑或是修改内核来实现的。前者能力太弱,后者开发起来太麻烦,容易出错不提,还必须要与时俱进,跟上版本的变化,并且还不能自由的选择或关闭。因此,这都不是长远之计,Chrome提供一套类似于firefox的扩展机制,也许才是正道。据传说,Chrome团队正在琢磨这件事,不知道最终会出来个怎么样的结果,是尽力接近firefox降低移植成本,还是另立门户特立独行,我想可以拭目以待一把。。。

在多进程模式下,Chrome的插件还有一个问题,前面提到过,就是关于UI控件的。由于NPAPI的标准,是允许插件创建HWND窗口的,这就使得当Plugin繁忙,且Browser进程发起HWND的同步的时候,主进程被挂起,这个浏览器停滞。在Render进程中,解决这个问题的思路是控制权限,不然Render创建HWND,到了Plugin中,这招不能使用,只能够使用另一招,就是监管。不停的检查Plugin是否太繁忙,无法响应,一旦发现,立即杀死该Plugin及其所处的页面。这就好比你想解决奶中有三氯氰胺的问题,要么控制奶源,不从奶站购买全部用自家的,要么加强监管,提高检查力度防止隐患。两种策略的优缺点一眼便知,依照不同环境采取不同策略即可。。。

总体说来,Chrome的可扩展性着实一般,不过Chrome还处于Beta中,我们可以继续期待。。。