源码分析.doc_第1页
源码分析.doc_第2页
源码分析.doc_第3页
源码分析.doc_第4页
源码分析.doc_第5页
已阅读5页,还剩23页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

chrome为我们提供的一张进程图:一个浏览器的主进程,n个渲染进程。主进程中包括了ui线程和资源分派线程,一个渲染进程包括了资源分派线程和主渲染线程其中浏览器进程和渲染进程之间靠的是通道.来进行连接的。 chrome有4种启动方式1:每个tab一个进程。2:每个域名一个进程。3:每个网页一个进程。4:每个网页以及从这个网页说打开的其他连接一个进程。详细资料参见multi-process architecture进程之间通讯-命名管道(named pipes) 所谓named pipes,其实是一个windonws内核对象,关于内核对象的介绍可以参考windows核心编程。named pipes 在nt以上的系统才被支持。named pipes分客户端和服务器端,服务器创建一个命名管道,客户端可以连接到这个管道上。windows对命名管道的支持非常完善,不当支持本地命名管道,还支持跨网络的命名管道,可以从一台机器上连接到另外一台机器。工作的基本流程是这样的: 服务器和客户端确定命名管道的名称,这个名称是有讲究的,具体怎么给管道取名,同学们可以去网上查看资料。 服务器:调用 createnamedpipe 创建一个命名管道,然后调用connectnamedpipe等待客户端的连接,采用writefile来传送数据,用readfile来读数据。 客户端:调用createfile来连接 服务器,采用writefile来传送数据,用readfile来读数据。其实同学们看见 cretefile,writefile,readfile,不比担心它们会写磁盘,其实写的是系统的一块缓冲区,所以效率不比担心,最耗效率的地方其实就是系统调用和用户本地调用的切换说花费的时钟周期。chrome中使用name pipes采用了异步的调用的方式,这就是所谓的完成端口模型。这会增加一点理解的复杂度。关于完成端口,我们可以把系统看成服务器,我们的程序是客户端,当需做一个任务,比如服务器调用connectnamedpipe,如果先前创建name piples设置了file_flag_overlapped,那么调用该函数会立即返回,然后系统工作,当有连接到来的时候,系统会激活先前设置的事件,来通知程序。和windows窗口口号类似:“你别等我,我会通知你的“。在chrome中,browerprocess和renderprocess, browerprocess和pluginprocess之间是怎么传递的呢?chrome中有一个叫channel的对象,这个对象封装了namepiple,所有的进程间通讯将通过这个对象来完成,也就是说,browerprocess和renderprocess内部都分别拥有一个channel的对象,用这个对象来实现彼此的互通。那么接下的问题是:这个对象发送的字节流的格式是什么?这就牵出了另外一个对象message,message是一个被精心定义的对象,它继承于pickle, pickle是个对二进制进行读写操作的类,当然读写操作由它的派生类来定义。channel有个send方法,参数就是message类型。channel也把消息的接收,处理,连接出错状态委托给ipc:channel:listener的接口,由外部类来处理,这里是serverlistener和clientlistener.这样两个进程直接发送数据,然后一堆问随之而来:1:不是说browerprocess里面有个io线程吗,io线程用来接受renderproces和网络下载的线程,那么当render通过ipc把消息发送给io线程了,io线程怎么转发消息到browerprocess的主线程?2:renderproces中的io线程和renderproces中的主线程各自职责又是什么?他们之间又是怎么通讯的?3:进程间异步和同步是怎么处理的?在什么情况下应用同步,什么情况下应用异步处理?chrome的线程模型-消息循环的手段。每一个chrome的线程,入口函数都差不多,都是启动一个消息循环(参见messagepump类),等待并执行任务。而其中,唯一的差别在于,根据线程处理事务类别的不同,所起的消息循环有所不同。比如处理进程间通信的线程(注意,在chrome中,这类线程都叫做io线程,估计是当初设计的时候谁的脑门子拍错了.)启用的是messagepumpforio类,处理ui的线程用的是messagepumpforui类,一般的线程用到的是messagepumpdefault类 (只讨论windows, windows, windows.)。不同的消息循环类,主要差异有两个,一是消息循环中需要处理什么样的消息和任务,第二个是循环流程(比如是死循环还是阻塞在某信号量上.)。下图是一个完整版的chrome消息循环图,包含处理windows的消息,处理各种task(task是什么,稍后揭晓,敬请期 待.),处理各个信号量观察者(watcher),然后阻塞在某个信号量上等待唤醒。图2 chrome的消息循环不同的messagepump类,实现是有所不同的,详见下表:messagepumpdefaultmessagepumpforiomessagepumpforui是否需要处理系统消息否是是是否需要处理task是是是是否需要处理watcher否是否是否阻塞在信号量上否是是task就是一个类,一个包含了 void run()抽象方法的类(参见task类.)。一个真实的任务,可以派生task类,并实现其run方法。每个messagepump类中,会有一个 messagepump:delegate的类的对象(messagepump:delegate的一个实现,请参见messageloop 类.),在这个对象中,会维护若干个task的队列。当你期望,你的一个逻辑在某个线程内执行的时候,你可以派生一个task,把你的逻辑封装在 run方法中,然后实例一个对象,调用期望线程中的posttask方法,将该task对象放入到其task队列中去,等待执行。在线程池,undoredo等模块的实现中,用的太多了。在chrome中,线程模型是统一且唯一的,这就相当于有了一套标准,它需要满足在各个线程上执行的几十上百种任务的需求,因此,必须在灵活行和易用性上有良好的表现,这就是设计标准的难度。为了满足这些需求,chrome在底层库上做了足够的功夫:1. 它提供了一大套的模板封装(参见task.h),可以将task摆脱继承结构、函数名、函数参数等限制(就是基于模板的伪function实现,想要更深入了解,建议直接看鼻祖modern c+和它的loki库.);2. 同时派生出cancelabletask、releasetask、deletetask等子类,提供更为良好的默认实现;3. 在消息循环中,按逻辑的不同,将task又分成即时处理的task、延时处理的task、idle时处理的task,满足不同场景的需求;4. task派生自tracked_objects:tracked,tracked是为了实现多线程环境下的日志记录、统计等功能,使得task天生就有良好的可调试性和可统计性;这一套七荤八素的都搭建完,这才算是一个完整的task模型多线程模型中,我们需要分清楚啥是同步 啥是异步,在同步模式下,一切看上去和单线程没啥区别,但同时也丧失了多线程的优势(沦落成为多线程串行.)。而如果采用异步的模式,那写起来就麻烦多了,你需要注册回调,小心管理对象的生命周期,程序写出来是嗷嗷恶心。在chrome的多线程模型下,同步和异步的编程模型区别就不复存在了,如果是这 样一个场景:a线程需要b线程做一些事情,然后回到a线程继续做一些事情;在chrome下你可以这样来做:生成一个task,放到b线程的队列中,在该 task的run方法最后,会生成另一个task,这个task会放回到a的线程队列,由a来执行。如此一来,同步异步,天下一统,都是task传来传 去,想不会,都难了。图4 chrome的一种异步执行的解决方案1:消息系统的概述(1)消息系统的静态结构这是消息系统的第一个部分,先看看和消息相关的静态类图:伎俩一:handle-body,pimpl, 桥接messageloop基本就是messagepump的一个代理类,扩充了一些messagepump没有的功能,chrome本意可以能是想让message来处理所有事务,而这个messgaepump可以做到对调用者透明。但是对于研究chrome代码的coder来说,了解messagepump是不可推卸的责任。后面都会详细分析的。messagepump和messageloop采用用了一种handle-body或称pimpl的伎俩,按照牛逼点的叫法叫着桥接,关于此伎俩可以参考四人帮的设计模式。伎俩二:委托chrome中已经用烂了改伎俩,基本上所有代码中都能看见此手法。一个类的内部操作委托给外面的一个对象,通过抽象接口。如上面代码所示,messagepump把 dowork dodelaywork, doidelwork通过messagepump:deletgate 的接口委托给m essageloop去处理,这样比较好的解决了代码间的耦合问题。类似伎俩在消息系统这块还有很多:messagepump:watcher 对应handle的事件处理messagepump:observer 监视windows消息的处理messagepump:dispatcher windows本地消息的分派messageloop:destructionobserver 用来跟踪messageloop的稀构这些都是委托的接口,只不过名字不像messagepump:deletgate这么张扬而已。把委托的接口类写到类的内部,对于chrome这种写法我是我以前没有考虑过的,是个非常清晰的代码风格,coder一看就能知道这个委托接口是干吗的。伎俩三:线程本地存储一个线程怎么获取到当前线程的消息循环对象,通过线程本地存储。所谓的线程本地存储就是把一个变量和一个线程相关联.最简单的说是我定义了一个全局的 int n变量,我把n设置为线程本地存储变量,当开启了4个线程,这四个线程都修改了 n这个变量,结果是n对应于每个线程都有一份拷贝,即四个线程四份n的值。chrome中是把 messageloop对象设置为线程本地存储,每个线程获取线程的消息循环很简单,直接通过调用messageloop一个静态的current()方法返回当前线程的消息循环。比如在一个线程里面运行一个消息循环1. messageloop:current()-run();伎俩四:关于chrome 添加任务的方式注意观察messageloop中的任务队列,会发现它有四个队列,如下:incoming_queue_所有任务都是首先添加到该队列中work_queue_当前的工作队列delayed_work_queue_推迟指定时间执行的任务队列deferred_non_nestable_work_queue_不能重入被推迟执行任务队列现在要弄明白每个队列的在mesageloop中的语意,只有先了解了语意才能知道为什么要这样设计。incoming_queue_ 和 work_queue_ 队列的区别?由于添加队列设计到多线程操作,必然需要对其加锁。程序的设计原则是能不用锁打死也不用,现在chrome的messageloop需要段的加入消息,循环内部需要不断地处理消息,如果每次添加和取消息都要对队列加锁,那么是比会影响其执行效率。如是,chrome采用了这样的一个措施,采用两个队列:一个用来从外部线程收集任务的队列(incoming_queue),一个是供内部使用的队列(work_queue),并且保证从work_queue队列中取出任务不需要加锁。遵循以下三个原则:1:每次添加一个任务都需要加锁(任务被添加到incoming_queue)2:每次从work_queue队列中取出任务不需要加锁。3:在work_queue为空时需要把incoming_queue队列中的内容取出来,取出的操作需要加锁这样循环的效率可以提高 40-50%。1. voidmessageloop:reloadworkqueue()2. /wecanimproveperformanceofourloadingtasksfromincoming_queue_to 3. /work_queue_bywaitinguntilthelastminute(work_queue_isempty)to 4. /load.thatreducesthenumberoflocks-per-tasksignificantlywhenour 5. /queuesgetlarge. 6. if(!work_queue_.empty()7. return;/waittillwe*really*needtolockandload. 8.9. /acquireallwecanfromtheinter-threadqueuewithonelockacquisition. 10. 11. autolocklock(incoming_queue_lock_);12. if(incoming_queue_.empty()13. return;14. std:swap(incoming_queue_,work_queue_);15. dcheck(incoming_queue_.empty();16. 17. (2)消息动态流程和windows的传统消息机制类似,但是它扩充了windows的消息循环机制,使得它能够支持事件对象和任务。chrome 对自己的线程采取一种lazycreate 的策略,就是每个线程在需要的时候才被创建。线程之间是通过g_browser_process这个全局对对象来获取相应的线程中的消息循环,然后再通过 消息循环中的posttask 系列的函数来发送任务到相应的线程队列中去。上一章对chrome进程间通讯做了一个简单的介绍,利用name piples来传递二进制数据,chrome把name piples封装在一个channel的类中,利用参数message相互发送消息。 那么现在将要深入browerprocess和 renderproces里面去,揭开里面有多少线程,线程间怎样交互。现在有有一下的问题: browerprocess中有ui显示部分,消息接受部分,http页面下载部分,然后其他一系列读取cookie,写文件,读写数据库,等操作是怎么协调?怎么分工的?之间又是怎么交互的? renderproces中渲染部分和接收 browerprocess消息部分是怎么交互的? renderproces是怎么发送消息的到browerprocess中的?注意为了方便理解这里先还是先抛开pluginprocess和sanbox不讲。按照上面的问题本章打算分三部分介绍,一:browerprocess 中的线程二:renderproces中的线程三:browerprocess和renderproces线程交互流程。一:browerprocess 中的线程 browerprocess里面的线程很多,其中最重要的是io线程和ui线程。除了这两个线程,还有管理数据库读写的db线程,管理本地文件读写的file线程等等。 要研究每个线程首先我们得了解每个线程的职能。ui 线程顾名思义,管理ui以及ui的消息循环,但是io线程不能太顾名思义了,io线程主要有两方面的职能,接收进程间消息(包括渲染进程和插件进程的消 息),还有个职能是接收网络消息所有http页面的下载的消息也由这个线程处理转发,不过除了用io来表示这个线程也想不出来更好的名字了j。可以先参看下how chromium displays web pages上面的介绍,先引用一张上面的图片: (browerprocess基本的线程结构)一个页面是怎样被创建的呢?先弄清楚下面几点说明: 1:一个browerprocess里面保存一个browser的列表,每个browser对象代表着一个浏览器窗口。 2:每个browser对象里面保存一个webcontents列表(这个列表是用了一个tabstripmodel的对象来封装),webcontents就是浏览器上面的html页面和标签。 3:每个webcontents中包含了一个renderviewhost对象。这里要多介绍一下webcontents和 renderviewhost各自的功能:renderviewhost主要表现的就是一个html页面,webcontents不说大家可能也已经猜到 了,它就是管理标签命令和导航命令的(html页面以外的消息由它处理)。讲 一些题外话,google声明说他们会在将来支持其他程序调用renderviewhost的功能,这对微软来说是个相当打的挑战,虽然说瘦死的骆驼比马 大,但是google会一步步地同食微软的市场,这匹瘦骆驼也无力于健壮的马来竞争,ie只是他们计划中的一个小计划,闲话不多扯了,杀回来继续。 4:每个renderviewhost被创建的时候它会创建一个renderprocesshost的对象,并且创建一个rander进程,renderprocesshost的对象会等待rander进程的连接消息。 5:一个renderprocesshost对象会创建一个channelproxy的代理对象(这个对象将被分配到io线程里面去运 行),channelproxy对象的职责是转发render进程的消息和网络消息(http页面下载),并且把需要网络消息转发给render进程。 renderprocesshost对象还会创建另外一个过滤消息的对象resourcemessagefilter的过滤器,该过滤器会被添加到 channelproxy中,此处也是采用上面重复提到的委托伎俩,channelproxy有个过滤消息的委托接口类,然后把消息交给由外面派生类 (resourcemessagefilter)来处理,如果处理了那么就不转发消息给ui线程了,如果没处理,那么转发消息。 6:每个channelproxy里面会包含一个真正的ipc:channel对象,如果看过我上一篇文章的同学肯定还记的这个 ipc:channel,不就是进行进程间通讯的东东吗。channel会把接受到的消息转发给channelproxy,由channelproxy 决定该消息路由到什么地方。另外一点就是channelproxy会收到本进程的消息(网络消息和ui消息和其他的消息),这些消息会根据情况被转发给 render进程。 channelproxy在io线程中是怎么把message转换为task的呢? 同学们可能很奇怪,message和task都都好像在前面见过,但是他们之间有什么关系呢? message是从render进程那儿接受到的消息,task是消息循环中执行的一个任务,io线程需要把message转换为task发送到ui线 程中去执行,chrome开发人员定义了一套newrunnablemethod 的方法,用来把message转换为相应的task,参看basetask.h代码。channelproxy里面保存了ui的消息循环对象的指针,然 后通过该对象posttask系列函数来发送消息到ui线程中。 一个对browerprocess里面的进程大概介绍就这样完成了,对上面的6点我们还可以总结出 1,2,3是在ui线程环境中运行的,4,5是在io线程中运行的,6是io和ui线程之间交互方式。/=飘逸的分割线=/ 下一章将对renderproces里面的线程做简单的介绍,有了browerprocess的介绍这就简单得多了:)上一章对chrome进程间通讯做了一个简单的介绍,利用name piples来传递二进制数据,chrome把name piples封装在一个channel的类中,利用参数message相互发送消息。 那么现在将要深入browerprocess和 renderproces里面去,揭开里面有多少线程,线程间怎样交互。现在有有一下的问题: browerprocess中有ui显示部分,消息接受部分,http页面下载部分,然后其他一系列读取cookie,写文件,读写数据库,等操作是怎么协调?怎么分工的?之间又是怎么交互的? renderproces中渲染部分和接收 browerprocess消息部分是怎么交互的? renderproces是怎么发送消息的到browerprocess中的?注意为了方便理解这里先还是先抛开pluginprocess和sanbox不讲。按照上面的问题本章打算分三部分介绍,一:browerprocess 中的线程二:renderproces中的线程三:browerprocess和renderproces线程交互流程。一:browerprocess 中的线程 browerprocess里面的线程很多,其中最重要的是io线程和ui线程。除了这两个线程,还有管理数据库读写的db线程,管理本地文件读写的file线程等等。 要研究每个线程首先我们得了解每个线程的职能。ui 线程顾名思义,管理ui以及ui的消息循环,但是io线程不能太顾名思义了,io线程主要有两方面的职能,接收进程间消息(包括渲染进程和插件进程的消 息),还有个职能是接收网络消息所有http页面的下载的消息也由这个线程处理转发,不过除了用io来表示这个线程也想不出来更好的名字了j。可以先参看下how chromium displays web pages上面的介绍,先引用一张上面的图片: (browerprocess基本的线程结构)一个页面是怎样被创建的呢?先弄清楚下面几点说明: 1:一个browerprocess里面保存一个browser的列表,每个browser对象代表着一个浏览器窗口。 2:每个browser对象里面保存一个webcontents列表(这个列表是用了一个tabstripmodel的对象来封装),webcontents就是浏览器上面的html页面和标签。 3:每个webcontents中包含了一个renderviewhost对象。这里要多介绍一下webcontents和 renderviewhost各自的功能:renderviewhost主要表现的就是一个html页面,webcontents不说大家可能也已经猜到 了,它就是管理标签命令和导航命令的(html页面以外的消息由它处理)。讲 一些题外话,google声明说他们会在将来支持其他程序调用renderviewhost的功能,这对微软来说是个相当打的挑战,虽然说瘦死的骆驼比马 大,但是google会一步步地同食微软的市场,这匹瘦骆驼也无力于健壮的马来竞争,ie只是他们计划中的一个小计划,闲话不多扯了,杀回来继续。 4:每个renderviewhost被创建的时候它会创建一个renderprocesshost的对象,并且创建一个rander进程,renderprocesshost的对象会等待rander进程的连接消息。 5:一个renderprocesshost对象会创建一个channelproxy的代理对象(这个对象将被分配到io线程里面去运 行),channelproxy对象的职责是转发render进程的消息和网络消息(http页面下载),并且把需要网络消息转发给render进程。 renderprocesshost对象还会创建另外一个过滤消息的对象resourcemessagefilter的过滤器,该过滤器会被添加到 channelproxy中,此处也是采用上面重复提到的委托伎俩,channelproxy有个过滤消息的委托接口类,然后把消息交给由外面派生类 (resourcemessagefilter)来处理,如果处理了那么就不转发消息给ui线程了,如果没处理,那么转发消息。 6:每个channelproxy里面会包含一个真正的ipc:channel对象,如果看过我上一篇文章的同学肯定还记的这个 ipc:channel,不就是进行进程间通讯的东东吗。channel会把接受到的消息转发给channelproxy,由channelproxy 决定该消息路由到什么地方。另外一点就是channelproxy会收到本进程的消息(网络消息和ui消息和其他的消息),这些消息会根据情况被转发给 render进程。 channelproxy在io线程中是怎么把message转换为task的呢? 同学们可能很奇怪,message和task都都好像在前面见过,但是他们之间有什么关系呢? message是从render进程那儿接受到的消息,task是消息循环中执行的一个任务,io线程需要把message转换为task发送到ui线 程中去执行,chrome开发人员定义了一套newrunnablemethod 的方法,用来把message转换为相应的task,参看basetask.h代码。channelproxy里面保存了ui的消息循环对象的指针,然 后通过该对象posttask系列函数来发送消息到ui线程中。 一个对browerprocess里面的进程大概介绍就这样完成了,对上面的6点我们还可以总结出 1,2,3是在ui线程环境中运行的,4,5是在io线程中运行的,6是io和ui线程之间交互方式。/=飘逸的分割线=/ 下一章将对renderproces里面的线程做简单的介绍,有了browerprocess的介绍这就简单得多了:)前面写了chrome消息系统(1)前 比较抽象,这章来点具体的,当然要结合代码来看了!现在我要关注的问题是:一个renderprocess的消息怎么发送到browserprocess进程中的,这个消息走了那些路?注意,所说的io线程是browser进程中的io线程,非render进程中发的io。所谓的io线程主要用来接受网络消息和进程间的消息,我先把网络消息抛到一边,单独分析下renderprocess进程给browserprocess的消息是怎样流动的?通常把网络包分为上行和下行,在这里我把renderprocess到browserprocess称为上行消息,browserprocess到renderprocess的消息称为下行消息,这章只讨论上行消息。需要特别注意的几个类分别是:siteinstance:每个siteinstance对象对应于一个renderprocesshost,当创建renderviewhost时会传递一个siteinstance实例,该renderviewhost保存在siteinstance实例的renderprocesshost对象中。siteinstance对应于四种启动方式。renderprocesshost:每个renderprocesshost对应于一个renderprocess进程,renderprocess进程负责渲染所有的renderprocesshost中的renderviewhost的页面。webcontents: webcontents包括了renderviewhost和navigationcontroller。renderviewhostmanager:存在于webcontents主要保存一个renderviewhost对象,但是有一种情况比较复杂,那就是当一个interstitial webpage存在时,它负责加载interstitial webpage,并切换到用户请求页面。关于interstitial webpage请参看上上篇文章的解释。由于这种复杂度,这里没有直接采用renderviewhost而是采用renderviewhostmanager来控制管理。navigationcontroller:存在于webcontents中,控制一个tab的后退,前进,刷新,加载等操作。renderviewhost:对应于一个html页面channel:用于进程间通讯。channelproxy:对channel的代理,并且附加了一些过滤信息channelproxy:context:封装的channelsyncchannel:扩展了channelproxy,使之能支持同步信息。syncchannel:synccontext:对channelproxy:context的同步支持的封装。resourcedispatcherhost:所有消息将通过resourcedispatcherhost来过滤,resourcemessagefilter的消息也会通过resourcedispatcherhost,resourcedispatcherhost还过滤网络消息,并且做相应的转发。resourcemessagefilter:过滤channelproxy的一些相关信息。messageloopforio:提供支持apc事件通知的消息循环,这里是支持命名管道的消息。先大致走一趟上行消息的简单流程,然后结合代码仔细分析。消息最先达到的地方当然是channel这个对象了,channel是被channelproxy:context所封装,所以消息会被分派到channelproxy:context中,channelproxy:context对象是存在于channelproxy中的,channelproxy:contex又把消息提交给了channelproxy,channelproxy先过滤消息,如果消息没有被过滤掉,把消息推给renderprocesshost,然后由renderprocesshost把消息分配给每个相应的renderviewhost。上面是上行消息的一个简单的路由过程。其中细节很多,问题也是很多。0:一个tab页面是怎么被创建的出来的?1:channelproxy怎么由ui线程给分派到io线程中去运行?2:一个命名管道的消息怎么被通知到browserprocess进程中的?3:消息是通过什么方法逐渐往上一层传递的?4:resourcemessagefilter是怎么加进channelproxy中的,它会过滤掉什么样的消息,什么消息它会继续转发?5:resourcemessagefilter和resourcedispatcherhost有什么瓜葛?一:先来分析第一个问题:一个tab页面是怎么被创建的出来的?当用户点击浏览器上的添加按钮或者是从一个网页的一个连接来打开一个新的页面,这样一个新的页面就被创建了。一个webcontents对象对应于一个html页面和关联该页面的标签,创建一个页面其实就是创建一个webcontents对象。上面提到过renderviewhostmanager存在于webcontents中,renderviewhostmanager是用来保renderviewhost对象的,renderviewhost对象也是在renderviewhostmanager中被创建的。webcontents的构造函数中会传递一个siteinstance参数,renderviewhostmanager会创建renderviewhost,然后把创建的renderviewhost对象关联到siteinstance相对应的renderprocesshost中。仔细看renderprocesshost的结构会发现,renderprocesshost中有两个方法:voidattach(ipc:channel:listener* listener,introuting_id);voidrelease(intlistener_id);用这两个方法来关联和取消关联,具体细节参见前面的uml类图。这样一个renderviewhost的对象就被创建并关联到相应的renderprocesshost中了。二:分析第二个问题:channelproxy怎么由ui线程给分派到io线程中去运行?根据chrome官方技术文档可以看出来,每个renderprocesshost对应一个renderprocess,他们之间通过channelproxy来通讯的,也就是说renderprocesshost是通过channelproxy和renderprocess的channelproxy来通讯的。renderprocesshost和renderprocess分别都拥有一个channelproxy,renderprocesshost和renderprocess都是通过他们的大使channelproxy来沟通的。先抛开renderprocess和它的大使channelproxy,专心来分析renderprocesshost和它的大使channelproxy。先来分析renderprocesshost是怎么创建的?上面分析过,renderprocesshost是从siteinstance中获取的,先分析一段siteinstance获取renderprocesshost的代码:renderprocesshost* siteinstance:getprocess()renderprocesshost* process = null;if(process_host_id_ != -1)/首先从一个全局的renderprocesshost对象列表中获取和当前id相匹配的renderprocesshost对象process = renderprocesshost:fromid(process_host_id_);/如果没有,先恢复,如果恢复不了,那么创建一个行的对象if(!process)/判断是否恢复以前创建的renderprocesshost对象if(renderprocesshost:shouldtrytouseexistingprocesshost()process = renderprocesshost:getexistingprocesshost(browsing_instance_-profile();/恢复不了,那么创建一个行的对象if(!process)process =newrenderprocesshost(browsing_instance_-profile();/更新这个renderprocesshost对象的idprocess_host_id_ = process-host_id();/ make sure the process starts at the right max_page_idprocess-updatemaxpageid(max_page_id_);dcheck(process);/返回改对象returnprocess;这样一个对象就创建了,这里采用的策略是lazycreate,即是到了需要创建的时候才创建该对象。注意了,channel并不是在这个时候被创建的,channel是在加载时被创建的,renderprocesshost中的init函数中创建的。renderprocess也是在该函数中创建的,关于该函数,很长,我选出其中比较重要的几段,为了不影响阅读,我把一些sandbox的代码给去掉了,简化后的代码如下:boolrenderprocesshost:init() /如果channel_已经被创建了,那么直接返回,不需要后续处理了。if(channel_.get()returntrue;/安装resourcemessagefilterbase:thread* io_thread = g_browser_process-io_thread();scoped_refptr resource_message_filter =newresourcemessagefilter(g_browser_process-resource_dispatcher_host(),pluginservice:getinstance(),g_browser_process-print_job_manager(),host_id_,profile_,widget_helper_,profile_-getspellchecker();commandline browser_command_line;/安装ipc channelstd:wstring channel_id = generaterandomchannelid(this);channel_.reset(newipc:syncchannel(channel_id, ipc:channel:mode_server,this,resource_message_filter,io_thread-message_loop(),true,g_browser_process-shutdown_event();一堆生成命令行的代码、被我注释掉了。/是否是单进程模式boolrun_in_process = renderprocesshost:run_renderer_in_process();if(run_in_process)base:thread *render_thread =newrenderermainthread(channel_id);base:thread:options options;options.message_loop_type = messageloop:type_io;render_thread-startwithoptions(options);elsehandle process;if(!process_util:launchapp(cmd_line,false,false, &process)returnfalse;process_.set_handle(process);watcher_.startwatching(process_.handle(),this);returntrue;当我开始启动一个浏览器的时候,调试堆栈如下,可以看出init函数是什么时候第一次被调用的。上面的代码还是运行在ui线程中的,我还没有看出来channel对象是怎么给 分派带io线程中去运行的

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论