WebKit之NPAPI插件

转载 2015年11月20日 00:00:05

转载请注明原文地址:http://blog.csdn.net/milado_nju/article/details/7216136

# 插件机制(NPAPI plugin)

## 概述

Chromium中的NPAPI插件(plugin)来源于mozilla的插件机制。因为它被广泛的应用,很多插件厂商或者开发者基于它编写了数以万计的插件,因而chromium对它也提供了支持,不过chromium有自己独特的插件架构,后面我们会详细介绍。

NPAPI提供两组接口,一类以NPP打头,由插件来实现,被浏览器调用,主要包括一些插件创建,初始化,关闭,销毁,信息查询及事件处理,数据流,窗口设置,URL等;另一类以NPN打头,由浏览器来实现,被插件所调用,主要包括图形绘制,数据流处理,浏览器信息查询,内存分配和释放,浏览器的插件设置,URL等。

原始的NPAPI的接口使用起来不是很方便,因而有贡献者对其进行了封装以利于其使用。一个比较著名的开源项目是Firebreath。它将原始的C风格的NPAPI进行封装成C++风格的接口,非常方便用户使用,而且有针对Windows和X window的移植,用户无需对底层特别了解。特别的是,Firebreath也有对ActiveX的封装,因而对于现在主流的两种插件接口,你都可以基于Firebreath的接口进行编程,极大地方便了开发者。详情请参考Firebreath主页http://www.firebreath.org/display/documentation/FireBreath+Home

 ## 架构

因为chromium的安全模型,renderer进程没有访问除I/O读写等之外的权限,因而插件需要有自己的进程,这就是插件的out-of-process模型。下图给出chromium中插件的架构和进程模型。


每一种类型的plugin只有一个进程,这就是说,如果有两个或者多个renderer进程同时使用同一个插件,那么该插件会共享同一个进程。因为多个renderer进程共享同一种的plugin进程,那么plugin进程如何为它们服务呢?答案是为每个插件使用点在plugin进程中创建一个插件实例(PluginInstance).

值得注意的是,plugin进程是由browser进程来负责创建和销毁, 而不是renderer进程。 原因在于renderer进程没有创建的权限,而且plugin进程由browser进程来统一管理也更方便。 当plugin进程创建成功时,browser进程会返回IPCchannel handle用于创建和plugin进程通讯的PluginChannelHost. 那它什么时候被销毁呢?当没有任何插件实例并且空闲一段事件后,它才会被销毁,这样做的好处是避免频繁的创建和销毁plugin进程。

下图描述了browser和plugin进程间的通讯机制及其所涉及的相关的模块(类)。Browser进程通过PluginProcessHost发送消息调用Plugin进程的函数,响应动作由PluginThread完成。而Plugin进程则是通过WebPluginProxy发送消息调用browser的函数,响应动作有PluginProcessHost完成。


Browser和Plugin仅有较少的消息传递,用于创建等管理工作。主要的部分在renderer进程和plugin进程之间,机制也相对更复杂一些。HTMLPluginElement会包含一个WebPluginContainerImpl,而它包含一个WebPluginImpl,对plugin的调用有WebPluginDelegateProxy负责中转。在Plugin进程中,由WebPluginDelegateStub处理所有renderer过来的请求,并由WebPluginDelegateImpl调用创建好的PluginInstance对象。PluginInstance最终调用PluginLib读取的插件的函数入口地址,最终完成对插件实现的调用。而对插件实现中对NPN开头函数的调用,则是通过PluginHost来完成。

PluginHost主要负责实现NPN开头的函数,如前面所描述,这些函数被plugin进程所调用。可以在plugin和renderer进程被调用。当在plugin进程调用这些函数时,chromium会覆盖PluginHost的部分函数,而这些新的callback函数会调用NPObjectProxy来通过IPC发送请求到renderer进程。

PluginInstance实现了NPP开头的函数,被render所调用(webpluginImpl通过webplugindelegateImpl来调用),PluginInstance通过PluginLib获得了插件库的函数地址,从而把实际的调用桥接到具体的插件中。

具体的见下图所示,主要结构来源于chromium的官网,略有修改。


