首页 > 代码库 > chromium网络资源加载分析(二) 主资源加载逻辑分析 之head部分加载---chromium39

chromium网络资源加载分析(二) 主资源加载逻辑分析 之head部分加载---chromium39

转载请标注: from 你吧吧

上一个blog中,主要理顺了chromium kernel在load mainSource的时候,相互调用的逻辑。

这个blog中,我们来看看HttpCacheTransaction对象和HttpNetworkTransaction对象相互协调,一致将网页加载下来的逻辑。

1. HttpCacheTransaction对象跟浏览器的cache模式有关,而cache模式决定了浏览器网页加载的资源的来源与处理方式。

   cache模式有如下几种:

   READ、READ_WRITE、UPDATE

   针对上面的三种模式,chromium解释如下:

  // We now have access to the cache entry.
  //
  //  o if we are a reader for the transaction, then we can start reading the
  //    cache entry.
  //
  //  o if we can read or write, then we should check if the cache entry needs
  //    to be validated and then issue a network request if needed or just read
  //    from the cache if the cache entry is already valid.
  //
  //  o if we are set to UPDATE, then we are handling an externally
  //    conditionalized request (if-modified-since / if-none-match). We check
  //    if the request headers define a validation request.
  //

  默认下,浏览器的cache模式是READ_WRITE。至于在该模式下,如何去判断一个cache是否是validated,这个在后面在去研究。我们这里关注住资源的加载。

2. HttpCacheTransaction对象和HttpNetworkTransaction对象中,都有一个重要的方法:DoLoop。在这个方法中,针对该对象中变量:next_state_进行相关的逻辑调用。

我们这里以chromium content api加载www.baidu.com,来看看两者的调用逻辑关系:

