ImageVerifierCode 换一换
格式:DOCX , 页数:41 ,大小:119.22KB ,
资源ID:7956944      下载积分:3 金币
快捷下载
登录下载
邮箱/手机:
温馨提示:
快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。 如填写123,账号就是123,密码也是123。
特别说明:
请自助下载,系统不会自动发送文件的哦; 如果您已付费,想二次下载,请登录后访问:我的下载记录
支付方式: 支付宝    微信支付   
验证码:   换一换

加入VIP,免费下载
 

温馨提示:由于个人手机设置不同,如果发现不能下载,请复制以下地址【https://www.bdocx.com/down/7956944.html】到电脑端继续下载(重复下载不扣费)。

已注册用户请登录:
账号:
密码:
验证码:   换一换
  忘记密码?
三方登录: 微信登录   QQ登录  

下载须知

1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。
2: 试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。
3: 文件的所有权益归上传用户所有。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 本站仅提供交流平台,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

版权提示 | 免责声明

本文(Chromium的Plugin进程启动过程分析.docx)为本站会员(b****6)主动上传,冰豆网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知冰豆网(发送邮件至service@bdocx.com或直接QQ联系客服),我们立即给予删除!

Chromium的Plugin进程启动过程分析.docx

1、Chromium的Plugin进程启动过程分析Chromium的Plugin进程启动过程分析前面我们分析了Chromium的Render进程和GPU进程的启动过程,它们都是由Browser进程启动的。在Chromium中,还有一类进程是由Browser进程启动的,它们就是Plugin进程。顾名思义,Plugin进程是用来运行浏览器插件的。浏览器插件的作用是扩展网页功能,它们由第三方开发,安全性和稳定性都无法得到保证,因此运行在独立的进程中。本文接下来就详细分析Plugin进程的启动过程。在Chromium中,还有一种组件比较容易和浏览器插件混淆,它们称为浏览器扩展(Extension)。浏览器

2、扩展工作在浏览器层面上,用来扩展浏览器的功能,例如可以在浏览器的工具栏上增加一个按钮,并且通过浏览器提供的API实现某种功能,例如翻墙。浏览器插件工作在网页层面上,用来扩展网页的功能,例如在网页上显示一个PDF文档或者播放Flash视频。 本文要分析的是浏览器插件。在Chromium中,浏览器插件又分为两类,一类称为NPAPI插件,另一类称为PPAPI插件。NPAPI的全称是Netscape Plugin API,就是运行在Netscape Navigator浏览器上的一种插件,也就是由Netscape定义一套API接口,插件开发商通过调用这些API接口来扩展网页的功能。Netscape Na

3、vigator浏览器虽然早已离我们远去,但是NPAPI插件还顽强地活着,并且成为了一种几乎所有浏览器都支持的跨平台插件标准。因此,Chromium也对NPAPI插件进行了支持,目的是为了可以运行数以万计已经存在的NPAPI插件。 但是由于NPAPI插件定义的API接口太古老了,也太难用了,崩溃问题和安全问题也很多,无法适应现代浏览器的发展,因此Chromium搞了另外一套API接口,称为PPAPI接口,全称是Pepper Plugin API。基于PPAPI实现的插件就称为PPAPI插件。Chromium从2014年1月,逐渐放弃对NPAPI插件的支持,因此本文接下来要分析的是PPAPI插件。

4、 PPAPI插件使用了一种称为Native Client(NaCl)的技术来解决安全性问题。在Native Client技术中,我们可以使用熟悉的Native语言C/C+开发插件核心模块,以满足效率要求。这些C/C+模块通过IPC可以与网页中的JS进行通信,同时它们还可以通过PPAPI使用浏览器提供的功能,例如可以通过PPB_OpenGLES2接口使用浏览器提供的OpenGL渲染能力。为了保证安全性,Native Client在工具链层面上限制C/C+模块能够调用的本地OS提供的API接口。也就是说,PPAPI插件的C/C+模块要通过Native Client提供的编译工具进行编译,而这些编译

