chromium之content_shell源代码分析(一)

http://blog.csdn.net/chromium_webkit/article/details/8666005

介绍和入口函数

为了测试chromium和webkit的兼容性,chromium project 中有一个content shell,相对整个项目来说,它简单了很多,如果运行的化,就是一个简单的windows窗口程序,有利于程序员测试webkit的最新特征,和掌握html5等相关的新功能。其入口点在content/shell目录下的shell_main.cc(对于windows系统是如此),打开该文件,可以看到如下代码:

[cpp]  view plain copy
  1. #if defined(OS_WIN)  
  2.   
  3. int APIENTRY wWinMain(HINSTANCE instance, HINSTANCEwchar_t*, int) {  
  4.   sandbox::SandboxInterfaceInfo sandbox_info = {0};  
  5.   content::InitializeSandboxInfo(&sandbox_info);  
  6.   content::ShellMainDelegate delegate;  
  7.   return content::ContentMain(instance, &sandbox_info, &delegate);  
  8. }  
  9.   
  10. #else  
  11.   
  12. int main(int argc, const char** argv) {  
  13. #if defined(OS_MACOSX)  
  14.   // Do the delegate work in shell_content_main to avoid having to export the  
  15.   // delegate types.  
  16.   return ::ContentMain(argc, argv);  
  17. #else  
  18.   content::ShellMainDelegate delegate;  
  19.   return content::ContentMain(argc, argv, &delegate);  
  20. #endif  // OS_MACOSX  
  21. }  
  22.   
  23. #endif  // OS_POSIX  


和chrome工程的区别

可以看到它和chrome/app/chrome_exe_main_win.cc中的:

[cpp]  view plain copy
  1. int APIENTRY wWinMain(HINSTANCE instance, HINSTANCE prev, wchar_t*, int) {  
  2.   // Initialize the commandline singleton from the environment.  
  3.   CommandLine::Init(0, NULL);  
  4.   // The exit manager is in charge of calling the dtors of singletons.  
  5.   base::AtExitManager exit_manager;  
  6.   
  7.   
  8.   MetroDriver metro_driver;  
  9.   if (metro_driver.in_metro_mode())  
  10.     return metro_driver.RunInMetro(instance, &RunChrome);  
  11.   // Not in metro mode, proceed as normal.  
  12.   return RunChrome(instance);  
  13. }  

的不同之处:chrome中的main delegate是ChromeMainDelegate,content shell中的main delegate 是ShellMainDelegate,是content::ContentMainDelegate的不同子类实现版本,这样的设计就决定了上层界面有很大的不同,相对chrome来说,content shell的界面功能简单了很多,有利于大家理解浏览器的程序结构;


进入MainRunner

进入到Content_main.cc中的如下代码后:

[cpp]  view plain copy
  1. namespace content {  
  2.   
  3. #if defined(OS_WIN)  
  4. int ContentMain(HINSTANCE instance,  
  5.                 sandbox::SandboxInterfaceInfo* sandbox_info,  
  6.                 ContentMainDelegate* delegate) {  
  7. #else  
  8. int ContentMain(int argc,  
  9.                 const char** argv,  
  10.                 ContentMainDelegate* delegate) {  
  11. #endif  // OS_WIN  
  12.   
  13.   scoped_ptr<ContentMainRunner> main_runner(ContentMainRunner::Create());  
  14.   
  15.   int exit_code;  
  16.   
  17. #if defined(OS_WIN)  
  18.   exit_code = main_runner->Initialize(instance, sandbox_info, delegate);  
  19. #else  
  20.   exit_code = main_runner->Initialize(argc, argv, delegate);  
  21. #endif  // OS_WIN  
  22.   
  23.   if (exit_code >= 0)  
  24.     return exit_code;  
  25.   
  26.   exit_code = main_runner->Run();  
  27.   
  28.   main_runner->Shutdown();  
  29.   
  30.   return exit_code;  
  31. }  
  32.   
  33. }  // namespace content  

在ContentMainRunnerImpl中的Run函数中,调用delegate_(ShellMainDelegate的实例)的RunProcess,就会进入到content/shell/Shell_browser_main.cc中的如下代码:

[cpp]  view plain copy
  1. // Main routine for running as the Browser process.  
  2. int ShellBrowserMain(const content::MainFunctionParams& parameters) {  
  3.   scoped_ptr<content::BrowserMainRunner> main_runner_(  
  4.       content::BrowserMainRunner::Create());  
  5.   
  6.   int exit_code = main_runner_->Initialize(parameters);  
  7.   
  8.   if (exit_code >= 0)  
  9.     return exit_code;  
  10.   
  11.   if (CommandLine::ForCurrentProcess()->HasSwitch(  
  12.         switches::kCheckLayoutTestSysDeps)) {  
  13.     MessageLoop::current()->PostTask(FROM_HERE, MessageLoop::QuitClosure());  
  14.     main_runner_->Run();  
  15.     main_runner_->Shutdown();  
  16.     return 0;  
  17.   }  
  18.   
  19.   bool layout_test_mode =  
  20.       CommandLine::ForCurrentProcess()->HasSwitch(switches::kDumpRenderTree);  
  21.   
  22.   if (layout_test_mode) {  
  23.     content::WebKitTestController test_controller;  
  24.     std::string test_string;  
  25.     CommandLine::StringVector args =  
  26.         CommandLine::ForCurrentProcess()->GetArgs();  
  27.     size_t command_line_position = 0;  
  28.     bool ran_at_least_once = false;  
  29.   
  30. #if defined(OS_ANDROID)  
  31.     std::cout << "#READY\n";  
  32.     std::cout.flush();  
  33. #endif  
  34.   
  35.     while (GetNextTest(args, &command_line_position, &test_string)) {  
  36.       if (test_string.empty())  
  37.         continue;  
  38.       if (test_string == "QUIT")  
  39.         break;  
  40.   
  41.       bool enable_pixel_dumps;  
  42.       std::string pixel_hash;  
  43.       FilePath cwd;  
  44.       GURL test_url = GetURLForLayoutTest(  
  45.           test_string, &cwd, &enable_pixel_dumps, &pixel_hash);  
  46.       if (!content::WebKitTestController::Get()->PrepareForLayoutTest(  
  47.               test_url, cwd, enable_pixel_dumps, pixel_hash)) {  
  48.         break;  
  49.       }  
  50.   
  51.       ran_at_least_once = true;  
  52.       main_runner_->Run();  
  53.   
  54.       if (!content::WebKitTestController::Get()->ResetAfterLayoutTest())  
  55.         break;  
  56.     }  
  57.     if (!ran_at_least_once) {  
  58.       MessageLoop::current()->PostTask(FROM_HERE, MessageLoop::QuitClosure());  
  59.       main_runner_->Run();  
  60.     }  
  61.     exit_code = 0;  
  62.   } else {  
  63.     exit_code = main_runner_->Run();  
  64.   }  
  65.   
  66.   main_runner_->Shutdown();  
  67.   
  68.   return exit_code;  
  69. }  


进入MainLoop

这样的话,还是会进入到Browser_main_runner.cc的BrowserMainRunnerImpl类中,并呼叫其实列的Initialize函数和Run函数;在BrowserMainRunnerImpl的Initialize中会看到如下代码:

[cpp]  view plain copy
  1. base::StatisticsRecorder::Initialize();  
  2.   
  3.     notification_service_.reset(new NotificationServiceImpl);  
  4.   
  5.     main_loop_.reset(new BrowserMainLoop(parameters));  
  6.   
  7.     main_loop_->Init();  
  8.   
  9.     main_loop_->EarlyInitialization();  
  10.   
  11.     // Must happen before we try to use a message loop or display any UI.  
  12.     main_loop_->InitializeToolkit();  
  13.   
  14.     main_loop_->MainMessageLoopStart();  

在BrowserMainLoop的Init函数中,可以看到如下代码:

[cpp]  view plain copy
  1. void BrowserMainLoop::Init() {  
  2.   parts_.reset(  
  3.       GetContentClient()->browser()->CreateBrowserMainParts(parameters_));  
  4. }  

parts_的定义如下:

[cpp]  view plain copy
  1. scoped_ptr<BrowserMainParts> parts_;  

函数GetContentClient()在content/public/common/content_client.cc中定义如下:

[cpp]  view plain copy
  1. void SetContentClient(ContentClient* client) {  
  2.   g_client = client;  
  3.   
  4.   // Set the default user agent as provided by the client. We need to make  
  5.   // sure this is done before webkit_glue::GetUserAgent() is called (so that  
  6.   // the UA doesn't change).  
  7.   if (client) {  
  8.     webkit_glue::SetUserAgent(client->GetUserAgent(), false);  
  9.   }  
  10. }  
  11.   
  12. ContentClient* GetContentClient() {  
  13.   return g_client;  
  14. }  

和它对应的有个SetContentClient()函数;

让我们再回过头来看看前面的ContentMainRunnerImpl的Initialize函数中的部分代码:

[cpp]  view plain copy
  1. if (!GetContentClient())  
  2.       SetContentClient(&empty_content_client_);  
  3.     ContentClientInitializer::Set(process_type, delegate_);  

这段代码有点技巧在里面,好奇的人可以去阅读下这段代码中的相关函数就明白了,下面我们来看看ContentClientInitializer::Set函数:

 

[cpp]  view plain copy
  1.  public:  
  2.   static void Set(const std::string& process_type,  
  3.                   ContentMainDelegate* delegate) {  
  4.     ContentClient* content_client = GetContentClient();  
  5.     if (process_type.empty()) {  
  6.       if (delegate)  
  7.         content_client->browser_ = delegate->CreateContentBrowserClient();  
  8.       if (!content_client->browser_)  
  9.         content_client->browser_ = &g_empty_content_browser_client.Get();  
  10.     }  
  11.   
  12. #if !defined(OS_IOS)  
  13.     if (process_type == switches::kPluginProcess ||  
  14.         process_type == switches::kPpapiPluginProcess) {  
  15.       if (delegate)  
  16.         content_client->plugin_ = delegate->CreateContentPluginClient();  
  17.       if (!content_client->plugin_)  
  18.         content_client->plugin_ = &g_empty_content_plugin_client.Get();  
  19.     } else if (process_type == switches::kRendererProcess ||  
  20.                CommandLine::ForCurrentProcess()->HasSwitch(  
  21.                    switches::kSingleProcess)) {  
  22.       if (delegate)  
  23.         content_client->renderer_ = delegate->CreateContentRendererClient();  
  24.       if (!content_client->renderer_)  
  25.         content_client->renderer_ = &g_empty_content_renderer_client.Get();  
  26.     } else if (process_type == switches::kUtilityProcess) {  
  27.       if (delegate)  
  28.         content_client->utility_ = delegate->CreateContentUtilityClient();  
  29.       if (!content_client->utility_)  
  30.         content_client->utility_ = &g_empty_content_utility_client.Get();  
  31.     }  
  32. #endif  // !OS_IOS  
  33.   }  

我们关注的地方在:

[cpp]  view plain copy
  1. ContentClient* content_client = GetContentClient();  
  2.     if (process_type.empty()) {  
  3.       if (delegate)  
  4.         content_client->browser_ = delegate->CreateContentBrowserClient();  
  5.       if (!content_client->browser_)  
  6.         content_client->browser_ = &g_empty_content_browser_client.Get();  
  7.     }  
  8.       
  9.   
  10.       if (delegate)  
  11.         content_client->renderer_ = delegate->CreateContentRendererClient();  
  12.       if (!content_client->renderer_)  
  13.         content_client->renderer_ = &g_empty_content_renderer_client.Get();  

这样就设置好了ShellContentClient的两个成员变量:

[cpp]  view plain copy
  1. // The embedder API for participating in browser logic.  
  2.   ContentBrowserClient* browser_;  
  3. // The embedder API for participating in renderer logic.  
  4.   ContentRendererClient* renderer_;  

分别为ShellMainDelegate的两个函数返回的结果:

[cpp]  view plain copy
  1. ContentBrowserClient* ShellMainDelegate::CreateContentBrowserClient() {  
  2.   browser_client_.reset(new ShellContentBrowserClient);  
  3.   return browser_client_.get();  
  4. }  
  5. ContentRendererClient* ShellMainDelegate::CreateContentRendererClient() {  
  6.   renderer_client_.reset(new ShellContentRendererClient);  
  7.   return renderer_client_.get();  
  8. }  


主要类图


理解了以上过程,对解释BrowserMainLoop的运行过程有帮助。

下面我把content_shell启动过程中涉及的几个主要类图贴上来,希望对理解有帮助


ContentMainDelegate类的子类有ChromeMainDelegate和ShellMainDelegate等,其实例一般通过Conten::Main()传入,我们一般关注BasicStartupComplete和RunProcess两个接口,负责浏览器的系统初始化和进入浏览器主循环的入口。



  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值