chromium源码阅读--Browser进程初始化
2017-10-18 15:42
731 查看
最近在研读chromium源码,经过一段懵懂期,查阅了官网和网上的技术文章,是时候自己总结一下了,首先从Browser进程启动以及IPCmessageloop开始吧,这是每个主线程必须有的一个IPC消息轮训主体,类似之前的quagga里thread。
首先来看看chromium的多进程模型:
图1多进程模型
图1描述了chromium里browser进程,(隐含了zygote进程),render进程以及WebKit的关系,Webkit是网页渲染引擎,这里我就不发散开了。
浏览器进程有browser进程,render进程,还有GPU进程,plugin进程等等,首先启动肯定是browser进程。
那么我们先从browser进程开始,以下是Browser进程主函数,在chromium//src/content/browser/browser_main.cc33行:
当然,启动browser进程可以有多种方式,比如,shell模式的browser就是以ContentMain来启动的。这个函数很简单,创建了一个BrowserMainRunner对象,并且Run()起来就完成了所有的工作。
那么,事情肯定没这么简单,BrowserMainRunner就是browser进程执行主体实现,包揽了所有的事情,那么接着来看在chromium//src/content/browser/browser_main_runner.cc239行。
原来BrowserMainRunner只是定义了接口,是由它的子类BrowserMainRunnerImpl来实现,通过Impl模式来隐藏细节,那么看main_runner的initialize和Run函数是如何实现的
在chromium//src/content/browser/browser_main_runner.cc51行
可以看到main_loop_成员接管了所有的工作,那么它的声明是什么:
在chromium//src/content/browser/browser_main_loop.h里给出了BrowserMainLoop的声明,BrowserMainLoop的初始化顺序如下:
这个流程已经在前面的BrowserMainRunnerImpl的实例对象的initialize已经完成,包含了大量信息,这里我就主要看主线程的IPC消息循环的部分,如下声明了IPC消息轮询对象:
在chromium//src/content/browser/browser_main_loop.cc710行,MainMessageLoopStart函数负责初始化成员变量main_message_loop_,如果当前进程没有就指向一个base::MessageLoopForUI指针.
到了这里我们可以看到,base::MessageLoopForUI,顾名思义,是UI类型的IPC消息轮询,嗯,没错,Browser进程负责UI方面的IPC消息接收和转发(routing)。
接下来,就将这个消息轮询对象加入到主线程当中:
初始化完成之后,我们返回之前main_runner_的Run()是执行RunMainMessageLoopParts()函数:
这里我们需要分析一下BrowserMainParts这个类以及它的子类,因为它开始涉及到平台相关的内容了。
BrowserMainParts的子类有ChromeBrowserMainParts,ChromeBrowserMainPartsAndroid,ChromeBrowserMainPartsPosix等等,涉及chrome相关的,都没有重载MainMessageLoopRun,当然也有重载这个函数,比如ShellBrowserMainParts类。
那么在chromium//src/content/browser/browser_main_loop.cc1708行
RunLoop是一个可以处理嵌套IPC消息的辅助类,它里面声明了一个RunLoop::Delegate类,来协助完成对IPC消息轮询嵌套层级的执行。
这里简单解释一下消息嵌套,即当前处理的IPC消息过程中有收到了新的IPC消息。RunLoop以一种类似入栈出栈的思路来实现消息嵌套。
我们接着看RunLoop的声明:
构造函数:
默认的话是不支持嵌套的,通过ThreadTaskRunnerHandle::Get()获取当前线程的IPC消息sender,并且偷偷的将从当前线程变量里的tls_delegate来初始化RunLoop::Delegatedelegate_成员变量,那么tls_delegate是什么呢?
在chromium//src/base/run_loop.cc73行
到这里,又悄悄的把MessageLoop和RunLoop联系到了一起,RunLoop的delegate_指向一个MessageLoop指针,那么我们接下来可以看一下MessageLoop的声明了。
好了,可以看到RunLoop的Run函数实际上是调用的MessageLoop的Run函数,来到了消息循环的主体,到此由于篇幅过长,那么下面单独写一章来看消息处理的具体流程。
首先来看看chromium的多进程模型:
图1多进程模型
图1描述了chromium里browser进程,(隐含了zygote进程),render进程以及WebKit的关系,Webkit是网页渲染引擎,这里我就不发散开了。
浏览器进程有browser进程,render进程,还有GPU进程,plugin进程等等,首先启动肯定是browser进程。
那么我们先从browser进程开始,以下是Browser进程主函数,在
1//MainroutineforrunningastheBrowserprocess. 2intBrowserMain(constMainFunctionParams¶meters){ 3ScopedBrowserMainEventscoped_browser_main_event; 4 5base::trace_event::TraceLog::GetInstance()->SetProcessName("Browser"); 6base::trace_event::TraceLog::GetInstance()->SetProcessSortIndex( 7kTraceEventBrowserProcessSortIndex); 8 9std::unique_ptr<BrowserMainRunner>main_runner(BrowserMainRunner::Create()); 10 11intexit_code=main_runner->Initialize(parameters); 12if(exit_code>=0) 13returnexit_code; 14 15exit_code=main_runner->Run(); 16 17main_runner->Shutdown(); 18 19returnexit_code; 20
当然,启动browser进程可以有多种方式,比如,shell模式的browser就是以ContentMain来启动的。这个函数很简单,创建了一个BrowserMainRunner对象,并且Run()起来就完成了所有的工作。
那么,事情肯定没这么简单,BrowserMainRunner就是browser进程执行主体实现,包揽了所有的事情,那么接着来看
1//static 2BrowserMainRunner*BrowserMainRunner::Create(){ 3returnnewBrowserMainRunnerImpl(); 4}
原来BrowserMainRunner只是定义了接口,是由它的子类BrowserMainRunnerImpl来实现,通过Impl模式来隐藏细节,那么看main_runner的initialize和Run函数是如何实现的
在
classBrowserMainRunnerImpl:publicBrowserMainRunner{ intInitialize(constMainFunctionParams¶meters)override{ ...... constbase::TimeTicksstart_time_step1=base::TimeTicks::Now(); SkGraphics::Init(); base::StatisticsRecorder::Initialize(); notification_service_.reset(newNotificationServiceImpl); main_loop_.reset(newBrowserMainLoop(parameters)); main_loop_->Init(); main_loop_->EarlyInitialization(); ...... main_loop_->PreMainMessageLoopStart(); main_loop_->MainMessageLoopStart(); main_loop_->PostMainMessageLoopStart(); ui::InitializeInputMethod(); constbase::TimeTicksstart_time_step2=base::TimeTicks::Now(); main_loop_->CreateStartupTasks(); intresult_code=main_loop_->GetResultCode(); if(result_code>0) returnresult_code; ..... } intRun()override{ DCHECK(initialization_started_); DCHECK(!is_shutdown_); main_loop_->RunMainMessageLoopParts(); returnmain_loop_->GetResultCode(); } }
可以看到main_loop_成员接管了所有的工作,那么它的声明是什么:
1std::unique_ptr<BrowserMainLoop>main_loop_;
在
1//Quickreferenceforinitializationorder: 2//Constructor 3//Init() 4//EarlyInitialization() 5//InitializeToolkit() 6//PreMainMessageLoopStart() 7//MainMessageLoopStart() 8//InitializeMainThread() 9//PostMainMessageLoopStart() 10//CreateStartupTasks() 11//PreCreateThreads() 12//CreateThreads() 13//BrowserThreadsStarted() 14//InitializeMojo() 15//InitStartupTracingForDuration() 16//PreMainMessageLoopRun()
这个流程已经在前面的BrowserMainRunnerImpl的实例对象的initialize已经完成,包含了大量信息,这里我就主要看主线程的IPC消息循环的部分,如下声明了IPC消息轮询对象:
1//Membersinitializedin|MainMessageLoopStart()| 2std::unique_ptr<base::MessageLoop>main_message_loop_;
在
1voidBrowserMainLoop::MainMessageLoopStart(){ 2//DONOTaddmorecodehere.UsePreMainMessageLoopStart()aboveor 3//PostMainMessageLoopStart()below. 4 5TRACE_EVENT0("startup","BrowserMainLoop::MainMessageLoopStart"); 6 7//CreateaMessageLoopifonedoesnotalreadyexistforthecurrentthread. 8if(!base::MessageLoop::current()) 9main_message_loop_.reset(newbase::MessageLoopForUI); 10 11InitializeMainThread(); 12}
到了这里我们可以看到,base::MessageLoopForUI,顾名思义,是UI类型的IPC消息轮询,嗯,没错,Browser进程负责UI方面的IPC消息接收和转发(routing)。
接下来,就将这个消息轮询对象加入到主线程当中:
1voidBrowserMainLoop::InitializeMainThread(){ 2TRACE_EVENT0("startup","BrowserMainLoop::InitializeMainThread"); 3base::PlatformThread::SetName("CrBrowserMain"); 4 5//Registerthemainthreadbyinstantiatingit,butdon'tcallanymethods. 6main_thread_.reset( 7newBrowserThreadImpl(BrowserThread::UI,base::MessageLoop::current())); 8}
初始化完成之后,我们返回之前main_runner_的Run()是执行RunMainMessageLoopParts()函数:
1voidBrowserMainLoop::RunMainMessageLoopParts(){ 2//Don'tusetheTRACE_EVENT0macrobecausethetracinginfrastructuredoesn't 3//expectsynchronouseventsaroundthemainloopofathread. 4TRACE_EVENT_ASYNC_BEGIN0("toplevel","BrowserMain:MESSAGE_LOOP",this); 5 6boolran_main_loop=false; 7if(parts_) 8ran_main_loop=parts_->MainMessageLoopRun(&result_code_); 9 10if(!ran_main_loop) 11MainMessageLoopRun(); 12 13TRACE_EVENT_ASYNC_END0("toplevel","BrowserMain:MESSAGE_LOOP",this); 14}
这里我们需要分析一下BrowserMainParts这个类以及它的子类,因为它开始涉及到平台相关的内容了。
BrowserMainParts的子类有ChromeBrowserMainParts,ChromeBrowserMainPartsAndroid,ChromeBrowserMainPartsPosix等等,涉及chrome相关的,都没有重载MainMessageLoopRun,当然也有重载这个函数,比如ShellBrowserMainParts类。
那么在
1voidBrowserMainLoop::MainMessageLoopRun(){ 2#ifdefined(OS_ANDROID) 3//Android'smainmessageloopistheJavamessageloop. 4NOTREACHED(); 5#else 6DCHECK(base::MessageLoopForUI::IsCurrent()); 7if(parameters_.ui_task){ 8base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, 9*parameters_.ui_task); 10} 11 12base::RunLooprun_loop; 13run_loop.Run(); 14#endif 15}
RunLoop是一个可以处理嵌套IPC消息的辅助类,它里面声明了一个RunLoop::Delegate类,来协助完成对IPC消息轮询嵌套层级的执行。
这里简单解释一下消息嵌套,即当前处理的IPC消息过程中有收到了新的IPC消息。RunLoop以一种类似入栈出栈的思路来实现消息嵌套。
我们接着看RunLoop的声明:
1enumclassType{ 2kDefault, 3kNestableTasksAllowed, 4}; 5 6RunLoop(Typetype=Type::kDefault);
构造函数:
1RunLoop::RunLoop(Typetype) 2:delegate_(tls_delegate.Get().Get()), 3type_(type), 4origin_task_runner_(ThreadTaskRunnerHandle::Get()), 5weak_factory_(this){ 6DCHECK(delegate_)<<"ARunLoop::Delegatemustbeboundtothisthreadprior" 7"tousingRunLoop."; 8DCHECK(origin_task_runner_); 9 10DCHECK(IsNestingAllowedOnCurrentThread()|| 11type_!=Type::kNestableTasksAllowed); 12}
默认的话是不支持嵌套的,通过ThreadTaskRunnerHandle::Get()获取当前线程的IPC消息sender,并且偷偷的将从当前线程变量里的tls_delegate来初始化RunLoop::Delegatedelegate_成员变量,那么tls_delegate是什么呢?
1//static 2RunLoop::Delegate::Client*RunLoop::RegisterDelegateForCurrentThread( 3Delegate*delegate){ 4//Bind|delegate|tothisthread. 5DCHECK(!delegate->bound_); 6DCHECK_CALLED_ON_VALID_THREAD(delegate->bound_thread_checker_); 7 8//TherecanonlybeoneRunLoop::Delegateperthread. 9DCHECK(!tls_delegate.Get().Get()); 10tls_delegate.Get().Set(delegate); 11delegate->bound_=true; 12 13return&delegate->client_interface_; 14}
函数RegisterDelegateForCurrentThread负责对tls_delegate进行赋值。而这个函数是在MessageLoop的BindToCurrentThread函数里调用的。
1voidMessageLoop::BindToCurrentThread(){ 2DCHECK(!pump_); 3if(!pump_factory_.is_null()) 4pump_=std::move(pump_factory_).Run(); 5else 6pump_=CreateMessagePumpForType(type_); 7 8DCHECK(!current())<<"shouldonlyhaveonemessageloopperthread"; 9GetTLSMessageLoop()->Set(this); 10 11incoming_task_queue_->StartScheduling(); 12unbound_task_runner_->BindToCurrentThread(); 13unbound_task_runner_=nullptr; 14SetThreadTaskRunnerHandle(); 15thread_id_=PlatformThread::CurrentId(); 16 17scoped_set_sequence_local_storage_map_for_current_thread_=std::make_unique< 18internal::ScopedSetSequenceLocalStorageMapForCurrentThread>( 19&sequence_local_storage_map_); 20 21run_loop_client_=RunLoop::RegisterDelegateForCurrentThread(this); 22}
到这里,又悄悄的把MessageLoop和RunLoop联系到了一起,RunLoop的delegate_指向一个MessageLoop指针,那么我们接下来可以看一下MessageLoop的声明了。
1classBASE_EXPORTMessageLoop:publicMessagePump::Delegate, 2publicRunLoop::Delegate{ 3...... 4 5}
好了,可以看到RunLoop的Run函数实际上是调用的MessageLoop的Run函数,来到了消息循环的主体,到此由于篇幅过长,那么下面单独写一章来看消息处理的具体流程。
相关文章推荐
- chromium源码阅读--进程的Message Loop
- [Chrome源码阅读] 理解Browser进程
- [Chrome源码阅读] 理解Browser进程
- chromium源码阅读--进程的Message Loop
- Spring源码阅读(九)—SpringMVC的初始化
- Tomcat源码阅读之初始化Server组件
- SpringMVC启动与初始化源码阅读
- [置顶] 源码阅读--进程管理
- Nutch源码阅读进程4---parseSegment
- Android进程间的通信 - IPC(机制)Binder的原理和源码阅读
- 内核源码阅读(八)进程调度器的实现
- Nutch源码阅读进程2---Generate
- [Chrome源码阅读] Browser相关的类
- 内核源码阅读(五)进程ID
- Nutch源码阅读进程5---updatedb
- [Chrome源码阅读] 理解Chrome导航网址的流程及render进程启动模式
- 内核源码阅读(二)进程复制
- 一起学习Chromium之Browser进程启动分析
- EventBus源码阅读(19)-EventBus初始化
- Tomcat源码阅读(一)初始化