对于NPObject相关的函数调用, 有专门的类来处理。NPObject的调用或者访问是双向的(renderer进程<->plugin进程),他们的具体实现是通过NPObjectProxy和NPObjectStub来完成。 NPObjectProxy接受来自对方的访问请求,转发给NPObjectStub,最后NPObjectStub调用真正的NPObject并返回结果。见下图所示。


下面示例给出一个插件如何被renderer进程触发创建的过程。


当页面中包含一个“embed”或者“object”元素,renderer进程会创建一个HTMLEmbedElement元素,当该元素被访问是,会触发创建相应的插件。HTMLEmbedElement会请求创建自己对应的RenderWidget(WebPluginContainerImpl),进而创建WebPluginImpl和WebPluginDelegateProxy。WebPluginDelegateProxy会发送消息来创建Plugin进程。Plugin进程被browser进程创建后,会响应renderer的请求来创建PluginInstance并初始化它,这样它们之间的联系就建立好了。

##  Window和windowless插件

可以通过设置”embed”或者”object”元素的属性。两者的区别主要在于绘图的方式不同。Window插件由renderer进程提供一个窗口(window), 插件直接在该窗口上进行绘制;而windowless插件则不同,插件将绘制的结构(Pixmap),通过共享内存方式(Transport DIB)传递给renderer进程,renderer绘制该内容到自己内部的存储结构(backing store)上。好处是,可以把插件绘制的结构和网页上的其他内容做各种形式的合成。但是,从上面不难看出,一般来讲,window模式的性能是要高于windowless的。

## 相关目录和文件

third_party/WebKit/Source/WebKit/chromium/public/webplugin.h:

         定义Webkit::WebPlugin接口,用于创建和销毁插件,及传送事件给插件

content/common/plugin_messages.h:

         定义plugin进程与renderer进程和browser进程间的消息结构体,包括五类:

PluginProcessMsg开头的消息- browser进程发给plugin进程

PluginProcessHostMsg开头的消息- plugin进程发给browser进程

PluginMsg开头的消息- renderer进程发给plugin进程

PluginHostMsg开头的消息- plugin进程发给renderer进程

NPObjectMsg开头的消息- plugin进程与render进程相互编码和解码NPObject

content/common/npobject_stub.(h&cc):

                   类NPObjectStub的定义和实现

content/common/npobject_Proxy.(h&cc):

                   类NPObjectProxy的定义和实现

content/plugin:

         该目录用于存放Plugin进程使用的IPC和WebPlugin相关的函数和类

content/plugin/webplugin_proxy.(h&cc):

                   实现WebKit::npapi::WebPlugin接口,把插件的调用通过IPC发送给renderer进程

content/plugin/webplugin_delegate_stub.(h&cc):

                   把WebPluginDelegateProxy的消息转换为对WebPluginDelegateImpl的调用

content/plugin/plugin_channel.(h&cc):

                   定义Plugin进程与renderer进程通信的通道

webkit/plugins/npapi/:

         该目录用于存放Plugin进程使用的对WebKit接口实现和插件库处理的相关的函数和类

webkit/plugins/npapi/webplugin.h:

                   定义WebPlugin接口,用于plugin端同web frame和webcore对象的交互

webkit/plugins/npapi/webplugin_impl.(h&cc):

                   实现WebKit::WebPlugin和WebPlugin接口,通过WebPluginPageDelegate来创建WebPluginDelegate

webkit/plugins/npapi/plugin_instance.(h&cc)

                   PluginInstance类的接口和实现,代表一个Plugin实例,对应于renderer进程的一个请求创建的plugin实例

webkit/plugins/npapi/webplugin_delegate.h:

                   定义WebPlugin代理,用来分离具体的插件的实现方式,例如可以使来实现进程内或者跨进程的插件架构,对WebPlugin来说,具体架构是透明的

webkit/plugins/npapi/webplugin_delegate_impl.(h&cc):

                   响应renderer进程实现对PluginInstance的调用请求,有gtk,win和aura三种不同的实现

webkit/plugins/npapi/plugin_host.(h&cc):

                   实现NPN开头的函数,在plugin进程和renderer进程有不同的实现

webkit/plugins/npapi/plugin_lib.(h&cc):

                   PluginLib用来管理实际插件库的生命周期

