chromium 55 URL 加载流程

   浏览器从界面上看都很简单,输入一个地址后就可以跳转,今天这里先整理chromium AndroidWebView.apk中从输入URL,到资源加载的流程,暂不涉及渲染,渲染后续进行介绍。从Java层往c++层逐步分析。

  AndroidWebView.apk启动后有个地址输入栏,如果输入地址按下确定键会调用到loadUrl进行url加载。

    private void initializeUrlField() {
        mUrlTextView = (EditText) findViewById(R.id.url);
        mUrlTextView.setOnEditorActionListener(new OnEditorActionListener() {
            @Override
            public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
                if ((actionId != EditorInfo.IME_ACTION_GO) && (event == null
                        || event.getKeyCode() != KeyEvent.KEYCODE_ENTER
                        || event.getAction() != KeyEvent.ACTION_DOWN)) {
                    return false;
                }
                ......
                mAwTestContainerView.getAwContents().loadUrl(url);
                mUrlTextView.clearFocus();
                setKeyboardVisibilityForUrl(false);
                mAwTestContainerView.requestFocus();
                return true;
            }
        });
      ......
    }

  代码路径:./android_webview/test/shell/src/org/chromium/android_webview/shell/AwShellActivity.java。

  NavigationController.java 只定义了loadUrl接口,实现是在NavigationControllerImpl.java中,其实现是调用jni接口。

    public void loadUrl(LoadUrlParams params) {
        //Log.e("NavigationControllerImpl.java", "loadUrl Url()"+params.getUrl());
        //Exception e = new Exception("Chrome_debug");
        //e.printStackTrace();
        if (mNativeNavigationControllerAndroid != 0) {
            nativeLoadUrl(mNativeNavigationControllerAndroid, params.getUrl(),
                    params.getLoadUrlType(), params.getTransitionType(),
                    params.getReferrer() != null ? params.getReferrer().getUrl() : null,
                    params.getReferrer() != null ? params.getReferrer().getPolicy() : 0,
                    params.getUserAgentOverrideOption(), params.getExtraHeadersString(),
                    params.getPostData(), params.getBaseUrl(), params.getVirtualUrlForDataUrl(),
                    params.getDataUrlAsString(), params.getCanLoadLocalResources(),
                    params.getIsRendererInitiated(), params.getShouldReplaceCurrentEntry());
        }
    }

代码目录:./content/public/android/java/src/org/chromium/content/browser/framehost/NavigationControllerImpl.java

nativeLoadUrl 调用到的是navigation_controller_android.cc LoadURL函数

void NavigationControllerAndroid::LoadUrl(
    JNIEnv* env,
    const JavaParamRef& obj,
    const JavaParamRef& url,
    jint load_url_type,
    jint transition_type,
    const JavaParamRef& j_referrer_url,
    jint referrer_policy,
    jint ua_override_option,
    const JavaParamRef& extra_headers,
    const JavaParamRef& j_post_data,
    const JavaParamRef& base_url_for_data_url,
    const JavaParamRef& virtual_url_for_data_url,
    const JavaParamRef& data_url_as_string,
    jboolean can_load_local_resources,
    jboolean is_renderer_initiated,
    jboolean should_replace_current_entry) {
  ......
  navigation_controller_->LoadURLWithParams(params);
}

代码路径:./content/browser/frame_host/navigation_controller_android.cc

LoadURLWithParams调用LoadEntry

void NavigationControllerImpl::LoadURLWithParams(const LoadURLParams& params) {
  ......
  LoadEntry(std::move(entry));
}

LoadEntry接着往下的调用关系如下图,如果有兴趣,可以在render_frame_host_impl.cc Navigate函数中添加堆栈打印,也可以打印出想过堆栈,进而获取调用关系:

接着看看Navigate函数的实现,这里需要关注的是navigate调用了SendNavigateMessage:

