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();    }

这里出现了新的对象,mWebViewCore,是在WebView初始化的时候创建的,WebViewCore主要负责和Core(核心库)的交流。

实际接收这个事件的是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);    }

调用browserFrame的loadurl方法,在webkit中,每一个网页都被称为一个frame。

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;    }

  调用JNI的方法:

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());}

在这一步里创建了DocumentLoader,并将其传入方法load中:

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);}


调用loadWithDocumentLoader

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;}


调用client的的policycheck,这里的client即是FrameLoaderClientAndroid

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);}

9. 回调policychecker:

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);}

m_navigationFuction就是:FrameLoader::callContinueLoadAfterNavigationPolicy

 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();}

调用documentloader,去loadmainres。

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;}

创建了mainresourceloader,并调用它的load函数。


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;}

对于Android来说,这类的start是ResourceLoadererAndroid的静态方法start:

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;}

15 external/webkit/Source/WebKit/android/WebCoreSupport/ResourceLoaderAndroid.cpp

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}

这里有个宏,如果开启这个宏,就使用external/ chromium/下的库,如果没有,就使用apache-http。

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 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




更多相关文章

  1. android软键盘弹出,会把原来的界面挤上去的问题 处理方法
  2. Android并发编程线程间通信的三种基本方式
  3. Android的线程使用来更新UI----Thread、Handler、Looper、TimerT
  4. Android学习方法路线
  5. android的线程特点
  6. Android横竖屏切换方法
  7. 在deepin系统中adb操作android文件的方法

随机推荐

  1. Android修改system只读权限:remount
  2. Android(安卓)ObjectAnimator不调用onAni
  3. android 图形系统
  4. Android入门教程五十五之DrawerLayout(官
  5. android 显示pdf文件内容
  6. HTML---Android与js交互实例
  7. 索引:Android Studio安装及工程项目目录简
  8. Android学习笔记之开发必备
  9. FFMpeg For Android之Ubuntu下编译
  10. Android设计原则/Android Design Princip