首页 > 代码库 > 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