I/chromium( 2529): [http_cache_transaction.cc(418)]  HttpCache::Transaction::Start
I/chromium( 2529): [http_cache_transaction.cc(820)]  HttpCache::Transaction::DoLoop
I/chromium( 2529): [http_cache_transaction.cc(829)]  HttpCache::Transaction::DoLoop 1 STATE_GET_BACKEND
I/chromium( 2529): [http_cache_transaction.cc(820)]  HttpCache::Transaction::DoLoop
I/chromium( 2529): [http_cache_transaction.cc(833)]  HttpCache::Transaction::DoLoop 2 STATE_GET_BACKEND_COMPLETE
I/chromium( 2529): [http_cache_transaction.cc(861)]  HttpCache::Transaction::DoLoop 8 STATE_INIT_ENTRY
I/chromium( 2529): [http_cache_transaction.cc(866)]  HttpCache::Transaction::DoLoop 9 STATE_OPEN_ENTRY
I/chromium( 2529): [http_cache_transaction.cc(820)]  HttpCache::Transaction::DoLoop
I/chromium( 2529): [http_cache_transaction.cc(870)]  HttpCache::Transaction::DoLoop 10 STATE_OPEN_ENTRY_COMPLETE
I/chromium( 2529): [http_cache_transaction.cc(892)]  HttpCache::Transaction::DoLoop 15 STATE_ADD_TO_ENTRY
I/chromium( 2529): [http_cache_transaction.cc(897)]  HttpCache::Transaction::DoLoop 16 STATE_ADD_TO_ENTRY_COMPLETE
I/chromium( 2529): [http_cache_transaction.cc(947)]  HttpCache::Transaction::DoLoop 27 STATE_CACHE_READ_RESPONSE
I/chromium( 2529): [http_cache_transaction.cc(820)]  HttpCache::Transaction::DoLoop
I/chromium( 2529): [http_cache_transaction.cc(952)]  HttpCache::Transaction::DoLoop 28 STATE_CACHE_READ_RESPONSE_COMPLETE
I/chromium( 2529): [http_cache_transaction.cc(838)] HttpCache::Transaction::DoLoop 3 STATE_SEND_REQUEST
I/chromium( 2529): [http_network_transaction.cc(188)]  HttpNetworkTransaction::Start
I/chromium( 2529): [http_network_transaction.cc(622)]  HttpNetworkTransaction::DoLoop 1 STATE_NOTIFY_BEFORE_CREATE_STREAM
I/chromium( 2529): [http_network_transaction.cc(627)]  HttpNetworkTransaction::DoLoop 2 STATE_CREATE_STREAM
I/chromium( 2529): [http_network_transaction.cc(631)]   HttpNetworkTransaction::DoLoop 3 STATE_CREATE_STREAM_COMPLETE
I/chromium( 2529): [http_network_transaction.cc(636)]   HttpNetworkTransaction::DoLoop 4 STATE_INIT_STREAM
I/chromium( 2529): [http_network_transaction.cc(640)]   HttpNetworkTransaction::DoLoop 5 STATE_INIT_STREAM
I/chromium( 2529): [http_network_transaction.cc(645)]   HttpNetworkTransaction::DoLoop 6 STATE_GENERATE_PROXY_AUTH_TOKEN
I/chromium( 2529): [http_network_transaction.cc(649)]   HttpNetworkTransaction::DoLoop 7 STATE_GENERATE_PROXY_AUTH_TOKEN_COMPLETE
I/chromium( 2529): [http_network_transaction.cc(654)]   HttpNetworkTransaction::DoLoop 9 STATE_GENERATE_SERVER_AUTH_TOKEN
I/chromium( 2529): [http_network_transaction.cc(658)]   HttpNetworkTransaction::DoLoop 10 STATE_GENERATE_SERVER_AUTH_TOKEN_COMPLETE
I/chromium( 2529): [http_network_transaction.cc(663)]   HttpNetworkTransaction::DoLoop 11 STATE_INIT_REQUEST_BODY
I/chromium( 2529): [http_network_transaction.cc(667)]   HttpNetworkTransaction::DoLoop 12 STATE_INIT_REQUEST_BODY_COMPLETE
I/chromium( 2529): [http_network_transaction.cc(672)]   HttpNetworkTransaction::DoLoop 13 STATE_BUILD_REQUEST
I/chromium( 2529): [http_network_transaction.cc(677)]   HttpNetworkTransaction::DoLoop 14 STATE_BUILD_REQUEST_COMPLETE
I/chromium( 2529): [http_network_transaction.cc(681)]   HttpNetworkTransaction::DoLoop 15 STATE_SEND_REQUEST
I/chromium( 2529): [http_network_transaction.cc(686)]   HttpNetworkTransaction::DoLoop 16 STATE_SEND_REQUEST_COMPLETE
I/chromium( 2529): [http_network_transaction.cc(693)]   HttpNetworkTransaction::DoLoop STATE_READ_HEADERS
I/chromium( 2529): [http_network_transaction.cc(698)]   HttpNetworkTransaction::DoLoop STATE_READ_HEADERS_COMPLETE
I/chromium( 2529): [http_cache_transaction.cc(820)]  HttpCache::Transaction::DoLoop
I/chromium( 2529): [http_cache_transaction.cc(842)]  HttpCache::Transaction::DoLoop 4 STATE_SEND_REQUEST_COMPLETE
I/chromium( 2529): [http_cache_transaction.cc(846)]  HttpCache::Transaction::DoLoop 5 STATE_SUCCESSFUL_SEND_REQUEST
I/chromium( 2529): [http_cache_transaction.cc(919)]  HttpCache::Transaction::DoLoop 21 STATE_OVERWRITE_CACHED_RESPONSE
I/chromium( 2529): [http_cache_transaction.cc(956)]  HttpCache::Transaction::DoLoop 29 STATE_CACHE_WRITE_RESPONSE
I/chromium( 2529): [http_cache_transaction.cc(966)]  HttpCache::Transaction::DoLoop 31 STATE_CACHE_WRITE_RESPONSE_COMPLETE
I/chromium( 2529): [http_cache_transaction.cc(924)]  HttpCache::Transaction::DoLoop 22 STATE_TRUNCATE_CACHED_DATA
I/chromium( 2529): [http_cache_transaction.cc(929)]  HttpCache::Transaction::DoLoop 23 STATE_TRUNCATE_CACHED_DATA_COMPLETE
I/chromium( 2529): [http_cache_transaction.cc(933)]  HttpCache::Transaction::DoLoop 24 STATE_TRUNCATE_CACHED_METADATA
I/chromium( 2529): [http_cache_transaction.cc(820)]  HttpCache::Transaction::DoLoop
I/chromium( 2529): [http_cache_transaction.cc(938)]  HttpCache::Transaction::DoLoop 25 STATE_TRUNCATE_CACHED_METADATA_COMPLETE
I/chromium( 2529): [http_cache_transaction.cc(942)]  HttpCache::Transaction::DoLoop 26 STATE_PARTIAL_HEADERS_RECEIVED

上面这段,是将百度主页的head部分加载下来。

我们这里来研究下head部分的加载逻辑。

连接上篇blog,我们从third_party/WebKit/下的ResourceLoader.cpp文件的start()方法开始看。

1. 该start方法中有代码:

    m_loader = adoptPtr(blink::Platform::current()->createURLLoader());

   并且,之后有:m_loader->loadAsynchronously(wrappedRequest, this);

   这里的URLLoader对象是content/下的WebURLLoaderImpl对象。

