Skip to content

Commit b7dc501

Browse files
committed
core: For Android, ignores DNS cache
There is a known issue that causes DNS lookup issue when network siwtchover on android. This issue is tracked separately in grpc#4962. This change simply disables DNS cache to avoid the issue on Android.
1 parent 0a7fa14 commit b7dc501

File tree

3 files changed

+69
-25
lines changed

3 files changed

+69
-25
lines changed

core/src/main/java/io/grpc/internal/DnsNameResolver.java

Lines changed: 31 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,8 @@ final class DnsNameResolver extends NameResolver {
9898
* <p>Default value is -1 (cache forever) if security manager is installed. If security manager is
9999
* not installed, the ttl value is {@code null} which falls back to {@link
100100
* #DEFAULT_NETWORK_CACHE_TTL_SECONDS gRPC default value}.
101+
*
102+
* <p>For android, gRPC doesn't attempt to cache; this property value will be ignored.
101103
*/
102104
@VisibleForTesting
103105
static final String NETWORKADDRESS_CACHE_TTL_PROPERTY = "networkaddress.cache.ttl";
@@ -143,7 +145,7 @@ final class DnsNameResolver extends NameResolver {
143145

144146
DnsNameResolver(@Nullable String nsAuthority, String name, Attributes params,
145147
Resource<ExecutorService> executorResource, ProxyDetector proxyDetector,
146-
Stopwatch stopwatch) {
148+
Stopwatch stopwatch, boolean isAndroid) {
147149
// TODO: if a DNS server is provided as nsAuthority, use it.
148150
// https://www.captechconsulting.com/blogs/accessing-the-dusty-corners-of-dns-with-java
149151
this.executorResource = executorResource;
@@ -166,7 +168,7 @@ final class DnsNameResolver extends NameResolver {
166168
port = nameUri.getPort();
167169
}
168170
this.proxyDetector = proxyDetector;
169-
this.resolveRunnable = new Resolve(this, stopwatch);
171+
this.resolveRunnable = new Resolve(this, stopwatch, getNetworkAddressCacheTtlNanos(isAndroid));
170172
}
171173

172174
@Override
@@ -196,10 +198,10 @@ static final class Resolve implements Runnable {
196198
private final long cacheTtlNanos;
197199
private ResolutionResults cachedResolutionResults = null;
198200

199-
Resolve(DnsNameResolver resolver, Stopwatch stopwatch) {
201+
Resolve(DnsNameResolver resolver, Stopwatch stopwatch, long cacheTtlNanos) {
200202
this.resolver = resolver;
201203
this.stopwatch = Preconditions.checkNotNull(stopwatch, "stopwatch");
202-
this.cacheTtlNanos = getNetworkAddressCacheTtlNanos();
204+
this.cacheTtlNanos = cacheTtlNanos;
203205
}
204206

205207
@Override
@@ -230,23 +232,6 @@ private boolean cacheRefreshRequired() {
230232
|| (cacheTtlNanos > 0 && stopwatch.elapsed(TimeUnit.NANOSECONDS) > cacheTtlNanos);
231233
}
232234

233-
/** Returns value of network address cache ttl property. */
234-
private static long getNetworkAddressCacheTtlNanos() {
235-
String cacheTtlPropertyValue = System.getProperty(NETWORKADDRESS_CACHE_TTL_PROPERTY);
236-
long cacheTtl = DEFAULT_NETWORK_CACHE_TTL_SECONDS;
237-
if (cacheTtlPropertyValue != null) {
238-
try {
239-
cacheTtl = Long.parseLong(cacheTtlPropertyValue);
240-
} catch (NumberFormatException e) {
241-
logger.log(
242-
Level.WARNING,
243-
"Property({0}) valid is not valid number format({1}), fall back to default({2})",
244-
new Object[] {NETWORKADDRESS_CACHE_TTL_PROPERTY, cacheTtlPropertyValue, cacheTtl});
245-
}
246-
}
247-
return cacheTtl > 0 ? TimeUnit.SECONDS.toNanos(cacheTtl) : cacheTtl;
248-
}
249-
250235
@VisibleForTesting
251236
void resolveInternal(Listener savedListener) {
252237
InetSocketAddress destination =
@@ -483,6 +468,31 @@ private static final List<String> getHostnamesFromChoice(
483468
ServiceConfigUtil.getList(serviceConfigChoice, SERVICE_CONFIG_CHOICE_CLIENT_HOSTNAME_KEY));
484469
}
485470

471+
/**
472+
* Returns value of network address cache ttl property if not Android environment. For android,
473+
* DnsNameResolver does not cache the dns lookup result.
474+
*/
475+
private static long getNetworkAddressCacheTtlNanos(boolean isAndroid) {
476+
if (isAndroid) {
477+
// on Android, ignore dns cache.
478+
return 0;
479+
}
480+
481+
String cacheTtlPropertyValue = System.getProperty(NETWORKADDRESS_CACHE_TTL_PROPERTY);
482+
long cacheTtl = DEFAULT_NETWORK_CACHE_TTL_SECONDS;
483+
if (cacheTtlPropertyValue != null) {
484+
try {
485+
cacheTtl = Long.parseLong(cacheTtlPropertyValue);
486+
} catch (NumberFormatException e) {
487+
logger.log(
488+
Level.WARNING,
489+
"Property({0}) valid is not valid number format({1}), fall back to default({2})",
490+
new Object[] {NETWORKADDRESS_CACHE_TTL_PROPERTY, cacheTtlPropertyValue, cacheTtl});
491+
}
492+
}
493+
return cacheTtl > 0 ? TimeUnit.SECONDS.toNanos(cacheTtl) : cacheTtl;
494+
}
495+
486496
/**
487497
* Determines if a given Service Config choice applies, and if so, returns it.
488498
*

core/src/main/java/io/grpc/internal/DnsNameResolverProvider.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import com.google.common.base.Preconditions;
2020
import com.google.common.base.Stopwatch;
2121
import io.grpc.Attributes;
22+
import io.grpc.InternalServiceProviders;
2223
import io.grpc.NameResolverProvider;
2324
import java.net.URI;
2425

@@ -54,7 +55,8 @@ public DnsNameResolver newNameResolver(URI targetUri, Attributes params) {
5455
params,
5556
GrpcUtil.SHARED_CHANNEL_EXECUTOR,
5657
GrpcUtil.getDefaultProxyDetector(),
57-
Stopwatch.createUnstarted());
58+
Stopwatch.createUnstarted(),
59+
InternalServiceProviders.isAndroid(getClass().getClassLoader()));
5860
} else {
5961
return null;
6062
}

core/src/test/java/io/grpc/internal/DnsNameResolverTest.java

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -118,18 +118,34 @@ private DnsNameResolver newResolver(String name, int port) {
118118
return newResolver(name, port, GrpcUtil.NOOP_PROXY_DETECTOR, Stopwatch.createUnstarted());
119119
}
120120

121+
private DnsNameResolver newResolver(String name, int port, boolean isAndroid) {
122+
return
123+
newResolver(
124+
name, port, GrpcUtil.NOOP_PROXY_DETECTOR, Stopwatch.createUnstarted(), isAndroid);
125+
}
126+
121127
private DnsNameResolver newResolver(
122128
String name,
123129
int port,
124130
ProxyDetector proxyDetector,
125131
Stopwatch stopwatch) {
132+
return newResolver(name, port, proxyDetector, stopwatch, false);
133+
}
134+
135+
private DnsNameResolver newResolver(
136+
String name,
137+
int port,
138+
ProxyDetector proxyDetector,
139+
Stopwatch stopwatch,
140+
boolean isAndroid) {
126141
DnsNameResolver dnsResolver = new DnsNameResolver(
127142
null,
128143
name,
129144
Attributes.newBuilder().set(NameResolver.Factory.PARAMS_DEFAULT_PORT, port).build(),
130145
fakeExecutorResource,
131146
proxyDetector,
132-
stopwatch);
147+
stopwatch,
148+
isAndroid);
133149
return dnsResolver;
134150
}
135151

@@ -200,14 +216,30 @@ public void invalidDnsName_containsUnderscore() {
200216
}
201217
}
202218

219+
@Test
220+
public void resolve_androidIgnoresPropertyValue() throws Exception {
221+
System.setProperty(DnsNameResolver.NETWORKADDRESS_CACHE_TTL_PROPERTY, Long.toString(2));
222+
resolveNeverCache(true);
223+
}
224+
225+
@Test
226+
public void resolve_androidIgnoresPropertyValueCacheForever() throws Exception {
227+
System.setProperty(DnsNameResolver.NETWORKADDRESS_CACHE_TTL_PROPERTY, Long.toString(-1));
228+
resolveNeverCache(true);
229+
}
230+
203231
@Test
204232
public void resolve_neverCache() throws Exception {
205233
System.setProperty(DnsNameResolver.NETWORKADDRESS_CACHE_TTL_PROPERTY, "0");
234+
resolveNeverCache(false);
235+
}
236+
237+
private void resolveNeverCache(boolean isAndroid) throws Exception {
206238
final List<InetAddress> answer1 = createAddressList(2);
207239
final List<InetAddress> answer2 = createAddressList(1);
208240
String name = "foo.googleapis.com";
209241

210-
DnsNameResolver resolver = newResolver(name, 81);
242+
DnsNameResolver resolver = newResolver(name, 81, isAndroid);
211243
AddressResolver mockResolver = mock(AddressResolver.class);
212244
when(mockResolver.resolveAddress(Matchers.anyString())).thenReturn(answer1).thenReturn(answer2);
213245
resolver.setAddressResolver(mockResolver);
@@ -241,7 +273,7 @@ public List<InetAddress> resolveAddress(String host) throws Exception {
241273
}
242274
});
243275

244-
new DnsNameResolver.Resolve(nrf, Stopwatch.createUnstarted()).resolveInternal(mockListener);
276+
new DnsNameResolver.Resolve(nrf, Stopwatch.createUnstarted(), 0).resolveInternal(mockListener);
245277

246278
ArgumentCaptor<Status> ac = ArgumentCaptor.forClass(Status.class);
247279
verify(mockListener).onError(ac.capture());

0 commit comments

Comments
 (0)