chromium:LoadUrl之后会发生哪些事情之资源下载

来源:互联网 发布:高端游戏本 知乎 编辑:程序博客网 时间:2024/04/28 11:34

一 综述

  本文主要分析在Android系统上,基于chromium内核的浏览器loadUrl的流程。

作为android开发者都知道WebViewAndroi系统非常重要的组件,任何需要和网络打交道的app都需要WebView,而访问网络资源,加载一个网页页非常简单,形如

webview.loadUrl("http://m.baidu.com");就会在webview中把百度首页展示出来,是不是非常的神奇。

  那么本文会基于chromium44版本的content_shell_test和Android WebView 分析一下Browser的loadUrl后,内核到底发生了什么?有必要提一下,android4.4(Kitkat)以后,Android系统的WebView内核支持从WebKit切换成了google自家chromium/blink内核。给整个webview的架构带来了巨大的变化。应用开发者看到的是webview,下面与它对接的是WebViewChromium类,然后WebViewChromuim会调用AwContentsAwContents紧接着会相关到ContentViewCore, 如图1所示


图1 Android WebView架构图

上图中WebViewProvider是一个接口类,WebViewChromiumWebViewProvider的具体实现类,同时又起着连接Chromium的作用。

Android 4.4上,代码结构如下:

#1 frameworks/base/core/java/android/webkit

这里是对Application可见的WebViewWebViewSettings等等。

#2 frameworks/webview/chromium/java

这里是桥接层代码,比较重要的类是WebViewChromium,起到实现WebViewProvider接口,以及连接到chromium

#3 frameworks/webview/plat_support/

由于WebView的内核是chromium,在页面绘制时还需要调用Android系统相关接口,所以,这里主要是提供Android平台支持。

#4 external/chromium_org/android_webview/

这里是chromiumAndroid平台上的顶层入口部分。

二 WebView loadUrl

Application使用WebView进行网页显示时,都会调用loadUrl,并将想访问的网页URL作为参数传入:WebView.loadUrl()--->WebViewProvider.loadUrl()

WebViewProvider是一个接口类型,具体实现是WebViewChromium类。

WebViewChromium作用在代码中已有清晰的解释:This class is the delegate to which WebViewProxy forwards all API callsMost of the actual functionality is implemented by AwContents (or ContentViewCore within it)。

同时,这段解释还说明了其内部功能的正真实现是由AwContentsContentViewCore完成的。

--->WebViewChromium.loadUrl()-->loadUrlOnUiThread(loadUrlParams) --->AwContents.loadUrl(loadUrlParams)

AwContentsloadUrl中会调用NavigationControllerloadUrl,而NavigationController又是一个接口类,它的具体实现是NavigationControllerImpl类。

--->NavigationControllerImpl.loadUrl(params)

通过JNI进入到native层的navigation_controller_impl.cc, 

NavigationControllerImpl::LoadURL()--->LoadURLWithParams()

--->NavigationControllerImpl::LoadEntry(NavigationEntryImpl* entry)

--->NavigationControllerImpl::NavigateToPendingEntry()

--->NavigationControllerDelegate::NavigateToPendingEntry()

NavigationControllerDelegate是一个虚基类,它的主要作用是Interface for objects embedding a NavigationController to provide the functionality NavigationController needs.

WebContentsImpl实现了NavigationControllerDelegate

--->WebContentsImpl::NavigateToPendingEntry()

--->NavigatorImpl.NavigateToPendingEntry()

--->NavigatorImpl::NavigateToEntry()

--->RenderFrameHostImpl::Navigate(navigate_params)

以上过程发生在Application --> Android_webview-->content如下图图2所示。


图2 LoadUrlcontent中流程

RenderFrameHostImpl通过IPCRenderFrameImpl发送异步IPC加载消息:Send(new FrameMsg_Navigate(routing_id_, params))RenderFrameImpl接收到IPC消息后,进行处理

RenderFrameImpl::OnNavigate(),在这里把url以及其他所有信息打包到一个WebURLRequest中,调用Blink中的WebFrame至此,LoadUrl已经走到Blink了,开始发起网络请求loadRequest(request);

WebFrameWebLocalFrameWebRemoteFrame的基类,

WebLocalFrameWebRemoteFrame是由是否在同一进程内来区别,在同一进程内的是local,在不同进程内的是remote

// Frames may be rendered in process ('local') or out of process ('remote').                                                                                                                             

// A remote frame is always cross-site; a local frame may be either same-site or

// cross-site.

// WebFrame is the base class for both WebLocalFrame and WebRemoteFrame and

// contains methods that are valid on both local and remote frames, such as 

// getting a frame's parent or its opener.

WebFrame只是提供了简单的树节点之间的操作,其他大部分功能都是由WebLocalFrameWebRemoteFrame来实现。

