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

Side by Side 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, 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 unified diff | Download patch
OLDNEW
1 /* 1 /*
2 * Copyright 2015 The WebRTC project authors. All Rights Reserved. 2 * Copyright 2015 The WebRTC project authors. All Rights Reserved.
3 * 3 *
4 * Use of this source code is governed by a BSD-style license 4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source 5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found 6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may 7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree. 8 * be found in the AUTHORS file in the root of the source tree.
9 */ 9 */
10 10
11 #include "webrtc/api/android/jni/androidnetworkmonitor_jni.h" 11 #include "webrtc/api/android/jni/androidnetworkmonitor_jni.h"
12 12
13 #include <dlfcn.h> 13 #include <dlfcn.h>
14 // This was added in Lollipop to dlfcn.h
15 #define RTLD_NOLOAD 4
14 16
15 #include "webrtc/api/android/jni/classreferenceholder.h" 17 #include "webrtc/api/android/jni/classreferenceholder.h"
16 #include "webrtc/api/android/jni/jni_helpers.h" 18 #include "webrtc/api/android/jni/jni_helpers.h"
17 #include "webrtc/base/bind.h" 19 #include "webrtc/base/bind.h"
18 #include "webrtc/base/common.h" 20 #include "webrtc/base/common.h"
19 #include "webrtc/base/ipaddress.h" 21 #include "webrtc/base/ipaddress.h"
20 22
21 namespace webrtc_jni { 23 namespace webrtc_jni {
22 24
25 enum AndroidSdkVersion {
26 SDK_VERSION_LOLLIPOP = 21,
27 SDK_VERSION_MARSHMALLOW = 23
28 };
29
23 jobject AndroidNetworkMonitor::application_context_ = nullptr; 30 jobject AndroidNetworkMonitor::application_context_ = nullptr;
31 int AndroidNetworkMonitor::android_sdk_int_ = 0;
24 32
25 static NetworkType GetNetworkTypeFromJava(JNIEnv* jni, jobject j_network_type) { 33 static NetworkType GetNetworkTypeFromJava(JNIEnv* jni, jobject j_network_type) {
26 std::string enum_name = 34 std::string enum_name =
27 GetJavaEnumName(jni, "org/webrtc/NetworkMonitorAutoDetect$ConnectionType", 35 GetJavaEnumName(jni, "org/webrtc/NetworkMonitorAutoDetect$ConnectionType",
28 j_network_type); 36 j_network_type);
29 if (enum_name == "CONNECTION_UNKNOWN") { 37 if (enum_name == "CONNECTION_UNKNOWN") {
30 return NetworkType::NETWORK_UNKNOWN; 38 return NetworkType::NETWORK_UNKNOWN;
31 } 39 }
32 if (enum_name == "CONNECTION_ETHERNET") { 40 if (enum_name == "CONNECTION_ETHERNET") {
33 return NetworkType::NETWORK_ETHERNET; 41 return NetworkType::NETWORK_ETHERNET;
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after
116 ip_addresses->push_back(ip); 124 ip_addresses->push_back(ip);
117 } 125 }
118 } 126 }
119 127
120 static NetworkInformation GetNetworkInformationFromJava( 128 static NetworkInformation GetNetworkInformationFromJava(
121 JNIEnv* jni, 129 JNIEnv* jni,
122 jobject j_network_info) { 130 jobject j_network_info) {
123 jclass j_network_info_class = GetObjectClass(jni, j_network_info); 131 jclass j_network_info_class = GetObjectClass(jni, j_network_info);
124 jfieldID j_interface_name_id = 132 jfieldID j_interface_name_id =
125 GetFieldID(jni, j_network_info_class, "name", "Ljava/lang/String;"); 133 GetFieldID(jni, j_network_info_class, "name", "Ljava/lang/String;");
126 jfieldID j_handle_id = GetFieldID(jni, j_network_info_class, "handle", "I"); 134 jfieldID j_handle_id = GetFieldID(jni, j_network_info_class, "handle", "J");
127 jfieldID j_type_id = 135 jfieldID j_type_id =
128 GetFieldID(jni, j_network_info_class, "type", 136 GetFieldID(jni, j_network_info_class, "type",
129 "Lorg/webrtc/NetworkMonitorAutoDetect$ConnectionType;"); 137 "Lorg/webrtc/NetworkMonitorAutoDetect$ConnectionType;");
130 jfieldID j_ip_addresses_id = 138 jfieldID j_ip_addresses_id =
131 GetFieldID(jni, j_network_info_class, "ipAddresses", 139 GetFieldID(jni, j_network_info_class, "ipAddresses",
132 "[Lorg/webrtc/NetworkMonitorAutoDetect$IPAddress;"); 140 "[Lorg/webrtc/NetworkMonitorAutoDetect$IPAddress;");
133 141
134 NetworkInformation network_info; 142 NetworkInformation network_info;
135 network_info.interface_name = JavaToStdString( 143 network_info.interface_name = JavaToStdString(
136 jni, GetStringField(jni, j_network_info, j_interface_name_id)); 144 jni, GetStringField(jni, j_network_info, j_interface_name_id));
137 network_info.handle = 145 network_info.handle = static_cast<NetworkHandle>(
138 static_cast<NetworkHandle>(GetIntField(jni, j_network_info, j_handle_id)); 146 GetLongField(jni, j_network_info, j_handle_id));
139 network_info.type = GetNetworkTypeFromJava( 147 network_info.type = GetNetworkTypeFromJava(
140 jni, GetObjectField(jni, j_network_info, j_type_id)); 148 jni, GetObjectField(jni, j_network_info, j_type_id));
141 jobjectArray j_ip_addresses = static_cast<jobjectArray>( 149 jobjectArray j_ip_addresses = static_cast<jobjectArray>(
142 GetObjectField(jni, j_network_info, j_ip_addresses_id)); 150 GetObjectField(jni, j_network_info, j_ip_addresses_id));
143 GetIPAddressesFromJava(jni, j_ip_addresses, &network_info.ip_addresses); 151 GetIPAddressesFromJava(jni, j_ip_addresses, &network_info.ip_addresses);
144 return network_info; 152 return network_info;
145 } 153 }
146 154
147 std::string NetworkInformation::ToString() const { 155 std::string NetworkInformation::ToString() const {
148 std::stringstream ss; 156 std::stringstream ss;
(...skipping 22 matching lines...) Expand all
171 jni()->CallStaticObjectMethod( 179 jni()->CallStaticObjectMethod(
172 *j_network_monitor_class_, 180 *j_network_monitor_class_,
173 GetStaticMethodID( 181 GetStaticMethodID(
174 jni(), 182 jni(),
175 *j_network_monitor_class_, 183 *j_network_monitor_class_,
176 "init", 184 "init",
177 "(Landroid/content/Context;)Lorg/webrtc/NetworkMonitor;"), 185 "(Landroid/content/Context;)Lorg/webrtc/NetworkMonitor;"),
178 application_context_)) { 186 application_context_)) {
179 ASSERT(application_context_ != nullptr); 187 ASSERT(application_context_ != nullptr);
180 CHECK_EXCEPTION(jni()) << "Error during NetworkMonitor.init"; 188 CHECK_EXCEPTION(jni()) << "Error during NetworkMonitor.init";
189 if (android_sdk_int_ <= 0) {
190 jmethodID m = GetStaticMethodID(jni(), *j_network_monitor_class_,
191 "androidSdkInt", "()I");
192 android_sdk_int_ = jni()->CallStaticIntMethod(*j_network_monitor_class_, m);
193 CHECK_EXCEPTION(jni()) << "Error during NetworkMonitor.androidSdkInt";
194 }
181 } 195 }
182 196
183 void AndroidNetworkMonitor::Start() { 197 void AndroidNetworkMonitor::Start() {
184 RTC_CHECK(thread_checker_.CalledOnValidThread()); 198 RTC_CHECK(thread_checker_.CalledOnValidThread());
185 if (started_) { 199 if (started_) {
186 return; 200 return;
187 } 201 }
188 started_ = true; 202 started_ = true;
189 203
190 // This is kind of magic behavior, but doing this allows the SocketServer to 204 // This is kind of magic behavior, but doing this allows the SocketServer to
(...skipping 22 matching lines...) Expand all
213 227
214 jmethodID m = 228 jmethodID m =
215 GetMethodID(jni(), *j_network_monitor_class_, "stopMonitoring", "(J)V"); 229 GetMethodID(jni(), *j_network_monitor_class_, "stopMonitoring", "(J)V");
216 jni()->CallVoidMethod(*j_network_monitor_, m, jlongFromPointer(this)); 230 jni()->CallVoidMethod(*j_network_monitor_, m, jlongFromPointer(this));
217 CHECK_EXCEPTION(jni()) << "Error during NetworkMonitor.stopMonitoring"; 231 CHECK_EXCEPTION(jni()) << "Error during NetworkMonitor.stopMonitoring";
218 232
219 network_handle_by_address_.clear(); 233 network_handle_by_address_.clear();
220 network_info_by_handle_.clear(); 234 network_info_by_handle_.clear();
221 } 235 }
222 236
237 // The implementation is largely taken from UDPSocketPosix::BindToNetwork in
238 // https://cs.chromium.org/chromium/src/net/udp/udp_socket_posix.cc
223 int AndroidNetworkMonitor::BindSocketToNetwork(int socket_fd, 239 int AndroidNetworkMonitor::BindSocketToNetwork(int socket_fd,
224 const rtc::IPAddress& address) { 240 const rtc::IPAddress& address) {
225 RTC_CHECK(thread_checker_.CalledOnValidThread()); 241 RTC_CHECK(thread_checker_.CalledOnValidThread());
226 // Android prior to Lollipop didn't have support for binding sockets to 242 // Android prior to Lollipop didn't have support for binding sockets to
227 // networks. However, in that case it should not have reached here because 243 // networks. In that case it should not have reached here because
228 // |network_handle_by_address_| should only be populated in Android Lollipop 244 // |network_handle_by_address_| is only populated in Android Lollipop
229 // and above. 245 // and above.
230 // TODO(honghaiz): Add a check for Android version here so that it won't try 246 if (android_sdk_int_ < SDK_VERSION_LOLLIPOP) {
231 // to look for handle if the Android version is before Lollipop. 247 LOG(LS_ERROR) << "BindSocketToNetwork is not supported in Android SDK "
248 << android_sdk_int_;
249 return rtc::NETWORK_BIND_NOT_IMPLEMENTED;
250 }
251
232 auto iter = network_handle_by_address_.find(address); 252 auto iter = network_handle_by_address_.find(address);
233 if (iter == network_handle_by_address_.end()) { 253 if (iter == network_handle_by_address_.end()) {
234 return rtc::NETWORK_BIND_ADDRESS_NOT_FOUND; 254 return rtc::NETWORK_BIND_ADDRESS_NOT_FOUND;
235 } 255 }
236 NetworkHandle network_handle = iter->second; 256 NetworkHandle network_handle = iter->second;
237 257
238 // NOTE: This does rely on Android implementation details, but 258 int rv = 0;
239 // these details are unlikely to change. 259 if (android_sdk_int_ >= SDK_VERSION_MARSHMALLOW) {
240 typedef int (*SetNetworkForSocket)(unsigned netId, int socketFd); 260 // See declaration of android_setsocknetwork() here:
241 static SetNetworkForSocket setNetworkForSocket; 261 // http://androidxref.com/6.0.0_r1/xref/development/ndk/platforms/android-M/ include/android/multinetwork.h#65
242 // This is not threadsafe, but we are running this only on the worker thread. 262 // Function cannot be called directly as it will cause app to fail to load
243 if (setNetworkForSocket == nullptr) { 263 // on pre-marshmallow devices.
244 // Android's netd client library should always be loaded in our address 264 typedef int (*MarshmallowSetNetworkForSocket)(NetworkHandle net,
245 // space as it shims libc functions like connect(). 265 int socket);
246 const std::string net_library_path = "libnetd_client.so"; 266 static MarshmallowSetNetworkForSocket marshmallowSetNetworkForSocket;
247 void* lib = dlopen(net_library_path.c_str(), RTLD_LAZY); 267 // This is not thread-safe, but we are running this only on the worker
248 if (lib == nullptr) { 268 // thread.
249 LOG(LS_ERROR) << "Library " << net_library_path << " not found!"; 269 if (!marshmallowSetNetworkForSocket) {
270 const std::string android_native_lib_path = "libandroid.so";
271 void* lib = dlopen(android_native_lib_path.c_str(), RTLD_NOW);
272 if (lib == nullptr) {
273 LOG(LS_ERROR) << "Library " << android_native_lib_path << " not found!";
274 return rtc::NETWORK_BIND_NOT_IMPLEMENTED;
275 }
276 marshmallowSetNetworkForSocket =
277 reinterpret_cast<MarshmallowSetNetworkForSocket>(
278 dlsym(lib, "android_setsocknetwork"));
279 }
280 if (!marshmallowSetNetworkForSocket) {
281 LOG(LS_ERROR) << "Symbol marshmallowSetNetworkForSocket is not found";
250 return rtc::NETWORK_BIND_NOT_IMPLEMENTED; 282 return rtc::NETWORK_BIND_NOT_IMPLEMENTED;
251 } 283 }
252 setNetworkForSocket = reinterpret_cast<SetNetworkForSocket>( 284 rv = marshmallowSetNetworkForSocket(network_handle, socket_fd);
253 dlsym(lib, "setNetworkForSocket")); 285 } else {
286 // NOTE: This relies on Android implementation details, but it won't change
287 // because Lollipop is already released.
288 typedef int (*LollipopSetNetworkForSocket)(unsigned net, int socket);
289 static LollipopSetNetworkForSocket lollipopSetNetworkForSocket;
290 // This is not threadsafe, but we are running this only on the worker
291 // thread.
292 if (!lollipopSetNetworkForSocket) {
293 // Android's netd client library should always be loaded in our address
294 // space as it shims libc functions like connect().
295 const std::string net_library_path = "libnetd_client.so";
296 // Use RTLD_NOW to match Android's prior loading of the library:
297 // http://androidxref.com/6.0.0_r5/xref/bionic/libc/bionic/NetdClient.cpp# 37
298 // Use RTLD_NOLOAD to assert that the library is already loaded and
299 // avoid doing any disk IO.
300 void* lib = dlopen(net_library_path.c_str(), RTLD_NOW | RTLD_NOLOAD);
301 if (lib == nullptr) {
302 LOG(LS_ERROR) << "Library " << net_library_path << " not found!";
303 return rtc::NETWORK_BIND_NOT_IMPLEMENTED;
304 }
305 lollipopSetNetworkForSocket =
306 reinterpret_cast<LollipopSetNetworkForSocket>(
307 dlsym(lib, "setNetworkForSocket"));
308 }
309 if (!lollipopSetNetworkForSocket) {
310 LOG(LS_ERROR) << "Symbol lollipopSetNetworkForSocket is not found ";
311 return rtc::NETWORK_BIND_NOT_IMPLEMENTED;
312 }
313 rv = lollipopSetNetworkForSocket(network_handle, socket_fd);
254 } 314 }
255 if (setNetworkForSocket == nullptr) { 315
256 LOG(LS_ERROR) << "Symbol setNetworkForSocket not found ";
257 return rtc::NETWORK_BIND_NOT_IMPLEMENTED;
258 }
259 int rv = setNetworkForSocket(network_handle, socket_fd);
260 // If |network| has since disconnected, |rv| will be ENONET. Surface this as 316 // If |network| has since disconnected, |rv| will be ENONET. Surface this as
261 // ERR_NETWORK_CHANGED, rather than MapSystemError(ENONET) which gives back 317 // ERR_NETWORK_CHANGED, rather than MapSystemError(ENONET) which gives back
262 // the less descriptive ERR_FAILED. 318 // the less descriptive ERR_FAILED.
263 if (rv == 0) { 319 if (rv == 0) {
264 return rtc::NETWORK_BIND_SUCCESS; 320 return rtc::NETWORK_BIND_SUCCESS;
265 } 321 }
266 if (rv == ENONET) { 322 if (rv == ENONET) {
267 return rtc::NETWORK_BIND_NETWORK_CHANGED; 323 return rtc::NETWORK_BIND_NETWORK_CHANGED;
268 } 324 }
269 return rtc::NETWORK_BIND_FAILURE; 325 return rtc::NETWORK_BIND_FAILURE;
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after
362 jobject j_network_info) { 418 jobject j_network_info) {
363 AndroidNetworkMonitor* network_monitor = 419 AndroidNetworkMonitor* network_monitor =
364 reinterpret_cast<AndroidNetworkMonitor*>(j_native_monitor); 420 reinterpret_cast<AndroidNetworkMonitor*>(j_native_monitor);
365 NetworkInformation network_info = 421 NetworkInformation network_info =
366 GetNetworkInformationFromJava(jni, j_network_info); 422 GetNetworkInformationFromJava(jni, j_network_info);
367 network_monitor->OnNetworkConnected(network_info); 423 network_monitor->OnNetworkConnected(network_info);
368 } 424 }
369 425
370 JOW(void, NetworkMonitor_nativeNotifyOfNetworkDisconnect)( 426 JOW(void, NetworkMonitor_nativeNotifyOfNetworkDisconnect)(
371 JNIEnv* jni, jobject j_monitor, jlong j_native_monitor, 427 JNIEnv* jni, jobject j_monitor, jlong j_native_monitor,
372 jint network_handle) { 428 jlong network_handle) {
373 AndroidNetworkMonitor* network_monitor = 429 AndroidNetworkMonitor* network_monitor =
374 reinterpret_cast<AndroidNetworkMonitor*>(j_native_monitor); 430 reinterpret_cast<AndroidNetworkMonitor*>(j_native_monitor);
375 network_monitor->OnNetworkDisconnected( 431 network_monitor->OnNetworkDisconnected(
376 static_cast<NetworkHandle>(network_handle)); 432 static_cast<NetworkHandle>(network_handle));
377 } 433 }
378 434
379 } // namespace webrtc_jni 435 } // namespace webrtc_jni
OLDNEW
« 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