Chromium插件(Plugin)实例(Instance)创建过程分析

分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.csdn.net/jiangjunshow

也欢迎大家转载本篇文章。分享知识,造福人民,实现我们中华民族伟大复兴!

               

      Chromium在解析网页时,每遇到一个<embed>标签,就会创建一个Plugin Instance。一般来说,Plugin Instance是在Plugin进程中创建和运行的。一个Plugin Module对应一个Plugin进程,同时可以创建多个不同的Plugin Instance。前面我们已经分析Plugin Module的加载过程了,本文继续分析Plugin Instance的创建过程。

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

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

      Plugin Instance在运行的过程中,需要调用Chromium提供的API。这些API是实现在Render进程中的。与此同时,Render进程也需要主动与Plugin Instance通信,例如当网页的<embed>标签发生变化时,需要向它对应的Plugin Instance发出通知。为了方便Plugin Instance与Render进程相互通信,每一个Plugin Instance在Render进程中都对应有一个Proxy。这些Proxy通过PepperPluginInstanceImpl类描述。

      Plugin Instance的创建是由运行在Render进程中的WebKit发起的。WebKit又是通过请求Chromium的Content层创建Plugin Instance的。Content层在创建Plugin Instance之前,先会检查它对应的Plugin Module是否已经加载。如果还没有加载,那么就会先加载。这个加载过程可以参考前面Chromium插件(Plugin)模块(Module)加载过程分析一文。接下来,Content层又会创建一个Plugin Instance Proxy,即一个PepperPluginInstanceImpl对象,然后再通过个PepperPluginInstanceImpl对象请求在相应的Plugin进程中创建一个Plugin Instance。这个过程如图1所示:


图1 Plugin Instance的创建过程

       在PepperPluginInstanceImpl对象的创建这程中,会初始化一系列的接口。以后PepperPluginInstanceImpl对象就是通这些接口与运行在Plugin进程的Plugin Instance通信的。其中的一个接口在创建Plugin Instance的过程中也会用到。这个接口称为PPP_INSTANCE_INTERFACE_1_1,它提供了一个DidCreate函数。通过这个函数,PepperPluginInstanceImpl对象就可以请求在指定的Plugin进程中创建一个Plugin Instance。

       接口PPP_INSTANCE_INTERFACE_1_1提供的函数DidCreate会向Plugin进程发送一个类型为PpapiMsg_PPPInstance_DidCreate的IPC消息。这个IPC消息携带了一个参数API_ID_INSTANCE,表示该消息是分发给一个PPP_Instance_Proxy对象处理。这个PPP_Instance_Proxy对象又会在Plugin进程中获得一个PPP_INSTANCE_INTERFACE_1_1接口,并且调用该接品提供的函数DidCreate。后者在执行的过程中,就会创建一个pp::Instance对象。这个pp::Instance对象就是用来在Plugin对象中描述一个Plugin Instance的。

       从前面Chromium的GPU进程启动过程分析Chromium插件(Plugin)模块(Module)加载过程分析这两篇文章可以知道,WebKit请求Chromium的Content层为<embed>标签创建了一个PepperWebPluginImpl对象之后,就会调用这个PepperWebPluginImpl对象的成员函数initialize执行初始化工作。在初始化的过程中,就会创建Plugin Instance。因此,接下来我们就从PepperWebPluginImpl类的成员函数initialize开始,分析在Plugin Instance的创建过程.

       PepperWebPluginImpl类的成员函数initialize的实现如下所示:

