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

Unified Diff: webrtc/sdk/android/src/jni/androidnetworkmonitor_jni.cc

Issue 2989323002: Revert of Break peerconnection_jni.cc into multiple files, in "pc" directory. (Closed)
Patch Set: Created 3 years, 4 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
« no previous file with comments | « webrtc/sdk/android/src/jni/androidnetworkmonitor_jni.h ('k') | webrtc/sdk/android/src/jni/audio_jni.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: webrtc/sdk/android/src/jni/androidnetworkmonitor_jni.cc
diff --git a/webrtc/sdk/android/src/jni/androidnetworkmonitor_jni.cc b/webrtc/sdk/android/src/jni/androidnetworkmonitor_jni.cc
new file mode 100644
index 0000000000000000000000000000000000000000..19f9b303ffd92a89a5fbbf74dbf3bfc1573c6b8b
--- /dev/null
+++ b/webrtc/sdk/android/src/jni/androidnetworkmonitor_jni.cc
@@ -0,0 +1,433 @@
+/*
+ * Copyright 2015 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.
+ */
+
+#include "webrtc/sdk/android/src/jni/androidnetworkmonitor_jni.h"
+
+#include <dlfcn.h>
+// This was added in Lollipop to dlfcn.h
+#define RTLD_NOLOAD 4
+
+#include "webrtc/rtc_base/bind.h"
+#include "webrtc/rtc_base/checks.h"
+#include "webrtc/rtc_base/ipaddress.h"
+#include "webrtc/sdk/android/src/jni/classreferenceholder.h"
+#include "webrtc/sdk/android/src/jni/jni_helpers.h"
+
+namespace webrtc_jni {
+
+enum AndroidSdkVersion {
+ SDK_VERSION_LOLLIPOP = 21,
+ SDK_VERSION_MARSHMALLOW = 23
+};
+
+int AndroidNetworkMonitor::android_sdk_int_ = 0;
+
+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_UNKNOWN_CELLULAR") {
+ return NetworkType::NETWORK_UNKNOWN_CELLULAR;
+ }
+ if (enum_name == "CONNECTION_BLUETOOTH") {
+ return NetworkType::NETWORK_BLUETOOTH;
+ }
+ if (enum_name == "CONNECTION_NONE") {
+ return NetworkType::NETWORK_NONE;
+ }
+ RTC_NOTREACHED();
+ return NetworkType::NETWORK_UNKNOWN;
+}
+
+static rtc::AdapterType AdapterTypeFromNetworkType(NetworkType network_type) {
+ switch (network_type) {
+ case NETWORK_UNKNOWN:
+ return rtc::ADAPTER_TYPE_UNKNOWN;
+ case NETWORK_ETHERNET:
+ return rtc::ADAPTER_TYPE_ETHERNET;
+ case NETWORK_WIFI:
+ return rtc::ADAPTER_TYPE_WIFI;
+ case NETWORK_4G:
+ case NETWORK_3G:
+ case NETWORK_2G:
+ case NETWORK_UNKNOWN_CELLULAR:
+ return rtc::ADAPTER_TYPE_CELLULAR;
+ case NETWORK_BLUETOOTH:
+ // There is no corresponding mapping for bluetooth networks.
+ // Map it to VPN for now.
+ return rtc::ADAPTER_TYPE_VPN;
+ default:
+ RTC_NOTREACHED() << "Invalid network type " << network_type;
+ return rtc::ADAPTER_TYPE_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", "J");
+ 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>(
+ GetLongField(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();
+}
+
+AndroidNetworkMonitor::AndroidNetworkMonitor()
+ : j_network_monitor_class_(jni(),
+ FindClass(jni(), "org/webrtc/NetworkMonitor")),
+ j_network_monitor_(
+ jni(),
+ jni()->CallStaticObjectMethod(
+ *j_network_monitor_class_,
+ GetStaticMethodID(jni(),
+ *j_network_monitor_class_,
+ "getInstance",
+ "()Lorg/webrtc/NetworkMonitor;"))) {
+ CHECK_EXCEPTION(jni()) << "Error during NetworkMonitor.init";
+ if (android_sdk_int_ <= 0) {
+ jmethodID m = GetStaticMethodID(jni(), *j_network_monitor_class_,
+ "androidSdkInt", "()I");
+ android_sdk_int_ = jni()->CallStaticIntMethod(*j_network_monitor_class_, m);
+ CHECK_EXCEPTION(jni()) << "Error during NetworkMonitor.androidSdkInt";
+ }
+}
+
+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));
+ CHECK_EXCEPTION(jni()) << "Error during CallVoidMethod";
+}
+
+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_handle_by_address_.clear();
+ network_info_by_handle_.clear();
+}
+
+// The implementation is largely taken from UDPSocketPosix::BindToNetwork in
+// https://cs.chromium.org/chromium/src/net/udp/udp_socket_posix.cc
+rtc::NetworkBindingResult AndroidNetworkMonitor::BindSocketToNetwork(
+ int socket_fd,
+ const rtc::IPAddress& address) {
+ RTC_CHECK(thread_checker_.CalledOnValidThread());
+
+ if (socket_fd == 0 /* NETWORK_UNSPECIFIED */) {
+ return rtc::NetworkBindingResult::NOT_IMPLEMENTED;
+ }
+
+ jmethodID network_binding_supported_id = GetMethodID(
+ jni(), *j_network_monitor_class_, "networkBindingSupported", "()Z");
+ // Android prior to Lollipop didn't have support for binding sockets to
+ // networks. This may also occur if there is no connectivity manager service.
+ bool network_binding_supported = jni()->CallBooleanMethod(
+ *j_network_monitor_, network_binding_supported_id);
+ CHECK_EXCEPTION(jni())
+ << "Error during NetworkMonitor.networkBindingSupported";
+ if (!network_binding_supported) {
+ LOG(LS_WARNING) << "BindSocketToNetwork is not supported on this platform "
+ << "(Android SDK: " << android_sdk_int_ << ")";
+ return rtc::NetworkBindingResult::NOT_IMPLEMENTED;
+ }
+
+ auto iter = network_handle_by_address_.find(address);
+ if (iter == network_handle_by_address_.end()) {
+ return rtc::NetworkBindingResult::ADDRESS_NOT_FOUND;
+ }
+ NetworkHandle network_handle = iter->second;
+
+ int rv = 0;
+ if (android_sdk_int_ >= SDK_VERSION_MARSHMALLOW) {
+ // See declaration of android_setsocknetwork() here:
+ // http://androidxref.com/6.0.0_r1/xref/development/ndk/platforms/android-M/include/android/multinetwork.h#65
+ // Function cannot be called directly as it will cause app to fail to load
+ // on pre-marshmallow devices.
+ typedef int (*MarshmallowSetNetworkForSocket)(NetworkHandle net,
+ int socket);
+ static MarshmallowSetNetworkForSocket marshmallowSetNetworkForSocket;
+ // This is not thread-safe, but we are running this only on the worker
+ // thread.
+ if (!marshmallowSetNetworkForSocket) {
+ const std::string android_native_lib_path = "libandroid.so";
+ void* lib = dlopen(android_native_lib_path.c_str(), RTLD_NOW);
+ if (lib == nullptr) {
+ LOG(LS_ERROR) << "Library " << android_native_lib_path << " not found!";
+ return rtc::NetworkBindingResult::NOT_IMPLEMENTED;
+ }
+ marshmallowSetNetworkForSocket =
+ reinterpret_cast<MarshmallowSetNetworkForSocket>(
+ dlsym(lib, "android_setsocknetwork"));
+ }
+ if (!marshmallowSetNetworkForSocket) {
+ LOG(LS_ERROR) << "Symbol marshmallowSetNetworkForSocket is not found";
+ return rtc::NetworkBindingResult::NOT_IMPLEMENTED;
+ }
+ rv = marshmallowSetNetworkForSocket(network_handle, socket_fd);
+ } else {
+ // NOTE: This relies on Android implementation details, but it won't change
+ // because Lollipop is already released.
+ typedef int (*LollipopSetNetworkForSocket)(unsigned net, int socket);
+ static LollipopSetNetworkForSocket lollipopSetNetworkForSocket;
+ // This is not threadsafe, but we are running this only on the worker
+ // thread.
+ if (!lollipopSetNetworkForSocket) {
+ // 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";
+ // Use RTLD_NOW to match Android's prior loading of the library:
+ // http://androidxref.com/6.0.0_r5/xref/bionic/libc/bionic/NetdClient.cpp#37
+ // Use RTLD_NOLOAD to assert that the library is already loaded and
+ // avoid doing any disk IO.
+ void* lib = dlopen(net_library_path.c_str(), RTLD_NOW | RTLD_NOLOAD);
+ if (lib == nullptr) {
+ LOG(LS_ERROR) << "Library " << net_library_path << " not found!";
+ return rtc::NetworkBindingResult::NOT_IMPLEMENTED;
+ }
+ lollipopSetNetworkForSocket =
+ reinterpret_cast<LollipopSetNetworkForSocket>(
+ dlsym(lib, "setNetworkForSocket"));
+ }
+ if (!lollipopSetNetworkForSocket) {
+ LOG(LS_ERROR) << "Symbol lollipopSetNetworkForSocket is not found ";
+ return rtc::NetworkBindingResult::NOT_IMPLEMENTED;
+ }
+ rv = lollipopSetNetworkForSocket(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::NetworkBindingResult::SUCCESS;
+ }
+ if (rv == ENONET) {
+ return rtc::NetworkBindingResult::NETWORK_CHANGED;
+ }
+ return rtc::NetworkBindingResult::FAILURE;
+}
+
+void AndroidNetworkMonitor::OnNetworkConnected(
+ const NetworkInformation& network_info) {
+ worker_thread()->Invoke<void>(
+ RTC_FROM_HERE, rtc::Bind(&AndroidNetworkMonitor::OnNetworkConnected_w,
+ this, network_info));
+ // Fire SignalNetworksChanged to update the list of networks.
+ OnNetworksChanged();
+}
+
+void AndroidNetworkMonitor::OnNetworkConnected_w(
+ const NetworkInformation& network_info) {
+ LOG(LS_INFO) << "Network connected: " << network_info.ToString();
+ adapter_type_by_name_[network_info.interface_name] =
+ AdapterTypeFromNetworkType(network_info.type);
+ network_info_by_handle_[network_info.handle] = network_info;
+ for (const rtc::IPAddress& address : network_info.ip_addresses) {
+ network_handle_by_address_[address] = network_info.handle;
+ }
+}
+
+void AndroidNetworkMonitor::OnNetworkDisconnected(NetworkHandle handle) {
+ LOG(LS_INFO) << "Network disconnected for handle " << handle;
+ worker_thread()->Invoke<void>(
+ RTC_FROM_HERE,
+ rtc::Bind(&AndroidNetworkMonitor::OnNetworkDisconnected_w, this, handle));
+}
+
+void AndroidNetworkMonitor::OnNetworkDisconnected_w(NetworkHandle handle) {
+ auto iter = network_info_by_handle_.find(handle);
+ if (iter != network_info_by_handle_.end()) {
+ for (const rtc::IPAddress& address : iter->second.ip_addresses) {
+ network_handle_by_address_.erase(address);
+ }
+ network_info_by_handle_.erase(iter);
+ }
+}
+
+void AndroidNetworkMonitor::SetNetworkInfos(
+ const std::vector<NetworkInformation>& network_infos) {
+ RTC_CHECK(thread_checker_.CalledOnValidThread());
+ network_handle_by_address_.clear();
+ network_info_by_handle_.clear();
+ LOG(LS_INFO) << "Android network monitor found " << network_infos.size()
+ << " networks";
+ for (NetworkInformation network : network_infos) {
+ OnNetworkConnected_w(network);
+ }
+}
+
+rtc::AdapterType AndroidNetworkMonitor::GetAdapterType(
+ const std::string& if_name) {
+ auto iter = adapter_type_by_name_.find(if_name);
+ rtc::AdapterType type = (iter == adapter_type_by_name_.end())
+ ? rtc::ADAPTER_TYPE_UNKNOWN
+ : iter->second;
+ if (type == rtc::ADAPTER_TYPE_UNKNOWN) {
+ LOG(LS_WARNING) << "Get an unknown type for the interface " << if_name;
+ }
+ return type;
+}
+
+rtc::NetworkMonitorInterface*
+AndroidNetworkMonitorFactory::CreateNetworkMonitor() {
+ return new AndroidNetworkMonitor();
+}
+
+JOW(void, NetworkMonitor_nativeNotifyConnectionTypeChanged)(
+ JNIEnv* jni, jobject j_monitor, jlong j_native_monitor) {
+ rtc::NetworkMonitorInterface* network_monitor =
+ reinterpret_cast<rtc::NetworkMonitorInterface*>(j_native_monitor);
+ network_monitor->OnNetworksChanged();
+}
+
+JOW(void, NetworkMonitor_nativeNotifyOfActiveNetworkList)(
+ JNIEnv* jni, jobject j_monitor, jlong j_native_monitor,
+ jobjectArray j_network_infos) {
+ AndroidNetworkMonitor* network_monitor =
+ reinterpret_cast<AndroidNetworkMonitor*>(j_native_monitor);
+ std::vector<NetworkInformation> network_infos;
+ size_t num_networks = jni->GetArrayLength(j_network_infos);
+ for (size_t i = 0; i < num_networks; ++i) {
+ jobject j_network_info = jni->GetObjectArrayElement(j_network_infos, i);
+ CHECK_EXCEPTION(jni) << "Error during GetObjectArrayElement";
+ network_infos.push_back(GetNetworkInformationFromJava(jni, j_network_info));
+ }
+ network_monitor->SetNetworkInfos(network_infos);
+}
+
+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->OnNetworkConnected(network_info);
+}
+
+JOW(void, NetworkMonitor_nativeNotifyOfNetworkDisconnect)(
+ JNIEnv* jni, jobject j_monitor, jlong j_native_monitor,
+ jlong network_handle) {
+ AndroidNetworkMonitor* network_monitor =
+ reinterpret_cast<AndroidNetworkMonitor*>(j_native_monitor);
+ network_monitor->OnNetworkDisconnected(
+ static_cast<NetworkHandle>(network_handle));
+}
+
+} // namespace webrtc_jni
« no previous file with comments | « webrtc/sdk/android/src/jni/androidnetworkmonitor_jni.h ('k') | webrtc/sdk/android/src/jni/audio_jni.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698