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

Unified Diff: webrtc/api/android/jni/androidnetworkmonitor_jni.cc

Issue 2189753002: Use a newer method to bind socket to network in Android M and later. (Closed) Base URL: https://chromium.googlesource.com/external/webrtc.git@master
Patch Set: Fix a test Created 4 years, 5 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: webrtc/api/android/jni/androidnetworkmonitor_jni.cc
diff --git a/webrtc/api/android/jni/androidnetworkmonitor_jni.cc b/webrtc/api/android/jni/androidnetworkmonitor_jni.cc
index 403badc515b1905a3e516025f9191e6f63a4f665..16da5faa9238fa3b6b1ee7ab63b268c257b90276 100644
--- a/webrtc/api/android/jni/androidnetworkmonitor_jni.cc
+++ b/webrtc/api/android/jni/androidnetworkmonitor_jni.cc
@@ -11,6 +11,8 @@
#include "webrtc/api/android/jni/androidnetworkmonitor_jni.h"
#include <dlfcn.h>
+// This was added in Lollipop to dlfcn.h
+#define RTLD_NOLOAD 4
#include "webrtc/api/android/jni/classreferenceholder.h"
#include "webrtc/api/android/jni/jni_helpers.h"
@@ -20,7 +22,13 @@
namespace webrtc_jni {
+enum AndroidSdkVersion {
+ SDK_VERSION_LOLLIPOP = 21,
+ SDK_VERSION_MARSHMALLOW = 23
+};
+
jobject AndroidNetworkMonitor::application_context_ = nullptr;
+int AndroidNetworkMonitor::android_sdk_int_ = 0;
static NetworkType GetNetworkTypeFromJava(JNIEnv* jni, jobject j_network_type) {
std::string enum_name =
@@ -123,7 +131,7 @@ static NetworkInformation GetNetworkInformationFromJava(
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_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;");
@@ -134,8 +142,8 @@ static NetworkInformation GetNetworkInformationFromJava(
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.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>(
@@ -178,6 +186,12 @@ AndroidNetworkMonitor::AndroidNetworkMonitor()
application_context_)) {
ASSERT(application_context_ != nullptr);
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() {
@@ -220,43 +234,85 @@ void AndroidNetworkMonitor::Stop() {
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
int AndroidNetworkMonitor::BindSocketToNetwork(int socket_fd,
const rtc::IPAddress& address) {
RTC_CHECK(thread_checker_.CalledOnValidThread());
// 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_handle_by_address_| should only be populated in Android Lollipop
+ // networks. In that case it should not have reached here because
+ // |network_handle_by_address_| is only populated in Android Lollipop
// and above.
- // TODO(honghaiz): Add a check for Android version here so that it won't try
- // to look for handle if the Android version is before Lollipop.
+ if (android_sdk_int_ < SDK_VERSION_LOLLIPOP) {
+ LOG(LS_ERROR) << "BindSocketToNetwork is not supported in Android SDK "
+ << android_sdk_int_;
+ return rtc::NETWORK_BIND_NOT_IMPLEMENTED;
+ }
+
auto iter = network_handle_by_address_.find(address);
if (iter == network_handle_by_address_.end()) {
return rtc::NETWORK_BIND_ADDRESS_NOT_FOUND;
}
NetworkHandle network_handle = iter->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!";
+ 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::NETWORK_BIND_NOT_IMPLEMENTED;
+ }
+ marshmallowSetNetworkForSocket =
+ reinterpret_cast<MarshmallowSetNetworkForSocket>(
+ dlsym(lib, "android_setsocknetwork"));
+ }
+ if (!marshmallowSetNetworkForSocket) {
+ LOG(LS_ERROR) << "Symbol marshmallowSetNetworkForSocket is 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;
+ 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::NETWORK_BIND_NOT_IMPLEMENTED;
+ }
+ lollipopSetNetworkForSocket =
+ reinterpret_cast<LollipopSetNetworkForSocket>(
+ dlsym(lib, "setNetworkForSocket"));
+ }
+ if (!lollipopSetNetworkForSocket) {
+ LOG(LS_ERROR) << "Symbol lollipopSetNetworkForSocket is not found ";
+ return rtc::NETWORK_BIND_NOT_IMPLEMENTED;
+ }
+ rv = lollipopSetNetworkForSocket(network_handle, socket_fd);
}
- 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.
@@ -369,7 +425,7 @@ JOW(void, NetworkMonitor_nativeNotifyOfNetworkConnect)(
JOW(void, NetworkMonitor_nativeNotifyOfNetworkDisconnect)(
JNIEnv* jni, jobject j_monitor, jlong j_native_monitor,
- jint network_handle) {
+ jlong network_handle) {
AndroidNetworkMonitor* network_monitor =
reinterpret_cast<AndroidNetworkMonitor*>(j_native_monitor);
network_monitor->OnNetworkDisconnected(
« no previous file with comments | « webrtc/api/android/jni/androidnetworkmonitor_jni.h ('k') | webrtc/api/androidtests/src/org/webrtc/NetworkMonitorTest.java » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698