void RenderFrameHostImpl::Navigate(
    const CommonNavigationParams& common_params,
    const StartNavigationParams& start_params,
    const RequestNavigationParams& request_params) {
......
  if (navigations_suspended_) {
    // This may replace an existing set of params, if this is a pending RFH that
    // is navigated twice consecutively.
    suspended_nav_params_.reset(
        new NavigationParams(common_params, start_params, request_params));
  } else {
    // Get back to a clean state, in case we start a new navigation without
    // completing an unload handler.
    ResetWaitingState();
	//YH_LOGD("[%s][%d]\n",__FUNCTION__,__LINE__);
    SendNavigateMessage(common_params, start_params, request_params);
  }
......
}

SendNavigateMessage 的实现如下,是发送一个FrameMsg_Navigate msg,是browser线程发送,render线程接收,资源的加载在render线程中进行实现,可以在render线程中添加堆栈,跟踪资源加载流程:

void RenderFrameHostImpl::SendNavigateMessage(
    const CommonNavigationParams& common_params,
    const StartNavigationParams& start_params,
    const RequestNavigationParams& request_params) {
......   
  RenderFrameDevToolsAgentHost::OnBeforeNavigation(
      frame_tree_node_->current_frame_host(), this);
  Send(new FrameMsg_Navigate(
      routing_id_, common_params, start_params, request_params));
}

看看render_frame_impl.cc文件中监听了FrameMsg_Navigate消息,收到FrameMsg_Navigate消息执行OnNavigate函数

bool RenderFrameImpl::OnMessageReceived(const IPC::Message& msg) {
......
  IPC_BEGIN_MESSAGE_MAP(RenderFrameImpl, msg)
    IPC_MESSAGE_HANDLER(FrameMsg_Navigate, OnNavigate)
......
  IPC_END_MESSAGE_MAP()

  return handled;
}

 OnNavigate接着往下的调用关系如下图,

chromium 55 URL 加载流程_第1张图片

来看看StartAsync的实现,又是发送一个ResourceHostMsg_RequestResource给browser线程进行处理:

int ResourceDispatcher::StartAsync(
    std::unique_ptr request,
    int routing_id,
    scoped_refptr loading_task_runner,
    const GURL& frame_origin,
    std::unique_ptr peer,
    blink::WebURLRequest::LoadingIPCType ipc_type,
    mojom::URLLoaderFactory* url_loader_factory) {
......

  if (ipc_type == blink::WebURLRequest::LoadingIPCType::Mojo) {
    std::unique_ptr client(
        new URLLoaderClientImpl(request_id, this, main_thread_task_runner_));
    mojom::URLLoaderPtr url_loader;
    url_loader_factory->CreateLoaderAndStart(
        GetProxy(&url_loader), routing_id, request_id, *request,
        client->CreateInterfacePtrAndBind());
    pending_requests_[request_id]->url_loader = std::move(url_loader);
    pending_requests_[request_id]->url_loader_client = std::move(client);
  } else {
    //base::debug::StackTrace();
    message_sender_->Send(
        new ResourceHostMsg_RequestResource(routing_id, request_id, *request));
  }

  return request_id;
}

resource_dispatcher_host_impl.cc监听ResourceHostMsg_RequestResource,调用OnRequestResource,

