Skip to content

Commit 27a1c90

Browse files
authored
android: initialize listener with isConnected=false (grpc#4606)
1 parent 8c52e13 commit 27a1c90

File tree

2 files changed

+23
-27
lines changed

2 files changed

+23
-27
lines changed

android/src/main/java/io/grpc/android/AndroidChannelBuilder.java

Lines changed: 15 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -187,37 +187,26 @@ static final class AndroidChannel extends ManagedChannel {
187187
if (context != null) {
188188
connectivityManager =
189189
(ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
190-
configureNetworkMonitoring();
190+
try {
191+
configureNetworkMonitoring();
192+
} catch (SecurityException e) {
193+
Log.w(
194+
LOG_TAG,
195+
"Failed to configure network monitoring. Does app have ACCESS_NETWORK_STATE"
196+
+ " permission?",
197+
e);
198+
}
191199
} else {
192200
connectivityManager = null;
193201
}
194202
}
195203

196204
@GuardedBy("lock")
197205
private void configureNetworkMonitoring() {
198-
// Eagerly check current network state to verify app has required permissions
199-
NetworkInfo currentNetwork;
200-
try {
201-
currentNetwork = connectivityManager.getActiveNetworkInfo();
202-
} catch (SecurityException e) {
203-
Log.w(
204-
LOG_TAG,
205-
"Failed to configure network monitoring. Does app have ACCESS_NETWORK_STATE"
206-
+ " permission?",
207-
e);
208-
return;
209-
}
210-
211206
// Android N added the registerDefaultNetworkCallback API to listen to changes in the device's
212207
// default network. For earlier Android API levels, use the BroadcastReceiver API.
213208
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && connectivityManager != null) {
214-
// The connection status may change before registration of the listener is complete, but
215-
// this will at worst result in invoking resetConnectBackoff() instead of enterIdle() (or
216-
// vice versa) on the first network change.
217-
boolean isConnected = currentNetwork != null && currentNetwork.isConnected();
218-
219-
final DefaultNetworkCallback defaultNetworkCallback =
220-
new DefaultNetworkCallback(isConnected);
209+
final DefaultNetworkCallback defaultNetworkCallback = new DefaultNetworkCallback();
221210
connectivityManager.registerDefaultNetworkCallback(defaultNetworkCallback);
222211
unregisterRunnable =
223212
new Runnable() {
@@ -313,12 +302,13 @@ public void enterIdle() {
313302
/** Respond to changes in the default network. Only used on API levels 24+. */
314303
@TargetApi(Build.VERSION_CODES.N)
315304
private class DefaultNetworkCallback extends ConnectivityManager.NetworkCallback {
305+
// Registering a listener may immediate invoke onAvailable/onLost: the API docs do not specify
306+
// if the methods are always invoked once, then again on any change, or only on change. When
307+
// onAvailable() is invoked immediately without an actual network change, it's preferable to
308+
// (spuriously) resetConnectBackoff() rather than enterIdle(), as the former is a no-op if the
309+
// channel has already moved to CONNECTING.
316310
private boolean isConnected = false;
317311

318-
private DefaultNetworkCallback(boolean isConnected) {
319-
this.isConnected = isConnected;
320-
}
321-
322312
@Override
323313
public void onAvailable(Network network) {
324314
if (isConnected) {

android/src/test/java/io/grpc/android/AndroidChannelBuilderTest.java

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -256,15 +256,21 @@ public void resetConnectBackoffAndEnterIdle_api24() {
256256

257257
@Test
258258
@Config(sdk = 24)
259-
public void newChannelWithConnection_entersIdleOnConnectionChange_api24() {
259+
public void newChannelWithConnection_entersIdleOnSecondConnectionChange_api24() {
260260
shadowConnectivityManager.setActiveNetworkInfo(MOBILE_CONNECTED);
261261
TestChannel delegateChannel = new TestChannel();
262262
ManagedChannel androidChannel =
263263
new AndroidChannelBuilder.AndroidChannel(
264264
delegateChannel, RuntimeEnvironment.application.getApplicationContext());
265265

266+
// The first onAvailable() may just signal that the device was connected when the callback is
267+
// registered, rather than indicating a changed network, so we do not enter idle.
266268
shadowConnectivityManager.setActiveNetworkInfo(WIFI_CONNECTED);
267-
assertThat(delegateChannel.resetCount).isEqualTo(0);
269+
assertThat(delegateChannel.resetCount).isEqualTo(1);
270+
assertThat(delegateChannel.enterIdleCount).isEqualTo(0);
271+
272+
shadowConnectivityManager.setActiveNetworkInfo(MOBILE_CONNECTED);
273+
assertThat(delegateChannel.resetCount).isEqualTo(1);
268274
assertThat(delegateChannel.enterIdleCount).isEqualTo(1);
269275

270276
androidChannel.shutdown();

0 commit comments

Comments
 (0)