其中,WebLocalFrameWebRemoteFrame都有其Impl类,分别叫WebLocalFrameImplWebRemoteFrameImplWebFrame的各类关系如下图图3所示。

 

图3 WebFrame以及子类

WebLocalFrameImplloadRequest中,request会被进一步封装成FrameLoadRequest,然后进入到FrameLoaderloadFrameLoadRequest)中,

--->FrameLoader.startLoad()在该方法中,创建了DocumentLoader

m_policyDocumentLoader = client()->createDocumentLoader(m_frame, request, frameLoadRequest.substituteData().isValid() ? frameLoadRequest.substituteData() : defaultSubstituteDataForURL(request.url()));

且该对象从m_policyDocumentLoader变为m_provisionalDocumentLoader m_provisionalDocumentLoader = m_policyDocumentLoader.release();

--->DocumentLoader中调用startLoadingMainResourcem_provisionalDocumentLoader->startLoadingMainResource();

--->ResourceFetecher中调用

m_mainResource = m_fetcher->fetchMainResource(cachedResourceRequest, m_substituteData);

其中m_mainResourceRawResource

Resource是基类,ResourceFetcher会根据requestresource类型的不同,创建不同类型的资源,resource类型一共有13种,分别为MainResourceImageCSSStyleSheetScriptFontRawSVGDocumentXSLStyleSheetLinkPrefetchLinkSubresourceTextTrackImportResource, Media等,Resource及其部分子类如图4所示。


图4 Resource及其部分子类

继续执行到requestResource(),在这里,首先判断请求的资源在本地cache中是否已存在,然后继续判断是否是reloadload以及revalidate等来决定不同资源加载策略。

因为是load执行会到createResourceForLoading(),继续执行createResource(),创建好resource后,执行resource->load(this, request.options());

这里的resource会根据加载的资源类型创建不同的resource,因为这里是主文档,所以是RawResource,它继承于基类Resource

---->m_loader = ResourceLoader::create(fetcher, this, request, options);

m_loader->start();

---->ResourceLoader::start();

在这里通过m_loader = adoptPtr(blink::Platform::current()->createURLLoader());

创建不同平台的WebURLLoaderWebURLLoader是虚基类。

其实现类是content中的web_url_loader_impl.h

---->WebURLLoaderImpl::loadAsynchronously()

--->WebURLLoaderImpl::Context::Start()

---->ResourceDispatcher::StartAsync( request_info, request_body.get(), this);

在这里会创建IPC消息:

Send(new ResourceHostMsg_RequestResource( request_info.routing_id, request_id, *request));

--->ResourceDispatcherHostImpl::OnMessageReceived()

接收到消息,并继续处理,

--->ResourceDispatcherHostImpl::OnRequestResource

-->BeginRequest()

-->BeginRequestInternal()

-->StartLoading()

--->ResourceLoaderStartRequest()

-->ResourceLoader::StartRequestInternal(),

接着会转到URLRequest中,

--->URLRequest::Start()

 -->URLRequest::StartJob().

接下来的流程就是调用网络库相关函数,进行资源下载等操作。

 

当接收到网络数据后,首先回调URLRequestFileJob::DidRead(scoped_refptr<IOBuffer> buf, int result) URLRequestFileJobURLRequestJob的子类,URLRequestFileJob会调用父类的

NotifyReadComplete()--->URLRequestJob::NotifyReadComplete(int bytes_read) 去读取数据,然后调用URLRequest::NotifyReadComplete(),

--->ResourceLoader::OnReadCompleted()

---->CompleteRead(bytes_read)

---->LayeredResourceHandler::OnReadCompleted()

---->BufferResourceHandler::OnReadCompleted()

---->AsyncResourceHandler::OnReadCompleted(int bytes_read, bool* defer)

然后它会向ResourceDispatcher发送IPC消息

filter->Send(new ResourceMsg_DataReceived(GetRequestID(), data_offset, bytes_read, encoded_data_length));

把获取的数据向内部传送,ResourceDispatcher会继续把数据向内部

传送,通过request_info->peer->OnReceivedData(data_ptr, data_lenght, ecoded_data_length),传送到WebURLLoaderImpl::Context::OnReceivedData();WebURLLoaderImpl::Context

有一个成员变量WebURLLoaderClient* client_,它的实现子类就是ResourceLoaderWebURLLoaderImpl::Context::OnReceivedData()会调用client_->didReceivedData(),至此,数据传到了WebKit内部,ResourceLoader::didReceivedData()会继续调用RawResourceappendData(),在RawResource::appendData()中回调用RawResourceClient::dataReceived(),把数据继续传到了DocumentLoader,接着就开始进行文档解析和DOMTree创建了,具体请看下一篇分析。


版权声明:本文为博主原创文章,未经博主允许不得转载。


 

0 0
原创粉丝点击