Index: net/dns/dns_config_service_posix.cc |
diff --git a/net/dns/dns_config_service_posix.cc b/net/dns/dns_config_service_posix.cc |
index 135f3fd68767a064c58a15652d8e549f7336d5da..6f103552aa1f919e7f0e266bc9fcf2ea4a927c6b 100644 |
--- a/net/dns/dns_config_service_posix.cc |
+++ b/net/dns/dns_config_service_posix.cc |
@@ -8,6 +8,7 @@ |
#include "base/basictypes.h" |
#include "base/bind.h" |
+#include "base/files/file.h" |
#include "base/files/file_path.h" |
#include "base/files/file_path_watcher.h" |
#include "base/lazy_instance.h" |
@@ -58,22 +59,14 @@ class DnsConfigWatcher { |
#elif defined(OS_ANDROID) |
// On Android, assume DNS config may have changed on every network change. |
-class DnsConfigWatcher : public NetworkChangeNotifier::NetworkChangeObserver { |
+class DnsConfigWatcher { |
public: |
- DnsConfigWatcher() { |
- NetworkChangeNotifier::AddNetworkChangeObserver(this); |
- } |
- |
- ~DnsConfigWatcher() override { |
- NetworkChangeNotifier::RemoveNetworkChangeObserver(this); |
- } |
- |
bool Watch(const base::Callback<void(bool succeeded)>& callback) { |
callback_ = callback; |
return true; |
} |
- void OnNetworkChanged(NetworkChangeNotifier::ConnectionType type) override { |
+ void OnNetworkChanged(NetworkChangeNotifier::ConnectionType type) { |
if (!callback_.is_null() && type != NetworkChangeNotifier::CONNECTION_NONE) |
callback_.Run(true); |
} |
@@ -201,8 +194,7 @@ ConfigParsePosixResult ReadDnsConfig(DnsConfig* dns_config) { |
class DnsConfigServicePosix::Watcher { |
public: |
explicit Watcher(DnsConfigServicePosix* service) |
- : service_(service), |
- weak_factory_(this) {} |
+ : service_(service), weak_factory_(this) {} |
~Watcher() {} |
bool Watch() { |
@@ -215,9 +207,9 @@ class DnsConfigServicePosix::Watcher { |
DNS_CONFIG_WATCH_FAILED_TO_START_CONFIG, |
DNS_CONFIG_WATCH_MAX); |
} |
- if (!hosts_watcher_.Watch(base::FilePath(kFilePathHosts), false, |
- base::Bind(&Watcher::OnHostsChanged, |
- base::Unretained(this)))) { |
+ if (!hosts_watcher_.Watch( |
+ base::FilePath(service_->file_path_hosts_), false, |
+ base::Bind(&Watcher::OnHostsChanged, base::Unretained(this)))) { |
LOG(ERROR) << "DNS hosts watch failed to start."; |
success = false; |
UMA_HISTOGRAM_ENUMERATION("AsyncDNS.WatchStatus", |
@@ -227,8 +219,17 @@ class DnsConfigServicePosix::Watcher { |
return success; |
} |
+#if defined(OS_ANDROID) |
+ void OnNetworkChanged(NetworkChangeNotifier::ConnectionType type) { |
+ config_watcher_.OnNetworkChanged(type); |
+ } |
+#endif // defined(OS_ANDROID) |
+ |
private: |
void OnConfigChanged(bool succeeded) { |
+#if defined(OS_ANDROID) |
+ service_->seen_config_change_ = true; |
+#endif // defined(OS_ANDROID) |
// Ignore transient flutter of resolv.conf by delaying the signal a bit. |
const base::TimeDelta kDelay = base::TimeDelta::FromMilliseconds(50); |
base::MessageLoop::current()->PostDelayedTask( |
@@ -265,6 +266,10 @@ class DnsConfigServicePosix::ConfigReader : public SerialWorker { |
void DoWork() override { |
base::TimeTicks start_time = base::TimeTicks::Now(); |
ConfigParsePosixResult result = ReadDnsConfig(&dns_config_); |
+ if (service_->dns_config_for_testing_) { |
+ dns_config_ = *service_->dns_config_for_testing_; |
+ result = CONFIG_PARSE_POSIX_OK; |
+ } |
switch (result) { |
case CONFIG_PARSE_POSIX_MISSING_OPTIONS: |
case CONFIG_PARSE_POSIX_UNHANDLED_OPTIONS: |
@@ -308,14 +313,15 @@ class DnsConfigServicePosix::ConfigReader : public SerialWorker { |
class DnsConfigServicePosix::HostsReader : public SerialWorker { |
public: |
explicit HostsReader(DnsConfigServicePosix* service) |
- : service_(service), path_(kFilePathHosts), success_(false) {} |
+ : service_(service), success_(false) {} |
private: |
~HostsReader() override {} |
void DoWork() override { |
base::TimeTicks start_time = base::TimeTicks::Now(); |
- success_ = ParseHostsFile(path_, &hosts_); |
+ success_ = |
+ ParseHostsFile(base::FilePath(service_->file_path_hosts_), &hosts_); |
UMA_HISTOGRAM_BOOLEAN("AsyncDNS.HostParseResult", success_); |
UMA_HISTOGRAM_TIMES("AsyncDNS.HostsParseDuration", |
base::TimeTicks::Now() - start_time); |
@@ -330,7 +336,6 @@ class DnsConfigServicePosix::HostsReader : public SerialWorker { |
} |
DnsConfigServicePosix* service_; |
- const base::FilePath path_; |
// Written in DoWork, read in OnWorkFinished, no locking necessary. |
DnsHosts hosts_; |
bool success_; |
@@ -339,8 +344,16 @@ class DnsConfigServicePosix::HostsReader : public SerialWorker { |
}; |
DnsConfigServicePosix::DnsConfigServicePosix() |
- : config_reader_(new ConfigReader(this)), |
- hosts_reader_(new HostsReader(this)) {} |
+ : file_path_hosts_(kFilePathHosts), |
+ dns_config_for_testing_(nullptr), |
+ config_reader_(new ConfigReader(this)), |
+ hosts_reader_(new HostsReader(this)) |
+#if defined(OS_ANDROID) |
+ , |
+ seen_config_change_(false) |
+#endif // defined(OS_ANDROID) |
+{ |
+} |
DnsConfigServicePosix::~DnsConfigServicePosix() { |
config_reader_->Cancel(); |
@@ -386,6 +399,12 @@ void DnsConfigServicePosix::OnHostsChanged(bool succeeded) { |
} |
} |
+void DnsConfigServicePosix::SetDnsConfigForTesting( |
+ const DnsConfig* dns_config) { |
+ DCHECK(CalledOnValidThread()); |
+ dns_config_for_testing_ = dns_config; |
+} |
+ |
#if !defined(OS_ANDROID) |
ConfigParsePosixResult ConvertResStateToDnsConfig(const struct __res_state& res, |
DnsConfig* dns_config) { |
@@ -493,7 +512,39 @@ ConfigParsePosixResult ConvertResStateToDnsConfig(const struct __res_state& res, |
} |
return CONFIG_PARSE_POSIX_OK; |
} |
-#endif // !defined(OS_ANDROID) |
+ |
+#else // defined(OS_ANDROID) |
+ |
+bool DnsConfigServicePosix::SeenChangeSince( |
+ const base::Time& since_time) const { |
+ DCHECK(CalledOnValidThread()); |
+ if (seen_config_change_) |
+ return true; |
+ base::File hosts(base::FilePath(file_path_hosts_), |
+ base::File::FLAG_OPEN | base::File::FLAG_READ); |
+ base::File::Info hosts_info; |
+ // File last modified times are not nearly as accurate as Time::Now() and are |
+ // rounded down. This means a file modified at 1:23.456 might only |
+ // be given a last modified time of 1:23.450. If we compared the last |
+ // modified time directly to |since_time| we might miss changes to the hosts |
+ // file because of this rounding down. To account for this the |since_time| |
+ // is pushed back by 1s which should more than account for any rounding. |
+ // In practice file modified times on Android are two orders of magnitude |
+ // more accurate than this 1s. In practice the hosts file on Android always |
+ // contains "127.0.0.1 localhost" and is never modified after Android is |
+ // installed. |
+ return !hosts.GetInfo(&hosts_info) || |
+ hosts_info.last_modified >= |
+ (since_time - base::TimeDelta::FromSeconds(1)); |
+} |
+ |
+void DnsConfigServicePosix::OnNetworkChanged( |
+ NetworkChangeNotifier::ConnectionType type) { |
+ DCHECK(CalledOnValidThread()); |
+ DCHECK(watcher_); |
+ watcher_->OnNetworkChanged(type); |
+} |
+#endif // defined(OS_ANDROID) |
} // namespace internal |