Chromium插件(Plugin)模块(Module)加载过程分析

本文详细分析了Chromium中Plugin Module的加载和初始化过程,包括Out-of-Process Plugin Module的创建、Plugin进程的启动、Plugin Module导出函数的调用,以及Chromium如何管理内置和用户安装的Plugin。重点讲解了Plugin Module加载流程,涉及到Browser进程、Render进程、Plugin进程之间的交互,以及Plugin与Chromium间的API接口交互。
摘要由CSDN通过智能技术生成

分享一下我老师大神的人工智能教程。零基础!通俗易懂!风趣幽默!还带黄段子!希望你也加入到我们人工智能的队伍中来!https://blog.csdn.net/jiangjunshow

               

       在Chromium中,每一个Plugin都对应一个Module,称为Plugin Module。一个Plugin Module可创建多个Plugin Instance。每一个Plugin Instance对应于网页中的一个<embed>标签。在为<embed>标签创建Plugin Instance之前,先要加载其对应的Plugin Module。本文接下来分析Plugin Module的加载过程。

老罗的新浪微博:http://weibo.com/shengyangluo,欢迎关注!

《Android系统源代码情景分析》一书正在进击的程序员网(http://0xcc0xcd.com)中连载,点击进入!

       Plugin Module的加载过程如图1所示:


图1 Plugin Module的加载过程

       WebKit请求Content层为网页中的<embed>标签创建Plugin Instance时,Content层会检查要创建的Plugin Instance对应的Plugin Module是否已经加载。如果还没有加载,那么通常就会创建一个Out-of-Process Plugin Module。这里说通常,是因为大部分Plugin都是运行在一个独立的进程中,只有内置Plugin才允许运行在Render进程中。本文我们只讨论Out-of-Process Plugin Module的情形。

       Content层在创建Out-of-Process Plugin Module的过程中,会请求Browser进程创建一个Plugin进程,并且请求该Plugin进程加载指定的Plugin Module。每一个Plugin Module都会有一个导出函数PPP_InitializeModule。Plugin Module加载完成之后,它导出的函数PPP_InitializeModule就会被调用,用来执行初始化工作。

       Plugin进程启动起来之后,它与Render进程之间的通信是通过一个PluginDispatcher对象进行的。与此同时,Render进程也会通过一个HostDispatcher对象与Plugin进程进行通信。例如,Content层请求Plugin进程加载指定的Plugin Module,就是通过Render进程中的HostDispatcher对象向Plugin进程中的PluginDispatcher对象发送IPC消息进行的。

       Content层在请求Browser进程创建一个Plugin进程加载一个Plugin Module之前,必须要知道这个Plugin Module的信息,例如它的SO文件路径。用户当前安装的所有Plugin是由Chromium中的一个Plugin Service进行管理的,因此Content层可以通过这个Plugin Service获得要加载的Plugin Module的信息。

       在分析Plugin Module的加载之前,我们先分析Plugin Service的启动过程。在启动的过程中,它就会注册所有内建(Built-In)的Plugin以及用户安装的Plugin在内部的一个List中。从前面Chromium扩展(Extension)加载过程分析一文可以知道,Chromium的Browser进程在启动的时候,会调用BrowserMainLoop类的成员函数CreateStartupTasks创建一系列的Startup Task。其中的一个Startup Task就是用来启动Plugin Service的,如下所示:

void BrowserMainLoop::CreateStartupTasks() {  ......  // First time through, we really want to create all the tasks  if (!startup_task_runner_.get()) {
   #if defined(OS_ANDROID)    startup_task_runner_ = make_scoped_ptr(new StartupTaskRunner(        base::Bind(&BrowserStartupComplete),        base::MessageLoop::current()->message_loop_proxy()));#else    startup_task_runner_ = make_scoped_ptr(new StartupTaskRunner(        base::Callback<void(int)>(),        base::MessageLoop::current()->message_loop_proxy()));#endif    StartupTask pre_create_threads =        base::Bind(&BrowserMainLoop::PreCreateThreads, base::Unretained(this));    startup_task_runner_->AddTask(pre_create_threads);    ......  }#if defined(OS_ANDROID)  if (!BrowserMayStartAsynchronously()) {    // A second request for asynchronous startup can be ignored, so    // StartupRunningTasksAsync is only called first time through. If, however,    // this is a request for synchronous startup then it must override any    // previous call for async startup, so we call RunAllTasksNow()    // unconditionally.    startup_task_runner_->RunAllTasksNow();  }#else  startup_task_runner_->RunAllTasksNow();#endif}
       这个函数定义在文件external/chromium_org/content/browser/browser_main_loop.cc中。

       这个Startup Task绑定了BrowserMainLoop类的成员函数PreCreateThreads,在创建各种Browser线程之前执行,执行过程如下所示:

int BrowserMainLoop::PreCreateThreads() {  ......#if defined(ENABLE_PLUGINS)  // Prior to any processing happening on the io thread, we create the  // plugin service as it is predominantly used from the io thread,  // but must be created on the main thread. The service ctor is  // inexpensive and does not invoke the io_thread() accessor.  {    TRACE_EVENT0("startup", "BrowserMainLoop::CreateThreads:PluginService");    PluginService::GetInstance()->Init();  }#endif  ......  return result_code_;}
      这个函数定义在文件external/chromium_org/content/browser/browser_main_loop.cc中。

      从这里可以看到,只有在编译时定义了宏ENABLE_PLUGINS,Chromium才会支持Plugin机制。在这种情况下,BrowserMainLoop类的成员函数PreCreateThreads首先会调用PluginService类的静态成员函数GetInstance获得一个PluginServiceImpl对象,如下所示:

PluginService* PluginService::GetInstance() {  return PluginServiceImpl::GetInstance();}
       这个函数定义在文件external/chromium_org/content/browser/plugin_service_impl.cc中。

       PluginService的静态成员函数GetInstance又是通过调用PluginServiceImpl类的静态成员函数GetInstance获得一个PluginServiceImpl对象的,如下所示:

PluginServiceImpl* PluginServiceImpl::GetInstance() {  return Singleton<PluginServiceImpl>::get();}
       这个函数定义在文件external/chromium_org/content/browser/plugin_service_impl.cc中。

       从这里可以看到,PluginServiceImpl类的静态成员函数GetInstance返回的PluginServiceImpl对象在当前进程(即Browser进程)是唯一的。这个PluginServiceImpl对象返回给BrowserMainLoop类的成员函数PreCreateThreads之后,后者会调用它的成员函数Init执行初始化工作,如下所示:

void PluginServiceImpl::Init() {  ......  RegisterPepperPlugins();  ......}

       这个函数定义在文件external/chromium_org/content/browser/plugin_service_impl.cc中。

       PluginServiceImpl类的成员函数Init会调用另外一个成员函数RegisterPepperPlugins注册那些Built-In Plugin以及用户安装的Plugin到Plugin Service中去,如下所示:

void PluginServiceImpl::RegisterPepperPlugins() {  ComputePepperPluginList(&ppapi_plugins_);  for (size_t i = 0; i < ppapi_plugins_.size(); ++i) {    RegisterInternalPlugin(ppapi_plugins_[i].ToWebPluginInfo(), true);  }}
       这个函数定义在文件external/chromium_org/content/browser/plugin_service_impl.cc中。

       PluginServiceImpl类的成员函数RegisterPepperPlugins首先调用函数ComputePepperPluginList获得那些Built-In Plugin和用户安装的Plugin,如下所示:

void ComputePepperPluginList(std::vector<PepperPluginInfo>* plugins) {  GetContentClient()->AddPepperPlugins(plugins);  ComputePluginsFromCommandLine(plugins);}
      这个函数定义在文件external/chromium_org/content/common/pepper_plugin_list.cc中。

      这里我们假设当前分析的是Chrome浏览器。在这种情况下,PluginServiceImpl类的成员函数RegisterPepperPlugins调用函数GetContentClient获得的是一个ChromeContentClient对象。调用这个ChromeContentClient对象的成员函数AddPepperPlugin即可以获得Built-In Plugin,如下所示:

void ChromeContentClient::AddPepperPlugins(    std::vector<content::PepperPluginInfo>* plugins) {  ComputeBuiltInPlugins(plugins);  AddPepperFlashFromCommandLine(plugins);  content::PepperPluginInfo plugin;  if (GetBundledPepperFlash(&plugin))    plugins->push_back(plugin);}

      这个函数定义在文件external/chromium_org/chrome/common/chrome_content_client.cc中。

      ChromeContentClient类的成员函数AddPepperPlugin首先调用函数ComputeBuiltInPlugins获得一些重要的Built-In Plugin,例如NaCl Plugin和PDF Plugin,如下所示:

void ComputeBuiltInPlugins(std::vector<content::PepperPluginInfo>* plugins) // PDF.  //  // Once we're sandboxed, we can't know if the PDF plugin is available or not;  // but (on Linux) this function is always called once before we're sandboxed.  // So the first time through test if the file is available and then skip the  // check on subsequent calls if yes.  static bool skip_pdf_file_check = false;  base::FilePath path;  if (PathService::Get(chrome::FILE_PDF_PLUGIN, &path)) {    if (skip_pdf_file_check || base::PathExists(path)) {      content::PepperPluginInfo pdf;      pdf.path = path;      pdf.name = ChromeContentClient::kPDFPluginName;      if (CommandLine::ForCurrentProcess()->HasSwitch(              switches::kOutOfProcessPdf)) {        pdf.is_out_of_process = true;        content::WebPluginMimeType pdf_mime_type(kPDFPluginOutOfProcessMimeType,                                                 kPDFPluginExtension,                                                 kPDFPlugi
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值