void ResourceDispatcherHostImpl::OnRequestResource(
    int routing_id,
    int request_id,
    const ResourceRequest& request_data) {
  OnRequestResourceInternal(routing_id, request_id, request_data, nullptr,
                            nullptr);
}
void ResourceDispatcherHostImpl::OnRequestResourceInternal(
    int routing_id,
    int request_id,
    const ResourceRequest& request_data,
    mojo::InterfaceRequest mojo_request,
    mojom::URLLoaderClientPtr url_loader_client) {
......
  BeginRequest(request_id, request_data, NULL, routing_id,
               std::move(mojo_request), std::move(url_loader_client));
}
void ResourceDispatcherHostImpl::BeginRequest(
    int request_id,
    const ResourceRequest& request_data,
    IPC::Message* sync_result,  // only valid for sync
    int route_id,
    mojo::InterfaceRequest mojo_request,
    mojom::URLLoaderClientPtr url_loader_client) {
......
  ContinuePendingBeginRequest(request_id, request_data, sync_result, route_id,
                              headers, std::move(mojo_request),
                              std::move(url_loader_client), true, 0);
}
void ResourceDispatcherHostImpl::ContinuePendingBeginRequest(
    int request_id,
    const ResourceRequest& request_data,
    IPC::Message* sync_result,  // only valid for sync
    int route_id,
    const net::HttpRequestHeaders& headers,
    mojo::InterfaceRequest mojo_request,
    mojom::URLLoaderClientPtr url_loader_client,
    bool continue_request,
    int error_code) {
......  
    BeginRequestInternal(std::move(new_request), std::move(handler));
}
void ResourceDispatcherHostImpl::BeginRequestInternal(
    std::unique_ptr request,
    std::unique_ptr handler) {
......
  StartLoading(info, std::move(loader));
}
void ResourceDispatcherHostImpl::StartLoading(
......
  loader_ptr->StartRequest();
}
void ResourceLoader::StartRequest() {
......
  if (defer_start) {
    deferred_stage_ = DEFERRED_START;
  } else {
    StartRequestInternal();
  }
}
void ResourceLoader::StartRequestInternal() {
......
  request_->Start();
  delegate_->DidStartRequest(this);
}

Web服务器响应了请求之后,Chromium的Net模块会调用ResourceLoader类的成员函数OnResponseStarted,如果请求状态返回的是OK的(eg 200),则调用StartReading

void ResourceLoader::OnResponseStarted(net::URLRequest* unused) {
......
  if (request_->status().is_success())
    StartReading(false);  // Read the first chunk.
  else
    ResponseCompleted();
}

StartReading 调用ReadMore读取Web服务器返回来的数据,保存在本地变量bytes_read

void ResourceLoader::StartReading(bool is_continuation) {
  int bytes_read = 0;
  ReadMore(&bytes_read);
......
  if (!is_continuation || bytes_read <= 0) {
    OnReadCompleted(request_.get(), bytes_read);
  } else {
    // Else, trigger OnReadCompleted asynchronously to avoid starving the IO
    // thread in case the URLRequest can provide data synchronously.
    base::ThreadTaskRunnerHandle::Get()->PostTask(
        FROM_HERE,
        base::Bind(&ResourceLoader::OnReadCompleted,
                   weak_ptr_factory_.GetWeakPtr(), request_.get(), bytes_read));
  }
}
void ResourceLoader::ReadMore(int* bytes_read) {
......
  request_->Read(buf.get(), buf_size, bytes_read);

  // No need to check the return value here as we'll detect errors by
  // inspecting the URLRequest's status.
}

然后我默默的翻翻罗升阳老师的博客,在EnsureResourceBufferIsInitialized函数中添加了堆栈打印,因为EnsureResourceBufferIsInitialized首先检查成员变量buffer_是否指向了一个ResourceBuffer对象,并且这个ResourceBuffer对象描述的共享内存是否已经创建。URL的加载是Render向Browser发送一个类型为ResourceHostMsg_RequestResource的IPC消息,Browser收到这个IPC消息之后,就会通过HTTP协议请求Web服务器将网页的内容返回来。请求得到响应后,Browser就会创建一块共享内存,并且通过一个类型为ResourceMsg_SetDataBuffer的IPC消息将这块共享内存传递给Render进程的。

URL加载看着很绕,因为不通线程IPC通信,你如果没先了解下它的msg,就会看着很懵,如果只是看net 部分请求都还好。chromium 55 URL 加载流程_第2张图片

你可能感兴趣的:(chromium)