5、工具会检查PPAPI插件的C/C+模块调用的API,并且禁止非法API调用。这样实际上就给PPAPI插件加上了两层安全保护。第一层安全保护体现在运行时,将PPAPI插件运行在一个受限进程中,即运行在一个沙箱中。第二层安全保护体现在编译时,禁止Native代码调用非法API。 PPAPI插件有三种运行模式。第一种模式是运行在一个受限的独立进程中,即运行在沙箱中。第二种模式运行在一个非受限的独立进程中。第三种模式直接运行在Render进程中。一个PPAPI插件运行在哪一种模式取决于浏览器内部实现和浏览器命令行参数。浏览器内部实现会对某些内部PPAPI的运行模式进行Hard Code,例如PDF插件

6、。这一点可以参考ChromeContentClient类的成员函数AddPepperPlugins(定义在文件external/chromium_org/chrome/common/chrome_content_client.cc中)。此外,如果浏览器命令行参数指定了switches:kPpapiInProcess选项,则其余安装的PPAPI插件将运行在第三种模式中,否则的话,就运行在第一种模式中。这一点可以参考函数ComputePluginsFromCommandLine(定义在文件external/chromium_org/content/common/pepper_plugin_list

7、.cc中)。 本文主要关注的是PPAPI插件进程的启动过程。通过这个启动过程,我们可以了解PPAPI插件进程与Browser进程和Render进程的关系,如下所示: Render进程在解析网页时,如果遇到一个embed标签,那么就会创建一个HTMLPlugInElement对象来描述该标签,并且调用该HTMLPlugInElement对象的成员函数loadPlugin加载对应的PPAPI插件。但是Render进程没有启动PPAPI插件进程的权限,因此它就会通过之前与Browser进程建立的IPC通道向Browser进程发出一个启动PPAPI插件进程的请求。 Browser进程接收到启动PPAP

8、I插件进程的请求之后,就会启动一个PPAPI插件进程,并且创建一个PpapiPluginProcessHost对象描述该PPAPI插件进程。PPAPI插件进程启动起来之后,会在内部创建一个ChildProcess对象,用来与Browser进程中的PpapiPluginProcessHost对象建立一个IPC通道。有了这个IPC通道之后,Browser进程请求PPAPI插件进程创建另外一个UINX Socket。该UNIX Socket的Server端文件描述符保留在PPAPI进程中,Client端文件描述符则返回给Render进程。基于这个UNIX Socket的Server端和Client端

9、文件描述符,PPAPI插件进程和Render进程将分别创建一个HostDispatcher对象和一个PluginDispatcher对象,构成一个Plugin通道。以后PPAPI插件进程和Render进程就通过该Plugin通道进行通信。 接下来,我们就从HTMLPlugInElement类的成员函数loadPlugin开始,分析PPAPI插件进程的启动过程,如下所示:cpp view plain copybool HTMLPlugInElement:loadPlugin(const KURL& url, const String& mimeType, const Vector& paramN

10、ames, const Vector& paramValues, bool useFallback, bool requireRenderer) LocalFrame* frame = document().frame(); . RefPtr widget = m_persistedPluginWidget; if (!widget) . widget = frame-loader().client()-createPlugin(this, url, paramNames, paramValues, mimeType, loadManually, policy); . return true;

11、 这个函数定义在文件external/chromium_org/third_party/WebKit/Source/core/html/HTMLPlugInElement.cpp中。 HTMLPlugInElement类的成员变量m_persistedPluginWidget的值等于NULL的时候,说明当前正在处理的HTMLPlugInElement对象描述的插件实例还没有创建,或者需要重新创建。在这种情况下,HTMLPlugInElement类的成员函数loadPlugin就会首先获得当前网页的Document对象,然后通过该Document对象获得一个LocalFrame对象,这个Loca

12、lFrame对象描述的是当前网页的页框。每一个LocalFrame对象都有一个关联的FrameLoader对象,这个FrameLoader对象用来加载当前网页的页框。每一个FrameLoader对象又关联有一个FrameLoaderClientImpl对象,通过这个FrameLoaderClientImpl对象,WebKit可以用来请求执行平台相关的操作,例如,HTMLPlugInElement类的成员函数loadPlugin就通过调用它的成员函数createPlugin创建一个插件实例。 FrameLoaderClientImpl类的成员函数createPlugin的实现如下所示:cpp v

