webkit总体上分成两块,核心库,android适配层。
下面通过webkit打开baidu来分析下具体的过程,就可以知道webkit的工作模式了。
1. 首先是app中创建了webView,并调用它的loadurl方法:
mWebView.loadUrl("http://www.baidu.com");
2. frameworks/base/core/java/android/webkit/webView.java
public void loadUrl(String url) {
checkThread();
loadUrlImpl(url);
}
继续去调他的实现:
private void loadUrlImpl(String url) {
if (url == null) {
return;
}
loadUrlImpl(url, null);
}
重载的函数:
private void loadUrlImpl(String url, Map extraHeaders) {
switchOutDrawHistory();
WebViewCore.GetUrlData arg = new WebViewCore.GetUrlData();
arg.mUrl = url;
arg.mExtraHeaders = extraHeaders;
mWebViewCore.sendMessage(EventHub.LOAD_URL, arg);
clearHelpers();
}
实际接收这个事件的是webViewCore的内部成员EventHub,其实从发送事件的类型大概也可以才出来。
3. frameworks/base/core/java/android/webkit/WebViewCore.java
EventHub.transferMessages()方法
private void transferMessages() {
//略
case LOAD_URL: {
CookieManager.getInstance().waitForCookieOperationsToComplete();
GetUrlData param = (GetUrlData) msg.obj;
loadUrl(param.mUrl, param.mExtraHeaders);
break;
}
//略
}
private void loadUrl(String url, Map extraHeaders) {
if (DebugFlags.WEB_VIEW_CORE) Log.v(LOGTAG, " CORE loadUrl " + url);
mBrowserFrame.loadUrl(url, extraHeaders);
}
4. frameworks/base/core/java/android/webkit/BrowserFrame.java
public void loadUrl(String url, Map extraHeaders) {
mLoadInitFromJava = true;
if (URLUtil.isJavaScriptUrl(url)) {
// strip off the scheme and evaluate the string
stringByEvaluatingJavaScriptFromString(
url.substring("javascript:".length()));
} else {
nativeLoadUrl(url, extraHeaders);
}
mLoadInitFromJava = false;
}
5. external/webkit/Source/WebKit/android/jni/WebCoreFrameBridge.cpp
j
static void LoadUrl(JNIEnv *env, jobject obj, jstring url, jobject headers)
{
//...
pFrame->loader()->load(request, false);
}
首先将传入的url打包到KURL中,再用KURL构造request。
这里的pFrame->loader()得到FrameLoader,再调用它的load方法:
6. external/webkit/Source/WebKit/WebCore/loader/FrameLoader.cpp
void FrameLoader::load(const ResourceRequest& request, bool lockHistory)
{
load(request, SubstituteData(), lockHistory);
}
void FrameLoader::load(const ResourceRequest& request, const SubstituteData& substituteData, bool lockHistory)
{
if (m_inStopAllLoaders)
return;
// FIXME: is this the right place to reset loadType? Perhaps this should be done after loading is finished or aborted.
m_loadType = FrameLoadTypeStandard;
RefPtr loader = m_client->createDocumentLoader(request, substituteData);
if (lockHistory && m_documentLoader)
loader->setClientRedirectSourceForHistory(m_documentLoader->didCreateGlobalHistoryEntry() ? m_documentLoader->urlForHistory().string() : m_documentLoader->clientRedirectSourceForHistory());
load(loader.get());
}
void FrameLoader::load(DocumentLoader* newDocumentLoader)
{
ResourceRequest& r = newDocumentLoader->request();
addExtraFieldsToMainResourceRequest(r);
FrameLoadType type;
if (shouldTreatURLAsSameAsCurrent(newDocumentLoader->originalRequest().url())) {
r.setCachePolicy(ReloadIgnoringCacheData);
type = FrameLoadTypeSame;
} else
type = FrameLoadTypeStandard;
if (m_documentLoader)
newDocumentLoader->setOverrideEncoding(m_documentLoader->overrideEncoding());
if (shouldReloadToHandleUnreachableURL(newDocumentLoader)) {
// shouldReloadToHandleUnreachableURL() returns true only when the original load type is back-forward.
// In this case we should save the document state now. Otherwise the state can be lost because load type is
// changed and updateForBackForwardNavigation() will not be called when loading is committed.
history()->saveDocumentAndScrollState();
ASSERT(type == FrameLoadTypeStandard);
type = FrameLoadTypeReload;
}
loadWithDocumentLoader(newDocumentLoader, type, 0);
}
void FrameLoader::loadWithDocumentLoader(DocumentLoader* loader, FrameLoadType type, PassRefPtr prpFormState)
{
// Retain because dispatchBeforeLoadEvent may release the last reference to it.
RefPtr protect(m_frame);
ASSERT(m_client->hasWebView());
// Unfortunately the view must be non-nil, this is ultimately due
// to parser requiring a FrameView. We should fix this dependency.
ASSERT(m_frame->view());
if (m_pageDismissalEventBeingDispatched)
return;
if (m_frame->document())
m_previousUrl = m_frame->document()->url();
policyChecker()->setLoadType(type);
RefPtr formState = prpFormState;
bool isFormSubmission = formState;
const KURL& newURL = loader->request().url();
const String& httpMethod = loader->request().httpMethod();
if (shouldScrollToAnchor(isFormSubmission, httpMethod, policyChecker()->loadType(), newURL)) {
RefPtr oldDocumentLoader = m_documentLoader;
NavigationAction action(newURL, policyChecker()->loadType(), isFormSubmission);
oldDocumentLoader->setTriggeringAction(action);
policyChecker()->stopCheck();
policyChecker()->checkNavigationPolicy(loader->request(), oldDocumentLoader.get(), formState,
callContinueFragmentScrollAfterNavigationPolicy, this);//注意这里传入的函数指针
} else {
if (Frame* parent = m_frame->tree()->parent())
loader->setOverrideEncoding(parent->loader()->documentLoader()->overrideEncoding());
policyChecker()->stopCheck();
setPolicyDocumentLoader(loader);
if (loader->triggeringAction().isEmpty())
loader->setTriggeringAction(NavigationAction(newURL, policyChecker()->loadType(), isFormSubmission));
if (Element* ownerElement = m_frame->ownerElement()) {
if (!ownerElement->dispatchBeforeLoadEvent(loader->request().url().string())) {
continueLoadAfterNavigationPolicy(loader->request(), formState, false);
return;
}
}
policyChecker()->checkNavigationPolicy(loader->request(), loader, formState,
callContinueLoadAfterNavigationPolicy, this);
}
}
7. external/webkit/Source/WebKit/WebCore/loader/PolicyCheker.cpp
void PolicyChecker::checkNavigationPolicy(const ResourceRequest& request, DocumentLoader* loader,
PassRefPtr formState, NavigationPolicyDecisionFunction function, void* argument)
{
NavigationAction action = loader->triggeringAction();
if (action.isEmpty()) {
action = NavigationAction(request.url(), NavigationTypeOther);
loader->setTriggeringAction(action);
}
if (equalIgnoringHeaderFields(request, loader->lastCheckedRequest()) || (!request.isNull() && request.url().isEmpty())) {
function(argument, request, 0, true);
loader->setLastCheckedRequest(request);
return;
}
// We are always willing to show alternate content for unreachable URLs;
// treat it like a reload so it maintains the right state for b/f list.
if (loader->substituteData().isValid() && !loader->substituteData().failingURL().isEmpty()) {
if (isBackForwardLoadType(m_loadType))
m_loadType = FrameLoadTypeReload;
function(argument, request, 0, true);
return;
}
loader->setLastCheckedRequest(request);
m_callback.set(request, formState.get(), function, argument);//将传入的callback赋值给m_callback.m_navigationFunction
m_delegateIsDecidingNavigationPolicy = true;
m_frame->loader()->client()->dispatchDecidePolicyForNavigationAction(&PolicyChecker::continueAfterNavigationPolicy,
action, request, formState);//将policychecker的continu函数传入,等待client回调
m_delegateIsDecidingNavigationPolicy = false;
}
8.external/webkit/Source/WebKit/android/support/FrameLoaderClientAndroid.cpp
void FrameLoaderClientAndroid::dispatchDecidePolicyForNewWindowAction(FramePolicyFunction func,
const NavigationAction& action, const ResourceRequest& request,
PassRefPtr formState, const String& frameName) {
ASSERT(m_frame);
ASSERT(func);
if (!func)
return;
if (request.isNull()) {
(m_frame->loader()->policyChecker()->*func)(PolicyIgnore);
return;
}
if (action.type() == NavigationTypeFormSubmitted || action.type() == NavigationTypeFormResubmitted)
m_frame->loader()->resetMultipleFormSubmissionProtection();
// If we get to this point it means that a link has a target that was not
// found by the frame tree. Instead of creating a new frame, return the
// current frame in dispatchCreatePage.
if (canHandleRequest(request))
(m_frame->loader()->policyChecker()->*func)(PolicyUse);
else
(m_frame->loader()->policyChecker()->*func)(PolicyIgnore);
}
external/webkit/Source/WebKit/WebCore/loader/PolicyCheker.cpp
void PolicyChecker::continueAfterNewWindowPolicy(PolicyAction policy)
{
PolicyCallback callback = m_callback;
m_callback.clear();
switch (policy) {
case PolicyIgnore:
callback.clearRequest();
break;
case PolicyDownload:
m_frame->loader()->client()->startDownload(callback.request());
callback.clearRequest();
break;
case PolicyUse:
break;
}
callback.call(policy == PolicyUse);//调用之前传入的函数指针
}
void PolicyCallback::call(bool shouldContinue)
{
if (m_navigationFunction)
m_navigationFunction(m_argument, m_request, m_formState.get(), shouldContinue);
if (m_newWindowFunction)
m_newWindowFunction(m_argument, m_request, m_formState.get(), m_frameName, m_navigationAction, shouldContinue);
ASSERT(!m_contentFunction);
}
10.external/webkit/Source/WebKit/WebCore/loader/FrameLoader.cpp
void FrameLoader::callContinueLoadAfterNavigationPolicy(void* argument,
const ResourceRequest& request, PassRefPtr formState, bool shouldContinue)
{
FrameLoader* loader = static_cast(argument);
loader->continueLoadAfterNavigationPolicy(request, formState, shouldContinue);
}
这里的loader就是当初传入的this,所以还是FrameLoader。
void FrameLoader::continueLoadAfterNavigationPolicy(const ResourceRequest&, PassRefPtr formState, bool shouldContinue)
{
//。。。
continueLoadAfterWillSubmitForm();
}
void FrameLoader::continueLoadAfterWillSubmitForm()
{
if (!m_provisionalDocumentLoader->startLoadingMainResource(identifier))
m_provisionalDocumentLoader->updateLoading();
}
11. external/webkit/Source/WebKit/WebCore/loader/DocumentLoader.cpp
bool DocumentLoader::startLoadingMainResource(unsigned long identifier)
{
ASSERT(!m_mainResourceLoader);
m_mainResourceLoader = MainResourceLoader::create(m_frame);
m_mainResourceLoader->setIdentifier(identifier);
// FIXME: Is there any way the extra fields could have not been added by now?
// If not, it would be great to remove this line of code.
frameLoader()->addExtraFieldsToMainResourceRequest(m_request);
if (!m_mainResourceLoader->load(m_request, m_substituteData)) {
// FIXME: If this should really be caught, we should just ASSERT this doesn't happen;
// should it be caught by other parts of WebKit or other parts of the app?
LOG_ERROR("could not create WebResourceHandle for URL %s -- should be caught by policy handler level", m_request.url().string().ascii().data());
m_mainResourceLoader = 0;
return false;
}
return true;
}
12. external/webkit/Source/WebKit/WebCore/loader/MainResourceLoader.cpp
bool MainResourceLoader::load(const ResourceRequest& r, const SubstituteData& substituteData)
{
ASSERT(!m_handle);
m_substituteData = substituteData;
ASSERT(documentLoader()->timing()->navigationStart);
ASSERT(!documentLoader()->timing()->fetchStart);
documentLoader()->timing()->fetchStart = currentTime();
ResourceRequest request(r);
#if ENABLE(OFFLINE_WEB_APPLICATIONS)
documentLoader()->applicationCacheHost()->maybeLoadMainResource(request, m_substituteData);
#endif
bool defer = defersLoading();
if (defer) {
bool shouldLoadEmpty = shouldLoadAsEmptyDocument(request.url());
if (shouldLoadEmpty)
defer = false;
}
if (!defer) {
if (loadNow(request)) {
// Started as an empty document, but was redirected to something non-empty.
ASSERT(defersLoading());
defer = true;
}
}
if (defer)
m_initialRequest = request;
return true;
}
bool MainResourceLoader::loadNow(ResourceRequest& r)
{
bool shouldLoadEmptyBeforeRedirect = shouldLoadAsEmptyDocument(r.url());
ASSERT(!m_handle);
ASSERT(shouldLoadEmptyBeforeRedirect || !defersLoading());
// Send this synthetic delegate callback since clients expect it, and
// we no longer send the callback from within NSURLConnection for
// initial requests.
willSendRequest(r, ResourceResponse());
//
// willSendRequest() is liable to make the call to frameLoader() return NULL, so we need to check that here
if (!frameLoader())
return false;
const KURL& url = r.url();
bool shouldLoadEmpty = shouldLoadAsEmptyDocument(url) && !m_substituteData.isValid();
if (shouldLoadEmptyBeforeRedirect && !shouldLoadEmpty && defersLoading())
return true;
resourceLoadScheduler()->addMainResourceLoad(this);
if (m_substituteData.isValid())
handleDataLoadSoon(r);
else if (shouldLoadEmpty || frameLoader()->representationExistsForURLScheme(url.protocol()))
handleEmptyLoad(url, !shouldLoadEmpty);
else
m_handle = ResourceHandle::create(m_frame->loader()->networkingContext(), r, this, false, true);
return false;
}
这里最关键的一步是创建了ResourceHandle,
13 external/webkit/Source/WebCore/platform/network/ResourceHandle.cpp
PassRefPtr ResourceHandle::create(NetworkingContext* context, const ResourceRequest& request, ResourceHandleClient* client, bool defersLoading, bool shouldContentSniff)
{
#if ENABLE(BLOB)
if (request.url().protocolIs("blob")) {
PassRefPtr handle = blobRegistry().createResourceHandle(request, client);
if (handle)
return handle;
}
#endif
RefPtr newHandle(adoptRef(new ResourceHandle(request, client, defersLoading, shouldContentSniff)));
if (newHandle->d->m_scheduledFailureType != NoFailure)
return newHandle.release();
if (newHandle->start(context))
return newHandle.release();
return 0;
}
14 . external/webkit/Source/WebCore/platform/network/android/ResourceHandleAndroid.cpp
bool ResourceHandle::start(NetworkingContext* context)
{
MainResourceLoader* mainLoader = context->mainResourceLoader();
bool isMainResource = static_cast(mainLoader) == static_cast(client());
RefPtr loader = ResourceLoaderAndroid::start(this, d->m_firstRequest, context->frameLoaderClient(), isMainResource, false);
if (loader) {
d->m_loader = loader.release();
return true;
}
return false;
}
PassRefPtr ResourceLoaderAndroid::start(
ResourceHandle* handle, const ResourceRequest& request, FrameLoaderClient* client, bool isMainResource, bool isSync)
{
// Called on main thread
FrameLoaderClientAndroid* clientAndroid = static_cast(client);
#if USE(CHROME_NETWORK_STACK)
WebViewCore* webViewCore = WebViewCore::getWebViewCore(clientAndroid->getFrame()->view());
bool isMainFrame = !(clientAndroid->getFrame()->tree() && clientAndroid->getFrame()->tree()->parent());
return WebUrlLoader::start(client, handle, request, isMainResource, isMainFrame, isSync, webViewCore->webRequestContext());
#else
return clientAndroid->webFrame()->startLoadingResource(handle, request, isMainResource, isSync);
#endif
}
4.0上这个宏是开启的,我们继续往下看。
首先是获取了clientAndroid,这个是上一步中的NetworkContext通过frameLoaderClient()来获取的。
而接下来通过clientAndroid获取到了WebViewCore,并得到了WebrequestContext,这个对象中存放了HTTP相关的环境设置,如UA,cache,语言等。
最后,将一系列的参数传入:
WebUrlLoader::start(client, handle, request, isMainResource, isMainFrame, isSync, webViewCore->webRequestContext());
client是frameLoaderClient,提供平台相关的信息,handle是ResourceHandle,request里封装了URL,webrequestContext里封装了环境设置。
接下来就是通过WebUrlloader来获取资源了。
WebUrlloader继承于ResourceLoaderAndroid
15. external/webkit/Source/WebKit/android/WebCoreSupport/WebUrlLoader.cpp
PassRefPtr WebUrlLoader::start(FrameLoaderClient* client, WebCore::ResourceHandle* resourceHandle,
const WebCore::ResourceRequest& resourceRequest, bool isMainResource, bool isMainFrame, bool isSync, WebRequestContext* context)
{
FrameLoaderClientAndroid* androidClient = static_cast(client);
WebFrame* webFrame = androidClient->webFrame();
webFrame->maybeSavePassword(androidClient->getFrame(), resourceRequest);
RefPtr loader = WebUrlLoader::create(webFrame, resourceHandle, resourceRequest);
loader->m_loaderClient->start(isMainResource, isMainFrame, isSync, context);
return loader.release();
}
没干啥事,把活丢给了m_loaderClient。
16.external/webkit/Source/WebKit/android/WebCoreSupport/WebUrlLoaderClient.cpp
bool WebUrlLoaderClient::start(bool isMainResource, bool isMainFrame, bool sync, WebRequestContext* context)
{
base::Thread* thread = ioThread();
if (!thread) {
return false;
}
m_isMainResource = isMainResource;
m_isMainFrame = isMainFrame;
m_sync = sync;
if (m_sync) {
AutoLock autoLock(*syncLock());
m_request->setSync(sync);
m_request->setRequestContext(context);
thread->message_loop()->PostTask(FROM_HERE, NewRunnableMethod(m_request.get(), &WebRequest::start));
// Run callbacks until the queue is exhausted and m_finished is true.
// Sometimes, a sync load can wait forever and lock up the WebCore thread,
// here we use TimedWait() with multiple tries to avoid locking.
const int kMaxNumTimeout = 3;
const int kCallbackWaitingTime = 10;
int num_timeout = 0;
while(!m_finished) {
while (!m_queue.empty()) {
OwnPtr task(m_queue.front());
m_queue.pop_front();
task->Run();
}
if (m_finished) break;
syncCondition()->TimedWait(base::TimeDelta::FromSeconds(kCallbackWaitingTime));
if (m_queue.empty()) {
LOGE("Synchronous request timed out after %d seconds for the %dth try, URL: %s",
kCallbackWaitingTime, num_timeout, m_request->getUrl().c_str());
num_timeout++;
if (num_timeout >= kMaxNumTimeout) {
cancel();
m_resourceHandle = 0;
return false;
}
}
}
// This may be the last reference to us, so we may be deleted now.
// Don't access any more member variables after releasing this reference.
m_resourceHandle = 0;
} else {
// Asynchronous start.
// Important to set this before the thread starts so it has a reference and can't be deleted
// before the task starts running on the IO thread.
m_request->setRequestContext(context);
thread->message_loop()->PostTask(FROM_HERE, NewRunnableMethod(m_request.get(), &WebRequest::start));
}
return true;
}
首先是创建了个线程(叫network,是个静态的,第一次会创建,后面就直接返回了),然后给线程丢了个tast,让他去调用m_request的start方法。
到这里就返回了,我们理一下到目前的调用栈的状况:
MessageLoop::PostTask
WebUrlLoaderClient::start()
WebUrlLoader::start()
ResourceLoaderAndroid::start()
ResourceHandle::start()
ResourceHandle::create()
MainResourceLoader::loadNow()
MainResourceLoader::load()
DocumentLoader::startLoadingMainResource()
FrameLoader::continueLoadAfterWillSubmitForm()
FrameLoader::continueLoadAfterNavigationPolicy()
FrameLoader::callContinueLoadAfterNavigationPolicy()
PolicyCallback::call()
PolicyChecker::continueAfterNavigationPolicy()
FrameLoaderClientAndroid::dispatchDecidePolicyForNavigationAction()
PolicyChecker::checkNavigationPolicy()
FrameLoader::loadWithDocumentLoader(DocumentLoader* loader, FrameLoadType type, PassRefPtr
FrameLoader::load(DocumentLoader* newDocumentLoader)
FrameLoader::load()
FrameLoader::load()
android:WebCoreFrameBridge::LoadUrl()
android:BrwoserFrame.nativeLoadUrl()
android:BrowserFrame.loadUrl()
android:WebVIewCore.loadUrl()
android:WebViewCore.EventHub.transferMessages()
android:WebView:loadUrlImpl()
android:WebView.loadUrlImpl()
android::WebView.loadUrl()
还是比较长的,其中关键的线就是url数据的打包和传递。
接下来看看request的实现:
假设现在MessageLoop调用了我们的WebRequest的start函数:
1. external/webkit/Source/WebKit/android/WebCoreSupport/WebRequest.cpp