Improving DNS Performance in Firefox for Android

Mozilla has been working hard to improve Firefox on Android. The following is a guest post from Steve Workman of Mozilla’s networking team which describes an effort to improve DNS performance. – Josh

It started with some crashes on Android that were due to getaddrinfo being called from multiple threads. The problem was that the version of getaddrinfo supplied by Bionic (Android’s minimal-but-fast libc implementation) in pre-Honeycomb Android isn’t thread-safe. This is because fopen/fclose etc. aren’t thread-safe. Multiple accesses were being made to a file pointer when reading the local hosts file, resulting in crashes.

Why were we calling getaddrinfo on multiple threads? Calls to getaddrinfo can block until a response is received from a DNS server. This can take a while, especially if there is a problem and we wait for the timeout. Making parallel getaddrinfo calls allows us to cut down on waiting and get more done at once. Sockets can be opened sooner, HTTP requests can be sent sooner, and ultimately your content can be received and displayed sooner. Not being able to make parallel calls to getaddrinfo would be a serious performance regression, especially on mobile where round trip times are generally longer.

First we needed a quick fix for the crash – a performance regression is better than a crash regression. We temporarily serialized calls to getaddrinfo and prefetching (predictive DNS resolution) was disabled.

After that, we decided to provide our own thread-safe version of getaddrinfo, bypassing Bionic’s. Our implementation would have mmap‘d access to the local hosts file, using open/close directly, thus providing a thread-safe function. However, since we were dealing with a library-exposed function, it meant calls to functions and use of structures which were not exposed; at least not officially. After a few failed attempts in which we were trying to get away with dependencies on some unofficially exposed symbols, we finally pulled in a pretty complete version of the host resolver from Gingerbread. This added to our library size a bit, but it allowed for parallel calls to getaddrinfo on Android again. Given the potential for such calls to block for the duration of a DNS request, we believe this is a good tradeoff.

This change is currently scheduled to ship in Firefox 11.

Steve Workman

6 thoughts on “Improving DNS Performance in Firefox for Android

  1. Have a link to the bug/commit?
    AFAIK DNS caching is done in the Java layer of Android’s stack.
    But when directly interacting with the Bionic layer, is _any_ DNS caching done? There typically isn’t on Linux systems that call getaddrinfo and use /etc/resolv.conf directly. Perhaps Firefox could further benefit by including a larger DNS cache.

  2. Samat, the bug ID is 694325 (

    Firefox already has a DNS cache in Gecko and calls getaddrinfo directly in Android, thus bypassing their Java code. We looked into their DNS mechanism for pre-honeycomb Android to see if they had a way around the multi-threading issue, but the code seems to be ultimately dependent on getaddrinfo for hostname resolution, and thus restricted by the same issue under discussion here.

    Also, in this case, a larger DNS cache wouldn’t make a difference – the problem is not that there are too many addresses for the cache to remember. Rather, a queue of hostnames requiring addresses means a lot of time waiting for getaddrinfo as it handles one request at a time. A larger cache would not make a difference in this case, because even if the cache remembered the hostname-address mappings for longer, it would only help if the mappings had already been learned. Instead, the problem is in cases when the DNS cache is empty (e.g. a where a page is loaded with links to hosts that have not been requested before, like a google search results page). We deal with this queue of new hostnames through multi-threaded, parallelised requests, allowing more hostname resolutions in a shorter length of time.

  3. Samat, that page seems to be a little out of date. Our current default is 400 entries. It can be changed using the config pref “network.dnsCacheEntries”, as you suggest.

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s