Overview
On Android, Chromium mainly supports three DNS mechanisms: the system-call-based getaddrinfo(), AsyncDNS which constructs packets and handles requests on its own, and a TCP-based DNS protocol. For now, this article only analyzes the first two. In fact, the last one is a fallback used when normal DNS requests fail, and there is nothing particularly special about it.
Core Idea
First, the actual DNS resolution is initiated by the HostResolverImpl::Job::Start() function. The class this function belongs to inherits from PrioritizedDispatcher::Job and HostResolverImpl::DnsTask::Delegate. From this multiple inheritance, it is clear that HostResolverImpl::Job effectively has two roles: on one hand, it is a task entity that can be scheduled for execution; on the other hand, it inherits the delegate interface of DnsTask, which is used to perform the actual request work. The generic abstract Job class mainly contains a Start() method to start the task. For the DNS request task, its Start() method corresponds to the main node in the flowchart below.
After the Start() method begins, it creates an event HOST_RESOLVER_IMPL_JOB_STARTED and records it in the log. Inside this method, it first checks certain conditions to decide whether to resolve DNS using a system call or using AsyncDNS. Chromium calls the former a "ProcTask" and the latter a "DnsTask".
For AsyncDNS-based resolution, Chromium effectively re-implements getaddrinfo() at the application layer according to the DNS protocol specification, except that it is implemented in a purely asynchronous way. Because opening a UDP socket directly yields an fd, this fd can be registered with the network library IO thread’s event loop (implemented on POSIX based on libevent), so the DNS resolution flow is unified under an asynchronous callback programming framework.
For system-call-based resolution, since getaddrinfo() is a blocking call, it must be dispatched to a shared thread pool. After it completes, it simply invokes a callback and returns the data; this flow is relatively straightforward. Chromium provides a static method like base::WorkerPool::PostTask(), specifically to handle tasks that "do not need to run on a specific event loop (MessageLoop) or thread".
Flowchart
Drawn with XMind. To download the corresponding source file, click here.