bool PepperWebPluginImpl::initialize(WebPluginContainer* container) {  // The plugin delegate may have gone away.  instance_ = init_data_->module->CreateInstance(      init_data_->render_frame, container, init_data_->url);  ......  bool success = instance_->Initialize(      init_data_->arg_names, init_data_->arg_values, full_frame_);  ......  return true;}

       这个函数定义在文件external/chromium_org/content/renderer/pepper/pepper_webplugin_impl.cc中。

       PepperWebPluginImpl类的成员变量init_data_指向的是一个InitData对象。这个InitData对象的成员变量module指向的是一个PluginModule对象。这个PluginModule对象用来在Render进程中描述一个Plugin Module,它的创建过程可以参考前面Chromium的GPU进程启动过程分析一文。

       有了上述PluginModule对象之后,PepperWebPluginImpl类的成员函数initialize就可以调用它的成员函数CreateInstance创建一个Plugin Instance Proxy,即一个PepperPluginInstanceImpl对象,并且接下来会调用这个PepperPluginInstanceImpl对象的成员函数Initialize执行进行初始化工作。在初始化的过程中,就会请求Plugin进程创建一个Plugin Instance。

       接下来我们先分析Plugin Instance Proxy的创建这程,也就是PluginModule类的成员函数CreateInstance的实现,如下所示:

PepperPluginInstanceImpl* PluginModule::CreateInstance(    RenderFrameImpl* render_frame,    blink::WebPluginContainer* container,    const GURL& plugin_url) {  PepperPluginInstanceImpl* instance = PepperPluginInstanceImpl::Create(      render_frame, this, container, plugin_url);  ......  return instance;}
      这个函数定义在文件external/chromium_org/content/renderer/pepper/plugin_module.cc中。

      PluginModule类的成员函数CreateInstance通过调用PepperPluginInstanceImpl类的静态成员函数Create创建一个PepperPluginInstanceImpl对象 ,如下所示:

PepperPluginInstanceImpl* PepperPluginInstanceImpl::Create(    RenderFrameImpl* render_frame,    PluginModule* module,    WebPluginContainer* container,    const GURL& plugin_url) {  base::Callback<const void*(const char*)> get_plugin_interface_func =      base::Bind(&PluginModule::GetPluginInterface, module);  PPP_Instance_Combined* ppp_instance_combined =      PPP_Instance_Combined::Create(get_plugin_interface_func);  if (!ppp_instance_combined)    return NULLreturn new PepperPluginInstanceImpl(      render_frame, module, ppp_instance_combined, container, plugin_url);}
       这个函数定义在文件external/chromium_org/content/renderer/pepper/pepper_plugin_instance_impl.cc中。

       PepperPluginInstanceImpl类的静态成员函数Create首先是将PluginModule类的成员函数GetPluginInterface封装在一个Callback中,然后再将这个Callback传递给PPP_Instance_Combined类的静态成员函数Create,用来创建一个PPP_Instance_Combined对象。有了这个PPP_Instance_Combined对象之后,就可以创建一个PepperPluginInstanceImpl对象了。

      接下来,我们首先分析上述PPP_Instance_Combined对象的创建过程,也就是PPP_Instance_Combined类的静态成员函数Create的实现,如下所示:

PPP_Instance_Combined* PPP_Instance_Combined::Create(    base::Callback<const void*(const char*)> get_interface_func) {  // Try 1.1.  const void* ppp_instance = get_interface_func.Run(PPP_INSTANCE_INTERFACE_1_1);  if (ppp_instance) {    const PPP_Instance_1_1* ppp_instance_1_1 =        static_cast<const PPP_Instance_1_1*>(ppp_instance);    return new PPP_Instance_Combined(*ppp_instance_1_1);  }  // Failing that, try 1.0.  ppp_instance = get_interface_func.Run(PPP_INSTANCE_INTERFACE_1_0);  if (ppp_instance) {    const PPP_Instance_1_0* ppp_instance_1_0 =        static_cast<const PPP_Instance_1_0*>(ppp_instance);    return new PPP_Instance_Combined(*ppp_instance_1_0);  }  // No supported PPP_Instance version found.  return NULL;}
       这个函数定义在文件external/chromium_org/ppapi/shared_impl/ppp_instance_combined.cc中。

       PPP_Instance_Combined类的静态成员函数Create首先尝试通过参数get_interface_func描述的Callback获得一个1.1版本的PPP_INSTANCE_INTERFACE接口。如果能成功获得该接口,那么就使用它来创建一个PPP_Instance_Combined对象返回给调用者。

       如果不能成功获得1.1版本的PPP_INSTANCE_INTERFACE接口,那么PPP_Instance_Combined类的静态成员函数Create接下来会尝试获得1.0版本的PPP_INSTANCE_INTERFACE接口。如果能成功获得该接口,那么同样会使用它来创建一个PPP_Instance_Combined对象返回给调用者。

       我们假设1.1版本的PPP_INSTANCE_INTERFACE接口能够成功获取,接下来我们就分析它的获得过程。从前面的分析可以知道,参数get_interface_func描述的Callback描述的实际上是PluginModule类的成员函数GetPluginInterface,因此,1.1版本的PPP_INSTANCE_INTERFACE接口实际上是通过调用PluginModule类的成员函数GetPluginInterface获得的,如下所示:

const void* PluginModule::GetPluginInterface(const char* name) constif (host_dispatcher_wrapper_)    return host_dispatcher_wrapper_->GetProxiedInterface(name);  ......}
       这个函数定义在文件external/chromium_org/content/renderer/pepper/plugin_module.cc中。

       PluginModule类的成员变量host_dispatcher_wrapper_指向的是一个HostDispatcherWrapper对象。这个HostDispatcherWrapper对象是在Plugin Module加载的过程中创建的,它内部封装了一个HostDispatcher对象,通过这个HostDispatcher对象可以与Plugin Module所加载在的Plugin进程通信。

       有了上述HostDispatcherWrapper对象之后,PluginModule类的成员函数GetPluginInterface就可以调用它的成员函数GetProxiedInterface获得版本为PPP_INSTANCE_INTERFACE接口,即PPP_INSTANCE_INTERFACE_1_1接口,如下所示:

const void* HostDispatcherWrapper::GetProxiedInterface(const char* name) {  return dispatcher_->GetProxiedInterface(name);}
       这个函数定义在文件external/chromium_org/content/renderer/pepper/host_dispatcher_wrapper.cc中。

       HostDispatcherWrapper类的成员变量dispatcher_指向的就是一个HostDispacther对象。HostDispatcherWrapper类的成员函数GetProxiedInterface通过调用这个HostDispacther对象的成员函数GetProxiedInterface获得PPP_INSTANCE_INTERFACE_1_1接口,如下所示:

const void* HostDispatcher::GetProxiedInterface(const std::string& iface_name) {  const void* proxied_interface =      InterfaceList::GetInstance()->GetInterfaceForPPP(iface_name);  if (!proxied_interface)    return NULL// Don't have a proxy for this interface, don't query further.  PluginSupportedMap::iterator iter(plugin_supported_.find(iface_name))if (iter == plugin_supported_.end()) {    // Need to query. Cache the result so we only do this once.    bool supported = false;    bool previous_reentrancy_value = allow_plugin_reentrancy_;    allow_plugin_reentrancy_ = true;    Send(new PpapiMsg_SupportsInterface(iface_name, &supported));    allow_plugin_reentrancy_ = previous_reentrancy_value;    std::pair<PluginSupportedMap::iterator, bool> iter_success_pair;    iter_success_pair = plugin_supported_.insert(        PluginSupportedMap::value_type(iface_name, supported));    iter = iter_success_pair.first;  }  if (iter->second)    return proxied_interface;  return NULL;}
       这个函数定义在文件external/chromium_org/ppapi/proxy/host_dispatcher.cc中。

       从前面Chromium插件(Plugin)模块(Module)加载过程分析一文可以知道,Plugin进程中存在一个InterfaceList单例对象。这个InterfaceList单例对象在创建的过程中,会初始化一系列的接口。这些接口是提供给Plugin Instance调用的,以便Plugin Instance可以与它们在Render进程中的Proxy进行通信。

       同样,在Render进程中,也存在一个InterfaceList单例对象。这个InterfaceList单例对象在创建的过程中,也会初始化一系列的接口,不过这些接口是提供给Plugin Instance Proxy调用的,以便Plugin Instance Proxy可以与它们在Plugin进程中的Plugin Instance进行通信。

       HostDispacther对象的成员函数GetProxiedInterface所做的事情就是检查Render进程中的InterfaceList单例对象是否提供了PPP_INSTANCE_INTERFACE_1_1接口。如果有提供,并且Plugin进程支持该接口,那么就会将它返回给调用者。注意,检查Plugin进程是否支持某个接口,是通过向它发送一个类型为PpapiMsg_SupportsInterface的IPC消息实现的。这里我们假设Plugin进程支持PPP_INSTANCE_INTERFACE_1_1接口。

       接下来我们先分析Render进程中的InterfaceList单例对象在创建过程中提供的三个Plugin Instance Proxy可以调用的接口,它们在接下来一篇文章分析Plugin Instance的3D渲染过程时将会使用到,如下所示:

InterfaceList::InterfaceList() {  memset(id_to_factory_, 0, sizeof(id_to_factory_));  // Register the API factories for each of the API types. This calls AddProxy  // for each InterfaceProxy type we support.  #define PROXIED_API(api_name) \      AddProxy(PROXY_API_ID(api_name), &PROXY_FACTORY_NAME(api_name));  // Register each proxied interface by calling AddPPB for each supported  // interface. Set current_required_permission to the appropriate value for  // the value you want expanded by this macro.  #define PROXIED_IFACE(iface_str, iface_struct) \      AddPPB(iface_str, \             INTERFACE_THUNK_NAME(iface_struct)(), \             current_required_permission);  {    Permission current_required_permission = PERMISSION_NONE;    ......    #include "ppapi/thunk/interfaces_ppb_public_stable.h"  }  ......  AddPPP(PPP_INSTANCE_INTERFACE_1_1,         PPP_Instance_Proxy::GetInstanceInterface());  ......}
       这个函数定义在文件external/chromium_org/ppapi/proxy/interface_list.cc。

       这三个接口分别是API_ID_PPB_INSTANCE、API_ID_PPB_GRAPHICS_3D和PPP_INSTANCE_INTERFACE_1_1。其中,API_ID_PPB_INSTANCE和API_ID_PPB_GRAPHICS_3D这两个接口是通过include文件interfaces_ppb_public_stable.h进行定义的,如下所示:

PROXIED_API(PPB_Graphics3D)......PROXIED_API(PPB_Instance)
       这两个接口定义在文件external/chromium_org/ppapi/thunk/interfaces_ppb_public_stable.h中。

       其中,接口API_ID_PPB_INSTANCE由语句PROXIED_API(PPB_Instance)定义。我们在前面Chromium插件(Plugin)模块(Module)加载过程分析一文已经分析过这个接口的定义了,因此这里不再复述。实现这个接口的是一个模板函数ProxyFactory<PPB_Instance_Proxy>。以后调用这个接口就相当于调用模板函数ProxyFactory<PPB_Instance_Proxy>,并且会在调用后得到一个PPB_Instance_Proxy对象。

       接口API_ID_PPB_GRAPHICS_3D由语句PROXIED_API(PPB_Graphics3D)定义。它的定义过程与接口API_ID_PPB_INSTANCE是一样的,因此,我们容易知道,实现这个接口的是另外一个模板函数ProxyFactory<PPB_Graphics3D_Proxy>。以后调用这个接口就相当于调用模板函数ProxyFactory<PPB_Graphics3D_Proxy>,并且会在调用后得到一个PPB_Graphics3D_Proxy对象。

       回到InterfaceList类的构造函数中,第三个接口PPP_INSTANCE_INTERFACE_1_1是由一个PPP_Instance_1_1对象实现的。这个PPP_Instance_1_1对象可以通过调用PPP_Instance_Proxy类的静态成员函数GetInstanceInterface获得,如下所示:

static const PPP_Instance_1_1 instance_interface = {  &DidCreate,  &DidDestroy,  &DidChangeView,  &DidChangeFocus,  &HandleDocumentLoad};......const PPP_Instance* PPP_Instance_Proxy::GetInstanceInterface() {  return &instance_interface;}
      这个函数定义在文件external/chromium_org/ppapi/proxy/ppp_instance_proxy.cc中。

      从这里我们就可以看到,接口PPP_INSTANCE_INTERFACE_1_1提供给Plugin Instance Proxy使用的函数,例如函数DidCreate,是用来请求Plugin进程创建一个Plugin Instance的,接下来我们就会看到这个函数的使用过程。

      分析到这里,我们就可以知道,HostDispacther类的成员函数GetProxiedInterface通过调用Render进程中的InterfaceList单例对象的成员函数GetInterfaceForPPP是可以获得PPP_INSTANCE_INTERFACE_1_1接口的。这个接口会沿着调用过程返回给PPP_Instance_Combined类的静态成员函数Create。

      PPP_Instance_Combined类的静态成员函数Create获得了PPP_INSTANCE_INTERFACE_1_1接口之后,就会使用它来创建一个PPP_Instance_Combined对象,如下所示:

PPP_Instance_Combined::PPP_Instance_Combined(    const PPP_Instance_1_1& instance_if)    : instance_1_1_(instance_if), did_change_view_1_0_(NULL) {}
      这个函数定义在文件external/chromium_org/ppapi/shared_impl/ppp_instance_combined.cc中。

      参数instance_if描述的就是前面获得的PPP_INSTANCE_INTERFACE_1_1接口。这个接口实际上是一个PPP_Instance_1_1对象。这个PPP_Instance_1_1对象将会保存在PPP_Instance_Combined类的成员变量instance_1_1_中。

      这一步执行完成后,我们就获得了一个PPP_Instance_Combined对象。这个PPP_Instance_Combined对象将会返回给前面分析的PepperPluginInstanceImpl类的静态成员函数Create,后者将会使用前者创建一个PepperPluginInstanceImpl对象。这个PepperPluginInstanceImpl对象的创建过程如下所示:

PepperPluginInstanceImpl::PepperPluginInstanceImpl(    RenderFrameImpl* render_frame,    PluginModule* module,    ppapi::PPP_Instance_Combined* instance_interface,    WebPluginContainer* container,    const GURL& plugin_url)    : ......,      module_(module),      instance_interface_(instance_interface),      ...... {  ......  RendererPpapiHostImpl* host_impl = module_->renderer_ppapi_host();  resource_creation_ = host_impl->CreateInProcessResourceCreationAPI(this);  ......}

      这个函数定义在文件external/chromium_org/content/renderer/pepper/pepper_plugin_instance_impl.cc中。

      PepperPluginInstanceImpl类的构造函数首先将参数module和instance_interface指向的PluginModule对象和PPP_Instance_Combined对象分别保存在成员变量module_和instance_interface_,接下来又会通过参数module指向的PluginModule对象获得一个RendererPpapiHostImpl对象。这个RendererPpapiHostImpl对象是用来在Render进程中描述一个Plugin进程的,它是在Plugin Module的加载过程中创建的,具体可以参考前面Chromium的Plugin进程启动过程分析一文。有了这个RendererPpapiHostImpl对象之后,PepperPluginInstanceImpl类的构造函数就调用它的成员函数CreateInProcessResourceCreationAPI创建一个资源创建接口,如下所示:

scoped_ptr<ppapi::thunk::ResourceCreationAPI>RendererPpapiHostImpl::CreateInProcessResourceCreationAPI(    PepperPluginInstanceImpl* instance) {  return scoped_ptr<ppapi::thunk::ResourceCreationAPI>(      new PepperInProcessResourceCreation(this, instance));}
       这个函数定义在文件external/chromium_org/content/renderer/pepper/renderer_ppapi_host_impl.cc中。

       从这里可以看到,这个资源创建接口是通过一个PepperInProcessResourceCreation对象描述的。这个PepperInProcessResourceCreation对象返回给PepperPluginInstanceImpl类的构造函数之后,将会保存在后者的成员变量resource_creation_中。在接下来一篇文章分析Plugin的3D渲染过程时,我们就会看到这个接口的使用过程。

       这一步执行完成后,回到PepperWebPluginImpl类的成员函数initialize中,这时候它就创建了一个Plugin Instance Proxy,也就是一个PepperPluginInstanceImpl对象。接下来PepperWebPluginImpl类的成员函数initialize又会调用上述PepperPluginInstanceImpl对象的成员函数Initialize对其进行初始化。在初始化的过程中,就会请求目标Plugin进程创建一个Plugin Instance,如下所示:

bool PepperPluginInstanceImpl::Initialize(    const std::vector<std::string>& arg_names,    const std::vector<std::string>& arg_values,    bool full_frame) {  ......  argn_ = arg_names;  argv_ = arg_values;  scoped_ptr<const char * []> argn_array(StringVectorToArgArray(argn_));  scoped_ptr<const char * []> argv_array(StringVectorToArgArray(argv_));  bool success = PP_ToBool(instance_interface_->DidCreate(      pp_instance(), argn_.size(), argn_array.get(), argv_array.get()));  ......  return success;}
       这个函数定义在文件external/chromium_org/content/renderer/pepper/pepper_plugin_instance_impl.cc中。

       从前面的分析可以知道,PepperPluginInstanceImpl类的成员变量instance_interface_指向的是一个PPP_Instance_Combined对象。PepperPluginInstanceImpl类的成员函数Initialize主要是调用这个PPP_Instance_Combined对象的成员函数DidCreate请求在目标Plugin进程中创建一个Plugin Instance,如下所示:

PP_Bool PPP_Instance_Combined::DidCreate(PP_Instance instance,                                         uint32_t argc,                                         const char* argn[],                                         const char* argv[]) {  return CallWhileUnlocked(instance_1_1_.DidCreate, instance, argc, argn, argv);}
       这个函数定义在文件external/chromium_org/ppapi/shared_impl/ppp_instance_combined.cc中。

       从前面的分析可以知道,PPP_Instance_Combined类的成员变量instance_1_1_指向的是一个PPP_Instance_1_1对象。这个PPP_Instance_1_1对象描述的是一个PPP_INSTANCE_INTERFACE_1_1接口。PPP_Instance_Combined类的成员函数DidCreate通过一个帮助函数CallWhilleUnlocked调用这个PPP_INSTANCE_INTERFACE_1_1接口提供的函数DidCreate,以便请求目标Plugin进程创建一个Plugin Instance。

      从前面的分析还可以知道,上述PPP_INSTANCE_INTERFACE_1_1接口提供的函数DidCreate实现在ppp_instance_proxy.cc文件中,如下所示:

PP_Bool DidCreate(PP_Instance instance,                  uint32_t argc,                  const char* argn[],                  const char* argv[]) std::vector<std::string> argn_vect;  std::vector<std::string> argv_vect;  for (uint32_t i = 0; i < argc; i++) {    argn_vect.push_back(std::string(argn[i]));    argv_vect.push_back(std::string(argv[i]));  }  PP_Bool result = PP_FALSE;  HostDispatcher::GetForInstance(instance)->Send(      new PpapiMsg_PPPInstance_DidCreate(API_ID_PPP_INSTANCE, instance,                                         argn_vect, argv_vect, &result));  return result;}
       这个函数定义在文件external/chromium_org/ppapi/proxy/ppp_instance_proxy.cc中。

       函数DidCreate主要就是向目标Plugin进程发送一个类型为PpapiMsg_PPPInstance_DidCreate的IPC消息。这个IPC消息的Routing ID指定为API_ID_PPP_INSTANCE,表示它发送到目标Plugin进程后,要交给一个ID为API_ID_PPP_INSTANCE的PPAPI接口处理。

       目标Plugin进程可以通过参数instance描述的一个PP_Instance对象获得。在Render进程中,每一个Plugin Instance Proxy都关联有一个PP_Instance对象。因此,通过这个PP_Instance对象就可以找到它对应的Plugin Instance Proxy,也就是一个PepperPluginInstanceImpl对象。每一个PepperPluginInstanceImpl对象又对应有一个Plugin Moudle。该Plugin Module所加载在的Plugin进程即为目标进程。知道了目标Plugin进程之后,就可以通过之前它在启动时与Render进程建立的Plugin通道向它发送IPC消息了。

       从前面Chromium的Plugin进程启动过程分析一文可以知道,每一个Plugin进程都存在一个PluginDispatcher对象。Plugin进程将会通过这个PluginDispatcher对象的成员函数OnMessageReceived接收Render进程发送过来的IPC消息。这意味着前面从Render进程发送过来的类型为PpapiMsg_PPPInstance_DidCreate的IPC消息是通过PluginDispatcher类的成员函数OnMessageReceived接收的。

       PluginDispatcher类的成员函数OnMessageReceived是从父类Dispatcher继承下来的,它的实现如下所示:

bool Dispatcher::OnMessageReceived(const IPC::Message& msg) {  ......  InterfaceProxy* proxy = GetInterfaceProxy(      static_cast<ApiID>(msg.routing_id()));  ......  return proxy->OnMessageReceived(msg);}
       这个函数定义在文件external/chromium_org/ppapi/proxy/dispatcher.cc中。

       从前面的分析可以知道,此时参数msg指向的Message对象描述的是一个类型为PpapiMsg_PPPInstance_DidCreate的IPC消息,该消息的Routing ID为API_ID_PPP_INSTANCE。这个Routing ID描述的实际上是一个接口ID,Dispatcher类的成员函数OnMessageReceived通过调用另外一个成员函数GetInterfaceProxy可以获得该接口,如下所示:

InterfaceProxy* Dispatcher::GetInterfaceProxy(ApiID id) {  InterfaceProxy* proxy = proxies_[id].get();  if (!proxy) {    // Handle the first time for a given API by creating the proxy for it.    InterfaceProxy::Factory factory =        InterfaceList::GetInstance()->GetFactoryForID(id);    ......    proxy = factory(this);    DCHECK(proxy);    proxies_[id].reset(proxy);  }  return proxy;}
       这个函数定义在文件external/chromium_org/ppapi/proxy/dispatcher.cc中。

       Dispatcher类的成员函数GetInterfaceProxy首先在成员变量proxies_描述的数组中检查是否存在一个与ID为参数id的接口。如果存在,那么就直接将它返回给调用者。如果不存在,那么就会通过调用Plugin进程中的一个InterfaceList单例对象的成员函数GetFactoryForID检查它内部是否存在该接口。如果存在,那么就会获得一个类型为InterfaceProxy::Factory的函数。调用该函数将会获得一个InterfaceProxy对象。这个InterfaceProxy对象描述的就是一个ID为参数id的接口。

       Dispatcher类的成员函数GetInterfaceProxy在将获得的PPAPI接口返回给调用者之前,还会将其缓存在成员变量proxies_描述的数组中,以便以后可以直接获得,而不用通过Plugin进程中的InterfaceList单例对象获得。

       接下来,我们继续分析InterfaceList类的成员函数GetFactoryForID的实现,以便了解它返回的InterfaceProxy::Factory函数的实现,如下所示:

InterfaceProxy::Factory InterfaceList::GetFactoryForID(ApiID id) constint index = static_cast<int>(id);  ......  return id_to_factory_[index];}
       这个函数定义在文件external/chromium_org/ppapi/proxy/interface_list.cc中。

       从前面的分析可以知道,此时参数id的值等于API_ID_PPP_INSTANCE。从前面Chromium插件(Plugin)模块(Module)加载过程分析一文可以知道,Plugin进程在加载Plugin Module的时候,会在InterfaceList类的成员变量id_to_factory_描述的数组中注册一个ID为API_ID_PPP_INSTANCE的模板函数ProxyFactory<PPP_Instance_Proxy>。因此,这时候InterfaceList类的成员函数GetFactoryForID将会返回模板函数ProxyFactory<PPP_Instance_Proxy>给调用者,也就是Dispatcher类的成员函数GetInterfaceProxy。

       Dispatcher类的成员函数GetInterfaceProxy获得了模板函数ProxyFactory<PPP_Instance_Proxy>之后,就会调用它创建一个PPP_Instance_Proxy对象。这个PPP_Instance_Proxy对象以后就会负责处理Routing ID为API_ID_PPP_INSTANCE的IPC消息。

       PPP_Instance_Proxy对象在创建的过程中,将会获得一个PPP_INSTANCE_INTERFACE_1_1接口。这个PPP_INSTANCE_INTERFACE_1_1接口在处理类型为PpapiMsg_PPPInstance_DidCreate的IPC消息的过程中将会使用到。

       接下来,我们就继续分析PPP_Instance_Proxy对象的创建过程,也就是它的构造函数的实现,以便了解它获得PPP_INSTANCE_INTERFACE_1_1接口的过程,如下所示:

PPP_Instance_Proxy::PPP_Instance_Proxy(Dispatcher* dispatcher)    : InterfaceProxy(dispatcher) {  if (dispatcher->IsPlugin()) {    ......    combined_interface_.reset(PPP_Instance_Combined::Create(        base::Bind(dispatcher->local_get_interface())));  }}
       这个函数定义在文件external/chromium_org/ppapi/proxy/ppp_instance_proxy.cc中。

       从前面的调用过程可以知道,参数dispatcher指向的实际上是一个PluginDispatcher对象。调用这个PluginDispatcher对象的成员函数isPlugin得到的返回值为true。这时候PPP_Instance_Proxy类的构造函数会继续调用这个PluginDispatcher对象的成员函数local_get_interface获得一个PPP_GetInterface接口。这个接口是从Plugin Module导出来的。它的获取过程可以参考前面Chromium的Plugin进程启动过程分析一文。

       获得了从Plugin Module导出来的PPP_GetInterface接口之后,PPP_Instance_Proxy类的构造函数通过调用PPP_Instance_Combined类的静态成员函数Create将该接口封装在一个PPP_Instance_Combined对象中,如下所示:

PPP_Instance_Combined* PPP_Instance_Combined::Create(    base::Callback<const void*(const char*)> get_interface_func) {  // Try 1.1.  const void* ppp_instance = get_interface_func.Run(PPP_INSTANCE_INTERFACE_1_1);  if (ppp_instance) {    const PPP_Instance_1_1* ppp_instance_1_1 =        static_cast<const PPP_Instance_1_1*>(ppp_instance);    return new PPP_Instance_Combined(*ppp_instance_1_1);  }  // Failing that, try 1.0.  ppp_instance = get_interface_func.Run(PPP_INSTANCE_INTERFACE_1_0);  if (ppp_instance) {    const PPP_Instance_1_0* ppp_instance_1_0 =        static_cast<const PPP_Instance_1_0*>(ppp_instance);    return new PPP_Instance_Combined(*ppp_instance_1_0);  }  // No supported PPP_Instance version found.  return NULL;}
       这个函数定义在文件external/chromium_org/ppapi/shared_impl/ppp_instance_combined.cc中。

       前面我们已经分析过PPP_Instance_Combined类的静态成员函数Create的实现了。不过,这时候参数get_interface_func描述的是一个从Plugin Module导出来的PPP_GetInterface接口。从前面的分析可以知道,PPP_Instance_Combined类的静态成员函数Create最终会通过这个PPP_GetInterface接口获得另外一个类型为PPP_INSTANCE_INTERFACE_1_1的接口。

       Plugin Module导出来的PPP_GetInterface接口的实现如下所示:

PP_EXPORT const void* PPP_GetInterface(const char* interface_name) if (g_module_singleton)    return g_module_singleton->GetPluginInterface(interface_name);  ......  return NULL;}
       这个函数定义在文件external/chromium_org/ppapi/cpp/ppp_entrypoints.cc中。

       从前面Chromium插件(Plugin)模块(Module)加载过程分析一文可以知道,g_module_singleton是一个全局变量,它指向的是一个pp::Module对象。这个pp::Module对象描述的就是在当前Plugin进程中加载的Plugin Module。对于我们在前面Chromium插件(Plugin)机制简要介绍和学习计划一文中提到的GLES2 Example来说,这个pp::Module对象的实际类型为GLES2DemoModule。

       PPP_GetInterface接口主要就是调用上述pp::Module对象的成员函数GetPluginInterface获得与参数interface_name对应的接口。从前面的分析可以知道,此时参数interface_name的值等于PPP_INSTANCE_INTERFACE_1_1,也就是此时PPP_GetInterface接口是通过调用pp::Module类的成员函数GetPluginInterface获得PPP_INSTANCE_INTERFACE_1_1接口的,如下所示:

const void* Module::GetPluginInterface(const char* interface_name) {  ......  if (strcmp(interface_name, PPP_INSTANCE_INTERFACE) == 0)    return &instance_interface;  ......  return NULL;}
       这个函数定义在文件external/chromium_org/ppapi/cpp/module.cc中。

       PPP_INSTANCE_INTERFACE是一个宏,它的定义为:

#define PPP_INSTANCE_INTERFACE PPP_INSTANCE_INTERFACE_1_1
       这个宏定义在文件external/chromium_org/ppap/c/ppp_instance.h

       回到pp::Module类的成员函数GetPluginInterface中,由于此时参数interface_name的值等于PPP_INSTANCE_INTERFACE_1_1,因此这时候pp::Module类的成员函数GetPluginInterface会将全局变量instance_interface描述的一个PPP_Instance对象给调用者。这个PPP_Instance对象的定义如下所示:

static PPP_Instance instance_interface = {  &Instance_DidCreate,  &Instance_DidDestroy,  &Instance_DidChangeView,  &Instance_DidChangeFocus,  &Instance_HandleDocumentLoad};
       这个PPP_Instance对象定义在文件external/chromium_org/ppapi/cpp/module.cc中。

       从这里就可以看到,Plugin进程中的PPP_INSTANCE_INTERFACE_1_1接口的实现。例如,它的成员变量DidCreate是一个函数指针,指向的函数为Instance_DidCreate,它是用来在Plugin进程中创建一个Plugin Instance的。

       这一步执行完成后,回到PPP_Instance_Combined类的静态成员函数Create中,这时候它就会将上述PPP_Instance对象封装在一个PPP_Instance_Combined对象中,并且将该PPP_Instance_Combined对象返回给调用者,即PPP_Instance_Proxy类的构造函数的实现,后者再将该PPP_Instance_Combined对象保存在成员变量combined_interface_中。

       这样,我们就分析完成了Dispatcher类的成员函数GetInterfaceProxy通过模板函数ProxyFactory<PPP_Instance_Proxy>创建PPP_Instance_Proxy对象的过程。这个PPP_Instance_Proxy对象会返回给Dispatcher类的另外一个成员函数OnMessageReceived,后者会将前面从Render进程发送过来的类型为PpapiMsg_PPPInstance_DidCreate的IPC消息分发给该PPP_Instance_Proxy对象的成员函数OnMessageReceived处理,如下所示:

bool PPP_Instance_Proxy::OnMessageReceived(const IPC::Message& msg) {  ......  bool handled = true;  IPC_BEGIN_MESSAGE_MAP(PPP_Instance_Proxy, msg)    IPC_MESSAGE_HANDLER(PpapiMsg_PPPInstance_DidCreate,                        OnPluginMsgDidCreate)    ......    IPC_MESSAGE_UNHANDLED(handled = false)  IPC_END_MESSAGE_MAP()  return handled;}
       这个函数定义在文件external/chromium_org/ppapi/proxy/ppp_instance_proxy.cc中。

       PPP_Instance_Proxy类的成员函数OnMessageReceived将类型为PpapiMsg_PPPInstance_DidCreate的IPC消息分发给成员函数OnPluginMsgDidCreate处理,如下所示:

void PPP_Instance_Proxy::OnPluginMsgDidCreate(    PP_Instance instance,    const std::vector<std::string>& argn,    const std::vector<std::string>& argv,    PP_Bool* result) {  *result = PP_FALSE;  ......  // Make sure the arrays always have at least one element so we can take the  // address below.  std::vector<const char*> argn_array(      std::max(static_cast<size_t>(1), argn.size()));  std::vector<const char*> argv_array(      std::max(static_cast<size_t>(1), argn.size()));  for (size_t i = 0; i < argn.size(); i++) {    argn_array[i] = argn[i].c_str();    argv_array[i] = argv[i].c_str();  }  DCHECK(combined_interface_.get());  *result = combined_interface_->DidCreate(instance,                                           static_cast<uint32_t>(argn.size()),                                           &argn_array[0], &argv_array[0]);}
       这个函数定义在文件external/chromium_org/ppapi/proxy/ppp_instance_proxy.cc中。

       从前面的分析可以知道,PPP_Instance_Proxy类的成员变量combined_interface_指向的一个PPP_Instance_Combined对象。PPP_Instance_Proxy类的成员函数OnPluginMsgDidCreate主要是调用这个PPP_Instance_Combined对象的成员函数DidCreate在当前进程(Plugin进程)中创建一个Plugin Instance,如下所示:

PP_Bool PPP_Instance_Combined::DidCreate(PP_Instance instance,                                         uint32_t argc,                                         const char* argn[],                                         const char* argv[]) {  return CallWhileUnlocked(instance_1_1_.DidCreate, instance, argc, argn, argv);}
       这个函数定义在文件external/chromium_org/ppapi/shared_impl/ppp_instance_combined.cc中。

       从前面的分析可以知道,PPP_Instance_Combined类的成员变量instance_1_1_指向的是一个PPP_Instance对象。这个PPP_Instance对象的成员变量DidCreate是一个函数指针,它指向的函数为Instance_DidCreate。PPP_Instance_Combined类的成员函数DidCreate主要是调用这个函数来创建一个Plugin Instance。因此,接下来我们继续分析函数Instance_DidCreate的实现,如下所示:

PP_Bool Instance_DidCreate(PP_Instance pp_instance,                           uint32_t argc,                           const char* argn[],                           const char* argv[]) {  Module* module_singleton = Module::Get();  if (!module_singleton)    return PP_FALSE;  Instance* instance = module_singleton->CreateInstance(pp_instance);  if (!instance)    return PP_FALSE;  module_singleton->current_instances_[pp_instance] = instance;  return PP_FromBool(instance->Init(argc, argn, argv));}
       这个函数定义在文件external/chromium_org/ppapi/cpp/module.cc中。

       函数Instance_DidCreate首先调用Module类的静态成员函数Get获得当前Plugin进程中的一个pp::Module单例对象。从前面Chromium插件(Plugin)模块(Module)加载过程分析一文可以知道,这个pp::Module单例对象描述的就是在当前Plugin进程中加载的Plugin Module。有了这个pp::Module对象之后,就可以调用它的成员函数CreateInstance创建一个Plugin Instance,即一个pp::Instance对象。

       参数pp_instance的类型为PP_Instance。PP_Instance的实际类型为int32_t,也就是它描述的是一个有符号整数。这个有符号整数指定为当前创建的Plugin Instance的ID。与此同时,创建出来的Plugin Instance将会以它的ID为键值,保存在一个std::map中。这个std::map由上述获得的pp::Module单例对象的成员变量current_instances_描述。因此,通过这个std::map,我们就可以知道一个Plugin Module创建了多少个Plugin Instance。

       我们在开发一个Plugin的时候,会自定义一个pp::Module类。例如,在前面Chromium插件(Plugin)机制简要介绍和学习计划一文提到的GLES2 Example,它自定义的pp::Module类为GLES2DemoModule。自定义的 GLES2DemoModule类是从pp::Module类继承下来的,并且会重写成员函数CreateInstance。这意味着前面所创建的Plugin Instance的实际类型由自定义的pp::Module类决定的。

       例如,GLES2DemoModule类的成员函数CreateInstance创建的Plugin Instance的实际类型为GLES2DemoInstance,如下所示:

class GLES2DemoModule : public pp::Module { public:  ......  virtual pp::Instance* CreateInstance(PP_Instance instance) {    return new GLES2DemoInstance(instance, this);  }};
       这个函数定义在文件external/chromium_org/ppapi/examples/gles2/gles2.cc中。

       至此,Chromium的Render进程就请求目标Plugin进程创建了一个Plugin Instance。这个Plugin Instance的实际类型由开发者定义,只要它是从pp::Instance类继承下来即可。同时,在Render进程当中,存在一个对应的Plugin Instance Proxy。这个Plugin Instance Proxy是通过PepperPluginInstanceImpl类描述的。以后在Render进程中加载的网页需要使用Plugin Instance的功能时,就可以通过Plugin Instance Proxy实现,而在Plugin进程中创建的Plugin Instance需要使用Chromium提供的功能时,可以通过Chromium提供的接口(Browser Interface)实现。

       在接下来一篇文章中,我们将以GLES2 Example为例,分析Plugin Instance通过Chromium提供的3D接口渲染自己的UI的过程。通过这个过程,我们就可以看到Plugin Instance与网页的交互过程,从而更好的理解Chromium的Plugin机制。敬请关注!更多的信息也可以关注老罗的新浪微薄:http://weibo.com/shengyangluo

           

给我老师的人工智能教程打call!http://blog.csdn.net/jiangjunshow
这里写图片描述
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值