原文:http://www.cnblogs.com/duguguiyu/archive/2008/11/05/1326777.html
1. NPAPI
為了緊密的與各個(gè)開(kāi)源瀏覽器團(tuán)結(jié)起來(lái),共同抗擊IE的壟斷,Chrome的插件,也遵循了NPAPI(Netscape Plugin Application Programming Interface)標(biāo)準(zhǔn),支持這個(gè)標(biāo)準(zhǔn)的瀏覽器需要實(shí)現(xiàn)一組規(guī)定的API供插件調(diào)用,這組API形如NPN_XXX,比如NPN_GetURL,插件可以利用這些API進(jìn)行二次開(kāi)發(fā)。而NPAPI插件以一個(gè)Dll之類的作為物理載體(windows下dll,linux下是so...)進(jìn)行提供,里面同樣也實(shí)現(xiàn)了一組規(guī)定的API。形式包括NP_XXX和NPP_XXX,NP_XXX是系統(tǒng)需要默認(rèn)調(diào)用的方法,用于認(rèn)知這個(gè)插件,比如NP_Initialize, 而NPP_XXX是用于插件完成一些實(shí)際功能,比如NPP_New。。。
所有的插件dll都需要放置在指定目錄下(根據(jù)操作系統(tǒng)的不同而不同...),每個(gè)插件可以處理一種或多種MIME格式的數(shù)據(jù),比如application/pdf,說(shuō)明該插件可以處理pdf相關(guān)的文檔。在Chrome中鍵入about:plugins,可以查看當(dāng)前Chrome中具有的插件信息。。。
NPAPI是一個(gè)很經(jīng)典的插件方案,用dll進(jìn)行注入,用協(xié)定的API進(jìn)行通信,用字符串描述插件能力。插件宿主(在這里就是瀏覽器...),會(huì)根據(jù)能力描述,動(dòng)態(tài)加載插件,并負(fù)責(zé)插件調(diào)用的流程和生命周期管理。而插件中,負(fù)責(zé)真實(shí)邏輯的處理,并可以構(gòu)造UI與用戶交流。以此類方式實(shí)現(xiàn)的插件系統(tǒng),往往是處理的邏輯比較固定適用范圍一般(用API寫(xiě)死了邏輯...),但可擴(kuò)展性不錯(cuò)(用字符串描述能力,可無(wú)限擴(kuò)展...)。。。
在Chrome中nphostapi.h中,定義了所有NPAPI相關(guān)的函數(shù)指針和結(jié)構(gòu),這個(gè)文件放置在glue目錄下,如果看過(guò)前面碰過(guò)的文章就知道,在WebKit內(nèi)肯定也有一套相同的東西;在npapi.h/.cc中,提供了Chrome瀏覽器端的NPN_XXX系列函數(shù)的實(shí)現(xiàn);每一個(gè)插件物理實(shí)例,用PluginLib類來(lái)表示,而每一個(gè)插件的邏輯實(shí)例,用PluginInstance類來(lái)表示。這個(gè)概念牽強(qiáng)附會(huì)的可以用windows中的句柄來(lái)類比,當(dāng)你想操作一個(gè)內(nèi)核對(duì)象,你需要獲得一個(gè)內(nèi)核對(duì)象的句柄,每個(gè)進(jìn)程中的句柄肯定不相同,但后面的內(nèi)核對(duì)象卻是同一個(gè),內(nèi)核對(duì)象的生命周期通過(guò)句柄的計(jì)數(shù)來(lái)控制,有人用則或,無(wú)人用則死(當(dāng)然這個(gè)類比相當(dāng)?shù)臓繌?qiáng),主要是想說(shuō)明引用計(jì)數(shù)和邏輯與物理的關(guān)系,但一個(gè)關(guān)鍵性的區(qū)別在于,PluginLib與PluginInstance都是在一個(gè)進(jìn)程內(nèi)的,不能跨越進(jìn)程邊界...)。在Chrome中,PluginLib負(fù)責(zé)加載和銷毀一個(gè)dll,拿到所有導(dǎo)出函數(shù)的函數(shù)指針,PluginInstance對(duì)這些東西進(jìn)行了封裝,可以更好的來(lái)調(diào)用。。。
關(guān)于NPAPI的更多細(xì)節(jié),Chrome并沒(méi)有提供任何文檔,但是,各個(gè)先驅(qū)的瀏覽器們都提供了大量豐富的文檔。比如,你可以到 這里,查看firefox中的NPAPI文檔,基本通用。。。
2. Chrome的多進(jìn)程插件模型
Chrome的插件模型,與早先的瀏覽器的最大不同,是它采用了多進(jìn)程的方式,每一個(gè)插件,都有一個(gè)單獨(dú)的進(jìn)程來(lái)承載(Shift + Esc打開(kāi)Chrome進(jìn)程管理器,可以看到現(xiàn)在已經(jīng)加載的插件進(jìn)程...)。當(dāng)WebKit進(jìn)行頁(yè)面渲染的時(shí)候,發(fā)現(xiàn)了未知的MIME類型數(shù)據(jù),它會(huì)告知給Browser進(jìn)程,召喚它提供一個(gè)插件來(lái)解析。如果該插件還未加載,Browser會(huì)在指定目錄中搜尋出具有此實(shí)力的插件(如果沒(méi)有此類人才只能作罷...),并為它創(chuàng)建一個(gè)進(jìn)程,讓它負(fù)責(zé)所有的該插件相關(guān)的任務(wù),然后建立起一個(gè)IPC通路,與它“保持通話”。這套流程一定不會(huì)太陌生,因?yàn)樗cRender進(jìn)程的創(chuàng)建大同小異換湯不換藥。。。
Plugin進(jìn)程與Render進(jìn)程最大的區(qū)別在于,Render需要與Browser進(jìn)程大量通信,因?yàn)樗腍WND歸Browser老大掌管著,相關(guān)所有內(nèi)容都需要通信完成。但Plugin不需要與Browser頻繁聯(lián)系,它大部分的通信都是與Render進(jìn)程發(fā)生的。如果Plugin與Render之間的通信,還需要走Browser中轉(zhuǎn)一下,這就顯得有些脫褲子放屁了,雖然Browser是大頭,但不是冤大頭,它不會(huì)干這種吃力不討好的事情。他只是做了一回Render與Plugin間的媒婆而已。當(dāng)Plugin與Browser建立好了IPC通路后,它會(huì)讓Render建立一個(gè)新IPC通路,用以與Plugin通信,IPC的有名管道名,經(jīng)由Browser通知給Plugin。完成名字協(xié)商后,Render與Plugin的通信關(guān)系就建立好了,它們之間就可以直接進(jìn)行通信了。。。
整個(gè)通信模式,可以看 這里 。這是一個(gè)很標(biāo)準(zhǔn)的代理模式的應(yīng)用,稍有了解的都可以跳過(guò)我后面會(huì)做的一段羅嗦的描述,一看官方文檔中的圖便能知曉。在Render進(jìn)程端,WebPluginImpl是WebPlugin的一個(gè)子類,WebPlugin是供Webkit進(jìn)行調(diào)用的一個(gè)接口,利用依賴倒置,實(shí)現(xiàn)了擴(kuò)展。在Plugin進(jìn)程端,實(shí)現(xiàn)了一個(gè)WebPluginDelegateImpl類,該類會(huì)調(diào)用PluginInstance的相關(guān)接口實(shí)現(xiàn)真實(shí)的插件功能。這樣的話,只需要WebPluginImpl調(diào)用WebPluginDelegateImpl中的相應(yīng)方法,就可以實(shí)現(xiàn)功能。但問(wèn)題是WebPluginImpl與WebPluginDelegateImpl天各一方各處于一個(gè)進(jìn)程,很顯然,這里需要一個(gè)代理模式。這里沿用了COM的架構(gòu),Delegate + Stub + Proxy。WebPluginImpl調(diào)用代理WebPluginDelegateProxy,該代理會(huì)將調(diào)用轉(zhuǎn)換成消息,通過(guò)IPC發(fā)送給Plugin進(jìn)程,在Plugin端,通過(guò)WebPluginDelegateStub監(jiān)聽(tīng)消息,并轉(zhuǎn)換成對(duì)真實(shí)WebPluginDelegateImpl的調(diào)用,從而完成了跨進(jìn)程的一個(gè)調(diào)用,反之亦然。。。
3. Chrome的可擴(kuò)展性
總所周知,firefox通過(guò)三種方式進(jìn)行自定義,插件、擴(kuò)展和皮膚。其中,插件是使得瀏覽器能用,不會(huì)出現(xiàn)一大塊一大塊的無(wú)法顯示的區(qū)域;擴(kuò)展是使得瀏覽器好用,可以簡(jiǎn)單方便的進(jìn)行功能的定制和個(gè)性化配置;皮膚是幫助瀏覽器變得好看,畢竟羅卜白菜,給有所愛(ài)。。。
與之對(duì)比,來(lái)看Chrome。Chrome有了插件,有了皮膚,但是沒(méi)有擴(kuò)展。這就意味著,你很難為Chrome定制一些特色的功能。目前,所有對(duì)Chrome的功能擴(kuò)展,都是通過(guò)書(shū)簽抑或是修改內(nèi)核來(lái)實(shí)現(xiàn)的。前者能力太弱,后者開(kāi)發(fā)起來(lái)太麻煩,容易出錯(cuò)不提,還必須要與時(shí)俱進(jìn),跟上版本的變化,并且還不能自由的選擇或關(guān)閉。因此,這都不是長(zhǎng)遠(yuǎn)之計(jì),Chrome提供一套類似于firefox的擴(kuò)展機(jī)制,也許才是正道。據(jù)傳說(shuō),Chrome團(tuán)隊(duì)正在琢磨這件事,不知道最終會(huì)出來(lái)個(gè)怎么樣的結(jié)果,是盡力接近firefox降低移植成本,還是另立門戶特立獨(dú)行,我想可以拭目以待一把。。。
在多進(jìn)程模式下,Chrome的插件還有一個(gè)問(wèn)題,前面提到過(guò),就是關(guān)于UI控件的。由于NPAPI的標(biāo)準(zhǔn),是允許插件創(chuàng)建HWND窗口的,這就使得當(dāng)Plugin繁忙,且Browser進(jìn)程發(fā)起HWND的同步的時(shí)候,主進(jìn)程被掛起,這個(gè)瀏覽器停滯。在Render進(jìn)程中,解決這個(gè)問(wèn)題的思路是控制權(quán)限,不然Render創(chuàng)建HWND,到了Plugin中,這招不能使用,只能夠使用另一招,就是監(jiān)管。不停的檢查Plugin是否太繁忙,無(wú)法響應(yīng),一旦發(fā)現(xiàn),立即殺死該P(yáng)lugin及其所處的頁(yè)面。這就好比你想解決奶中有三氯氰胺的問(wèn)題,要么控制奶源,不從奶站購(gòu)買全部用自家的,要么加強(qiáng)監(jiān)管,提高檢查力度防止隱患。兩種策略的優(yōu)缺點(diǎn)一眼便知,依照不同環(huán)境采取不同策略即可。。。
總體說(shuō)來(lái),Chrome的可擴(kuò)展性著實(shí)一般,不過(guò)Chrome還處于Beta中,我們可以繼續(xù)期待。。。
本文鏈接:http://m.95time.cn/tech/program/2009/6571.asp
出處:Venus神廟
責(zé)任編輯:bluehearts
上一頁(yè) Chrome的UI繪制 下一頁(yè)
◎進(jìn)入論壇網(wǎng)絡(luò)編程版塊參加討論
|