13、iew plain copyPassRefPtr FrameLoaderClientImpl:createPlugin( HTMLPlugInElement* element, const KURL& url, const Vector& paramNames, const Vector& paramValues, const String& mimeType, bool loadManually, DetachedPluginPolicy policy) . WebPlugin* webPlugin = m_webFrame-client()-createPlugin(m_webFrame,

14、 params); . / The container takes ownership of the WebPlugin. RefPtr container = WebPluginContainerImpl:create(element, webPlugin); if (!webPlugin-initialize(container.get() return nullptr; . return container; 这个函数定义在文件external/chromium_org/third_party/WebKit/Source/web/FrameLoaderClientImpl.cpp中。 F

15、rameLoaderClientImpl类的成员变量m_webFrame指向的是一个WebLocalFrameImpl对象,该WebLocalFrameImpl对象用来描述当前处理的网页内容是在当前进程进行渲染的,并且通过该WebLocalFrameImpl对象的成员函数client可以获得一个WebFrameClient对象,该WebFrameClient对象是用WebKit用来与上层使用者,即Chromium进行交互的,例如WebKit就通过调用它的成员函数createPlugin创建一个插件实例。创建出来的插件实例在WebKit中用一个WebPlugin对象描述,这个WebPlugin对

16、象最后封装在一个WebPluginContainerImpl对象中返回给调用者。 创建出来的WebPlugin对象在返回给调用者之前,会先调用其成员函数initailize进行初始化。对于NPAPI插件来说,初始化工作包括请求Browser进程启动一个插件进程,但是对于PPAPI插件来说,插件进程是在上述的插件实例创建过程中请求Browser进程启动的,接下来我们就会到这一点。由于NPAPI插件进程和PPAPI插件进程的启动过程类似,因此我们只关注PPAPI插件进程的启动过程。 Chromium将上述WebFrameClient对象指定为一个RenderFrameImpl对象,这个Render

17、FrameImpl对象是Chromium用来描述当前正在处理的一个网页的,它的成员函数createPlugin的实现如下所示:cpp view plain copyblink:WebPlugin* RenderFrameImpl:createPlugin( blink:WebLocalFrame* frame, const blink:WebPluginParams& params) DCHECK_EQ(frame_, frame); blink:WebPlugin* plugin = NULL; if (GetContentClient()-renderer()-OverrideCreate

18、Plugin( this, frame, params, &plugin) return plugin; if (base:UTF16ToASCII(params.mimeType) = kBrowserPluginMimeType) return render_view_-GetBrowserPluginManager()-CreateBrowserPlugin( render_view_.get(), frame, false); #if defined(ENABLE_PLUGINS) WebPluginInfo info; std:string mime_type; bool found

19、 = false; Send(new FrameHostMsg_GetPluginInfo( routing_id_, params.url, frame-top()-document().url(), params.mimeType.utf8(), &found, &info, &mime_type); if (!found) return NULL; if (info.type = content:WebPluginInfo:PLUGIN_TYPE_BROWSER_PLUGIN) return render_view_-GetBrowserPluginManager()-CreateBro

20、wserPlugin( render_view_.get(), frame, true); WebPluginParams params_to_use = params; params_to_use.mimeType = WebString:fromUTF8(mime_type); return CreatePlugin(frame, info, params_to_use); #else return NULL; #endif / defined(ENABLE_PLUGINS) 这个函数定义在文件external/chromium_org/content/renderer/render_fr

21、ame_impl.cc中。 Chromium是多层架构的,从上到下大概分为浏览器层、Content层和WebKit层。其中,WebKit层用来解析网页,Content层位于WebKit层之上,并且提供多进程架构。这样我们就可以基于Content层,实现一个浏览器。例如,Chrome就是基于Chromium的Content层提供的API实现的。这意味着我们也可以基于Chromium的Content层实现一个与Chrome类似的浏览器。 Chromium为了能够让浏览层定制一些Content层的行为,允许浏览器层设置一个Content Client到Content层来。Chromium在执行某些操

22、作时,就会首先通过函数GetContentClient获得上述Content Client,然后再通过它询问浏览层是否需要接管该操作。例如,在我们这个场景中,RenderFrameImpl类的成员函数createPlugin会先询问浏览器层是否需要接管创建插件实例的操作。如果浏览器层需要接管,那么它就负责根据指定的参数创建一个相应的插件实现,这时候RenderFrameImpl类的成员函数createPlugin就什么也不用做。 浏览器层设置到Content层的Content Client包含有两个部分,一部分称为Browser端,另一部分称为Renderer端。其中,Browser端运行在C

23、hromium的Browser进程中,负责接管Chromium的Browser进程的某些操作,而Renderer端运行在Chromium的Render进程中,负责接管Chromium的Render进程的某些操作。从这里我们可以看到,RenderFrameImpl类的成员函数createPlugin是通过调用浏览器层设置到Content层的Content Client的Renderer端的成员函数OverrideCreatePlugin来询问浏览层是否需要接管创建插件实例的操作的。 假设浏览层不接管创建插件实例的操作,那么RenderFrameImpl类的成员函数createPlugin接下来判

24、断embed标签的type属性值是否等于kBrowserPluginMimeType,即“application/browser-plugin”。如果等于的话,那么就意味着要创建一个Browser Plugin,这是通过调用一个Browser Plugin Manager的成员函数CreateBrowserPlugin创建的。Browser Plugin的作用类似于HTML中的iframe,是用来在当前网页中内嵌另外一个网页的,更详细的信息可以参考这里:。注意,Browser Plugin是由Chromium提供实现支持的,而不是某一个Plugin。 假设embed标签的type属性值不等于k

25、BrowserPluginMimeType,那么RenderFrameImpl类的成员函数createPlugin接下来向Browser进程发送一个类型为FrameHostMsg_GetPluginInfo的IPC消息,用来获取要创建的插件实例的更详细的信息,实际上就是通过embed标签的type属性值在已安装的插件列表找到一个对应的插件。 如果没有找到与embed标签的type属性值对应的插件,那么RenderFrameImpl类的成员函数createPlugin就什么也不做就返回了。另一方面,如果找到的插件的类型为content:WebPluginInfo:PLUGIN_TYPE_BROW

26、SER_PLUGIN,那么同样意味要创建一个Browser Plugin,因此这时候也会调用Browser Plugin Manager的成员函数CreateBrowserPlugin创建一个Browser Plugin。 假设找到了一个对应的插件,并且该插件的类型不是content:WebPluginInfo:PLUGIN_TYPE_BROWSER_PLUGIN,那么RenderFrameImpl类的成员函数createPlugin接下来就会调用另外一个成员函数CreatePlugin创建一个插件实现,如下所示:cpp view plain copyblink:WebPlugin* Rend

27、erFrameImpl:CreatePlugin( blink:WebFrame* frame, const WebPluginInfo& info, const blink:WebPluginParams& params) DCHECK_EQ(frame_, frame); #if defined(ENABLE_PLUGINS) bool pepper_plugin_was_registered = false; scoped_refptr pepper_module(PluginModule:Create( this, info, &pepper_plugin_was_registered

28、); if (pepper_plugin_was_registered) if (pepper_module.get() return new PepperWebPluginImpl(pepper_module.get(), params, this); . / TODO(jam): change to take RenderFrame. return new WebPluginImpl(frame, params, info.path, render_view_, this); #endif #else return NULL; #endif 这个函数定义在文件external/chromi

29、um_org/content/renderer/render_frame_impl.cc中。 RenderFrameImpl类的成员函数CreatePlugin首先是调用PluginModule类的成员函数Create查询要创建的插件是否是一个PPAPI插件。如果是的话,那么PluginModule类的成员函数Create会将输出参数pepper_plugin_was_registered的值设置为true,并且会返回一个PluginModule对象,用来描述PPAPI插件所在的模块,最后这个PluginModule对象将会被封装在一个PepperWebPluginImpl对象,并且返回给调用

30、者。这意味着PPAPI插件是通过PepperWebPluginImpl类来描述的。 另一方面,如果PluginModule类的成员函数Create将输出参数pepper_plugin_was_registered的值设置为false,那么就意味着要创建的是一个NPAPI插件。NPAPI插件通过WebPluginImpl类来描述,因此在这种情况下,RenderFrameImpl类的成员函数CreatePlugin就创建一个WebPluginImpl对象返回给调用者。 接下来我们继续分析PluginModule类的成员函数Create的实现,如下所示:cpp view plain copyscop

31、ed_refptr PluginModule:Create( RenderFrameImpl* render_frame, const WebPluginInfo& webplugin_info, bool* pepper_plugin_was_registered) *pepper_plugin_was_registered = true; / See if a module has already been loaded for this plugin. base:FilePath path(webplugin_info.path); scoped_refptr module = PepperPluginRegistry:GetInstance()-GetLiveModule(path);

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1