Chromium DNS流程分析

概述

在Android平台上,Chromium主要支持三种DNS机制,分别为基于系统调用的getaddrinfo(),自己构造数据包并处理请求的AsyncDNS,以及基于TCP的DNS协议。本文暂时仅分析前两者,事实上最后一项是在普通DNS请求失败时所进行的fallback,没有什么特殊的地方。

核心思路

首先,DNS解析的实际操作由HostResolverImpl::Job::Start()函数发起,该函数所属的类继承自PrioritizedDispatcher::Job以及HostResolverImpl::DnsTask::Delegate。由这个多重继承可见,HostResolverImpl::Job实际上具备两种属性:一方面,它是一个能够被调度执行的任务实体;另一方面,它继承了DnsTask的委托接口,用于执行实际的请求工作。通用的抽象Job类主要包含一个Start()方法,用于启动任务。而对于DNS请求这项任务,其Start()方法也就对应着下述流程图的主节点。

Start()方法启动后,会创建一个事件HOST_RESOLVER_IMPL_JOB_STARTED并记录到日志中。该方法内部首先根据一些条件来判断是使用系统调用来解析DNS,还是使用AsyncDNS来进行解析。对于前者,Chromium称之为"ProcTask";对于后者称为"DnsTask"。

对于基于AsyncDNS的解析,Chromium相当于按照DNS协议规范,在应用层重新实现了getaddrinfo(),只不过是按照纯异步的方式来实现的。因为打开UDP socket可以直接得到fd,因此这个fd能够被注册到网络库IO线程的事件循环中(在POSIX上是基于libevent来实现),使得DNS解析的流程被统一到异步回调的编程框架下。

而对于基于系统调用的解析,由于getaddrinfo()是一个阻塞调用,因此必须将其投放到公共线程池中进行操作,完成后再回调并返回数据即可,这个流程相对简单。Chromium提供了base::WorkerPool::PostTask()这样一个静态方法,专门去处理那些“不需要在特定事件循环(MessageLoop)或者线程上执行的任务”。

流程图

使用XMind绘制,相应源文件请点击这里下载。

Chromium DNS

comments powered by Disqus
Published:
2016-04-12
分类:
Tag: