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<String, String> 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<String, String> 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<String, String> 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<DocumentLoader> 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<FormState> prpFormState) { // Retain because dispatchBeforeLoadEvent may release the last reference to it. RefPtr<Frame> 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> 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<DocumentLoader> 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> 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> 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> formState, bool shouldContinue) { FrameLoader* loader = static_cast<FrameLoader*>(argument); loader->continueLoadAfterNavigationPolicy(request, formState, shouldContinue); }
这里的loader就是当初传入的this,所以还是FrameLoader。
void FrameLoader::continueLoadAfterNavigationPolicy(const ResourceRequest&, PassRefPtr<FormState> 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()); // <rdar://problem/4801066> // 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> ResourceHandle::create(NetworkingContext* context, const ResourceRequest& request, ResourceHandleClient* client, bool defersLoading, bool shouldContentSniff) { #if ENABLE(BLOB) if (request.url().protocolIs("blob")) { PassRefPtr<ResourceHandle> handle = blobRegistry().createResourceHandle(request, client); if (handle) return handle; } #endif RefPtr<ResourceHandle> 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<void*>(mainLoader) == static_cast<void*>(client()); RefPtr<ResourceLoaderAndroid> loader = ResourceLoaderAndroid::start(this, d->m_firstRequest, context->frameLoaderClient(), isMainResource, false); if (loader) { d->m_loader = loader.release(); return true; } return false; }
PassRefPtr<ResourceLoaderAndroid> ResourceLoaderAndroid::start( ResourceHandle* handle, const ResourceRequest& request, FrameLoaderClient* client, bool isMainResource, bool isSync) { // Called on main thread FrameLoaderClientAndroid* clientAndroid = static_cast<FrameLoaderClientAndroid*>(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> WebUrlLoader::start(FrameLoaderClient* client, WebCore::ResourceHandle* resourceHandle, const WebCore::ResourceRequest& resourceRequest, bool isMainResource, bool isMainFrame, bool isSync, WebRequestContext* context) { FrameLoaderClientAndroid* androidClient = static_cast<FrameLoaderClientAndroid*>(client); WebFrame* webFrame = androidClient->webFrame(); webFrame->maybeSavePassword(androidClient->getFrame(), resourceRequest); RefPtr<WebUrlLoader> 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> 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<FormState> prpFormState)
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