您的位置:首页 > 其它

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行:

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进程执行主体实现,包揽了所有的事情,那么接着来看在chromium//src/content/browser/browser_main_runner.cc239行。

1//static
2BrowserMainRunner*BrowserMainRunner::Create(){
3returnnewBrowserMainRunnerImpl();
4}


原来BrowserMainRunner只是定义了接口,是由它的子类BrowserMainRunnerImpl来实现,通过Impl模式来隐藏细节,那么看main_runner的initialize和Run函数是如何实现的

chromium//src/content/browser/browser_main_runner.cc51行

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_;


chromium//src/content/browser/browser_main_loop.h里给出了BrowserMainLoop的声明,BrowserMainLoop的初始化顺序如下:

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_;


chromium//src/content/browser/browser_main_loop.cc710行,MainMessageLoopStart函数负责初始化成员变量main_message_loop_,如果当前进程没有就指向一个base::MessageLoopForUI指针.

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类。

那么在chromium//src/content/browser/browser_main_loop.cc1708行

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是什么呢?

在chromium//src/base/run_loop.cc73行

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函数,来到了消息循环的主体,到此由于篇幅过长,那么下面单独写一章来看消息处理的具体流程。


                                            
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: