一 综述
本文主要分析在Android系统上,基于chromium内核的浏览器loadUrl的流程。
作为android开发者都知道WebView是Androi系统非常重要的组件,任何需要和网络打交道的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会调用AwContents,AwContents紧接着会相关到ContentViewCore, 如图1所示。
图1 Android WebView架构图
上图中WebViewProvider是一个接口类,WebViewChromium是WebViewProvider的具体实现类,同时又起着连接Chromium的作用。
在Android 4.4上,代码结构如下:
#1 frameworks/base/core/java/android/webkit
这里是对Application可见的WebView,WebViewSettings等等。
#2 frameworks/webview/chromium/java
这里是桥接层代码,比较重要的类是WebViewChromium,起到实现WebViewProvider接口,以及连接到chromium。
#3 frameworks/webview/plat_support/
由于WebView的内核是chromium,在页面绘制时还需要调用Android系统相关接口,所以,这里主要是提供Android平台支持。
#4 external/chromium_org/android_webview/
这里是chromium在Android平台上的顶层入口部分。
二 WebView loadUrl
当Application使用WebView进行网页显示时,都会调用loadUrl,并将想访问的网页URL作为参数传入:WebView.loadUrl()--->WebViewProvider.loadUrl()
WebViewProvider是一个接口类型,具体实现是WebViewChromium类。
WebViewChromium的作用在代码中已有清晰的解释:This class is the delegate to which WebViewProxy forwards all API calls。Most of the actual functionality is implemented by AwContents (or ContentViewCore within it)。
同时,这段解释还说明了其内部功能的正真实现是由AwContents和ContentViewCore完成的。
--->WebViewChromium.loadUrl()-->loadUrlOnUiThread(loadUrlParams) --->AwContents.loadUrl(loadUrlParams)
在AwContents的loadUrl中会调用NavigationController的loadUrl,而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 LoadUrl在content中流程
RenderFrameHostImpl通过IPC向RenderFrameImpl发送异步IPC加载消息:Send(new FrameMsg_Navigate(routing_id_, params)),RenderFrameImpl接收到IPC消息后,进行处理
RenderFrameImpl::OnNavigate(),在这里把url以及其他所有信息打包到一个WebURLRequest中,调用Blink中的WebFrame,至此,LoadUrl已经走到Blink了,开始发起网络请求loadRequest(request);
WebFrame是WebLocalFrame和WebRemoteFrame的基类,
(WebLocalFrame和WebRemoteFrame是由是否在同一进程内来区别,在同一进程内的是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只是提供了简单的树节点之间的操作,其他大部分功能都是由WebLocalFrame和WebRemoteFrame来实现。
其中,WebLocalFrame和WebRemoteFrame都有其Impl类,分别叫WebLocalFrameImpl和WebRemoteFrameImpl。WebFrame的各类关系如下图图3所示。
图3 WebFrame以及子类
在WebLocalFrameImpl的loadRequest中,request会被进一步封装成FrameLoadRequest,然后进入到FrameLoader的load(FrameLoadRequest)中,
--->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中调用startLoadingMainResource:m_provisionalDocumentLoader->startLoadingMainResource();
--->到ResourceFetecher中调用
m_mainResource = m_fetcher->fetchMainResource(cachedResourceRequest, m_substituteData);
其中m_mainResource是RawResource,
Resource是基类,ResourceFetcher会根据request中resource类型的不同,创建不同类型的资源,resource类型一共有13种,分别为MainResource,Image,CSSStyleSheet,Script,Font,Raw,SVGDocument,XSLStyleSheet,LinkPrefetch,LinkSubresource,TextTrack,ImportResource, Media等,Resource及其部分子类如图4所示。
图4 Resource及其部分子类
继续执行到requestResource(),在这里,首先判断请求的资源在本地cache中是否已存在,然后继续判断是否是reload,load以及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());
创建不同平台的WebURLLoader,WebURLLoader是虚基类。
其实现类是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
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_,它的实现子类就是ResourceLoader,WebURLLoaderImpl::Context::OnReceivedData()会调用client_->didReceivedData(),至此,数据传到了WebKit内部,ResourceLoader::didReceivedData()会继续调用RawResource的appendData(),在RawResource::appendData()中回调用RawResourceClient::dataReceived(),把数据继续传到了DocumentLoader,接着就开始进行文档解析和DOMTree创建了,具体请看下一篇分析。
版权声明:本文为博主原创文章,未经博主允许不得转载。