先说明一下,我这里采用的chrome源代码版本是4.1.249.1064。如果你采用的不是此版本,则可能和我描述的源代码文件名、代码位置不一致,后续关于chrome的文章均采用此版本,不再另作说明。采用此版本没有任何特殊理由,仅仅是当我开始学习chrome的那个时间点的最新版本而已。
另外虽然chrome的版本升级非常快,但其核心体系架构是没有变化的。升级的变更的内容主要体现在下面几个方面:
1.安全性、稳定性、速度提升
2.新功能点增加
3.HTML5相关内容
4.整合集成google自己的产品服务
因此从学习角度看,如果不是特别需要对某些新增加的特性感兴趣,如果重点是想学习其基础体系结构和web核心相关模块,那么选择一个较早的版本来学习反而更好。因为这样代码量少,重点突出,干扰少些。当掌握好基本体系结构后,后续的版本自然就很容易上手了。
下面简要说明chrome的启动流程,这里重点不会分析代码细节,而是快速定位几个比较关键的位置,可以在这些位置设置断点,然后你可以查看调用栈以了解具体的调用流程。这样可以先初步进入开始单步跟踪。
为了便于跟踪说明,请在浏览器选项菜单中将启动的主页地址设置为一个具体地址比如http://www.baidu.com/。
注意:因为chrome是多进程结构,所以在调试的时候需要附加到对应的进程才能看到断点效果。如果不想那么麻烦,也可以以单进程模式启动调试,具体是在chrome exe的工程属性中加命令行参数 --single-process。我将以多进程模式为例来讲解。
EXE启动入口
应用程序执行文件的WinMain入口函数在chrome exe工程的chrome_exe_main.cc文件中,在一些初始化代码后,加载
chrome.dll内核文件,代码如下:
...MainDllLoader* loader = MakeMainDllLoader();int rc = loader->Launch(instance, &sandbox_info);
...
MainDllLoader::Launch的实现在client_util.cc中,其中有代码(…为我忽略掉的代码):
int MainDllLoader::Launch(HINSTANCE instance,
sandbox::SandboxInterfaceInfo* sbox_info) {...dll_ = Load(&version, &file);...DLL_MAIN entry_point =reinterpret_cast<DLL_MAIN>(::GetProcAddress(dll_, "ChromeMain"));...int rc = entry_point(instance, sbox_info, ::GetCommandLineW());
return OnBeforeExit(rc);
}
通过调用Win32 API GetProcAddress来动态获取chrome.dll中的入口函数“ChromeMain”的地址然后调用进入。
DLL入口函数
chrome.dll的入口函数是ChromeMain,其工程名为chrome_dll。
ChromeMain的实现在chrome_dll_main.cc中:
DLLEXPORT int __cdecl ChromeMain(HINSTANCE instance,
sandbox::SandboxInterfaceInfo* sandbox_info,TCHAR* command_line){...int rv = -1;
if (process_type == switches::kRendererProcess) {
rv = RendererMain(main_params);} else if (process_type == switches::kExtensionProcess) {// An extension process is just a renderer process. We use a different
// command line argument to differentiate crash reports.
rv = RendererMain(main_params);} else if (process_type == switches::kPluginProcess) {rv = PluginMain(main_params);} else if (process_type == switches::kUtilityProcess) {rv = UtilityMain(main_params);} else if (process_type == switches::kProfileImportProcess) {...