Search code examples
androidandroid-serviceokhttpsocket-timeout-exception

Network connection can stop in power saving mode, with java.net.SocketTimeoutException


When investigating one of the reports I got from users, I noticed that when the Power-Saving mode is enabled (Nexus 4, Android 5.1.1), the background service that downloads data gets a connection exception after some time. This happens when the device screen is off. I didn't test it with the screen on.

There are hold both PowerManager.PARTIAL_WAKE_LOCK and WifiManager.WIFI_MODE_FULL during the operations. I am using OkHttp for connections and the Wifi was turned on all the time.

What else can I do except holding both locks (wifi and partial_wake) in such situation? This is critical for the user to have those connections working.

Stacktrace of errors - however it is not really relevant here I think:

W/System.err: java.util.concurrent.ExecutionException:   java.net.ConnectException: Failed to connect to *************
W/System.err:     at java.util.concurrent.FutureTask.report(FutureTask.java:93)
W/System.err:     at java.util.concurrent.FutureTask.get(FutureTask.java:177)
....
W/System.err: Caused by: java.net.ConnectException: Failed to connect to **************
W/System.err:     at okhttp3.internal.io.RealConnection.connectSocket(RealConnection.java:139)
W/System.err:     at okhttp3.internal.io.RealConnection.connect(RealConnection.java:108)
W/System.err:     at okhttp3.internal.http.StreamAllocation.findConnection(StreamAllocation.java:188)
W/System.err:     at okhttp3.internal.http.StreamAllocation.findHealthyConnection(StreamAllocation.java:127)
W/System.err:     at okhttp3.internal.http.StreamAllocation.newStream(StreamAllocation.java:97)
W/System.err:     at okhttp3.internal.http.HttpEngine.connect(HttpEngine.java:289)
W/System.err:     at okhttp3.internal.http.HttpEngine.sendRequest(HttpEngine.java:241)
W/System.err:     at okhttp3.RealCall.getResponse(RealCall.java:240)
W/System.err:     at okhttp3.RealCall$ApplicationInterceptorChain.proceed(RealCall.java:198)
W/System.err:     at okhttp3.RealCall.getResponseWithInterceptorChain(RealCall.java:160)
W/System.err:     at okhttp3.RealCall.execute(RealCall.java:57)
...

Another way this can happen is with different versions of java.net.SocketTimeoutException , like this:

Exception: java.net.SocketTimeoutException: timeout
    at okhttp3.internal.http2.Http2Stream$StreamTimeout.newTimeoutException(Http2Stream.kt:675)
    at okhttp3.internal.http2.Http2Stream$StreamTimeout.exitAndThrowIfTimedOut(Http2Stream.kt:684)
    at okhttp3.internal.http2.Http2Stream.takeHeaders(Http2Stream.kt:143)
    at okhttp3.internal.http2.Http2ExchangeCodec.readResponseHeaders(Http2ExchangeCodec.kt:96)
    at okhttp3.internal.connection.Exchange.readResponseHeaders(Exchange.kt:106)
    at okhttp3.internal.http.CallServerInterceptor.intercept(CallServerInterceptor.kt:79)
    ...

or

Exception: java.net.SocketTimeoutException: failed to connect to website.com/XX.XX.XX.XXX (port 443) from /XXX.XXX.X.XX (port 58522) after 10000ms
    at libcore.io.IoBridge.connectErrno(IoBridge.java:235)
    at libcore.io.IoBridge.connect(IoBridge.java:179)
    at java.net.PlainSocketImpl.socketConnect(PlainSocketImpl.java:142)
    at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:390)
    at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:230)
    at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:212)
    at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:436)
    at java.net.Socket.connect(Socket.java:646)
    ....

or

Exception: java.net.SocketTimeoutException: Read timed out
    at java.net.SocketInputStream.socketRead0(SocketInputStream.java)
    at java.net.SocketInputStream.socketRead(SocketInputStream.java:118)
    at java.net.SocketInputStream.read(SocketInputStream.java:173)
    at java.net.SocketInputStream.read(SocketInputStream.java:143)
    at com.android.org.conscrypt.ConscryptEngineSocket$SSLInputStream.readFromSocket(ConscryptEngineSocket.java:945)
    ...

Edit: This happens with both WiFi and mobile-data connections. I also confirmed that wake locks are being held and everything is working as supposed, except the fact that no connection is possible. When the screen is on, everything works fine, but keeping screen on is not an acceptable solution here.


Solution

  • As you mentioned - this is likely because of Power Saving mode. In this mode system tries to minimize the number of wake calls and stops all the processes it considers unnecessary.

    Luckily Android foresees a way to deal with this - it's called Foreground Service. If Service is started as Foreground it will be treated as User activity and will not be a subject for removal when low on resources.

    You may consider moving all critical activities to Foreground and leave all supportive modules (for example, analytics) in Background services