Avoid initial NetworkChangeNotifier OnDNSChanged() signal on Android

When the DnsConfigServicePosix finishes its initial reading of the
system DNS config, it normally triggers a NetworkChangeNotifier (NCN)
OnDNSChanged() signal.  This can cause in-flight network requests to
abort with ERR_NETWORK_CHANGED.  Avoid aborting requests by:
1. Adding a new NCN signal, OnInitialDNSConfigRead which indicates
   the initial DNS config reading completed but does not represent
   a change in DNS config.
2. Modify HostResolverImpl to not abort requests upon this new
   signal (like it does for the OnDNSChanged signal).
3. Add logic to NetworkChangeNotifierAndroid to emit this new
   signal when safe to do so.  Network requests begin being issued
   immediately after the NCN (and hence DnsConfigService) is
   initialized, so we need to be sure no network change signals
   are missed between NCN initialization completing and the
   OnInitialDNSConfigRead signal.  This is tricky because the
   NCN (and hence DnsConfigService) is initialized on threads
   where file I/O is not allowed.  Were file I/O allowed we could
   simply slurp up the DNS config and hosts file.  Instead we
   start listening for network changes (which is our trigger signal
   for DNS changes on Android) on the initialization thread and
   record the current time to later compare against the hosts
   file's last-modified time to check for changes to the file.
   Actual loading of the DNS config and hosts file is done on
   another thread that allows file I/O.

BUG=470897

Review URL: https://codereview.chromium.org/1047103002

Cr-Commit-Position: refs/heads/master@{#325560}
diff --git a/net/dns/host_resolver_impl.cc b/net/dns/host_resolver_impl.cc
index f294b8c4..35ea2fa2 100644
--- a/net/dns/host_resolver_impl.cc
+++ b/net/dns/host_resolver_impl.cc
@@ -2289,7 +2289,15 @@
   // |this| may be deleted inside AbortAllInProgressJobs().
 }
 
+void HostResolverImpl::OnInitialDNSConfigRead() {
+  UpdateDNSConfig(false);
+}
+
 void HostResolverImpl::OnDNSChanged() {
+  UpdateDNSConfig(true);
+}
+
+void HostResolverImpl::UpdateDNSConfig(bool config_changed) {
   DnsConfig dns_config;
   NetworkChangeNotifier::GetDnsConfig(&dns_config);
 
@@ -2310,27 +2318,33 @@
   // the newly started jobs use the new config.
   if (dns_client_.get()) {
     dns_client_->SetConfig(dns_config);
-    if (dns_client_->GetConfig())
+    if (dns_client_->GetConfig()) {
       UMA_HISTOGRAM_BOOLEAN("AsyncDNS.DnsClientEnabled", true);
+      // If we just switched DnsClients, restart jobs using new resolver.
+      // TODO(pauljensen): Is this necessary?
+      config_changed = true;
+    }
   }
 
-  // If the DNS server has changed, existing cached info could be wrong so we
-  // have to drop our internal cache :( Note that OS level DNS caches, such
-  // as NSCD's cache should be dropped automatically by the OS when
-  // resolv.conf changes so we don't need to do anything to clear that cache.
-  if (cache_.get())
-    cache_->clear();
+  if (config_changed) {
+    // If the DNS server has changed, existing cached info could be wrong so we
+    // have to drop our internal cache :( Note that OS level DNS caches, such
+    // as NSCD's cache should be dropped automatically by the OS when
+    // resolv.conf changes so we don't need to do anything to clear that cache.
+    if (cache_.get())
+      cache_->clear();
 
-  // Life check to bail once |this| is deleted.
-  base::WeakPtr<HostResolverImpl> self = weak_ptr_factory_.GetWeakPtr();
+    // Life check to bail once |this| is deleted.
+    base::WeakPtr<HostResolverImpl> self = weak_ptr_factory_.GetWeakPtr();
 
-  // Existing jobs will have been sent to the original server so they need to
-  // be aborted.
-  AbortAllInProgressJobs();
+    // Existing jobs will have been sent to the original server so they need to
+    // be aborted.
+    AbortAllInProgressJobs();
 
-  // |this| may be deleted inside AbortAllInProgressJobs().
-  if (self.get())
-    TryServingAllJobsFromHosts();
+    // |this| may be deleted inside AbortAllInProgressJobs().
+    if (self.get())
+      TryServingAllJobsFromHosts();
+  }
 }
 
 bool HostResolverImpl::HaveDnsConfig() const {