导航

[翻译]Chromium源代码周边相关

Posted on 2010-09-30 09:26  maconel  阅读(2096)  评论(0)    收藏  举报

译文

Chromium源代码周边相关

总体概览
Chromium分为3个大模块(包括第三方库):浏览器,渲染器,WebKit。浏览器负责主进程,UI展现和I/O。渲染器一般是由浏览器调用的标签子进程。它嵌入WebKit中做布局和渲染。
你应该熟读多进程架构Chromium如何显示web页

快速介绍sln文件
有2个sln文件,chrome.sln是使用V8引擎的普通版本,chrome_kjs.sln是使用Webkit的JavaScriptCore(JSC)引擎的版本。一般都是用V8,保留JSC就是为了看有bug时,这bug是不是跟V8有关。
-App/chrome_dll和App/chrome工程是启动代码。
-Libraries/base工程是通用库代码。这个代码是所有工程共用的,我们会尽量让它保持短小精悍。
-Browser/common中是浏览器相关的通用库代码。它是浏览器和渲染器共用的。
-Webkit(只读)目录下的工程是Webkit的代码。它的上层是Google的支持Windows接口的WebKit(自己的)/port,WebKit(自己的)/glue是嵌入层。
-glue与Browser/renderer工程相关,它用来展示每个子标签页里跑的子进程。
-Browser/browser工程提供了UI、存储、网络等功能。

顶层工程
拿到Chromium代码后,你会发现有很多顶级目录。有这些:
-base:所有子工程共用的通用代码。它包括字符串操作,通用库等。只有在所有顶层工程间共用时,才往这里加东西。
  -gfx:共用图形类。它是Chromium的GUI的基础。chrome/common/gfx下还有一些图形类,它是Chromium应用程序专用的。
-breakpad:Google的开源crash报告工程。它是直接从Google Code的svn中拉过来的。
-build:所有工程共用的编译配置。
-chrome:Chromium浏览器(参考下面)。
-data:运行证书测试的data文件。
-gears:离线浏览。
-googleurl:Google的开源URL解析判别库。它是直接从Google Code的svn中拉过来的。
-net:Chromium中的网络库。在运行webkit里的简单test_shell时,它可以从Chromium中分离出来单独用。可以参考下chrome/common/net。
-sandbox:沙箱。它能防止恶意页面修改你的系统。
-skia:Google为Android开发的Skia图形库。它是从Android代码里复制过来的。base/gfx中的附加类封装了它。
-testing:包含Google的开源单元测试工具GTest。
-third_party:集中放第三方库,比如图片解码,压缩库之类的。也有些Chrome专用的第三方库放在chrome/third_party里。添加新包
-tools:不解释,你知道的。
-V8:V8 js库。它是直接从Google Code的svn中拉过来的。
-webkit:所有跟Chromium的Webkit相关的东西:
  -build:工程文件和其他工程相关的配置。
  -data:大多数目录下的data都是给转换层的单元测试用的。layout_tests目录是直接从Apple拉过来的WebKit的布局测试套件。
  -glue:glue层是个嵌入层。它负责Webcore类型和Chrome程序类型(大多STL)之间的转换,同时还提供了很多好用的函数来访问我们需要用到的Webcore的对象。
  -tools
    -layout_tests:运行WebCore布局测试的脚本。
    -merge:帮助合并WebKit树的脚本。
    -npapi_layout_test_plugin:专门用来测试插件层的插件。
    -test_shell:一个非常简单的独立的浏览器。不用运行巨大的Chromium程序,就可以测试glue和转换代码。

"chrome/"下目录树的简要说明
-app:"app"是最基础的程序。它一开始就运行,根据当前进程的能力来分别分派到浏览器或渲染器代码中。它包括chrome.exe和chrome.dll 2个工程。一般你不需要修改它,顶多就是改改图片和字符串这些资源。
  -locales:此工程用来生成本地化dll。
  -resources:图标和光标。
  -theme:窗体主题的图片。
