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

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: . 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
« no previous file with comments | « webrtc/api/android/jni/androidnetworkmonitor_jni.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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);
AlexG 2016/07/27 23:37:02 Add CHECK_EXCEPTION(jni())
honghaiz3 2016/07/29 17:28:18 Done.
193 }
181 } 194 }
182 195
183 void AndroidNetworkMonitor::Start() { 196 void AndroidNetworkMonitor::Start() {
184 RTC_CHECK(thread_checker_.CalledOnValidThread()); 197 RTC_CHECK(thread_checker_.CalledOnValidThread());
185 if (started_) { 198 if (started_) {
186 return; 199 return;
187 } 200 }
188 started_ = true; 201 started_ = true;
189 202
190 // This is kind of magic behavior, but doing this allows the SocketServer to 203 // This is kind of magic behavior, but doing this allows the SocketServer to
(...skipping 22 matching lines...) Expand all
213 226
214 jmethodID m = 227 jmethodID m =
215 GetMethodID(jni(), *j_network_monitor_class_, "stopMonitoring", "(J)V"); 228 GetMethodID(jni(), *j_network_monitor_class_, "stopMonitoring", "(J)V");
216 jni()->CallVoidMethod(*j_network_monitor_, m, jlongFromPointer(this)); 229 jni()->CallVoidMethod(*j_network_monitor_, m, jlongFromPointer(this));
217 CHECK_EXCEPTION(jni()) << "Error during NetworkMonitor.stopMonitoring"; 230 CHECK_EXCEPTION(jni()) << "Error during NetworkMonitor.stopMonitoring";
218 231
219 network_handle_by_address_.clear(); 232 network_handle_by_address_.clear();
220 network_info_by_handle_.clear(); 233 network_info_by_handle_.clear();
221 } 234 }
222 235
236 // The implementation is largely taken from UDPSocketPosix::BindToNetwork in
237 // https://cs.chromium.org/chromium/src/net/udp/udp_socket_posix.cc
223 int AndroidNetworkMonitor::BindSocketToNetwork(int socket_fd, 238 int AndroidNetworkMonitor::BindSocketToNetwork(int socket_fd,
224 const rtc::IPAddress& address) { 239 const rtc::IPAddress& address) {
225 RTC_CHECK(thread_checker_.CalledOnValidThread()); 240 RTC_CHECK(thread_checker_.CalledOnValidThread());
226 // Android prior to Lollipop didn't have support for binding sockets to 241 // 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 242 // networks. In that case it should not have reached here because
228 // |network_handle_by_address_| should only be populated in Android Lollipop 243 // |network_handle_by_address_| is only populated in Android Lollipop
229 // and above. 244 // and above.
230 // TODO(honghaiz): Add a check for Android version here so that it won't try 245 if (android_sdk_int_ < SDK_VERSION_LOLLIPOP) {
231 // to look for handle if the Android version is before Lollipop. 246 LOG(LS_ERROR) << "BindSocketToNetwork is not supported in Android SDK "
247 << android_sdk_int_;
248 return rtc::NETWORK_BIND_NOT_IMPLEMENTED;
249 }
250
232 auto iter = network_handle_by_address_.find(address); 251 auto iter = network_handle_by_address_.find(address);
233 if (iter == network_handle_by_address_.end()) { 252 if (iter == network_handle_by_address_.end()) {
234 return rtc::NETWORK_BIND_ADDRESS_NOT_FOUND; 253 return rtc::NETWORK_BIND_ADDRESS_NOT_FOUND;
235 } 254 }
236 NetworkHandle network_handle = iter->second; 255 NetworkHandle network_handle = iter->second;
237 256
238 // NOTE: This does rely on Android implementation details, but 257 int rv = 0;
239 // these details are unlikely to change. 258 if (android_sdk_int_ >= SDK_VERSION_MARSHMALLOW) {
240 typedef int (*SetNetworkForSocket)(unsigned netId, int socketFd); 259 // See declaration of android_setsocknetwork() here:
241 static SetNetworkForSocket setNetworkForSocket; 260 // 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. 261 // Function cannot be called directly as it will cause app to fail to load
243 if (setNetworkForSocket == nullptr) { 262 // on pre-marshmallow devices.
244 // Android's netd client library should always be loaded in our address 263 typedef int (*MarshmallowSetNetworkForSocket)(NetworkHandle net,
245 // space as it shims libc functions like connect(). 264 int socket);
246 const std::string net_library_path = "libnetd_client.so"; 265 static MarshmallowSetNetworkForSocket marshmallowSetNetworkForSocket;
247 void* lib = dlopen(net_library_path.c_str(), RTLD_LAZY); 266 // This is not thread-safe, but we are running this only on the worker
248 if (lib == nullptr) { 267 // thread.
249 LOG(LS_ERROR) << "Library " << net_library_path << " not found!"; 268 if (!marshmallowSetNetworkForSocket) {
269 const std::string android_native_lib_path = "libandroid.so";
270 void* lib = dlopen(android_native_lib_path.c_str(), RTLD_NOW);
AlexG 2016/07/27 23:37:03 Keep check for lib == nullptr ?
honghaiz3 2016/07/29 17:28:18 Done.
271 marshmallowSetNetworkForSocket =
272 reinterpret_cast<MarshmallowSetNetworkForSocket>(
273 dlsym(lib, "android_setsocknetwork"));
274 }
275 if (!marshmallowSetNetworkForSocket) {
276 LOG(LS_ERROR) << "Symbol marshmallowSetNetworkForSocket is not found";
250 return rtc::NETWORK_BIND_NOT_IMPLEMENTED; 277 return rtc::NETWORK_BIND_NOT_IMPLEMENTED;
251 } 278 }
252 setNetworkForSocket = reinterpret_cast<SetNetworkForSocket>( 279 rv = marshmallowSetNetworkForSocket(network_handle, socket_fd);
253 dlsym(lib, "setNetworkForSocket")); 280 } else {
281 // NOTE: This relies on Android implementation details, but it won't change
282 // because Lollipop is already released.
283 typedef int (*LollipopSetNetworkForSocket)(unsigned net, int socket);
284 static LollipopSetNetworkForSocket lollipopSetNetworkForSocket;
285 // This is not threadsafe, but we are running this only on the worker
286 // thread.
287 if (!lollipopSetNetworkForSocket) {
288 // Android's netd client library should always be loaded in our address
289 // space as it shims libc functions like connect().
290 const std::string net_library_path = "libnetd_client.so";
291 // Use RTLD_NOW to match Android's prior loading of the library:
292 // http://androidxref.com/6.0.0_r5/xref/bionic/libc/bionic/NetdClient.cpp# 37
293 // Use RTLD_NOLOAD to assert that the library is already loaded and
294 // avoid doing any disk IO.
295 void* lib = dlopen(net_library_path.c_str(), RTLD_NOW | RTLD_NOLOAD);
AlexG 2016/07/27 23:37:02 ditto: keep check for lib == nullptr?
honghaiz3 2016/07/29 17:28:18 Done.
296 lollipopSetNetworkForSocket =
297 reinterpret_cast<LollipopSetNetworkForSocket>(
298 dlsym(lib, "setNetworkForSocket"));
299 }
300 if (!lollipopSetNetworkForSocket) {
301 LOG(LS_ERROR) << "Symbol lollipopSetNetworkForSocket is not found ";
302 return rtc::NETWORK_BIND_NOT_IMPLEMENTED;
303 }
304 rv = lollipopSetNetworkForSocket(network_handle, socket_fd);
254 } 305 }
255 if (setNetworkForSocket == nullptr) { 306
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 307 // If |network| has since disconnected, |rv| will be ENONET. Surface this as
261 // ERR_NETWORK_CHANGED, rather than MapSystemError(ENONET) which gives back 308 // ERR_NETWORK_CHANGED, rather than MapSystemError(ENONET) which gives back
262 // the less descriptive ERR_FAILED. 309 // the less descriptive ERR_FAILED.
263 if (rv == 0) { 310 if (rv == 0) {
264 return rtc::NETWORK_BIND_SUCCESS; 311 return rtc::NETWORK_BIND_SUCCESS;
265 } 312 }
266 if (rv == ENONET) { 313 if (rv == ENONET) {
267 return rtc::NETWORK_BIND_NETWORK_CHANGED; 314 return rtc::NETWORK_BIND_NETWORK_CHANGED;
268 } 315 }
269 return rtc::NETWORK_BIND_FAILURE; 316 return rtc::NETWORK_BIND_FAILURE;
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after
362 jobject j_network_info) { 409 jobject j_network_info) {
363 AndroidNetworkMonitor* network_monitor = 410 AndroidNetworkMonitor* network_monitor =
364 reinterpret_cast<AndroidNetworkMonitor*>(j_native_monitor); 411 reinterpret_cast<AndroidNetworkMonitor*>(j_native_monitor);
365 NetworkInformation network_info = 412 NetworkInformation network_info =
366 GetNetworkInformationFromJava(jni, j_network_info); 413 GetNetworkInformationFromJava(jni, j_network_info);
367 network_monitor->OnNetworkConnected(network_info); 414 network_monitor->OnNetworkConnected(network_info);
368 } 415 }
369 416
370 JOW(void, NetworkMonitor_nativeNotifyOfNetworkDisconnect)( 417 JOW(void, NetworkMonitor_nativeNotifyOfNetworkDisconnect)(
371 JNIEnv* jni, jobject j_monitor, jlong j_native_monitor, 418 JNIEnv* jni, jobject j_monitor, jlong j_native_monitor,
372 jint network_handle) { 419 jlong network_handle) {
373 AndroidNetworkMonitor* network_monitor = 420 AndroidNetworkMonitor* network_monitor =
374 reinterpret_cast<AndroidNetworkMonitor*>(j_native_monitor); 421 reinterpret_cast<AndroidNetworkMonitor*>(j_native_monitor);
375 network_monitor->OnNetworkDisconnected( 422 network_monitor->OnNetworkDisconnected(
376 static_cast<NetworkHandle>(network_handle)); 423 static_cast<NetworkHandle>(network_handle));
377 } 424 }
378 425
379 } // namespace webrtc_jni 426 } // namespace webrtc_jni
OLDNEW
« no previous file with comments | « webrtc/api/android/jni/androidnetworkmonitor_jni.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698