Add a new interface for creating a udp socket in which it binds the socket to a network if the network handle is set.

Plus, in stunport, turnport and allocation sequence, create a socket using the new interface.

BUG=

Review URL: https://codereview.webrtc.org/1556743002

Cr-Commit-Position: refs/heads/master@{#11279}
This commit is contained in:
honghaiz 2016-01-15 14:49:09 -08:00 committed by Commit bot
parent 56271ed889
commit cec0a08275
17 changed files with 457 additions and 62 deletions

View File

@ -15,6 +15,7 @@
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
<instrumentation
android:name="android.test.InstrumentationTestRunner"

View File

@ -29,6 +29,7 @@ package org.webrtc;
import static org.webrtc.NetworkMonitorAutoDetect.ConnectionType;
import static org.webrtc.NetworkMonitorAutoDetect.ConnectivityManagerDelegate;
import static org.webrtc.NetworkMonitorAutoDetect.INVALID_NET_ID;
import static org.webrtc.NetworkMonitorAutoDetect.NetworkInformation;
import static org.webrtc.NetworkMonitorAutoDetect.NetworkState;
import android.annotation.SuppressLint;
@ -138,6 +139,9 @@ public class NetworkMonitorTest extends ActivityTestCase {
@Override
public void onConnectionTypeChanged(ConnectionType newConnectionType) {}
@Override
public void onNetworkConnect(NetworkInformation networkInfo) {}
}
private static final Object lock = new Object();
@ -178,7 +182,7 @@ public class NetworkMonitorTest extends ActivityTestCase {
private NetworkMonitorAutoDetect.ConnectionType getCurrentConnectionType() {
final NetworkMonitorAutoDetect.NetworkState networkState =
receiver.getCurrentNetworkState();
return receiver.getCurrentConnectionType(networkState);
return receiver.getConnectionType(networkState);
}
@Override

View File

@ -29,9 +29,11 @@ package org.webrtc;
import static org.webrtc.NetworkMonitorAutoDetect.ConnectionType;
import static org.webrtc.NetworkMonitorAutoDetect.INVALID_NET_ID;
import static org.webrtc.NetworkMonitorAutoDetect.NetworkInformation;
import org.webrtc.Logging;
import android.content.Context;
import android.util.Log;
import java.util.ArrayList;
@ -117,14 +119,14 @@ public class NetworkMonitor {
// Called by the native code.
private void startMonitoring(long nativeObserver) {
Log.d(TAG, "Start monitoring from native observer " + nativeObserver);
Logging.d(TAG, "Start monitoring from native observer " + nativeObserver);
nativeNetworkObservers.add(nativeObserver);
setAutoDetectConnectivityStateInternal(true);
}
// Called by the native code.
private void stopMonitoring(long nativeObserver) {
Log.d(TAG, "Stop monitoring from native observer " + nativeObserver);
Logging.d(TAG, "Stop monitoring from native observer " + nativeObserver);
setAutoDetectConnectivityStateInternal(false);
nativeNetworkObservers.remove(nativeObserver);
}
@ -156,11 +158,15 @@ public class NetworkMonitor {
public void onConnectionTypeChanged(ConnectionType newConnectionType) {
updateCurrentConnectionType(newConnectionType);
}
@Override
public void onNetworkConnect(NetworkInformation networkInfo) {
updateNetworkInformation(networkInfo);
}
},
applicationContext);
final NetworkMonitorAutoDetect.NetworkState networkState =
autoDetector.getCurrentNetworkState();
updateCurrentConnectionType(autoDetector.getCurrentConnectionType(networkState));
updateCurrentConnectionType(autoDetector.getConnectionType(networkState));
}
}
@ -181,6 +187,12 @@ public class NetworkMonitor {
}
}
private void updateNetworkInformation(NetworkInformation networkInfo) {
for (long nativeObserver : nativeNetworkObservers) {
nativeNotifyOfNetworkConnect(nativeObserver, networkInfo);
}
}
/**
* Adds an observer for any connection type changes.
*/
@ -216,6 +228,8 @@ public class NetworkMonitor {
private native void nativeNotifyConnectionTypeChanged(long nativePtr);
private native void nativeNotifyOfNetworkConnect(long nativePtr, NetworkInformation networkInfo);
// For testing only.
static void resetInstanceForTests(Context context) {
instance = new NetworkMonitor(context);

View File

@ -29,6 +29,8 @@ package org.webrtc;
import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
import org.webrtc.Logging;
import android.Manifest.permission;
import android.annotation.SuppressLint;
import android.content.BroadcastReceiver;
@ -37,14 +39,17 @@ import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.net.ConnectivityManager;
import android.net.ConnectivityManager.NetworkCallback;
import android.net.LinkAddress;
import android.net.LinkProperties;
import android.net.Network;
import android.net.NetworkCapabilities;
import android.net.NetworkInfo;
import android.net.NetworkRequest;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.os.Build;
import android.telephony.TelephonyManager;
import android.util.Log;
/**
* Borrowed from Chromium's
@ -66,6 +71,28 @@ public class NetworkMonitorAutoDetect extends BroadcastReceiver {
CONNECTION_NONE
}
public static class IPAddress {
public final byte[] address;
public IPAddress (byte[] address) {
this.address = address;
}
}
/** Java version of NetworkMonitor.NetworkInformation */
public static class NetworkInformation{
public final String name;
public final ConnectionType type;
public final int handle;
public final IPAddress[] ipAddresses;
public NetworkInformation(String name, ConnectionType type, int handle,
IPAddress[] addresses) {
this.name = name;
this.type = type;
this.handle = handle;
this.ipAddresses = addresses;
}
};
static class NetworkState {
private final boolean connected;
// Defined from ConnectivityManager.TYPE_XXX for non-mobile; for mobile, it is
@ -101,6 +128,7 @@ public class NetworkMonitorAutoDetect extends BroadcastReceiver {
* gracefully below.
*/
private final ConnectivityManager connectivityManager;
private NetworkCallback networkCallback;
ConnectivityManagerDelegate(Context context) {
connectivityManager =
@ -211,30 +239,69 @@ public class NetworkMonitorAutoDetect extends BroadcastReceiver {
connectivityManager.getNetworkCapabilities(network);
return capabilities != null && capabilities.hasCapability(NET_CAPABILITY_INTERNET);
}
@SuppressLint("NewApi")
public void requestMobileNetwork(final Observer observer) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP ||
connectivityManager == null) {
return;
}
networkCallback = new NetworkCallback() {
@Override
public void onAvailable(Network network) {
super.onAvailable(network);
LinkProperties linkProperties = connectivityManager.getLinkProperties(network);
NetworkInformation networkInformation = new NetworkInformation(
linkProperties.getInterfaceName(),
getConnectionType(getNetworkState(network)),
networkToNetId(network),
getIPAddresses(linkProperties));
Logging.d(TAG, "Network " + networkInformation.name + " is connected ");
observer.onNetworkConnect(networkInformation);
}
};
Logging.d(TAG, "Requesting cellular network");
NetworkRequest.Builder builder = new NetworkRequest.Builder();
builder.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
builder.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
connectivityManager.requestNetwork(builder.build(), networkCallback);
}
@SuppressLint("NewApi")
IPAddress[] getIPAddresses(LinkProperties linkProperties) {
IPAddress[] ipAddresses = new IPAddress[linkProperties.getLinkAddresses().size()];
int i = 0;
for (LinkAddress linkAddress : linkProperties.getLinkAddresses()) {
ipAddresses[i] = new IPAddress(linkAddress.getAddress().getAddress());
++i;
}
return ipAddresses;
}
@SuppressLint("NewApi")
public void releaseCallback() {
if (networkCallback != null) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
connectivityManager.unregisterNetworkCallback(networkCallback);
}
networkCallback = null;
}
}
}
/** Queries the WifiManager for SSID of the current Wifi connection. */
static class WifiManagerDelegate {
private final Context context;
private final WifiManager wifiManager;
private final boolean hasWifiPermission;
WifiManagerDelegate(Context context) {
this.context = context;
hasWifiPermission = context.getPackageManager().checkPermission(
permission.ACCESS_WIFI_STATE, context.getPackageName())
== PackageManager.PERMISSION_GRANTED;
wifiManager = hasWifiPermission
? (WifiManager) context.getSystemService(Context.WIFI_SERVICE) : null;
}
// For testing.
WifiManagerDelegate() {
// All the methods below should be overridden.
context = null;
wifiManager = null;
hasWifiPermission = false;
}
String getWifiSSID() {
@ -252,9 +319,6 @@ public class NetworkMonitorAutoDetect extends BroadcastReceiver {
return "";
}
boolean getHasWifiPermission() {
return hasWifiPermission;
}
}
static final int INVALID_NET_ID = -1;
@ -280,6 +344,7 @@ public class NetworkMonitorAutoDetect extends BroadcastReceiver {
* Called when default network changes.
*/
public void onConnectionTypeChanged(ConnectionType newConnectionType);
public void onNetworkConnect(NetworkInformation networkInfo);
}
/**
@ -292,8 +357,8 @@ public class NetworkMonitorAutoDetect extends BroadcastReceiver {
wifiManagerDelegate = new WifiManagerDelegate(context);
final NetworkState networkState = connectivityManagerDelegate.getNetworkState();
connectionType = getCurrentConnectionType(networkState);
wifiSSID = getCurrentWifiSSID(networkState);
connectionType = getConnectionType(networkState);
wifiSSID = getWifiSSID(networkState);
intentFilter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION);
registerReceiver();
}
@ -331,6 +396,7 @@ public class NetworkMonitorAutoDetect extends BroadcastReceiver {
if (!isRegistered) {
isRegistered = true;
context.registerReceiver(this, intentFilter);
connectivityManagerDelegate.requestMobileNetwork(observer);
}
}
@ -341,6 +407,7 @@ public class NetworkMonitorAutoDetect extends BroadcastReceiver {
if (isRegistered) {
isRegistered = false;
context.unregisterReceiver(this);
connectivityManagerDelegate.releaseCallback();
}
}
@ -361,7 +428,7 @@ public class NetworkMonitorAutoDetect extends BroadcastReceiver {
return connectivityManagerDelegate.getDefaultNetId();
}
public ConnectionType getCurrentConnectionType(NetworkState networkState) {
public static ConnectionType getConnectionType(NetworkState networkState) {
if (!networkState.isConnected()) {
return ConnectionType.CONNECTION_NONE;
}
@ -404,8 +471,8 @@ public class NetworkMonitorAutoDetect extends BroadcastReceiver {
}
}
private String getCurrentWifiSSID(NetworkState networkState) {
if (getCurrentConnectionType(networkState) != ConnectionType.CONNECTION_WIFI) return "";
private String getWifiSSID(NetworkState networkState) {
if (getConnectionType(networkState) != ConnectionType.CONNECTION_WIFI) return "";
return wifiManagerDelegate.getWifiSSID();
}
@ -419,13 +486,13 @@ public class NetworkMonitorAutoDetect extends BroadcastReceiver {
}
private void connectionTypeChanged(NetworkState networkState) {
ConnectionType newConnectionType = getCurrentConnectionType(networkState);
String newWifiSSID = getCurrentWifiSSID(networkState);
ConnectionType newConnectionType = getConnectionType(networkState);
String newWifiSSID = getWifiSSID(networkState);
if (newConnectionType == connectionType && newWifiSSID.equals(wifiSSID)) return;
connectionType = newConnectionType;
wifiSSID = newWifiSSID;
Log.d(TAG, "Network connectivity changed, type is: " + connectionType);
Logging.d(TAG, "Network connectivity changed, type is: " + connectionType);
observer.onConnectionTypeChanged(newConnectionType);
}

View File

@ -27,13 +27,125 @@
#include "talk/app/webrtc/java/jni/androidnetworkmonitor_jni.h"
#include <dlfcn.h>
#include "webrtc/base/bind.h"
#include "webrtc/base/common.h"
#include "webrtc/base/ipaddress.h"
#include "talk/app/webrtc/java/jni/classreferenceholder.h"
#include "talk/app/webrtc/java/jni/jni_helpers.h"
namespace webrtc_jni {
jobject AndroidNetworkMonitor::application_context_ = nullptr;
static NetworkType GetNetworkTypeFromJava(JNIEnv* jni, jobject j_network_type) {
std::string enum_name =
GetJavaEnumName(jni, "org/webrtc/NetworkMonitorAutoDetect$ConnectionType",
j_network_type);
if (enum_name == "CONNECTION_UNKNOWN") {
return NetworkType::NETWORK_UNKNOWN;
}
if (enum_name == "CONNECTION_ETHERNET") {
return NetworkType::NETWORK_ETHERNET;
}
if (enum_name == "CONNECTION_WIFI") {
return NetworkType::NETWORK_WIFI;
}
if (enum_name == "CONNECTION_4G") {
return NetworkType::NETWORK_4G;
}
if (enum_name == "CONNECTION_3G") {
return NetworkType::NETWORK_3G;
}
if (enum_name == "CONNECTION_2G") {
return NetworkType::NETWORK_2G;
}
if (enum_name == "CONNECTION_BLUETOOTH") {
return NetworkType::NETWORK_BLUETOOTH;
}
if (enum_name == "CONNECTION_NONE") {
return NetworkType::NETWORK_NONE;
}
ASSERT(false);
return NetworkType::NETWORK_UNKNOWN;
}
static rtc::IPAddress GetIPAddressFromJava(JNIEnv* jni, jobject j_ip_address) {
jclass j_ip_address_class = GetObjectClass(jni, j_ip_address);
jfieldID j_address_id = GetFieldID(jni, j_ip_address_class, "address", "[B");
jbyteArray j_addresses =
static_cast<jbyteArray>(GetObjectField(jni, j_ip_address, j_address_id));
size_t address_length = jni->GetArrayLength(j_addresses);
jbyte* addr_array = jni->GetByteArrayElements(j_addresses, nullptr);
CHECK_EXCEPTION(jni) << "Error during GetIPAddressFromJava";
if (address_length == 4) {
// IP4
struct in_addr ip4_addr;
memcpy(&ip4_addr.s_addr, addr_array, 4);
jni->ReleaseByteArrayElements(j_addresses, addr_array, JNI_ABORT);
return rtc::IPAddress(ip4_addr);
}
// IP6
RTC_CHECK(address_length == 16);
struct in6_addr ip6_addr;
memcpy(ip6_addr.s6_addr, addr_array, address_length);
jni->ReleaseByteArrayElements(j_addresses, addr_array, JNI_ABORT);
return rtc::IPAddress(ip6_addr);
}
static void GetIPAddressesFromJava(JNIEnv* jni,
jobjectArray j_ip_addresses,
std::vector<rtc::IPAddress>* ip_addresses) {
ip_addresses->clear();
size_t num_addresses = jni->GetArrayLength(j_ip_addresses);
CHECK_EXCEPTION(jni) << "Error during GetArrayLength";
for (size_t i = 0; i < num_addresses; ++i) {
jobject j_ip_address = jni->GetObjectArrayElement(j_ip_addresses, i);
CHECK_EXCEPTION(jni) << "Error during GetObjectArrayElement";
rtc::IPAddress ip = GetIPAddressFromJava(jni, j_ip_address);
ip_addresses->push_back(ip);
}
}
static NetworkInformation GetNetworkInformationFromJava(
JNIEnv* jni,
jobject j_network_info) {
jclass j_network_info_class = GetObjectClass(jni, j_network_info);
jfieldID j_interface_name_id =
GetFieldID(jni, j_network_info_class, "name", "Ljava/lang/String;");
jfieldID j_handle_id = GetFieldID(jni, j_network_info_class, "handle", "I");
jfieldID j_type_id =
GetFieldID(jni, j_network_info_class, "type",
"Lorg/webrtc/NetworkMonitorAutoDetect$ConnectionType;");
jfieldID j_ip_addresses_id =
GetFieldID(jni, j_network_info_class, "ipAddresses",
"[Lorg/webrtc/NetworkMonitorAutoDetect$IPAddress;");
NetworkInformation network_info;
network_info.interface_name = JavaToStdString(
jni, GetStringField(jni, j_network_info, j_interface_name_id));
network_info.handle =
static_cast<NetworkHandle>(GetIntField(jni, j_network_info, j_handle_id));
network_info.type = GetNetworkTypeFromJava(
jni, GetObjectField(jni, j_network_info, j_type_id));
jobjectArray j_ip_addresses = static_cast<jobjectArray>(
GetObjectField(jni, j_network_info, j_ip_addresses_id));
GetIPAddressesFromJava(jni, j_ip_addresses, &network_info.ip_addresses);
return network_info;
}
std::string NetworkInformation::ToString() const {
std::stringstream ss;
ss << "NetInfo[name " << interface_name << "; handle " << handle << "; type "
<< type << "; address";
for (const rtc::IPAddress address : ip_addresses) {
ss << " " << address.ToString();
}
ss << "]";
return ss.str();
}
// static
void AndroidNetworkMonitor::SetAndroidContext(JNIEnv* jni, jobject context) {
if (application_context_) {
@ -61,6 +173,16 @@ AndroidNetworkMonitor::AndroidNetworkMonitor()
void AndroidNetworkMonitor::Start() {
RTC_CHECK(thread_checker_.CalledOnValidThread());
if (started_) {
return;
}
started_ = true;
// This is kind of magic behavior, but doing this allows the SocketServer to
// use this as a NetworkBinder to bind sockets on a particular network when
// it creates sockets.
worker_thread()->socketserver()->set_network_binder(this);
jmethodID m =
GetMethodID(jni(), *j_network_monitor_class_, "startMonitoring", "(J)V");
jni()->CallVoidMethod(*j_network_monitor_, m, jlongFromPointer(this));
@ -69,10 +191,89 @@ void AndroidNetworkMonitor::Start() {
void AndroidNetworkMonitor::Stop() {
RTC_CHECK(thread_checker_.CalledOnValidThread());
if (!started_) {
return;
}
started_ = false;
// Once the network monitor stops, it will clear all network information and
// it won't find the network handle to bind anyway.
if (worker_thread()->socketserver()->network_binder() == this) {
worker_thread()->socketserver()->set_network_binder(nullptr);
}
jmethodID m =
GetMethodID(jni(), *j_network_monitor_class_, "stopMonitoring", "(J)V");
jni()->CallVoidMethod(*j_network_monitor_, m, jlongFromPointer(this));
CHECK_EXCEPTION(jni()) << "Error during NetworkMonitor.stopMonitoring";
network_info_by_address_.clear();
}
int AndroidNetworkMonitor::BindSocketToNetwork(int socket_fd,
const rtc::IPAddress& address) {
RTC_CHECK(thread_checker_.CalledOnValidThread());
auto it = network_info_by_address_.find(address);
if (it == network_info_by_address_.end()) {
return rtc::NETWORK_BIND_ADDRESS_NOT_FOUND;
}
// Android prior to Lollipop didn't have support for binding sockets to
// networks. However, in that case it should not have reached here because
// |network_info_by_address_| should only be populated in Android Lollipop
// and above.
NetworkInformation network = it->second;
// NOTE: This does rely on Android implementation details, but
// these details are unlikely to change.
typedef int (*SetNetworkForSocket)(unsigned netId, int socketFd);
static SetNetworkForSocket setNetworkForSocket;
// This is not threadsafe, but we are running this only on the worker thread.
if (setNetworkForSocket == nullptr) {
// Android's netd client library should always be loaded in our address
// space as it shims libc functions like connect().
const std::string net_library_path = "libnetd_client.so";
void* lib = dlopen(net_library_path.c_str(), RTLD_LAZY);
if (lib == nullptr) {
LOG(LS_ERROR) << "Library " << net_library_path << " not found!";
return rtc::NETWORK_BIND_NOT_IMPLEMENTED;
}
setNetworkForSocket = reinterpret_cast<SetNetworkForSocket>(
dlsym(lib, "setNetworkForSocket"));
}
if (setNetworkForSocket == nullptr) {
LOG(LS_ERROR) << "Symbol setNetworkForSocket not found ";
return rtc::NETWORK_BIND_NOT_IMPLEMENTED;
}
int rv = setNetworkForSocket(network.handle, socket_fd);
// If |network| has since disconnected, |rv| will be ENONET. Surface this as
// ERR_NETWORK_CHANGED, rather than MapSystemError(ENONET) which gives back
// the less descriptive ERR_FAILED.
if (rv == 0) {
return rtc::NETWORK_BIND_SUCCESS;
}
if (rv == ENONET) {
return rtc::NETWORK_BIND_NETWORK_CHANGED;
}
return rtc::NETWORK_BIND_FAILURE;
}
void AndroidNetworkMonitor::OnNetworkAvailable(
const NetworkInformation& network_info) {
worker_thread()->Invoke<void>(rtc::Bind(
&AndroidNetworkMonitor::OnNetworkAvailable_w, this, network_info));
}
void AndroidNetworkMonitor::OnNetworkAvailable_w(
const NetworkInformation& network_info) {
LOG(LS_INFO) << "Network available: " << network_info.ToString();
for (rtc::IPAddress address : network_info.ip_addresses) {
network_info_by_address_[address] = network_info;
}
}
rtc::NetworkMonitorInterface*
AndroidNetworkMonitorFactory::CreateNetworkMonitor() {
return new AndroidNetworkMonitor();
}
JOW(void, NetworkMonitor_nativeNotifyConnectionTypeChanged)(
@ -82,4 +283,14 @@ JOW(void, NetworkMonitor_nativeNotifyConnectionTypeChanged)(
network_monitor->OnNetworksChanged();
}
JOW(void, NetworkMonitor_nativeNotifyOfNetworkConnect)(
JNIEnv* jni, jobject j_monitor, jlong j_native_monitor,
jobject j_network_info) {
AndroidNetworkMonitor* network_monitor =
reinterpret_cast<AndroidNetworkMonitor*>(j_native_monitor);
NetworkInformation network_info =
GetNetworkInformationFromJava(jni, j_network_info);
network_monitor->OnNetworkAvailable(network_info);
}
} // namespace webrtc_jni

View File

@ -30,12 +30,41 @@
#include "webrtc/base/networkmonitor.h"
#include <map>
#include "webrtc/base/basictypes.h"
#include "webrtc/base/thread_checker.h"
#include "talk/app/webrtc/java/jni/jni_helpers.h"
namespace webrtc_jni {
class AndroidNetworkMonitor : public rtc::NetworkMonitorBase {
typedef uint32_t NetworkHandle;
// c++ equivalent of java NetworkMonitorAutoDetect.ConnectionType.
enum NetworkType {
NETWORK_UNKNOWN,
NETWORK_ETHERNET,
NETWORK_WIFI,
NETWORK_4G,
NETWORK_3G,
NETWORK_2G,
NETWORK_BLUETOOTH,
NETWORK_NONE
};
// The information is collected from Android OS so that the native code can get
// the network type and handle (Android network ID) for each interface.
struct NetworkInformation {
std::string interface_name;
NetworkHandle handle;
NetworkType type;
std::vector<rtc::IPAddress> ip_addresses;
std::string ToString() const;
};
class AndroidNetworkMonitor : public rtc::NetworkMonitorBase,
public rtc::NetworkBinderInterface {
public:
AndroidNetworkMonitor();
@ -44,22 +73,28 @@ class AndroidNetworkMonitor : public rtc::NetworkMonitorBase {
void Start() override;
void Stop() override;
int BindSocketToNetwork(int socket_fd,
const rtc::IPAddress& address) override;
void OnNetworkAvailable(const NetworkInformation& network_info);
private:
JNIEnv* jni() { return AttachCurrentThreadIfNeeded(); }
void OnNetworkAvailable_w(const NetworkInformation& network_info);
ScopedGlobalRef<jclass> j_network_monitor_class_;
ScopedGlobalRef<jobject> j_network_monitor_;
rtc::ThreadChecker thread_checker_;
static jobject application_context_;
bool started_ = false;
std::map<rtc::IPAddress, NetworkInformation> network_info_by_address_;
};
class AndroidNetworkMonitorFactory : public rtc::NetworkMonitorFactory {
public:
AndroidNetworkMonitorFactory() {}
rtc::NetworkMonitorInterface* CreateNetworkMonitor() override {
return new AndroidNetworkMonitor();
}
rtc::NetworkMonitorInterface* CreateNetworkMonitor() override;
};
} // namespace webrtc_jni

View File

@ -81,6 +81,9 @@ ClassReferenceHolder::ClassReferenceHolder(JNIEnv* jni) {
LoadClass(jni, "org/webrtc/EglBase$Context");
LoadClass(jni, "org/webrtc/EglBase14$Context");
LoadClass(jni, "org/webrtc/NetworkMonitor");
LoadClass(jni, "org/webrtc/NetworkMonitorAutoDetect$ConnectionType");
LoadClass(jni, "org/webrtc/NetworkMonitorAutoDetect$IPAddress");
LoadClass(jni, "org/webrtc/NetworkMonitorAutoDetect$NetworkInformation");
LoadClass(jni, "org/webrtc/MediaCodecVideoEncoder");
LoadClass(jni, "org/webrtc/MediaCodecVideoEncoder$OutputBufferInfo");
LoadClass(jni, "org/webrtc/MediaCodecVideoEncoder$VideoCodecType");

View File

@ -27,6 +27,8 @@
*/
#include "talk/app/webrtc/java/jni/jni_helpers.h"
#include "talk/app/webrtc/java/jni/classreferenceholder.h"
#include <asm/unistd.h>
#include <sys/prctl.h>
#include <sys/syscall.h>
@ -256,6 +258,19 @@ jobject JavaEnumFromIndex(JNIEnv* jni, jclass state_class,
return ret;
}
std::string GetJavaEnumName(JNIEnv* jni,
const std::string& className,
jobject j_enum) {
jclass enumClass = FindClass(jni, className.c_str());
jmethodID nameMethod =
GetMethodID(jni, enumClass, "name", "()Ljava/lang/String;");
jstring name =
reinterpret_cast<jstring>(jni->CallObjectMethod(j_enum, nameMethod));
CHECK_EXCEPTION(jni) << "error during CallObjectMethod for " << className
<< ".name";
return JavaToStdString(jni, name);
}
jobject NewGlobalRef(JNIEnv* jni, jobject o) {
jobject ret = jni->NewGlobalRef(o);
CHECK_EXCEPTION(jni) << "error during NewGlobalRef";

View File

@ -104,6 +104,11 @@ std::string JavaToStdString(JNIEnv* jni, const jstring& j_string);
jobject JavaEnumFromIndex(JNIEnv* jni, jclass state_class,
const std::string& state_class_name, int index);
// Returns the name of a Java enum.
std::string GetJavaEnumName(JNIEnv* jni,
const std::string& className,
jobject j_enum);
jobject NewGlobalRef(JNIEnv* jni, jobject o);
void DeleteGlobalRef(JNIEnv* jni, jobject o);

View File

@ -1395,18 +1395,6 @@ JOW(void, PeerConnectionFactory_nativeSetVideoHwAccelerationOptions)(
#endif
}
static std::string
GetJavaEnumName(JNIEnv* jni, const std::string& className, jobject j_enum) {
jclass enumClass = FindClass(jni, className.c_str());
jmethodID nameMethod =
GetMethodID(jni, enumClass, "name", "()Ljava/lang/String;");
jstring name =
reinterpret_cast<jstring>(jni->CallObjectMethod(j_enum, nameMethod));
CHECK_EXCEPTION(jni) << "error during CallObjectMethod for "
<< className << ".name";
return JavaToStdString(jni, name);
}
static PeerConnectionInterface::IceTransportsType
JavaIceTransportsTypeToNativeType(JNIEnv* jni, jobject j_ice_transports_type) {
std::string enum_name = GetJavaEnumName(

View File

@ -731,10 +731,13 @@ void BasicNetworkManager::StartNetworkMonitor() {
if (factory == nullptr) {
return;
}
network_monitor_.reset(factory->CreateNetworkMonitor());
if (!network_monitor_) {
return;
network_monitor_.reset(factory->CreateNetworkMonitor());
if (!network_monitor_) {
return;
}
}
network_monitor_->SignalNetworksChanged.connect(
this, &BasicNetworkManager::OnNetworksChanged);
network_monitor_->Start();
@ -745,7 +748,6 @@ void BasicNetworkManager::StopNetworkMonitor() {
return;
}
network_monitor_->Stop();
network_monitor_.reset();
}
void BasicNetworkManager::OnMessage(Message* msg) {

View File

@ -29,14 +29,18 @@ namespace {
class FakeNetworkMonitor : public NetworkMonitorBase {
public:
void Start() override {}
void Stop() override {}
void Start() override { started_ = true; }
void Stop() override { started_ = false; }
bool started() { return started_; }
private:
bool started_ = false;
};
class FakeNetworkMonitorFactory : public NetworkMonitorFactory {
public:
FakeNetworkMonitorFactory() {}
NetworkMonitorInterface* CreateNetworkMonitor() {
NetworkMonitorInterface* CreateNetworkMonitor() override {
return new FakeNetworkMonitor();
}
};
@ -72,9 +76,9 @@ class NetworkTest : public testing::Test, public sigslot::has_slots<> {
return list;
}
NetworkMonitorInterface* GetNetworkMonitor(
BasicNetworkManager& network_manager) {
return network_manager.network_monitor_.get();
FakeNetworkMonitor* GetNetworkMonitor(BasicNetworkManager& network_manager) {
return static_cast<FakeNetworkMonitor*>(
network_manager.network_monitor_.get());
}
void ClearNetworks(BasicNetworkManager& network_manager) {
for (const auto& kv : network_manager.networks_map_) {
@ -921,7 +925,8 @@ TEST_F(NetworkTest, TestNetworkMonitoring) {
FakeNetworkMonitorFactory* factory = new FakeNetworkMonitorFactory();
NetworkMonitorFactory::SetFactory(factory);
manager.StartUpdating();
NetworkMonitorInterface* network_monitor = GetNetworkMonitor(manager);
FakeNetworkMonitor* network_monitor = GetNetworkMonitor(manager);
EXPECT_TRUE(network_monitor && network_monitor->started());
EXPECT_TRUE_WAIT(callback_called_, 1000);
callback_called_ = false;
@ -932,9 +937,9 @@ TEST_F(NetworkTest, TestNetworkMonitoring) {
network_monitor->OnNetworksChanged();
EXPECT_TRUE_WAIT(callback_called_, 1000);
// Network manager is stopped; the network monitor is removed.
// Network manager is stopped.
manager.StopUpdating();
EXPECT_TRUE(GetNetworkMonitor(manager) == nullptr);
EXPECT_FALSE(GetNetworkMonitor(manager)->started());
NetworkMonitorFactory::ReleaseFactory(factory);
}

View File

@ -26,12 +26,12 @@ NetworkMonitorInterface::NetworkMonitorInterface() {}
NetworkMonitorInterface::~NetworkMonitorInterface() {}
NetworkMonitorBase::NetworkMonitorBase() : thread_(Thread::Current()) {}
NetworkMonitorBase::NetworkMonitorBase() : worker_thread_(Thread::Current()) {}
NetworkMonitorBase::~NetworkMonitorBase() {}
void NetworkMonitorBase::OnNetworksChanged() {
LOG(LS_VERBOSE) << "Network change is received at the network monitor";
thread_->Post(this, UPDATE_NETWORKS_MESSAGE);
worker_thread_->Post(this, UPDATE_NETWORKS_MESSAGE);
}
void NetworkMonitorBase::OnMessage(Message* msg) {

View File

@ -17,6 +17,27 @@
#include "webrtc/base/thread.h"
namespace rtc {
class IPAddress;
// Error values are negative.
enum NetworkBindingResults {
NETWORK_BIND_SUCCESS = 0, // No error
NETWORK_BIND_FAILURE = -1, // Generic error
NETWORK_BIND_NOT_IMPLEMENTED = -2,
NETWORK_BIND_ADDRESS_NOT_FOUND = -3,
NETWORK_BIND_NETWORK_CHANGED = -4
};
class NetworkBinderInterface {
public:
// Binds a socket to the network that is attached to |address| so that all
// packets on the socket |socket_fd| will be sent via that network.
// This is needed because some operating systems (like Android) require a
// special bind call to put packets on a non-default network interface.
virtual int BindSocketToNetwork(int socket_fd, const IPAddress& address) = 0;
};
/*
* Receives network-change events via |OnNetworksChanged| and signals the
* networks changed event.
@ -62,8 +83,11 @@ class NetworkMonitorBase : public NetworkMonitorInterface,
void OnMessage(Message* msg) override;
protected:
Thread* worker_thread() { return worker_thread_; }
private:
Thread* thread_;
Thread* worker_thread_;
};
/*

View File

@ -7,6 +7,7 @@
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "webrtc/base/physicalsocketserver.h"
#if defined(_MSC_VER) && _MSC_VER < 1300
#pragma warning(disable:4786)
@ -44,7 +45,7 @@
#include "webrtc/base/byteorder.h"
#include "webrtc/base/common.h"
#include "webrtc/base/logging.h"
#include "webrtc/base/physicalsocketserver.h"
#include "webrtc/base/networkmonitor.h"
#include "webrtc/base/timeutils.h"
#include "webrtc/base/winping.h"
#include "webrtc/base/win32socketinit.h"
@ -174,6 +175,14 @@ int PhysicalSocket::Bind(const SocketAddress& bind_addr) {
dbg_addr_.append(GetLocalAddress().ToString());
}
#endif
if (ss_->network_binder()) {
int result =
ss_->network_binder()->BindSocketToNetwork(s_, bind_addr.ipaddr());
if (result < 0) {
LOG(LS_INFO) << "Binding socket to network address "
<< bind_addr.ipaddr().ToString() << " result " << result;
}
}
return err;
}
@ -1109,7 +1118,7 @@ private:
PhysicalSocketServer* ss_;
WSAEVENT hev_;
};
#endif // WEBRTC_WIN
#endif // WEBRTC_WIN
// Sets the value of a boolean value to false when signaled.
class Signaler : public EventDispatcher {
@ -1603,6 +1612,6 @@ bool PhysicalSocketServer::Wait(int cmsWait, bool process_io) {
// Done
return true;
}
#endif // WEBRTC_WIN
#endif // WEBRTC_WIN
} // namespace rtc

View File

@ -16,6 +16,7 @@
namespace rtc {
class MessageQueue;
class NetworkBinderInterface;
// Provides the ability to wait for activity on a set of sockets. The Thread
// class provides a nice wrapper on a socket server.
@ -39,6 +40,16 @@ class SocketServer : public SocketFactory {
// Causes the current wait (if one is in progress) to wake up.
virtual void WakeUp() = 0;
// A network binder will bind the created sockets to a network.
// It is only used in PhysicalSocketServer.
void set_network_binder(NetworkBinderInterface* binder) {
network_binder_ = binder;
}
NetworkBinderInterface* network_binder() const { return network_binder_; }
private:
NetworkBinderInterface* network_binder_ = nullptr;
};
} // namespace rtc

View File

@ -10,6 +10,7 @@
<uses-sdk android:minSdkVersion="16" android:targetSdkVersion="21" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.INTERNET" />