2. 上面的loadAsynchronously方法在文件:content目录下:web_url_loader_impl.cc

     WebURLLoaderImpl::loadAsynchronously

    该方法中有代码:context_->Start(request, NULL);

3. 该代码执行的是同文件中方法:WebURLLoaderImpl::Context::Start(

    该方法中有代码:bridge_.reset(resource_dispatcher_->CreateBridge(request_info));

   上面方法会调用content目录下文件 resource_dispatcher.cc中方法:ResourceDispatcher::CreateBridge(

   再看,WebURLLoaderImpl::Context::Start(方法,该方法后面有代码:

    if (!bridge_->Start(this))

4. 上面方法会调用content目录下文件 resource_dispatcher.cc中方法:IPCResourceLoaderBridge::Start

    该方法中会发送消息:

      return dispatcher_->message_sender()->Send(
      new ResourceHostMsg_RequestResource(routing_id_, request_id_, request_));

5.  上面消息的处理是在文件:resource_dispatcher_host_impl.cc中方法:ResourceDispatcherHostImpl::OnMessageReceived

      最终处理该消息的方法是ResourceDispatcherHostImpl::OnRequestResource

6.  上面方法会调用同文件方法:ResourceDispatcherHostImpl::BeginRequest

     该方法中有代码:  new_request = request_context->CreateRequest(
      request_data.url, request_data.priority, NULL, cookie_store);

7.   上面是文件net目录下:url_request_context.cc文件中方法:URLRequestContext::CreateRequest

       该方法中会创建对象URLRequest。接着我们看看这个对象是如何Start的。

8.  我们接着6继续看,在方法:ResourceDispatcherHostImpl::BeginRequest中,

    之后有代码:

   

  scoped_ptr<ResourceHandler> handler(
       CreateResourceHandler(
           new_request.get(),
           request_data, sync_result, route_id, process_type, child_id,
           resource_context));

这里调用同文件的方法:ResourceDispatcherHostImpl::CreateResourceHandler

9. 该方法中有代码:

  throttles.push_back(
      scheduler_->ScheduleRequest(child_id, route_id, request).release());

该代码调用的方法是文件:content目录下文件:resource_scheduler.cc。

该文件中有方法:ResourceScheduler::ScheduleRequest(

该方法中有代码: request->Start();

  这里即是之前7中提到的URLRequest对象的Start的地方。

10. 在该Start方法中有代码:

  StartJob(URLRequestJobManager::GetInstance()->CreateJob(
      this, network_delegate_));

这里便启动了URLRequestJob的启动与kill的多个巡回。至于这里做的意义,这里也去深入研究。先记载下来,之后有时间再来研究下。TODO

由于这里用到了方法:URLRequestJobManager::CreateJob

为了查看方便,这里将这个方法贴出来。

URLRequestJob* URLRequestJobManager::CreateJob(
    URLRequest* request, NetworkDelegate* network_delegate) const {
  DCHECK(IsAllowedThread());
  LOG(INFO)<<" URLRequestJobManager::CreateJob";
  // If we are given an invalid URL, then don't even try to inspect the scheme.
  if (!request->url().is_valid()){
    URLRequestJob* job = new URLRequestErrorJob(request, network_delegate, ERR_INVALID_URL);
    <span style="color:#FF0000;"><strong><span style="font-size:14px;">LOG(INFO)<<" URLRequestJobManager::CreateJob 0 job is "<<job;</span></strong></span>
    return job;
  }
   // return new URLRequestErrorJob(request, network_delegate, ERR_INVALID_URL);

  // We do this here to avoid asking interceptors about unsupported schemes.
  const URLRequestJobFactory* job_factory = NULL;
  job_factory = request->context()->job_factory();

  const std::string& scheme = request->url().scheme();  // already lowercase
  if (!job_factory->IsHandledProtocol(scheme)) {
    URLRequestJob* job = new URLRequestErrorJob(
        request, network_delegate, ERR_UNKNOWN_URL_SCHEME);
    <span style="color:#FF0000;"><strong>LOG(INFO)<<" URLRequestJobManager::CreateJob 00 job is "<<job;</strong></span>
    return job;
    //return new URLRequestErrorJob(
    //    request, network_delegate, ERR_UNKNOWN_URL_SCHEME);
  }

  // THREAD-SAFETY NOTICE:
  //   We do not need to acquire the lock here since we are only reading our
  //   data structures.  They should only be modified on the current thread.

  // See if the request should be intercepted.
  //

  // TODO(pauljensen): Remove this when AppCacheInterceptor is a
  // ProtocolHandler, see crbug.com/161547.
  if (!(request->load_flags() & LOAD_DISABLE_INTERCEPT)) {
    InterceptorList::const_iterator i;
    for (i = interceptors_.begin(); i != interceptors_.end(); ++i) {
      URLRequestJob* job = (*i)->MaybeIntercept(request, network_delegate);
      if (job){
        <span style="color:#FF0000;"><strong>LOG(INFO)<<"URLRequestJobManager::CreateJob 000 job is "<<job;</strong></span>
        return job;
      }
        
    }
  }

  URLRequestJob* job = job_factory->MaybeCreateJobWithProtocolHandler(
      scheme, request, network_delegate);
  <span style="color:#FF0000;"><strong>LOG(INFO)<<" URLRequestJobManager::CreateJob job is "<<job;</strong></span>
  if (job)
    return job;

  // See if the request should be handled by a built-in protocol factory.
  for (size_t i = 0; i < arraysize(kBuiltinFactories); ++i) {
    if (scheme == kBuiltinFactories[i].scheme) {
      URLRequestJob* job = (kBuiltinFactories[i].factory)(
          request, network_delegate, scheme);
      DCHECK(job);  // The built-in factories are not expected to fail!
       <strong><span style="color:#FF0000;">LOG(INFO)<<" URLRequestJobManager::CreateJob job 2 is "<<job;</span></strong>
      return job;
    }
  }

  // If we reached here, then it means that a registered protocol factory
  // wasn't interested in handling the URL.  That is fairly unexpected, and we
  // don't have a specific error to report here :-(
  LOG(WARNING) << "Failed to map: " << request->url().spec();
  
//  return new URLRequestErrorJob(request, network_delegate, ERR_FAILED);
  job = new URLRequestErrorJob(request, network_delegate, ERR_FAILED);
  <span style="color:#FF0000;"><strong>LOG(INFO)<<" URLRequestJobManager::CreateJob job 3 is "<<job;</strong></span>
  return job;
}

我们接着看看在执行了10中提到的方法Start之后,log输出:

I/chromium( 2740): [url_request.cc(608)]  URLRequest::Start()
I/chromium( 2740): [url_request.cc(642)]  URLRequest::BeforeRequestComplete
I/chromium( 2740): [url_request_job_manager.cc(50)]  URLRequestJobManager::CreateJob
I/chromium( 2740): [url_request_job_manager.cc(87)]  URLRequestJobManager::CreateJob 000 job is 0x0048d520
I/xxx    ( 2740): Tab.java @@@@@@@@@@@@@@@  onPageStarted url is  http://www.baidu.com/
I/chromium( 2740): [url_request_job.cc(506)]  URLRequestJob::NotifyRestartRequired()
I/chromium( 2740): [url_request.cc(715)]  URLRequest::Restart()  
I/chromium( 2740): [url_request_job_manager.cc(50)]  URLRequestJobManager::CreateJob
I/chromium( 2740): [url_request_job_manager.cc(96)]  URLRequestJobManager::CreateJob job is 0x002f6380
I/chromium( 2740): [url_request_job.cc(53)]  URLRequestJob::Kill() and job is 0x0048d520
I/chromium( 2740): [service_worker_url_request_job.cc(59)]  ServiceWorkerURLRequestJob::Start()
I/chromium( 2740): [service_worker_url_request_job.cc(203)]  ServiceWorkerURLRequestJob::MaybeStartRequest()
I/chromium( 2740): [service_worker_url_request_job.cc(203)]  ServiceWorkerURLRequestJob::MaybeStartRequest()
I/chromium( 2740): [service_worker_url_request_job.cc(214)]  ServiceWorkerURLRequestJob::StartRequest()
I/chromium( 2740): [service_worker_url_request_job.cc(224)]  ServiceWorkerURLRequestJob::StartRequest() 1
I/chromium( 2740): [url_request_job.cc(506)]  URLRequestJob::NotifyRestartRequired()
I/chromium( 2740): [url_request.cc(715)]  URLRequest::Restart()  
I/chromium( 2740): [url_request_job_manager.cc(50)]  URLRequestJobManager::CreateJob
I/chromium( 2740): [url_request_job_manager.cc(87)]  URLRequestJobManager::CreateJob 000 job is 0x0048d520
I/chromium( 2740): [url_request_job.cc(53)]  URLRequestJob::Kill() and job is 0x002f6380
I/chromium( 2740): [INFO:url_request_job.cc(482)]  URLRequestJob::CompleteNotifyDone()
I/chromium( 2740): [INFO:url_request_job.cc(506)]  URLRequestJob::NotifyRestartRequired()
I/chromium( 2740): [url_request.cc(715)]  URLRequest::Restart()  
I/chromium( 2740): [url_request_job_manager.cc(50)]  URLRequestJobManager::CreateJob
I/chromium( 2740): [url_request_job_manager.cc(96)]  URLRequestJobManager::CreateJob job is 0x00000000
I/chromium( 2740): [url_request_http_job.cc(156)]  URLRequestJob* URLRequestHttpJob::Factory
I/chromium( 2740): [url_request_job_manager.cc(106)]  URLRequestJobManager::CreateJob job 2 is 0x00488a80
I/chromium( 2740): [url_request_job.cc(53)]  URLRequestJob::Kill() and job is 0x0048d520
I/chromium( 2740): [url_request_http_job.cc(565)]  URLRequestHttpJob::AddCookieHeaderAndStart 
I/chromium( 2740): [url_request_http_job.cc(592)]  URLRequestHttpJob::CheckCookiePolicyAndLoad 
I/chromium( 2740): [url_request_http_job.cc(600)]  URLRequestHttpJob::OnCookiesLoaded 



通过该log可以看出,经过了多个变化,最终创建了对象URLRequestHttpJob

11。我们看看上面log中

I/chromium( 2740): [url_request_http_job.cc(600)]  URLRequestHttpJob::OnCookiesLoaded 
在该方法中调用了同文件的方法:URLRequestHttpJob::StartTransactionInternal()

该方法中有代码:

        rv = transaction_->Start(
            &request_info_, start_callback_, request_->net_log());
这里之后,便是本blog中最初log的展示的逻辑。

 我们看看上面中的参数:start_callback_。这个变量是在URLRequestHttpJob对象构造函数中创建的,是URLRequestHttpJob对象的一个回调。

该回调调用的方法是本文件中的:URLRequestHttpJob::OnStartCompleted。当网页的head部分读取完毕,则调用此回调。

12. 我们继续看方法:URLRequestHttpJob::OnStartCompleted

      该函数中有代码SaveCookiesAndNotifyHeadersComplete(net::OK);  这里是同文件中方法:

     URLRequestHttpJob::SaveCookiesAndNotifyHeadersComplete(int result)

    在这个方法中将进行网页的cookie的保存操作。

13. 上面方法中,有代码:SaveNextCookie();该代码是同文件中的方法:URLRequestHttpJob::SaveNextCookie()

     在该方法中,会先后调用同文件种方法:

     URLRequestHttpJob::OnCookieSaved

    URLRequestHttpJob::NotifyHeadersComplete()

14. 方法:URLRequestHttpJob::NotifyHeadersComplete()又调用方法: URLRequestJob::NotifyHeadersComplete()

     该方法中有代码:request_->NotifyResponseStarted();

15. 上代码是net下文件 url_request.cc方法:URLRequest::NotifyResponseStarted()

      该方法中有代码:delegate_->OnResponseStarted(this);

16. 这个方法是content目录下文件:resource_loader.cc中方法: ResourceLoader::OnResponseStarted

 17. 上面方法中有代码:StartReading(false); 该代码 是同文件种方法:ResourceLoader::StartReading

18.  上面方法会调用同文件种方法:ResourceLoader::ReadMore。

      该方法中有代码:request_->Read(buf.get(), buf_size, bytes_read);

19. 上面代码调用的是net目录下文件url_request.cc中方法:URLRequest::Read

20.  上面方法中有代码:bool rv = job_->Read(dest, dest_size, bytes_read);

       该代码执行的是文件:url_request_job.cc中方法:URLRequestJob::Read,该方法又会调用同文件中的方法:

      URLRequestJob::ReadFilteredData

21. 上面方法又会调用同文件中方法:URLRequestJob::ReadRawDataForFilter

      该方法中有代码:rv = ReadRawDataHelper(stream_buffer, stream_buffer_size, bytes_read);

22. 方法ReadRawDataHelper中又会调用文件中url_request_http_job.cc方法:URLRequestHttpJob::ReadRawData

 

这就是网页加载过程中,head部分的加载过程。

之后,又会进入http_cache_transaction.cc文件中的DoLoop方法中,进行主资源的加载。

TODO:

  1.head读数据完毕之后的消息回馈还没有找出来

  2.关于Cookie和Cache的逻辑还需要继续研究下

 

难得有点时间自己看看源码,找个时间再将body部分的逻辑大体理顺下。




chromium网络资源加载分析(二) 主资源加载逻辑分析 之head部分加载---chromium39