Fix issues with NetworkMonitor singleton when used by multiple clients.

When you create multiple "PeerConnectionFactory"s, they end up using
the same NetworkMonitor singleton. But the second one's
"AndroidNetworkMonitor" class (in C++) wasn't getting the expected
network list update, and as a result it wasn't binding sockets to
networks successfully, acting as if the networks didn't exist.

The solution is just to move "updateActiveNetworkList" to
"startMonitoring". This CL also does some other minor
cleanup/refactoring, and fixes a more corner-casey issue where, if the
first PeerConnection is destroyed, the second one would stop receiving
network updates.

BUG=webrtc:7946

Review-Url: https://codereview.webrtc.org/2990693002
Cr-Commit-Position: refs/heads/master@{#19156}
This commit is contained in:
deadbeef
2017-07-26 11:56:49 -07:00
committed by Commit Bot
parent 8e245561f2
commit 54c721541d
3 changed files with 48 additions and 53 deletions

View File

@ -70,36 +70,40 @@ public class NetworkMonitor {
return instance; return instance;
} }
/**
* Enables auto detection of the current network state based on notifications from the system.
* Note that passing true here requires the embedding app have the platform ACCESS_NETWORK_STATE
* permission.
*
* @param shouldAutoDetect true if the NetworkMonitor should listen for system changes in
* network connectivity.
*/
public static void setAutoDetectConnectivityState(boolean shouldAutoDetect) {
getInstance().setAutoDetectConnectivityStateInternal(shouldAutoDetect);
}
private static void assertIsTrue(boolean condition) { private static void assertIsTrue(boolean condition) {
if (!condition) { if (!condition) {
throw new AssertionError("Expected to be true"); throw new AssertionError("Expected to be true");
} }
} }
// Called by the native code. /**
* Called by the native code.
*
* Enables auto detection of the current network state based on notifications
* from the system. Note that this requires the embedding app have the
* platform ACCESS_NETWORK_STATE permission.
*/
private void startMonitoring(long nativeObserver) { private void startMonitoring(long nativeObserver) {
Logging.d(TAG, "Start monitoring from native observer " + nativeObserver); Logging.d(TAG, "Start monitoring from native observer " + nativeObserver);
nativeNetworkObservers.add(nativeObserver); nativeNetworkObservers.add(nativeObserver);
setAutoDetectConnectivityStateInternal(true); if (autoDetector == null) {
createAutoDetector();
}
// The observers expect a network list update after they call startMonitoring.
final NetworkMonitorAutoDetect.NetworkState networkState =
autoDetector.getCurrentNetworkState();
updateCurrentConnectionType(NetworkMonitorAutoDetect.getConnectionType(networkState));
updateObserverActiveNetworkList(nativeObserver);
} }
// Called by the native code. // Called by the native code.
private void stopMonitoring(long nativeObserver) { private void stopMonitoring(long nativeObserver) {
Logging.d(TAG, "Stop monitoring from native observer " + nativeObserver); Logging.d(TAG, "Stop monitoring from native observer " + nativeObserver);
setAutoDetectConnectivityStateInternal(false);
nativeNetworkObservers.remove(nativeObserver); nativeNetworkObservers.remove(nativeObserver);
if (nativeNetworkObservers.isEmpty()) {
autoDetector.destroy();
autoDetector = null;
}
} }
// Called by the native code to determine if network binding is supported // Called by the native code to determine if network binding is supported
@ -121,19 +125,7 @@ public class NetworkMonitor {
return autoDetector == null ? INVALID_NET_ID : autoDetector.getDefaultNetId(); return autoDetector == null ? INVALID_NET_ID : autoDetector.getDefaultNetId();
} }
private void destroyAutoDetector() { private void createAutoDetector() {
if (autoDetector != null) {
autoDetector.destroy();
autoDetector = null;
}
}
private void setAutoDetectConnectivityStateInternal(boolean shouldAutoDetect) {
if (!shouldAutoDetect) {
destroyAutoDetector();
return;
}
if (autoDetector == null) {
autoDetector = new NetworkMonitorAutoDetect(new NetworkMonitorAutoDetect.Observer() { autoDetector = new NetworkMonitorAutoDetect(new NetworkMonitorAutoDetect.Observer() {
@Override @Override
@ -151,11 +143,6 @@ public class NetworkMonitor {
notifyObserversOfNetworkDisconnect(networkHandle); notifyObserversOfNetworkDisconnect(networkHandle);
} }
}, ContextUtils.getApplicationContext()); }, ContextUtils.getApplicationContext());
final NetworkMonitorAutoDetect.NetworkState networkState =
autoDetector.getCurrentNetworkState();
updateCurrentConnectionType(NetworkMonitorAutoDetect.getConnectionType(networkState));
updateActiveNetworkList();
}
} }
private void updateCurrentConnectionType(ConnectionType newConnectionType) { private void updateCurrentConnectionType(ConnectionType newConnectionType) {
@ -187,7 +174,7 @@ public class NetworkMonitor {
} }
} }
private void updateActiveNetworkList() { private void updateObserverActiveNetworkList(long nativeObserver) {
List<NetworkInformation> networkInfoList = autoDetector.getActiveNetworkList(); List<NetworkInformation> networkInfoList = autoDetector.getActiveNetworkList();
if (networkInfoList == null || networkInfoList.size() == 0) { if (networkInfoList == null || networkInfoList.size() == 0) {
return; return;
@ -195,10 +182,8 @@ public class NetworkMonitor {
NetworkInformation[] networkInfos = new NetworkInformation[networkInfoList.size()]; NetworkInformation[] networkInfos = new NetworkInformation[networkInfoList.size()];
networkInfos = networkInfoList.toArray(networkInfos); networkInfos = networkInfoList.toArray(networkInfos);
for (long nativeObserver : nativeNetworkObservers) {
nativeNotifyOfActiveNetworkList(nativeObserver, networkInfos); nativeNotifyOfActiveNetworkList(nativeObserver, networkInfos);
} }
}
/** /**
* Adds an observer for any connection type changes. * Adds an observer for any connection type changes.
@ -242,7 +227,12 @@ public class NetworkMonitor {
} }
// For testing only. // For testing only.
public static NetworkMonitorAutoDetect getAutoDetectorForTest() { static void createAutoDetectorForTest() {
getInstance().createAutoDetector();
}
// For testing only.
static NetworkMonitorAutoDetect getAutoDetectorForTest() {
return getInstance().autoDetector; return getInstance().autoDetector;
} }
} }

View File

@ -41,6 +41,10 @@ import org.junit.runner.RunWith;
/** /**
* Tests for org.webrtc.NetworkMonitor. * Tests for org.webrtc.NetworkMonitor.
*
* TODO(deadbeef): These tests don't cover the interaction between
* NetworkManager.java and androidnetworkmonitor_jni.cc, which is how this
* class is used in practice in WebRTC.
*/ */
@SuppressLint("NewApi") @SuppressLint("NewApi")
@RunWith(BaseJUnit4ClassRunner.class) @RunWith(BaseJUnit4ClassRunner.class)
@ -162,7 +166,7 @@ public class NetworkMonitorTest {
private void createTestMonitor() { private void createTestMonitor() {
Context context = InstrumentationRegistry.getTargetContext(); Context context = InstrumentationRegistry.getTargetContext();
NetworkMonitor.resetInstanceForTests(); NetworkMonitor.resetInstanceForTests();
NetworkMonitor.setAutoDetectConnectivityState(true); NetworkMonitor.createAutoDetectorForTest();
receiver = NetworkMonitor.getAutoDetectorForTest(); receiver = NetworkMonitor.getAutoDetectorForTest();
assertNotNull(receiver); assertNotNull(receiver);

View File

@ -65,6 +65,7 @@ class AndroidNetworkMonitor : public rtc::NetworkMonitorBase,
rtc::AdapterType GetAdapterType(const std::string& if_name) override; rtc::AdapterType GetAdapterType(const std::string& if_name) override;
void OnNetworkConnected(const NetworkInformation& network_info); void OnNetworkConnected(const NetworkInformation& network_info);
void OnNetworkDisconnected(NetworkHandle network_handle); void OnNetworkDisconnected(NetworkHandle network_handle);
// Always expected to be called on the network thread.
void SetNetworkInfos(const std::vector<NetworkInformation>& network_infos); void SetNetworkInfos(const std::vector<NetworkInformation>& network_infos);
private: private: