2

Seeing the following stack on old versions of Android (4.3 and earlier):

Caused by: java.lang.IncompatibleClassChangeError: interface not implemented
at okhttp3.internal.Util.closeQuietly(Util.java:100)
at okhttp3.internal.connection.StreamAllocation.streamFailed(StreamAllocation.java:332)
at okhttp3.internal.http.RetryAndFollowUpInterceptor.recover(RetryAndFollowUpInterceptor.java:209)
at okhttp3.internal.http.RetryAndFollowUpInterceptor.intercept(RetryAndFollowUpInterceptor.java:132)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:67)
at okhttp3.logging.HttpLoggingInterceptor.intercept(HttpLoggingInterceptor.java:212)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:67)
at okhttp3.RealCall.getResponseWithInterceptorChain(RealCall.java:179)
at okhttp3.RealCall.execute(RealCall.java:63)

This seems to suggest an incompatibility between okhttp and Java 6, where java.net.Socket doesn't implement Closeable.

And the problem appears to occur primarily as a result of a failed stream. It was difficult to reproduce until we started calling this php page (borrowed from https://stackoverflow.com/a/141026/315702), which forces a stream failure on the client side:

<?php
ob_end_clean();
header("Connection: close");
ignore_user_abort(true); // just to be safe
ob_start();
echo('Text the user will see');
$size = ob_get_length();
header("Content-Length: $size");
ob_end_flush(); // Strange behaviour, will not work
flush(); // Unless both are called !
sleep(30);
echo('Text user will never see');
?>
Community
  • 1
  • 1
Mark McClelland
  • 4,980
  • 4
  • 35
  • 48

1 Answers1

3

This appears to be a bug with the current okhttp 3.6.0-SNAPSHOT build. I filed a bug report on the okhttp github site. The exception is thrown when the connection closes unexpectedly. [Update: the bug was quickly fixed by replacing Closeable with Socket for backward compatibility with Java 6 in this pull request.]

In our case, the real heart of the problem was that we didn't mean to use okhttp 3.6.0-SNAPSHOT in the first place. In our build.gradle, we specified 3.4.1. It turned out one of our third-party libraries had a dependency on okhttp:+, which we discovered via the following gradle command:

./gradlew -q :app:dependencyInsight --dependency okhttp --configuration compile

Because of this, we were pulling in whatever happens to be the latest version of okhttp. In our case, the culprit library was the okhttp extension to exoplayer. By excluding the unwanted module dependency on okhttp:+, we were able to avoid loading 3.6.0-SNAPSHOT:

compile('com.google.android.exoplayer:extension-okhttp:r2.0.4') {
    exclude module: 'okhttp'
}
Mark McClelland
  • 4,980
  • 4
  • 35
  • 48
  • 2
    FWIW, it looks like they stopped using `+` by the time of `r2.1.1`. BTW, nice analysis! – CommonsWare Jan 20 '17 at 20:09
  • It took the collective IQ of several devs to get to the bottom of this one. And thanks -- I was going to check on whether the `+` dependency had been fixed! – Mark McClelland Jan 20 '17 at 20:12