I'm using Retrofit's coroutines adapter and I see that, if the network call fails because the URL is incorrect, the try/catch block will catch it, but if I remove the Internet permission so that we get a SecurityException, the app crashes instead.
This is the code handling the response from retrofit:
override suspend fun execute(): Result<IpAddress> = try {
val result = dataRepository.getIpAddress().await()
Result.Success(result)
} catch (throwable: Throwable) {
if (throwable is JobCancellationException) {
throw throwable
}
Result.Error(throwable)
}
The repository is simply
override suspend fun getIpAddress(): Deferred<IpAddress> = dataService.getIpAddress()
with
interface DataService {
@GET("/?format=json")
fun getIpAddress(): Deferred<IpAddress>
}
Why do exceptions like UnknownHostException get trapped but SecurityException crashes the app?
This is the crash log
09-09 12:27:25.467 12465 12495 E AndroidRuntime: FATAL EXCEPTION: OkHttp Dispatcher
09-09 12:27:25.467 12465 12495 E AndroidRuntime: Process: com.example.coroutines, PID: 12465
09-09 12:27:25.467 12465 12495 E AndroidRuntime: java.lang.SecurityException: Permission denied (missing INTERNET permission?)
09-09 12:27:25.467 12465 12495 E AndroidRuntime: at java.net.Inet6AddressImpl.lookupHostByName(Inet6AddressImpl.java:151)
09-09 12:27:25.467 12465 12495 E AndroidRuntime: at java.net.Inet6AddressImpl.lookupAllHostAddr(Inet6AddressImpl.java:105)
09-09 12:27:25.467 12465 12495 E AndroidRuntime: at java.net.InetAddress.getAllByName(InetAddress.java:1154)
09-09 12:27:25.467 12465 12495 E AndroidRuntime: at okhttp3.Dns$1.lookup(Dns.java:40)
09-09 12:27:25.467 12465 12495 E AndroidRuntime: at okhttp3.internal.connection.RouteSelector.resetNextInetSocketAddress(RouteSelector.java:185)
09-09 12:27:25.467 12465 12495 E AndroidRuntime: at okhttp3.internal.connection.RouteSelector.nextProxy(RouteSelector.java:149)
09-09 12:27:25.467 12465 12495 E AndroidRuntime: at okhttp3.internal.connection.RouteSelector.next(RouteSelector.java:84)
09-09 12:27:25.467 12465 12495 E AndroidRuntime: at okhttp3.internal.connection.StreamAllocation.findConnection(StreamAllocation.java:214)
09-09 12:27:25.467 12465 12495 E AndroidRuntime: at okhttp3.internal.connection.StreamAllocation.findHealthyConnection(StreamAllocation.java:135)
09-09 12:27:25.467 12465 12495 E AndroidRuntime: at okhttp3.internal.connection.StreamAllocation.newStream(StreamAllocation.java:114)
09-09 12:27:25.467 12465 12495 E AndroidRuntime: at okhttp3.internal.connection.ConnectInterceptor.intercept(ConnectInterceptor.java:42)
09-09 12:27:25.467 12465 12495 E AndroidRuntime: at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147)
09-09 12:27:25.467 12465 12495 E AndroidRuntime: at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:121)
09-09 12:27:25.467 12465 12495 E AndroidRuntime: at okhttp3.internal.cache.CacheInterceptor.intercept(CacheInterceptor.java:93)
09-09 12:27:25.467 12465 12495 E AndroidRuntime: at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147)
09-09 12:27:25.467 12465 12495 E AndroidRuntime: at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:121)
09-09 12:27:25.467 12465 12495 E AndroidRuntime: at okhttp3.internal.http.BridgeInterceptor.intercept(BridgeInterceptor.java:93)
09-09 12:27:25.467 12465 12495 E AndroidRuntime: at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147)
09-09 12:27:25.467 12465 12495 E AndroidRuntime: at okhttp3.internal.http.RetryAndFollowUpInterceptor.intercept(RetryAndFollowUpInterceptor.java:126)
09-09 12:27:25.467 12465 12495 E AndroidRuntime: at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147)
09-09 12:27:25.467 12465 12495 E AndroidRuntime: at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:121)
09-09 12:27:25.467 12465 12495 E AndroidRuntime: at okhttp3.RealCall.getResponseWithInterceptorChain(RealCall.java:200)
09-09 12:27:25.467 12465 12495 E AndroidRuntime: at okhttp3.RealCall$AsyncCall.execute(RealCall.java:147)
09-09 12:27:25.467 12465 12495 E AndroidRuntime: at okhttp3.internal.NamedRunnable.run(NamedRunnable.java:32)
09-09 12:27:25.467 12465 12495 E AndroidRuntime: at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
09-09 12:27:25.467 12465 12495 E AndroidRuntime: at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
09-09 12:27:25.467 12465 12495 E AndroidRuntime: at java.lang.Thread.run(Thread.java:764)
09-09 12:27:25.467 12465 12495 E AndroidRuntime: Caused by: android.system.GaiException: android_getaddrinfo failed: EAI_NODATA (No address associated with hostname)
09-09 12:27:25.467 12465 12495 E AndroidRuntime: at libcore.io.Linux.android_getaddrinfo(Native Method)
09-09 12:27:25.467 12465 12495 E AndroidRuntime: at libcore.io.BlockGuardOs.android_getaddrinfo(BlockGuardOs.java:172)
09-09 12:27:25.467 12465 12495 E AndroidRuntime: at java.net.Inet6AddressImpl.lookupHostByName(Inet6AddressImpl.java:137)
09-09 12:27:25.467 12465 12495 E AndroidRuntime: ... 26 more
09-09 12:27:25.467 12465 12495 E AndroidRuntime: Caused by: android.system.ErrnoException: android_getaddrinfo failed: EACCES (Permission denied)
09-09 12:27:25.467 12465 12495 E AndroidRuntime: ... 29 more
Because in one case Retrofit catches it internally and passes it back as an error, knowing you may wish to handle it. In the other case it doesn't catch it and it crashes the app. There's no way to change this short of forking Retrofit as it happens on their internal thread, just keep the internet permission in there.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With