Add interface for os/firmware to affect ICE selection.

This patch adds an interface for os/firmware to set a network
preference NOT_PREFERRED / NEUTRAL that can be picked up by
an IceController and used when selection ice candidate pair.

The patch exposes this using an Android Intent based interface.

BUG: webrtc:11825
Change-Id: Ic12b6bf704fde7f9c912020dd7bc79ccae4613ab
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/180883
Commit-Queue: Jonas Oreland <jonaso@webrtc.org>
Reviewed-by: Sami Kalliomäki <sakal@webrtc.org>
Reviewed-by: Harald Alvestrand <hta@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#31877}
This commit is contained in:
Jonas Oreland 2020-08-07 11:08:34 +02:00 committed by Commit Bot
parent c55e24acc7
commit f7721fb246
13 changed files with 406 additions and 187 deletions

View file

@ -1428,4 +1428,7 @@ if (is_android) {
"//third_party/android_deps:com_android_support_support_annotations_java",
]
}
java_cpp_enum("network_monitor_enums") {
sources = [ "network_monitor.h" ]
}
}

View file

@ -265,7 +265,9 @@ webrtc::MdnsResponderInterface* NetworkManager::GetMdnsResponder() const {
}
NetworkManagerBase::NetworkManagerBase()
: enumeration_permission_(NetworkManager::ENUMERATION_ALLOWED) {}
: enumeration_permission_(NetworkManager::ENUMERATION_ALLOWED),
signal_network_preference_change_(webrtc::field_trial::IsEnabled(
"WebRTC-SignalNetworkPreferenceChange")) {}
NetworkManagerBase::~NetworkManagerBase() {
for (const auto& kv : networks_map_) {
@ -382,6 +384,12 @@ void NetworkManagerBase::MergeNetworkList(const NetworkList& new_networks,
if (!existing_net->active()) {
*changed = true;
}
if (net->network_preference() != existing_net->network_preference()) {
existing_net->set_network_preference(net->network_preference());
if (signal_network_preference_change_) {
*changed = true;
}
}
RTC_DCHECK(net->active());
if (existing_net != net) {
delete net;
@ -536,6 +544,7 @@ void BasicNetworkManager::ConvertIfAddrs(struct ifaddrs* interfaces,
AdapterType adapter_type = ADAPTER_TYPE_UNKNOWN;
AdapterType vpn_underlying_adapter_type = ADAPTER_TYPE_UNKNOWN;
NetworkPreference network_preference = NetworkPreference::NEUTRAL;
if (cursor->ifa_flags & IFF_LOOPBACK) {
adapter_type = ADAPTER_TYPE_LOOPBACK;
} else {
@ -543,6 +552,8 @@ void BasicNetworkManager::ConvertIfAddrs(struct ifaddrs* interfaces,
// Otherwise, get the adapter type based on a few name matching rules.
if (network_monitor_) {
adapter_type = network_monitor_->GetAdapterType(cursor->ifa_name);
network_preference =
network_monitor_->GetNetworkPreference(cursor->ifa_name);
}
if (adapter_type == ADAPTER_TYPE_UNKNOWN) {
adapter_type = GetAdapterTypeFromName(cursor->ifa_name);
@ -568,6 +579,7 @@ void BasicNetworkManager::ConvertIfAddrs(struct ifaddrs* interfaces,
network->AddIP(ip);
network->set_ignored(IsIgnoredNetwork(*network));
network->set_underlying_type_for_vpn(vpn_underlying_adapter_type);
network->set_network_preference(network_preference);
if (include_ignored || !network->ignored()) {
current_networks[key] = network.get();
networks->push_back(network.release());
@ -580,6 +592,7 @@ void BasicNetworkManager::ConvertIfAddrs(struct ifaddrs* interfaces,
existing_network->set_underlying_type_for_vpn(
vpn_underlying_adapter_type);
}
existing_network->set_network_preference(network_preference);
}
}
}

View file

@ -215,6 +215,10 @@ class RTC_EXPORT NetworkManagerBase : public NetworkManager {
// network id 0 because we only compare the network ids in the old and the new
// best connections in the transport channel.
uint16_t next_available_network_id_ = 1;
// True if calling network_preference() with a changed value
// should result in firing the SignalNetworkChanged signal.
bool signal_network_preference_change_ = false;
};
// Basic implementation of the NetworkManager interface that gets list
@ -306,9 +310,13 @@ class RTC_EXPORT Network {
AdapterType type);
Network(const Network&);
~Network();
// This signal is fired whenever type() or underlying_type_for_vpn() changes.
sigslot::signal1<const Network*> SignalTypeChanged;
// This signal is fired whenever network preference changes.
sigslot::signal1<const Network*> SignalNetworkPreferenceChanged;
const DefaultLocalAddressProvider* default_local_address_provider() {
return default_local_address_provider_;
}
@ -453,6 +461,17 @@ class RTC_EXPORT Network {
}
}
// Property set by operating system/firmware that has information
// about connection strength to e.g WIFI router or CELL base towers.
NetworkPreference network_preference() const { return network_preference_; }
void set_network_preference(NetworkPreference val) {
if (network_preference_ == val) {
return;
}
network_preference_ = val;
SignalNetworkPreferenceChanged(this);
}
// Debugging description of this network
std::string ToString() const;
@ -473,6 +492,7 @@ class RTC_EXPORT Network {
bool active_ = true;
uint16_t id_ = 0;
bool use_differentiated_cellular_costs_ = false;
NetworkPreference network_preference_ = NetworkPreference::NEUTRAL;
friend class NetworkManager;
};

View file

@ -30,6 +30,14 @@ enum class NetworkBindingResult {
NETWORK_CHANGED = -4
};
// NetworkPreference property set by operating system/firmware that has
// information about connection strength to e.g WIFI router or CELL base towers.
// GENERATED_JAVA_ENUM_PACKAGE: org.webrtc
enum class NetworkPreference {
NEUTRAL = 0,
NOT_PREFERRED = -1,
};
class NetworkBinderInterface {
public:
// Binds a socket to the network that is attached to |address| so that all
@ -78,6 +86,8 @@ class NetworkMonitorInterface {
virtual AdapterType GetAdapterType(const std::string& interface_name) = 0;
virtual AdapterType GetVpnUnderlyingAdapterType(
const std::string& interface_name) = 0;
virtual NetworkPreference GetNetworkPreference(
const std::string& interface_name) = 0;
};
class NetworkMonitorBase : public NetworkMonitorInterface,

View file

@ -57,6 +57,9 @@ class FakeNetworkMonitor : public NetworkMonitorBase {
}
return ADAPTER_TYPE_UNKNOWN;
}
NetworkPreference GetNetworkPreference(const std::string& if_name) override {
return NetworkPreference::NEUTRAL;
}
private:
bool started_ = false;

View file

@ -276,12 +276,13 @@ if (is_android) {
"api/org/webrtc/NativeLibraryLoader.java",
"api/org/webrtc/NativePeerConnectionFactory.java",
"api/org/webrtc/NetEqFactoryFactory.java",
"api/org/webrtc/NetworkChangeDetector.java",
"api/org/webrtc/NetworkChangeDetectorFactory.java",
"api/org/webrtc/NetworkControllerFactoryFactory.java",
"api/org/webrtc/NetworkMonitor.java", # TODO(sakal): Break dependencies
# and move to base_java.
"api/org/webrtc/NetworkMonitorAutoDetect.java", # TODO(sakal): Break
# dependencies and move
# to base_java.
# TODO(sakal): Break dependencies and move to base_java.
"api/org/webrtc/NetworkMonitor.java",
"api/org/webrtc/NetworkMonitorAutoDetect.java",
"api/org/webrtc/NetworkStatePredictorFactoryFactory.java",
"api/org/webrtc/PeerConnection.java",
"api/org/webrtc/PeerConnectionDependencies.java",
@ -328,6 +329,7 @@ if (is_android) {
srcjar_deps = [
"//api:priority_enums",
"//api/video:video_frame_enums",
"//rtc_base:network_monitor_enums",
]
}
@ -1171,8 +1173,8 @@ if (current_os == "linux" || is_android) {
generate_jni("generated_base_jni") {
sources = [
"api/org/webrtc/NetworkChangeDetector.java",
"api/org/webrtc/NetworkMonitor.java",
"api/org/webrtc/NetworkMonitorAutoDetect.java",
"api/org/webrtc/RefCounted.java",
"src/java/org/webrtc/Histogram.java",
"src/java/org/webrtc/JniCommon.java",

View file

@ -0,0 +1,116 @@
/*
* Copyright 2020 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
package org.webrtc;
import android.support.annotation.Nullable;
import java.util.List;
/** Interface for detecting network changes */
public interface NetworkChangeDetector {
// java equivalent of c++ android_network_monitor.h / NetworkType.
public static enum ConnectionType {
CONNECTION_UNKNOWN,
CONNECTION_ETHERNET,
CONNECTION_WIFI,
CONNECTION_5G,
CONNECTION_4G,
CONNECTION_3G,
CONNECTION_2G,
CONNECTION_UNKNOWN_CELLULAR,
CONNECTION_BLUETOOTH,
CONNECTION_VPN,
CONNECTION_NONE
}
public static class IPAddress {
public final byte[] address;
public IPAddress(byte[] address) {
this.address = address;
}
@CalledByNative("IPAddress")
private byte[] getAddress() {
return address;
}
}
/** Java version of NetworkMonitor.NetworkInformation */
public static class NetworkInformation {
public final String name;
public final ConnectionType type;
// Used to specify the underlying network type if the type is CONNECTION_VPN.
public final ConnectionType underlyingTypeForVpn;
public final long handle;
public final IPAddress[] ipAddresses;
public NetworkInformation(String name, ConnectionType type, ConnectionType underlyingTypeForVpn,
long handle, IPAddress[] addresses) {
this.name = name;
this.type = type;
this.underlyingTypeForVpn = underlyingTypeForVpn;
this.handle = handle;
this.ipAddresses = addresses;
}
@CalledByNative("NetworkInformation")
private IPAddress[] getIpAddresses() {
return ipAddresses;
}
@CalledByNative("NetworkInformation")
private ConnectionType getConnectionType() {
return type;
}
@CalledByNative("NetworkInformation")
private ConnectionType getUnderlyingConnectionTypeForVpn() {
return underlyingTypeForVpn;
}
@CalledByNative("NetworkInformation")
private long getHandle() {
return handle;
}
@CalledByNative("NetworkInformation")
private String getName() {
return name;
}
};
/** Observer interface by which observer is notified of network changes. */
public static interface Observer {
/** Called when default network changes. */
public void onConnectionTypeChanged(ConnectionType newConnectionType);
public void onNetworkConnect(NetworkInformation networkInfo);
public void onNetworkDisconnect(long networkHandle);
/**
* Called when network preference change for a (list of) connection type(s). (e.g WIFI) is
* |NOT_PREFERRED| or |NEUTRAL|.
*
* <p>note: |types| is a list of ConnectionTypes, so that all cellular types can be modified in
* one call.
*/
public void onNetworkPreference(List<ConnectionType> types, @NetworkPreference int preference);
}
public ConnectionType getCurrentConnectionType();
public boolean supportNetworkCallback();
@Nullable public List<NetworkInformation> getActiveNetworkList();
public void destroy();
}

View file

@ -0,0 +1,17 @@
/*
* Copyright 2020 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
package org.webrtc;
import android.content.Context;
public interface NetworkChangeDetectorFactory {
public NetworkChangeDetector create(NetworkChangeDetector.Observer observer, Context context);
}

View file

@ -10,14 +10,12 @@
package org.webrtc;
import static org.webrtc.NetworkMonitorAutoDetect.INVALID_NET_ID;
import android.content.Context;
import android.os.Build;
import android.support.annotation.Nullable;
import java.util.ArrayList;
import java.util.List;
import org.webrtc.NetworkMonitorAutoDetect;
import org.webrtc.NetworkChangeDetector;
/**
* Borrowed from Chromium's
@ -32,7 +30,7 @@ public class NetworkMonitor {
* Alerted when the connection type of the network changes. The alert is fired on the UI thread.
*/
public interface NetworkObserver {
public void onConnectionTypeChanged(NetworkMonitorAutoDetect.ConnectionType connectionType);
public void onConnectionTypeChanged(NetworkChangeDetector.ConnectionType connectionType);
}
private static final String TAG = "NetworkMonitor";
@ -43,24 +41,43 @@ public class NetworkMonitor {
static final NetworkMonitor instance = new NetworkMonitor();
}
// Factory for creating NetworkChangeDetector.
private NetworkChangeDetectorFactory networkChangeDetectorFactory =
new NetworkChangeDetectorFactory() {
@Override
public NetworkChangeDetector create(
NetworkChangeDetector.Observer observer, Context context) {
return new NetworkMonitorAutoDetect(observer, context);
}
};
// Native observers of the connection type changes.
private final ArrayList<Long> nativeNetworkObservers;
// Java observers of the connection type changes.
private final ArrayList<NetworkObserver> networkObservers;
private final Object autoDetectLock = new Object();
private final Object networkChangeDetectorLock = new Object();
// Object that detects the connection type changes and brings up mobile networks.
@Nullable private NetworkMonitorAutoDetect autoDetect;
@Nullable private NetworkChangeDetector networkChangeDetector;
// Also guarded by autoDetectLock.
private int numObservers;
private volatile NetworkMonitorAutoDetect.ConnectionType currentConnectionType;
private volatile NetworkChangeDetector.ConnectionType currentConnectionType;
private NetworkMonitor() {
nativeNetworkObservers = new ArrayList<Long>();
networkObservers = new ArrayList<NetworkObserver>();
numObservers = 0;
currentConnectionType = NetworkMonitorAutoDetect.ConnectionType.CONNECTION_UNKNOWN;
currentConnectionType = NetworkChangeDetector.ConnectionType.CONNECTION_UNKNOWN;
}
/**
* Set the factory that will be used to create the network change detector.
* Needs to be called before the monitoring is starts.
*/
public void setNetworkChangeDetectorFactory(NetworkChangeDetectorFactory factory) {
assertIsTrue(numObservers == 0);
this.networkChangeDetectorFactory = factory;
}
// TODO(sakal): Remove once downstream dependencies have been updated.
@ -85,13 +102,12 @@ public class NetworkMonitor {
* CHANGE_NETWORK_STATE permission.
*/
public void startMonitoring(Context applicationContext) {
synchronized (autoDetectLock) {
synchronized (networkChangeDetectorLock) {
++numObservers;
if (autoDetect == null) {
autoDetect = createAutoDetect(applicationContext);
if (networkChangeDetector == null) {
networkChangeDetector = createNetworkChangeDetector(applicationContext);
}
currentConnectionType =
NetworkMonitorAutoDetect.getConnectionType(autoDetect.getCurrentNetworkState());
currentConnectionType = networkChangeDetector.getCurrentConnectionType();
}
}
@ -122,12 +138,15 @@ public class NetworkMonitor {
notifyObserversOfConnectionTypeChange(currentConnectionType);
}
/** Stop network monitoring. If no one is monitoring networks, destroy and reset autoDetect. */
/**
* Stop network monitoring. If no one is monitoring networks, destroy and reset
* networkChangeDetector.
*/
public void stopMonitoring() {
synchronized (autoDetectLock) {
synchronized (networkChangeDetectorLock) {
if (--numObservers == 0) {
autoDetect.destroy();
autoDetect = null;
networkChangeDetector.destroy();
networkChangeDetector = null;
}
}
}
@ -144,8 +163,8 @@ public class NetworkMonitor {
// Returns true if network binding is supported on this platform.
@CalledByNative
private boolean networkBindingSupported() {
synchronized (autoDetectLock) {
return autoDetect != null && autoDetect.supportNetworkCallback();
synchronized (networkChangeDetectorLock) {
return networkChangeDetector != null && networkChangeDetector.supportNetworkCallback();
}
}
@ -154,27 +173,19 @@ public class NetworkMonitor {
return Build.VERSION.SDK_INT;
}
private NetworkMonitorAutoDetect.ConnectionType getCurrentConnectionType() {
private NetworkChangeDetector.ConnectionType getCurrentConnectionType() {
return currentConnectionType;
}
private long getCurrentDefaultNetId() {
synchronized (autoDetectLock) {
return autoDetect == null ? INVALID_NET_ID : autoDetect.getDefaultNetId();
}
}
private NetworkMonitorAutoDetect createAutoDetect(Context appContext) {
return new NetworkMonitorAutoDetect(new NetworkMonitorAutoDetect.Observer() {
private NetworkChangeDetector createNetworkChangeDetector(Context appContext) {
return networkChangeDetectorFactory.create(new NetworkChangeDetector.Observer() {
@Override
public void onConnectionTypeChanged(
NetworkMonitorAutoDetect.ConnectionType newConnectionType) {
public void onConnectionTypeChanged(NetworkChangeDetector.ConnectionType newConnectionType) {
updateCurrentConnectionType(newConnectionType);
}
@Override
public void onNetworkConnect(NetworkMonitorAutoDetect.NetworkInformation networkInfo) {
public void onNetworkConnect(NetworkChangeDetector.NetworkInformation networkInfo) {
notifyObserversOfNetworkConnect(networkInfo);
}
@ -182,18 +193,23 @@ public class NetworkMonitor {
public void onNetworkDisconnect(long networkHandle) {
notifyObserversOfNetworkDisconnect(networkHandle);
}
@Override
public void onNetworkPreference(
List<NetworkChangeDetector.ConnectionType> types, int preference) {
notifyObserversOfNetworkPreference(types, preference);
}
}, appContext);
}
private void updateCurrentConnectionType(
NetworkMonitorAutoDetect.ConnectionType newConnectionType) {
private void updateCurrentConnectionType(NetworkChangeDetector.ConnectionType newConnectionType) {
currentConnectionType = newConnectionType;
notifyObserversOfConnectionTypeChange(newConnectionType);
}
/** Alerts all observers of a connection change. */
private void notifyObserversOfConnectionTypeChange(
NetworkMonitorAutoDetect.ConnectionType newConnectionType) {
NetworkChangeDetector.ConnectionType newConnectionType) {
List<Long> nativeObservers = getNativeNetworkObserversSync();
for (Long nativeObserver : nativeObservers) {
nativeNotifyConnectionTypeChanged(nativeObserver);
@ -209,7 +225,7 @@ public class NetworkMonitor {
}
private void notifyObserversOfNetworkConnect(
NetworkMonitorAutoDetect.NetworkInformation networkInfo) {
NetworkChangeDetector.NetworkInformation networkInfo) {
List<Long> nativeObservers = getNativeNetworkObserversSync();
for (Long nativeObserver : nativeObservers) {
nativeNotifyOfNetworkConnect(nativeObserver, networkInfo);
@ -223,17 +239,28 @@ public class NetworkMonitor {
}
}
private void notifyObserversOfNetworkPreference(
List<NetworkChangeDetector.ConnectionType> types, int preference) {
List<Long> nativeObservers = getNativeNetworkObserversSync();
for (NetworkChangeDetector.ConnectionType type : types) {
for (Long nativeObserver : nativeObservers) {
nativeNotifyOfNetworkPreference(nativeObserver, type, preference);
}
}
}
private void updateObserverActiveNetworkList(long nativeObserver) {
List<NetworkMonitorAutoDetect.NetworkInformation> networkInfoList;
synchronized (autoDetectLock) {
networkInfoList = (autoDetect == null) ? null : autoDetect.getActiveNetworkList();
List<NetworkChangeDetector.NetworkInformation> networkInfoList;
synchronized (networkChangeDetectorLock) {
networkInfoList =
(networkChangeDetector == null) ? null : networkChangeDetector.getActiveNetworkList();
}
if (networkInfoList == null || networkInfoList.size() == 0) {
return;
}
NetworkMonitorAutoDetect.NetworkInformation[] networkInfos =
new NetworkMonitorAutoDetect.NetworkInformation[networkInfoList.size()];
NetworkChangeDetector.NetworkInformation[] networkInfos =
new NetworkChangeDetector.NetworkInformation[networkInfoList.size()];
networkInfos = networkInfoList.toArray(networkInfos);
nativeNotifyOfActiveNetworkList(nativeObserver, networkInfos);
}
@ -278,30 +305,35 @@ public class NetworkMonitor {
/** Checks if there currently is connectivity. */
public static boolean isOnline() {
NetworkMonitorAutoDetect.ConnectionType connectionType =
getInstance().getCurrentConnectionType();
return connectionType != NetworkMonitorAutoDetect.ConnectionType.CONNECTION_NONE;
NetworkChangeDetector.ConnectionType connectionType = getInstance().getCurrentConnectionType();
return connectionType != NetworkChangeDetector.ConnectionType.CONNECTION_NONE;
}
private native void nativeNotifyConnectionTypeChanged(long nativeAndroidNetworkMonitor);
private native void nativeNotifyOfNetworkConnect(
long nativeAndroidNetworkMonitor, NetworkMonitorAutoDetect.NetworkInformation networkInfo);
long nativeAndroidNetworkMonitor, NetworkChangeDetector.NetworkInformation networkInfo);
private native void nativeNotifyOfNetworkDisconnect(
long nativeAndroidNetworkMonitor, long networkHandle);
private native void nativeNotifyOfActiveNetworkList(
long nativeAndroidNetworkMonitor, NetworkMonitorAutoDetect.NetworkInformation[] networkInfos);
long nativeAndroidNetworkMonitor, NetworkChangeDetector.NetworkInformation[] networkInfos);
private native void nativeNotifyOfNetworkPreference(
long nativeAndroidNetworkMonitor, NetworkChangeDetector.ConnectionType type, int preference);
// For testing only.
@Nullable
NetworkMonitorAutoDetect getNetworkMonitorAutoDetect() {
synchronized (autoDetectLock) {
return autoDetect;
NetworkChangeDetector getNetworkChangeDetector() {
synchronized (networkChangeDetectorLock) {
return networkChangeDetector;
}
}
// For testing only.
int getNumObservers() {
synchronized (autoDetectLock) {
synchronized (networkChangeDetectorLock) {
return numObservers;
}
}
@ -309,7 +341,9 @@ public class NetworkMonitor {
// For testing only.
static NetworkMonitorAutoDetect createAndSetAutoDetectForTest(Context context) {
NetworkMonitor networkMonitor = getInstance();
NetworkMonitorAutoDetect autoDetect = networkMonitor.createAutoDetect(context);
return networkMonitor.autoDetect = autoDetect;
NetworkChangeDetector networkChangeDetector =
networkMonitor.createNetworkChangeDetector(context);
networkMonitor.networkChangeDetector = networkChangeDetector;
return (NetworkMonitorAutoDetect) networkChangeDetector;
}
}

View file

@ -41,80 +41,10 @@ import java.util.List;
* Borrowed from Chromium's
* src/net/android/java/src/org/chromium/net/NetworkChangeNotifierAutoDetect.java
*
* Used by the NetworkMonitor to listen to platform changes in connectivity.
* Note that use of this class requires that the app have the platform
* ACCESS_NETWORK_STATE permission.
* <p>Used by the NetworkMonitor to listen to platform changes in connectivity. Note that use of
* this class requires that the app have the platform ACCESS_NETWORK_STATE permission.
*/
public class NetworkMonitorAutoDetect extends BroadcastReceiver {
public static enum ConnectionType {
CONNECTION_UNKNOWN,
CONNECTION_ETHERNET,
CONNECTION_WIFI,
CONNECTION_5G,
CONNECTION_4G,
CONNECTION_3G,
CONNECTION_2G,
CONNECTION_UNKNOWN_CELLULAR,
CONNECTION_BLUETOOTH,
CONNECTION_VPN,
CONNECTION_NONE
}
public static class IPAddress {
public final byte[] address;
public IPAddress(byte[] address) {
this.address = address;
}
@CalledByNative("IPAddress")
private byte[] getAddress() {
return address;
}
}
/** Java version of NetworkMonitor.NetworkInformation */
public static class NetworkInformation {
public final String name;
public final ConnectionType type;
// Used to specify the underlying network type if the type is CONNECTION_VPN.
public final ConnectionType underlyingTypeForVpn;
public final long handle;
public final IPAddress[] ipAddresses;
public NetworkInformation(String name, ConnectionType type, ConnectionType underlyingTypeForVpn,
long handle, IPAddress[] addresses) {
this.name = name;
this.type = type;
this.underlyingTypeForVpn = underlyingTypeForVpn;
this.handle = handle;
this.ipAddresses = addresses;
}
@CalledByNative("NetworkInformation")
private IPAddress[] getIpAddresses() {
return ipAddresses;
}
@CalledByNative("NetworkInformation")
private ConnectionType getConnectionType() {
return type;
}
@CalledByNative("NetworkInformation")
private ConnectionType getUnderlyingConnectionTypeForVpn() {
return underlyingTypeForVpn;
}
@CalledByNative("NetworkInformation")
private long getHandle() {
return handle;
}
@CalledByNative("NetworkInformation")
private String getName() {
return name;
}
};
public class NetworkMonitorAutoDetect extends BroadcastReceiver implements NetworkChangeDetector {
static class NetworkState {
private final boolean connected;
// Defined from ConnectivityManager.TYPE_XXX for non-mobile; for mobile, it is
@ -410,8 +340,8 @@ public class NetworkMonitorAutoDetect extends BroadcastReceiver {
}
NetworkState networkState = getNetworkState(network);
ConnectionType connectionType = getConnectionType(networkState);
if (connectionType == ConnectionType.CONNECTION_NONE) {
NetworkChangeDetector.ConnectionType connectionType = getConnectionType(networkState);
if (connectionType == NetworkChangeDetector.ConnectionType.CONNECTION_NONE) {
// This may not be an error. The OS may signal a network event with connection type
// NONE when the network disconnects.
Logging.d(TAG, "Network " + network.toString() + " is disconnected");
@ -420,13 +350,14 @@ public class NetworkMonitorAutoDetect extends BroadcastReceiver {
// Some android device may return a CONNECTION_UNKNOWN_CELLULAR or CONNECTION_UNKNOWN type,
// which appears to be usable. Just log them here.
if (connectionType == ConnectionType.CONNECTION_UNKNOWN
|| connectionType == ConnectionType.CONNECTION_UNKNOWN_CELLULAR) {
if (connectionType == NetworkChangeDetector.ConnectionType.CONNECTION_UNKNOWN
|| connectionType == NetworkChangeDetector.ConnectionType.CONNECTION_UNKNOWN_CELLULAR) {
Logging.d(TAG, "Network " + network.toString() + " connection type is " + connectionType
+ " because it has type " + networkState.getNetworkType() + " and subtype "
+ networkState.getNetworkSubType());
}
// ConnectionType.CONNECTION_UNKNOWN if the network is not a VPN or the underlying network is
// NetworkChangeDetector.ConnectionType.CONNECTION_UNKNOWN if the network is not a VPN or the
// underlying network is
// unknown.
ConnectionType underlyingConnectionTypeForVpn =
getUnderlyingConnectionTypeForVpn(networkState);
@ -529,12 +460,12 @@ public class NetworkMonitorAutoDetect extends BroadcastReceiver {
// (NETWORK_UNSPECIFIED) for these addresses.
private static final int WIFI_P2P_NETWORK_HANDLE = 0;
private final Context context;
private final Observer observer;
private final NetworkChangeDetector.Observer observer;
// Network information about a WifiP2p (aka WiFi-Direct) network, or null if no such network is
// connected.
@Nullable private NetworkInformation wifiP2pNetworkInfo;
WifiDirectManagerDelegate(Observer observer, Context context) {
WifiDirectManagerDelegate(NetworkChangeDetector.Observer observer, Context context) {
this.context = context;
this.observer = observer;
IntentFilter intentFilter = new IntentFilter();
@ -599,9 +530,10 @@ public class NetworkMonitorAutoDetect extends BroadcastReceiver {
ipAddresses[i] = new IPAddress(interfaceAddresses.get(i).getAddress());
}
wifiP2pNetworkInfo =
new NetworkInformation(wifiP2pGroup.getInterface(), ConnectionType.CONNECTION_WIFI,
ConnectionType.CONNECTION_NONE, WIFI_P2P_NETWORK_HANDLE, ipAddresses);
wifiP2pNetworkInfo = new NetworkInformation(wifiP2pGroup.getInterface(),
NetworkChangeDetector.ConnectionType.CONNECTION_WIFI,
NetworkChangeDetector.ConnectionType.CONNECTION_NONE, WIFI_P2P_NETWORK_HANDLE,
ipAddresses);
observer.onNetworkConnect(wifiP2pNetworkInfo);
}
@ -614,11 +546,11 @@ public class NetworkMonitorAutoDetect extends BroadcastReceiver {
}
}
static final long INVALID_NET_ID = -1;
private static final long INVALID_NET_ID = -1;
private static final String TAG = "NetworkMonitorAutoDetect";
// Observer for the connection type change.
private final Observer observer;
private final NetworkChangeDetector.Observer observer;
private final IntentFilter intentFilter;
private final Context context;
// Used to request mobile network. It does not do anything except for keeping
@ -632,26 +564,12 @@ public class NetworkMonitorAutoDetect extends BroadcastReceiver {
private WifiDirectManagerDelegate wifiDirectManagerDelegate;
private boolean isRegistered;
private ConnectionType connectionType;
private NetworkChangeDetector.ConnectionType connectionType;
private String wifiSSID;
/**
* Observer interface by which observer is notified of network changes.
*/
public static interface Observer {
/**
* Called when default network changes.
*/
public void onConnectionTypeChanged(ConnectionType newConnectionType);
public void onNetworkConnect(NetworkInformation networkInfo);
public void onNetworkDisconnect(long networkHandle);
}
/**
* Constructs a NetworkMonitorAutoDetect. Should only be called on UI thread.
*/
/** Constructs a NetworkMonitorAutoDetect. Should only be called on UI thread. */
@SuppressLint("NewApi")
public NetworkMonitorAutoDetect(Observer observer, Context context) {
public NetworkMonitorAutoDetect(NetworkChangeDetector.Observer observer, Context context) {
this.observer = observer;
this.context = context;
connectivityManagerDelegate = new ConnectivityManagerDelegate(context);
@ -686,6 +604,7 @@ public class NetworkMonitorAutoDetect extends BroadcastReceiver {
}
}
@Override
public boolean supportNetworkCallback() {
return connectivityManagerDelegate.supportNetworkCallback();
}
@ -712,8 +631,9 @@ public class NetworkMonitorAutoDetect extends BroadcastReceiver {
return isRegistered;
}
@Override
@Nullable
List<NetworkInformation> getActiveNetworkList() {
public List<NetworkInformation> getActiveNetworkList() {
List<NetworkInformation> connectivityManagerList =
connectivityManagerDelegate.getActiveNetworkList();
if (connectivityManagerList == null) {
@ -727,6 +647,7 @@ public class NetworkMonitorAutoDetect extends BroadcastReceiver {
return result;
}
@Override
public void destroy() {
if (allNetworkCallback != null) {
connectivityManagerDelegate.releaseCallback(allNetworkCallback);
@ -776,21 +697,21 @@ public class NetworkMonitorAutoDetect extends BroadcastReceiver {
return connectivityManagerDelegate.getDefaultNetId();
}
private static ConnectionType getConnectionType(
private static NetworkChangeDetector.ConnectionType getConnectionType(
boolean isConnected, int networkType, int networkSubtype) {
if (!isConnected) {
return ConnectionType.CONNECTION_NONE;
return NetworkChangeDetector.ConnectionType.CONNECTION_NONE;
}
switch (networkType) {
case ConnectivityManager.TYPE_ETHERNET:
return ConnectionType.CONNECTION_ETHERNET;
return NetworkChangeDetector.ConnectionType.CONNECTION_ETHERNET;
case ConnectivityManager.TYPE_WIFI:
return ConnectionType.CONNECTION_WIFI;
return NetworkChangeDetector.ConnectionType.CONNECTION_WIFI;
case ConnectivityManager.TYPE_WIMAX:
return ConnectionType.CONNECTION_4G;
return NetworkChangeDetector.ConnectionType.CONNECTION_4G;
case ConnectivityManager.TYPE_BLUETOOTH:
return ConnectionType.CONNECTION_BLUETOOTH;
return NetworkChangeDetector.ConnectionType.CONNECTION_BLUETOOTH;
case ConnectivityManager.TYPE_MOBILE:
// Use information from TelephonyManager to classify the connection.
switch (networkSubtype) {
@ -800,7 +721,7 @@ public class NetworkMonitorAutoDetect extends BroadcastReceiver {
case TelephonyManager.NETWORK_TYPE_1xRTT:
case TelephonyManager.NETWORK_TYPE_IDEN:
case TelephonyManager.NETWORK_TYPE_GSM:
return ConnectionType.CONNECTION_2G;
return NetworkChangeDetector.ConnectionType.CONNECTION_2G;
case TelephonyManager.NETWORK_TYPE_UMTS:
case TelephonyManager.NETWORK_TYPE_EVDO_0:
case TelephonyManager.NETWORK_TYPE_EVDO_A:
@ -811,30 +732,36 @@ public class NetworkMonitorAutoDetect extends BroadcastReceiver {
case TelephonyManager.NETWORK_TYPE_EHRPD:
case TelephonyManager.NETWORK_TYPE_HSPAP:
case TelephonyManager.NETWORK_TYPE_TD_SCDMA:
return ConnectionType.CONNECTION_3G;
return NetworkChangeDetector.ConnectionType.CONNECTION_3G;
case TelephonyManager.NETWORK_TYPE_LTE:
case TelephonyManager.NETWORK_TYPE_IWLAN:
return ConnectionType.CONNECTION_4G;
return NetworkChangeDetector.ConnectionType.CONNECTION_4G;
case TelephonyManager.NETWORK_TYPE_NR:
return ConnectionType.CONNECTION_5G;
return NetworkChangeDetector.ConnectionType.CONNECTION_5G;
default:
return ConnectionType.CONNECTION_UNKNOWN_CELLULAR;
return NetworkChangeDetector.ConnectionType.CONNECTION_UNKNOWN_CELLULAR;
}
case ConnectivityManager.TYPE_VPN:
return ConnectionType.CONNECTION_VPN;
return NetworkChangeDetector.ConnectionType.CONNECTION_VPN;
default:
return ConnectionType.CONNECTION_UNKNOWN;
return NetworkChangeDetector.ConnectionType.CONNECTION_UNKNOWN;
}
}
public static ConnectionType getConnectionType(NetworkState networkState) {
public static NetworkChangeDetector.ConnectionType getConnectionType(NetworkState networkState) {
return getConnectionType(networkState.isConnected(), networkState.getNetworkType(),
networkState.getNetworkSubType());
}
private static ConnectionType getUnderlyingConnectionTypeForVpn(NetworkState networkState) {
@Override
public NetworkChangeDetector.ConnectionType getCurrentConnectionType() {
return getConnectionType(getCurrentNetworkState());
}
private static NetworkChangeDetector.ConnectionType getUnderlyingConnectionTypeForVpn(
NetworkState networkState) {
if (networkState.getNetworkType() != ConnectivityManager.TYPE_VPN) {
return ConnectionType.CONNECTION_NONE;
return NetworkChangeDetector.ConnectionType.CONNECTION_NONE;
}
return getConnectionType(networkState.isConnected(),
networkState.getUnderlyingNetworkTypeForVpn(),
@ -842,7 +769,7 @@ public class NetworkMonitorAutoDetect extends BroadcastReceiver {
}
private String getWifiSSID(NetworkState networkState) {
if (getConnectionType(networkState) != ConnectionType.CONNECTION_WIFI)
if (getConnectionType(networkState) != NetworkChangeDetector.ConnectionType.CONNECTION_WIFI)
return "";
return wifiManagerDelegate.getWifiSSID();
}
@ -857,7 +784,7 @@ public class NetworkMonitorAutoDetect extends BroadcastReceiver {
}
private void connectionTypeChanged(NetworkState networkState) {
ConnectionType newConnectionType = getConnectionType(networkState);
NetworkChangeDetector.ConnectionType newConnectionType = getConnectionType(networkState);
String newWifiSSID = getWifiSSID(networkState);
if (newConnectionType == connectionType && newWifiSSID.equals(wifiSSID))
return;

View file

@ -15,7 +15,6 @@ import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.webrtc.NetworkMonitorAutoDetect.INVALID_NET_ID;
import android.annotation.SuppressLint;
import android.content.Context;
@ -31,14 +30,15 @@ import android.support.test.annotation.UiThreadTest;
import android.support.test.filters.MediumTest;
import android.support.test.filters.SmallTest;
import android.support.test.rule.UiThreadTestRule;
import java.util.List;
import org.chromium.base.test.BaseJUnit4ClassRunner;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.webrtc.NetworkMonitorAutoDetect.ConnectionType;
import org.webrtc.NetworkChangeDetector.ConnectionType;
import org.webrtc.NetworkChangeDetector.NetworkInformation;
import org.webrtc.NetworkMonitorAutoDetect.ConnectivityManagerDelegate;
import org.webrtc.NetworkMonitorAutoDetect.NetworkInformation;
import org.webrtc.NetworkMonitorAutoDetect.NetworkState;
/**
@ -53,6 +53,9 @@ import org.webrtc.NetworkMonitorAutoDetect.NetworkState;
public class NetworkMonitorTest {
@Rule public UiThreadTestRule uiThreadTestRule = new UiThreadTestRule();
private static final long INVALID_NET_ID = -1;
private NetworkChangeDetector detector;
/**
* Listens for alerts fired by the NetworkMonitor when network status changes.
*/
@ -155,6 +158,10 @@ public class NetworkMonitorTest {
@Override
public void onNetworkDisconnect(long networkHandle) {}
@Override
public void onNetworkPreference(List<ConnectionType> types, @NetworkPreference int preference) {
}
}
private static final Object lock = new Object();
@ -179,6 +186,17 @@ public class NetworkMonitorTest {
*/
private void createTestMonitor() {
Context context = InstrumentationRegistry.getTargetContext();
NetworkMonitor.getInstance().setNetworkChangeDetectorFactory(
new NetworkChangeDetectorFactory() {
@Override
public NetworkChangeDetector create(
NetworkChangeDetector.Observer observer, Context context) {
detector = new NetworkMonitorAutoDetect(observer, context);
return detector;
}
});
receiver = NetworkMonitor.createAndSetAutoDetectForTest(context);
assertNotNull(receiver);
@ -311,9 +329,9 @@ public class NetworkMonitorTest {
Context context = ContextUtils.getApplicationContext();
networkMonitor.startMonitoring(context);
assertEquals(1, networkMonitor.getNumObservers());
assertNotNull(networkMonitor.getNetworkMonitorAutoDetect());
assertEquals(detector, networkMonitor.getNetworkChangeDetector());
networkMonitor.stopMonitoring();
assertEquals(0, networkMonitor.getNumObservers());
assertNull(networkMonitor.getNetworkMonitorAutoDetect());
assertNull(networkMonitor.getNetworkChangeDetector());
}
}

View file

@ -21,7 +21,7 @@
#include "rtc_base/ip_address.h"
#include "rtc_base/logging.h"
#include "rtc_base/strings/string_builder.h"
#include "sdk/android/generated_base_jni/NetworkMonitorAutoDetect_jni.h"
#include "sdk/android/generated_base_jni/NetworkChangeDetector_jni.h"
#include "sdk/android/generated_base_jni/NetworkMonitor_jni.h"
#include "sdk/android/native_api/jni/java_types.h"
#include "sdk/android/src/jni/jni_helpers.h"
@ -413,6 +413,17 @@ void AndroidNetworkMonitor::OnNetworkDisconnected_w(NetworkHandle handle) {
}
}
void AndroidNetworkMonitor::OnNetworkPreference(
NetworkType type,
rtc::NetworkPreference preference) {
worker_thread()->Invoke<void>(RTC_FROM_HERE, [&] {
auto adapter_type =
AdapterTypeFromNetworkType(type, surface_cellular_types_);
network_preference_by_adapter_type_[adapter_type] = preference;
});
OnNetworksChanged();
}
void AndroidNetworkMonitor::SetNetworkInfos(
const std::vector<NetworkInformation>& network_infos) {
RTC_CHECK(thread_checker_.IsCurrent());
@ -446,6 +457,29 @@ rtc::AdapterType AndroidNetworkMonitor::GetVpnUnderlyingAdapterType(
return type;
}
rtc::NetworkPreference AndroidNetworkMonitor::GetNetworkPreference(
const std::string& if_name) {
auto iter = adapter_type_by_name_.find(if_name);
if (iter == adapter_type_by_name_.end()) {
return rtc::NetworkPreference::NEUTRAL;
}
rtc::AdapterType adapter_type = iter->second;
if (adapter_type == rtc::ADAPTER_TYPE_VPN) {
auto iter2 = vpn_underlying_adapter_type_by_name_.find(if_name);
if (iter2 != vpn_underlying_adapter_type_by_name_.end()) {
adapter_type = iter2->second;
}
}
auto preference_iter = network_preference_by_adapter_type_.find(adapter_type);
if (preference_iter == network_preference_by_adapter_type_.end()) {
return rtc::NetworkPreference::NEUTRAL;
}
return preference_iter->second;
}
AndroidNetworkMonitorFactory::AndroidNetworkMonitorFactory()
: j_application_context_(nullptr) {}
@ -494,5 +528,16 @@ void AndroidNetworkMonitor::NotifyOfNetworkDisconnect(
OnNetworkDisconnected(static_cast<NetworkHandle>(network_handle));
}
void AndroidNetworkMonitor::NotifyOfNetworkPreference(
JNIEnv* env,
const JavaRef<jobject>& j_caller,
const JavaRef<jobject>& j_connection_type,
jint jpreference) {
NetworkType type = GetNetworkTypeFromJava(env, j_connection_type);
rtc::NetworkPreference preference =
static_cast<rtc::NetworkPreference>(jpreference);
OnNetworkPreference(type, preference);
}
} // namespace jni
} // namespace webrtc

View file

@ -27,7 +27,7 @@ namespace jni {
typedef int64_t NetworkHandle;
// c++ equivalent of java NetworkMonitorAutoDetect.ConnectionType.
// c++ equivalent of java NetworkChangeDetector.ConnectionType.
enum NetworkType {
NETWORK_UNKNOWN,
NETWORK_ETHERNET,
@ -80,8 +80,13 @@ class AndroidNetworkMonitor : public rtc::NetworkMonitorBase,
rtc::AdapterType GetAdapterType(const std::string& if_name) override;
rtc::AdapterType GetVpnUnderlyingAdapterType(
const std::string& if_name) override;
rtc::NetworkPreference GetNetworkPreference(
const std::string& if_name) override;
void OnNetworkConnected(const NetworkInformation& network_info);
void OnNetworkDisconnected(NetworkHandle network_handle);
void OnNetworkPreference(NetworkType type, rtc::NetworkPreference preference);
// Always expected to be called on the network thread.
void SetNetworkInfos(const std::vector<NetworkInformation>& network_infos);
@ -96,6 +101,10 @@ class AndroidNetworkMonitor : public rtc::NetworkMonitorBase,
void NotifyOfActiveNetworkList(JNIEnv* env,
const JavaRef<jobject>& j_caller,
const JavaRef<jobjectArray>& j_network_infos);
void NotifyOfNetworkPreference(JNIEnv* env,
const JavaRef<jobject>& j_caller,
const JavaRef<jobject>& j_connection_type,
jint preference);
// Visible for testing.
absl::optional<NetworkHandle> FindNetworkHandleFromAddress(
@ -114,6 +123,8 @@ class AndroidNetworkMonitor : public rtc::NetworkMonitorBase,
std::map<std::string, rtc::AdapterType> vpn_underlying_adapter_type_by_name_;
std::map<rtc::IPAddress, NetworkHandle> network_handle_by_address_;
std::map<NetworkHandle, NetworkInformation> network_info_by_handle_;
std::map<rtc::AdapterType, rtc::NetworkPreference>
network_preference_by_adapter_type_;
bool find_network_handle_without_ipv6_temporary_part_;
bool surface_cellular_types_;
};