Skip to content

Commit bff6301

Browse files
committed
networking: Fix requests failing when turning network off and on facebook#19709.
This bug is probably actually a bug in OkHttp: square/okhttp#4079 Both issues linked above contain extensive details about the issue, its likely origins and how to reproduce it. A short summary of the issue and the fix in this commit: On Android, disconnecting from the network somehow corrupts the idle connections in okhttp clients. New requests made over these clients fail. This commit works around that bug by clearing the idle connection pool of each client when Android disconnects from the network.
1 parent 370bcff commit bff6301

File tree

2 files changed

+66
-1
lines changed

2 files changed

+66
-1
lines changed

ReactAndroid/src/main/java/com/facebook/react/ReactActivity.java

+8
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,18 @@
99

1010
import javax.annotation.Nullable;
1111

12+
import android.Manifest;
1213
import android.app.Activity;
1314
import android.content.Intent;
15+
import android.content.pm.PackageManager;
1416
import android.os.Bundle;
17+
import android.support.v4.content.ContextCompat;
1518
import android.view.KeyEvent;
1619

1720
import com.facebook.react.modules.core.DefaultHardwareBackBtnHandler;
1821
import com.facebook.react.modules.core.PermissionAwareActivity;
1922
import com.facebook.react.modules.core.PermissionListener;
23+
import com.facebook.react.modules.network.OkHttpClientProvider;
2024

2125
/**
2226
* Base Activity for React Native applications.
@@ -50,6 +54,10 @@ protected ReactActivityDelegate createReactActivityDelegate() {
5054
protected void onCreate(Bundle savedInstanceState) {
5155
super.onCreate(savedInstanceState);
5256
mDelegate.onCreate(savedInstanceState);
57+
if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_NETWORK_STATE)
58+
== PackageManager.PERMISSION_GRANTED) {
59+
OkHttpClientProvider.addNetworkListenerToEvictIdleConnectionsOnNetworkChange(getApplicationContext());
60+
}
5361
}
5462

5563
@Override

ReactAndroid/src/main/java/com/facebook/react/modules/network/OkHttpClientProvider.java

+58-1
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,25 @@
77

88
package com.facebook.react.modules.network;
99

10+
import android.content.BroadcastReceiver;
11+
import android.content.Context;
12+
import android.content.Intent;
13+
import android.content.IntentFilter;
14+
import android.net.ConnectivityManager;
15+
import android.net.NetworkInfo;
16+
import android.os.AsyncTask;
1017
import android.os.Build;
18+
import android.os.Bundle;
1119

1220
import com.facebook.common.logging.FLog;
21+
import com.facebook.react.ReactActivity;
22+
import com.facebook.react.bridge.ReactApplicationContext;
1323

1424
import java.util.ArrayList;
25+
import java.util.Collections;
1526
import java.util.List;
27+
import java.util.Set;
28+
import java.util.WeakHashMap;
1629
import java.util.concurrent.TimeUnit;
1730

1831
import javax.annotation.Nullable;
@@ -33,6 +46,9 @@ public class OkHttpClientProvider {
3346
// User-provided OkHttpClient factory
3447
private static @Nullable OkHttpClientFactory sFactory;
3548

49+
private final static Set<OkHttpClient> sClients = Collections.newSetFromMap(
50+
new WeakHashMap<OkHttpClient, Boolean>());
51+
3652
public static void setOkHttpClientFactory(OkHttpClientFactory factory) {
3753
sFactory = factory;
3854
}
@@ -43,6 +59,38 @@ public static OkHttpClient getOkHttpClient() {
4359
}
4460
return sClient;
4561
}
62+
63+
private static class EvictIdleConnectionsTask extends AsyncTask {
64+
@Override
65+
protected Object doInBackground(Object[] objects) {
66+
for (OkHttpClient client: sClients) {
67+
client.connectionPool().evictAll();
68+
}
69+
return null;
70+
}
71+
}
72+
73+
/*
74+
See https://github.com/facebook/react-native/issues/19709 for context.
75+
We know that idle connections get corrupted when the connectivity state
76+
changes to disconnected, but the debugging of this issue hasn't been
77+
exhaustive and it's possible that other changes in connectivity also
78+
corrupt idle connections. `CONNECTIVITY_ACTION`s occur infrequently
79+
enough to go safe and evict all idle connections on every such action.
80+
*/
81+
public static void addNetworkListenerToEvictIdleConnectionsOnNetworkChange(Context context) {
82+
final BroadcastReceiver br = new BroadcastReceiver() {
83+
@Override
84+
public void onReceive(Context context, Intent intent) {
85+
if (intent.getAction().equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
86+
new EvictIdleConnectionsTask().execute();
87+
}
88+
}
89+
};
90+
final IntentFilter intentFilter = new IntentFilter();
91+
intentFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
92+
context.registerReceiver(br, intentFilter);
93+
}
4694

4795
// okhttp3 OkHttpClient is immutable
4896
// This allows app to init an OkHttpClient with custom settings.
@@ -51,10 +99,15 @@ public static void replaceOkHttpClient(OkHttpClient client) {
5199
}
52100

53101
public static OkHttpClient createClient() {
102+
OkHttpClient client;
54103
if (sFactory != null) {
55104
return sFactory.createNewNetworkModuleClient();
56105
}
57-
return createClientBuilder().build();
106+
else {
107+
client = createClientBuilder().build();
108+
registerClientToEvictIdleConnectionsOnNetworkChange(client);
109+
return client;
110+
}
58111
}
59112

60113
public static OkHttpClient.Builder createClientBuilder() {
@@ -68,6 +121,10 @@ public static OkHttpClient.Builder createClientBuilder() {
68121
return enableTls12OnPreLollipop(client);
69122
}
70123

124+
public static void registerClientToEvictIdleConnectionsOnNetworkChange(OkHttpClient client) {
125+
sClients.add(client);
126+
}
127+
71128
/*
72129
On Android 4.1-4.4 (API level 16 to 19) TLS 1.1 and 1.2 are
73130
available but not enabled by default. The following method

0 commit comments

Comments
 (0)