content/renderer/webplugin_delegate_proxy.(h&cc)

                   定义和实现WebPluginDelegateProxy类,桥接所有来自于WebPlugin的请求到WebPluginDelegateImpl

content/browser/plugin_process_host.(h&cc):

                   类PluginProcessHost的定义和实现,用于Browser进程与plugin进程的交互

content/browser/plugin_service_impl.(h&cc):

                   类PluginServiceImpl的定义和实现,用于响应Renderer进程创建插件请求及其他一些插件管理工作

浏览器插件编程NPAPI之入门篇——NPAPI的介绍

浏览器插件编程NPAPI之入门篇——NPAPI的介绍 最近在学习Mac OSX平台下浏览器的插件开发,首先我查看了Xcode的Document关于WebKit的Plugins的介绍,却看到苹果有...
  • djinglan
  • djinglan
  • 2013年09月23日 21:37
  • 7553

注册表部署firefox的NPAPI插件

这里只讲插件如何通过注册表部署到firefox浏览器,不讲npapi插件的生成(这部分会抽出时间另写一篇文章) 假如已经生成了NPAPI插件,名字我们家设为npTest.dll。 一:要写入的注册...
  • wwwwxhh
  • wwwwxhh
  • 2015年05月15日 17:20
  • 1706

浏览器插件开发之——NPAPI

 一 浏览器概述    关于什么是浏览器,强大的wiki已经做了比较完善的解释http://en.wikipedia.org/wiki/Web_browser。相关浏览器的比较参考:http://en...
  • cnjet
  • cnjet
  • 2011年02月10日 10:47
  • 5442

NPAPI插件回调JS方法

NPAPI插件回调js方法比较简单,通过调用invoke函数就能够执行js中的方法,在调用这个函数之前得做一下几点准备: 1.一个NPNetScapeFuncs类型的全局变量,这个变量在调用NP_I...
  • wll111162
  • wll111162
  • 2013年04月27日 15:46
  • 1541

NPAPI插件开发详细记录:插件开发入门

为什么这还是入门呢?因为前面的我们什么都没学会,只是学会了建立一个dll项目,并生成了一个Firefox可以识别dll,在测试页面中不会弹出需要下载插件的错误。而任何功能都没有实现。所以这里才是真正的...
  • yuan_lo
  • yuan_lo
  • 2016年06月01日 10:05
  • 2104

NPAPI插件开发详细记录:实用功能——改变插件窗口大小

我们有时候需要调整插件窗口的尺寸大小,比如说,当你创建一个视频播放窗口,在用户点击播放之后想要将窗口的大小调整为视频的实际大小。播放完毕之后又将窗口尺寸调整回原来的尺寸大小。 要实现这样一个功能,最...
  • z6482
  • z6482
  • 2012年12月16日 15:56
  • 9154

NPAPI插件开发详细记要:插件运行流程分析

NPAPI插件开发详细记录:插件运行流程分析 本文详细分析插件的代码是如何执行的,主要分析np_entry.cpp、npn_gate.cpp和npp_gate.cpp.希望能够有所收获。 在windo...
  • yuan_lo
  • yuan_lo
  • 2016年06月01日 10:20
  • 1434

开发顺带NPAPI插件的Chrome扩展

开发附带NPAPI插件的Chrome扩展 1     NPAPI插件 1.1   NPAPI简介 NPAPI(Netscape Plugin Application Programmin...
  • bible521125
  • bible521125
  • 2015年12月30日 18:47
  • 1074

NPAPI插件开发详细记录:与JS交互

插件主要用于HTML页面中增强HTML页面可以支持的资源类型,在HTML页面中最重要的一个特性就是可以利用脚本语言来实现与用户的交互,之前的文章也提及过相关的议题,不过在交流过程中还是发现好多开发者对...
  • z6482
  • z6482
  • 2014年04月05日 17:39
  • 5799

NPAPI插件与JS交互开发详细记录

可以在JS中使用document.getElementsByTagName或者document.getElementById来获取页面中已经存在的插件对象,还可以在JS中使用document.crea...
  • xujinming0124
  • xujinming0124
  • 2015年06月24日 13:43
  • 1246
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:WebKit之NPAPI插件
举报原因:
原因补充:

(最多只允许输入30个字)