Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1468)

Unified Diff: talk/app/webrtc/java/jni/androidnetworkmonitor_jni.cc

Issue 1556743002: Bind a socket to a network if the network handle is set. (Closed) Base URL: https://chromium.googlesource.com/external/webrtc.git@master
Patch Set: Merge with head Created 4 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: talk/app/webrtc/java/jni/androidnetworkmonitor_jni.cc
diff --git a/talk/app/webrtc/java/jni/androidnetworkmonitor_jni.cc b/talk/app/webrtc/java/jni/androidnetworkmonitor_jni.cc
index f7a8c07c60a3e63926ec1914dabf3aae08cfbe69..948b2bc394a50d1c435877c747447d9f3b51fdb0 100644
--- a/talk/app/webrtc/java/jni/androidnetworkmonitor_jni.cc
+++ b/talk/app/webrtc/java/jni/androidnetworkmonitor_jni.cc
@@ -27,13 +27,126 @@
#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, NULL);
Taylor Brandstetter 2016/01/15 19:36:12 nit: "nullptr" instead of "NULL", since that's wha
honghaiz3 2016/01/15 21:37:36 Done.
+ CHECK_EXCEPTION(jni) << "Error during NetworkMonitor.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);
+ for (size_t i = 0; i < num_addresses; ++i) {
+ jobject j_ip_address = jni->GetObjectArrayElement(j_ip_addresses, i);
+ rtc::IPAddress ip = GetIPAddressFromJava(jni, j_ip_address);
+
Taylor Brandstetter 2016/01/15 19:36:12 nit: Seems like extra whitespace here.
honghaiz3 2016/01/15 21:37:36 Done.
+ ip_addresses->push_back(ip);
+ }
+ CHECK_EXCEPTION(jni) << "Error during NetworkMonitor.GetIPAddressesFromJava";
Taylor Brandstetter 2016/01/15 19:36:12 Should this CHECK_EXCEPTION be right after GetArra
honghaiz3 2016/01/15 21:37:36 Done. Added another check after GetObjectArrayElem
+}
+
+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);
+ CHECK_EXCEPTION(jni) << "Error during NetworkMonitor.GetNetworkInfoFromJava";
Taylor Brandstetter 2016/01/15 19:36:12 I don't think you need this CHECK_EXCEPTION since
honghaiz3 2016/01/15 21:37:36 Done.
+ 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() << " ";
Taylor Brandstetter 2016/01/15 19:36:12 nit: This will leave an extra space between the la
honghaiz3 2016/01/15 21:37:36 Done. Thanks!
+ }
+ ss << "]";
+ return ss.str();
+}
+
// static
void AndroidNetworkMonitor::SetAndroidContext(JNIEnv* jni, jobject context) {
if (application_context_) {
@@ -61,6 +174,11 @@ AndroidNetworkMonitor::AndroidNetworkMonitor()
void AndroidNetworkMonitor::Start() {
RTC_CHECK(thread_checker_.CalledOnValidThread());
+ if (started_) {
+ return;
+ }
+ started_ = true;
+
jmethodID m =
GetMethodID(jni(), *j_network_monitor_class_, "startMonitoring", "(J)V");
jni()->CallVoidMethod(*j_network_monitor_, m, jlongFromPointer(this));
@@ -69,10 +187,83 @@ void AndroidNetworkMonitor::Start() {
void AndroidNetworkMonitor::Stop() {
RTC_CHECK(thread_checker_.CalledOnValidThread());
+ if (!started_) {
+ return;
+ }
+ started_ = false;
+
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::ERR_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) {
Taylor Brandstetter 2016/01/15 19:36:12 nit: "if (!setNetworkForSocket)", here and below.
honghaiz3 2016/01/15 21:37:36 I feel using explicit checking is more readable an
+ // 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) {
Taylor Brandstetter 2016/01/15 19:36:12 nit: "if (!lib)"
honghaiz3 2016/01/15 21:37:36 same as above.
+ LOG(LS_ERROR) << "Library " << net_library_path << " not found!";
+ return rtc::ERR_NOT_IMPLEMENTED;
+ }
+ setNetworkForSocket = reinterpret_cast<SetNetworkForSocket>(
+ dlsym(lib, "setNetworkForSocket"));
+ }
+ if (setNetworkForSocket == nullptr) {
+ LOG(LS_ERROR) << "Symbol setNetworkForSocket not found ";
+ return rtc::ERR_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::OK;
+ }
+ if (rv == ENONET) {
+ return rtc::ERR_NETWORK_CHANGED;
+ }
+ return rtc::ERR_FAILED;
+}
+
+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 +273,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

Powered by Google App Engine
This is Rietveld 408576698