-browser:前端包括主窗体和UI,后端包括I/O和存储。它与渲染器管理页面相关。
-common:这下面的文件在浏览器和渲染器之间共用,同时也给一些其他的工程用。这些代码是专门给Chromium(而不是基础程序)用的,但在chrome/浏览器和chrome/渲染器目录之间可以共用。
  -gfx:Chromium专用的图形和渲染相关的助手代码。有些图形上的东西必须也提供给外面顶层的base/gfx使用。
  -net:net上层的顶级模块上一些Chromium专用的东西。将会与browser/net合并。
-installer:制作安装包(MSI包)的源文件和工程文件。
-plugin:在其他进程中运行浏览器插件的代码。
test:
  -automation:测试用来驱动浏览器UI的,比如test/ui,test/startup等。它会在浏览器中与browser/automation交互。
  -page_cycler:执行页面循环测试的代码(比如性能测试)。参考tools/perf/dashboard。
  -reliability:页面载入的分布式可靠性测试和crash定位。
  -selenium:ajax和js等的第三方测试套件的选择性测试的代码。参考test/third_party/selenium_core。
  -startup:测试启动性能。参考tools/perf/dashboard和tools/test/reference_build。
  -ui:浏览器UI测试,比如打开标签页等。它使用test/automation来完成大部分操作。
  -unit:单元测试的基础代码。测试代码一般和被测试文件放在一起,命名为*_unittest.cc。
-third_party:Chromium专用的第三方库。还有一些第三方库放在顶层的third_party里。
-tools
  -build:编译相关的工具等。
    -buildbot:编译机器人配置。编译机器人管理自动编译系统。参考third_pary/buildbot。
    -win:在Windows下编译的东西,包括工程属性用的.vsprops文件和脚本。
  -memory:内存工具。现在包括设置页面堆配置的gflags。
  -perf/dashboard:将性能日志(比如test/startup_test)转换为数据和图形。
  -profiles:历史数据随机生成器。用来生成测试概况(profile)。
-views:用来开发UI的简单框架,提供渲染、布局和事件处理。大多数浏览器UI都是用这个系统实现的。这个目录包括基础对象。另外还有些浏览器专用的对象在browser/views里。

通用操作的代码路径
附加信息和更多的例子在Chromium如何显示web页面里。

程序启动
1.WinMain函数在chrome/app/main.cc中,它在chrome工程中编译。
2.WinMain执行Google自动更新客户端。它会找到当前版本的子目录,然后载入chrome.dll。
3.调用刚载入的库里的ChromeMain,代码在chrome_dll工程里的chrome_main.cc。
4.ChromeMain初始化通用组件,然后如果命令行指定这是个子进程,就调用chrome/renderer/renderer_main.cc里的RendererMain,如果不是程序的新拷贝(也就是说程序第一次启动),就调用chrome/browser/browser_main.cc里的BBrowserMain。现在已经启动了,是时候启动浏览器了。
5.BrowserMain会初始化浏览器。不同的情况它会以不同的方式运行,比如如果是安装web应用程序就安装它,如果是在测试就连接到自动系统,等等。
6.chrome/browser/browser.cc里会创建一个新的浏览器对象,它会调用browser_init.cc里的LaunchWithProfile。这个对象会生成一个顶级窗口。这时会生成第一个标签页。

启动标签页并初始化导航
1.chrome/browser/browser.cc里的Browser::AppendTab会被调用,并创建一个新标签页。
2.创建一个browser/tab_contents/tab_contents.cc里的TabContents对象。
3.TabContents会通过chrome/browser/tab_contents/render_view_host_manager.cc里的RenderViewMostManager的初始化函数创建一个chrome/browser/renderer_host/render_view_host.cc里的RenderViewHost。通过SiteInstance,RenderViewHost会生成一个新的渲染进程(RenderProcess),或者重用一个已有的。RenderProcess是浏览器里的一个对象,负责一个单独的渲染子进程。
4.chrome/browser/tab_contents/navigation_controller.cc里的NavigationController会被标签页容器持有,并调用NavigationController::LoadURL来在新标签页打开一个URL地址。从这里到后面的3个步骤,描述的是从地址栏打开一个URL地址。

从地址栏打开一个URL地址
1.当用户输入,或者地址栏收到一个回车时,自动完成编辑框会算出最终目标URL,并传给AutocompleteEdit::OpenURL。(说用户输入可能不够确切——比如,搜索结果里的一个URL。)
2.NavigationController::LoadURL里的导航控制器(NavigationController)会去打开URL。
3.NavigationController调用TabContents::Navigate,并传入一个NavigationEntry来负责页面转换。这将会导致子进程如果需要,就创建一个RenderViewHost。如果是第一次导航,就不会有RenderView,否则如果渲染器crash了,会导致它被crash里的覆盖。
4.Navigate继续调用RenderViewHost::NavigateToEntry。NavigationController存储这个导航入口,但是会打一个"pending"的标记,因为它不知道到底会不会转换(可能主机无法解析)。
5.RenderViewHost::NavigateToEntry会给渲染进程里新的RenderView发一个ViewMsg_Navigate。
6.导航时,RenderView可能会导航,可能会失败,也可能会导航到其他地方(比如用户点了一个链接)。RenderViewHost会等待RenderView发一个ViewHostMsg_FrameNavigate。
7.当载入状态被WebKit改成"committed"时(server响应并发送了数据),RenderView就会发这个消息,并被RenderViewHost::OnMsgNavigate捕获处理。
8.过程中NavigationEntry会更新载入过程中的信息。例如点击的链接,之前浏览器是不知道的。如果导航是浏览器初始化的,就像启动时那样,在导航过程中可能会由于重定向而改变URL地址。
9.NavigationController给帐户把新的信息更新到导航列表中。

导航和会话历史
每个NavigationEntry都会存储一个页面ID和历史状态数据。页面ID用来唯一标识一个页面载入,这样我们就知道哪一个NavigationEntry与之对应。它在页面被提交时分配,所以一个pending状态的NavigationEntry的页面ID是-1。历史状态数据就是WebCore::HistoryItem序列化的一个字符串。它里面包含了页面URL,子frame URL,以及表格数据。
1.当浏览器初始化请求时(在地址栏中输入,或者点击后退/前进/刷新)
  1.生成一个WebRequest来表示导航,它会一直为书记员(bookkeeping)带着页面ID之类的信息。新导航的ID是-1。当页面是第一次访问时,旧入口的导航会把ID分配给NavigationEntry。到后面载入提交时,还会查询这个信息。
  2.主WebFrame会被调用来载入新的请求。
2.渲染器初始化请求时(用户点击链接,js改变了location,等):
  1.WebCore::FrameLoader的各个载入方法会被调用来载入请求。
3.无论什么情况,当收到服务器返回的第一个包时,载入会被提交(不再是"pending"或"provisional"状态)。
4.如果有一个新的导航,会fork出一个新的WebCore,它会创建一个新的HistoryItem,并加到BackForwardList中。用这个方法,我们可以区分哪个导航是新的,哪个是会话历史导航。
5.RenderView::DidCommitLoadForFrame处理载入的提交。在这,前一个页面的状态通过ViewHostMsg_UpdateState消息被存储在会话历史中。这告诉浏览器去更新对应的NavigationEntry(通过RenderView的当前页面ID标识)为新的历史状态。
6.RenderView的当前页面ID被更新为提交页面的ID。对于新的导航,会生成一个新的唯一页面ID。对会话历史导航,页面ID是第一次访问时的ID,初始化导航时,已经把它存在WebRequest里了。
7.发送一个ViewHostMsg_FrameNavigate消息给浏览器,更新对应的NavigationEntry(由RenderView刚更新的页面ID标识)的新URL和其他信息。

 

原文

Getting Around the Chromium Source Code

 

High-level overview

Chromium is separated into three main parts (excluding other libraries): the browser, the renderer, and Webkit. The browser is the main process and represents all the UI and I/O. The renderer is the (often) per-tab sub-process that is driven by the browser. It embeds Webkit to do layout and rendering.

You will want to read and become familiar with our multi-process architecture and how Chromium displays web pages.

Quick introduction to the solution file

We have two solution files, chrome.sln which is the normal version that uses V8 as the Javascript engine, and chrome_kjs.sln which uses Webkit's JavaScriptCore (JSC) engine. You will normally want to use the V8 version; we keep the JSC version around to see whether a bug is V8-related.

  • The startup code is in the App/chrome_dll and App/chrome projects.
  • Common shared library code is in the Libraries/base project. This code is shared between all projects, and we try to keep it as small as necessary.
  • Common browser-specific code is in the Browser/common project, this is shared between the browser and the renderer.
  • Webkit code is in the projects in Webkit(readonly). On top of this is Google's WebKit(ours)/port which interfaces with Windows, and then WebKit(ours)/glue which is our embedding layer.
  • The glue talks to the Browser/renderer project, which represents the subprocess where we run each tab.
  • The Browser/browser project provides the user interface, storage, network requests, etc.

Top-level projects

When you check out Chromium, you will notice a number of top-level directories.  These projects are as follows:

  • base: Common code shared between all sub-projects. This contains things like string manipulation, generic utilities, etc. Add things here only if it must be shared between more than one other top-level project.
    • gfx: Shared graphics classes. These form the base of Chromium's UI graphics. There are additional graphics classes in chrome/common/gfx which are specific to the Chromium application.
  • breakpad: Google's open source crash reporting project. This is pulled directly from Google Code's Subversion repository.
  • build: Build-related configuration shared by all projects.
  • chrome: The Chromium browser (see below).
  • data: Data files for running certain tests.
  • gears: Gears.
  • googleurl: Google's open source URL parsing and canonicalization library. This is pulled directly from Google Code's Subversion repository.
  • net: The networking library developed for Chromium. This can be used separately from Chromium when running our simple test_shell in the webkit repository. See alsochrome/common/net.
  • sandbox: The sandbox project which tries to prevent a hacked renderer from modifying the system.
  • skia: Google's Skia graphics library developed for Android. This is a copy from Android's tree. Our additional classes in base/gfx wrap Skia.
  • testing: Contains Google's open-sourced GTest code which we use for unit testing.
  • third_party: A bunch of external libraries such as image decoders and compression libraries. There are also some Chrome-specific third-party libraries in chrome/third_party.Adding new packages.
  • tools
  • v8: The V8 Javascript library. This is pulled directly from Google Code's Subversion repository.
  • webkit: All of Chromium's Webkit-related stuff:
    • build: Project files and configurations for the rest of the projects.
    • data: Most of the directories contain data used by unit tests of our porting layer. the layout_tests directory is WebKit's layout test suite that we pull directly from Apple.
    • glue: The glue layer is the embedding layer. It converts between Webcore types and our application's types (mostly STL), and provides more convenient methods that mirror a lot of Webcore's objects we need access to.
    • tools
      • layout_tests: Scripts for running WebCore's layout tests.
      • merge: Scripts for helping merge to WebKit's tree.
      • npapi_layout_test_plugin: A special plug-in used by some of our tests to exercise the plugin layer.
      • test_shell: A very simple standalone browser. This allows testing of our glue and port code without having to compile and run the very large Chromium application.

Quick reference for the directory tree under "chrome/"

  • app: The "app" is the most basic level of the program. It is run on startup, and dispatches to either the browser or renderer code depending on which capabilities the current process is in. It contains the projects for chrome.exe and chrome.dll. You won't generally need to change this stuff except for resources like images and strings.
    • locales: Projects for building localized DLLs.
    • resources: Icons and cursors.
    • theme: Images for the theme of the window.
  • browser: The frontend including the main window, UI, and the backend for the application which handles all I/O and storage. This talks to the renderer to manage web pages.
  • common: Files shared between the browser and the renderer, as well as other random projects. This is the code specific to Chromium (and not applicable to being in base) but that is shared between the chrome/browser and the chrome/renderer directories..
    • gfx: Graphics and rendering related helper code specific to Chromium. Some graphics stuff that mush be shared with outer toplevel modules is in base/gfx.
    • net: Some Chromium-specific stuff on top of the net top-level module. This should be merged with browser/net.
  • installer: Source files and projects for making the installer (MSI package).
  • plugin: Code for running browser plugins in other processes.
  • renderer: Code for the subprocess in each tab. This embeds WebKit and talks to browser for I/O.
  • test:
    • automation: Used by tests to drive the browser UI, for example, in test/uitest/startup, etc. This communicates with browser/automation in the browser.
    • page_cycler: Code for running page cycler tests (for performance measurement). See tools/perf/dashboard.
    • reliability: Reliability tests for distributed testing of page loads for reliability metrics and crash finding.
    • selenium: Code for running the selenium tests, which is a third-party test suite for Ajaxy and JavaScript stuff. See test/third_party/selenium_core.
    • startup: Tests for measuring startup performance. See tools/perf/dashboard and tools/test/reference_build.
    • ui: UI tests for poking at the browser UI, opening tabs, etc. It uses test/automation for doing most operations.
    • unit: The base code for the unit tests. The test code for individual tests is generally alongside the code it is testing in a *_unittest.cc file.
  • third_party: Third party libraries that are specific to Chromium. Some other third party libraries are in the top-level third_party library.
  • tools
    • build: Tools and random stuff related to building.
      • buildbot: Buildbot configuration. Buildbot manages our automated build system. See third_pary/buildbot.
      • win: Windows build stuff, including some .vsprops files used for project properties and scripts.
    • memory: Tools for memory stuff. Currently includes gflags for setting page heap options.
    • perf/dashboard: Code for converting performance logs (for example test/startup_test) into data and graphs.
    • profiles: Generator for random history data. Used to make test profiles.
  • views: A simple framework for doing UI development, providing rendering, layout and event handling. Most of the browser UI is implemented in this system. This directory contains the base objects. Some more browser-specific objects are in browser/views.

Code paths for common operations

There is additional information and more examples on how Chromium displays web pages.

Application startup

  1. Our WinMain function is in chrome/app/main.cc, and is linked in the chrome project.
  2. WinMain launches the Google Update Client, which is the installer/autoupdater. It will find the subdirectory for the current version, and load chrome.dll from there.
  3. It calls ChromeMain in the newly loaded library, which is in chrome_main.cc in the chrome_dll project.
  4. ChromeMain does initialization for common components, and then forwards to either RendererMain in chrome/renderer/renderer_main.cc if the command line flag indicates that this should be a subprocess, or BrowserMain in chrome/browser/browser_main.cc if not to load a new copy of the application. Since this is startup, we're launching the browser.
  5. BrowserMain does common browser initialization. It has different modes for running installed webapps, connecting to the automation system if the browser is being tested, etc.
  6. It calls LaunchWithProfile in browser_init.cc which creates a new Browser object in chrome/browser/browser.cc. This object encapsulates one toplevel window in the application. The first tab is appended at this time.

Tab startup & initial navigation

  1. Browser::AppendTab in chrome/browser/browser.cc is called to append a new tab.
  2. It will create a new TabContents object from browser/tab_contents/tab_contents.cc
  3. TabContents creates a RenderViewHost (chrome/browser/renderer_host/render_view_host.cc) via the RenderViewMostManager's Init function in chrome/browser/tab_contents/render_view_host_manager.cc). Depending on the SiteInstance, the RenderViewHost either spawns a new renderer process, or re-uses an existing RenderProcessRenderProcess is the object in the browser that represents a single renderer subprocess.
  4. The NavigationController in chrome/browser/tab_contents/navigation_controller.cc which is owned by the tab contents, is instructed to navigate to the URL for the new tab in NavigationController::LoadURL. "Navigating from the URL bar" from step 3 onward describes what happens from this point.

Navigating from the URL bar

  1. When the user types into or accepts an entry in the URL bar, the autocomplete edit box determines the final target URL and passes that to AutocompleteEdit::OpenURL. (This may not be exactly what the user typed - for example, an URL is generated in the case of a search query.)
  2. The navigation controller is instructed to navigate to the URL in NavigationController::LoadURL.
  3. The NavigationController calls TabContents::Navigate with the NavigationEntry it created to represent this particular page transition. It will create a new RenderViewHost if necessary, which will cause creation of a RenderViewHost in the renderer process. A RenderView won't exist if this is the first navigation, or if the renderer has crashed, so this will also recover from crashes.
  4. Navigate forwards to RenderViewHost::NavigateToEntry. The NavigationController stores this navigation entry, but it is marked as "pending" because it doesn't know for sure if the transition will take place (maybe the host can not be resolved).
  5. RenderViewHost::NavigateToEntry sends a ViewMsg_Navigate to the new RenderView in the renderer process.
  6. When told to navigate, RenderView may navigate, it my fail, or it may navigate somewhere else instead (for example, if the user clicks a link). RenderViewHost waits for aViewHostMsg_FrameNavigate from the RenderView.
  7. When the load is "committed" by WebKit (the server responded and is sending us data), the RenderView sends this message, which is handled inRenderViewHost::OnMsgNavigate.
  8. The NavigationEntry is updated with the information on the load. In the case of a link click, the browser has never seen this URL before. If the navigation was browser-initiated, as in the startup case, there may have been redirects that have changed the URL.
  9. The NavigationController updates its list of navigations to account for this new information.

Navigations and session history

Each NavigationEntry stores a page ID and a block of history state data. The page ID is used to uniquely identify a page load, so we know which NavigationEntry it corresponds to. It is assigned when the page is committed commit, so a pending NavigationEntry will have a page ID of -1. The history state data is simply a WebCore::HistoryItem serialized to a string. Included on this item are things like the page URL, subframe URLs, and form data.
  1. When the browser initiates the request (typing in the URL bar, or clicking back/forward/reload)
    1. WebRequest is made representing the navigation, along with extra information like a page ID for bookkeeping. New navigations have an ID of -1. Navigations to old entries have the ID assigned to the NavigationEntry when the page was first visited. This extra information will be queried later when the load commits.
    2. The main WebFrame is told to load the new request.
  2. When the renderer initiates the request (user clicks a link, javascript changes the location, etc):
    1. WebCore::FrameLoader is told to load the request via one of its bajillion varied load methods.
  3. In either case, when the first packet from the server is received, the load is committed (no longer "pending" or "provisional").
  4. If this was a new navigation, WebCore will create a new HistoryItem and add it to the BackForwardList, a WebCore class that we have forked. In this way, we can differentiate which navigations are new, and which are session history navigations.
  5. RenderView::DidCommitLoadForFrame handles the commit for the load. Here, the previous page's state is stored in session history, via the ViewHostMsg_UpdateState message. This will tell the browser to update the corresponding NavigationEntry (identified by RenderView's current page ID) with the new history state.
  6. RenderView's current page ID is updated to reflect the committed page. For a new navigation, a new unique page ID is generated. For a session history navigation, it will be thepage ID originally assigned when it was first visited, which we had stored on the WebRequest when initiating the navigation.
  7. ViewHostMsg_FrameNavigate message is sent to the browser, updating the corresponding NavigationEntry (identified by RenderView's newly updated page ID) with the new URL and other information.