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

Side by Side Diff: webrtc/sdk/android/src/jni/androidnetworkmonitor_jni.cc

Issue 2992103002: Relanding: Break peerconnection_jni.cc into multiple files, in "pc" directory. (Closed)
Patch Set: Add jni/androidnetworkmonitor_jni.h include for backwards comaptibility. 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 unified diff | Download patch
OLDNEW
(Empty)
1 /*
2 * Copyright 2015 The WebRTC project authors. All Rights Reserved.
3 *
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
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11 #include "webrtc/sdk/android/src/jni/androidnetworkmonitor_jni.h"
12
13 #include <dlfcn.h>
14 // This was added in Lollipop to dlfcn.h
15 #define RTLD_NOLOAD 4
16
17 #include "webrtc/rtc_base/bind.h"
18 #include "webrtc/rtc_base/checks.h"
19 #include "webrtc/rtc_base/ipaddress.h"
20 #include "webrtc/sdk/android/src/jni/classreferenceholder.h"
21 #include "webrtc/sdk/android/src/jni/jni_helpers.h"
22
23 namespace webrtc_jni {
24
25 enum AndroidSdkVersion {
26 SDK_VERSION_LOLLIPOP = 21,
27 SDK_VERSION_MARSHMALLOW = 23
28 };
29
30 int AndroidNetworkMonitor::android_sdk_int_ = 0;
31
32 static NetworkType GetNetworkTypeFromJava(JNIEnv* jni, jobject j_network_type) {
33 std::string enum_name =
34 GetJavaEnumName(jni, "org/webrtc/NetworkMonitorAutoDetect$ConnectionType",
35 j_network_type);
36 if (enum_name == "CONNECTION_UNKNOWN") {
37 return NetworkType::NETWORK_UNKNOWN;
38 }
39 if (enum_name == "CONNECTION_ETHERNET") {
40 return NetworkType::NETWORK_ETHERNET;
41 }
42 if (enum_name == "CONNECTION_WIFI") {
43 return NetworkType::NETWORK_WIFI;
44 }
45 if (enum_name == "CONNECTION_4G") {
46 return NetworkType::NETWORK_4G;
47 }
48 if (enum_name == "CONNECTION_3G") {
49 return NetworkType::NETWORK_3G;
50 }
51 if (enum_name == "CONNECTION_2G") {
52 return NetworkType::NETWORK_2G;
53 }
54 if (enum_name == "CONNECTION_UNKNOWN_CELLULAR") {
55 return NetworkType::NETWORK_UNKNOWN_CELLULAR;
56 }
57 if (enum_name == "CONNECTION_BLUETOOTH") {
58 return NetworkType::NETWORK_BLUETOOTH;
59 }
60 if (enum_name == "CONNECTION_NONE") {
61 return NetworkType::NETWORK_NONE;
62 }
63 RTC_NOTREACHED();
64 return NetworkType::NETWORK_UNKNOWN;
65 }
66
67 static rtc::AdapterType AdapterTypeFromNetworkType(NetworkType network_type) {
68 switch (network_type) {
69 case NETWORK_UNKNOWN:
70 return rtc::ADAPTER_TYPE_UNKNOWN;
71 case NETWORK_ETHERNET:
72 return rtc::ADAPTER_TYPE_ETHERNET;
73 case NETWORK_WIFI:
74 return rtc::ADAPTER_TYPE_WIFI;
75 case NETWORK_4G:
76 case NETWORK_3G:
77 case NETWORK_2G:
78 case NETWORK_UNKNOWN_CELLULAR:
79 return rtc::ADAPTER_TYPE_CELLULAR;
80 case NETWORK_BLUETOOTH:
81 // There is no corresponding mapping for bluetooth networks.
82 // Map it to VPN for now.
83 return rtc::ADAPTER_TYPE_VPN;
84 default:
85 RTC_NOTREACHED() << "Invalid network type " << network_type;
86 return rtc::ADAPTER_TYPE_UNKNOWN;
87 }
88 }
89
90 static rtc::IPAddress GetIPAddressFromJava(JNIEnv* jni, jobject j_ip_address) {
91 jclass j_ip_address_class = GetObjectClass(jni, j_ip_address);
92 jfieldID j_address_id = GetFieldID(jni, j_ip_address_class, "address", "[B");
93 jbyteArray j_addresses =
94 static_cast<jbyteArray>(GetObjectField(jni, j_ip_address, j_address_id));
95 size_t address_length = jni->GetArrayLength(j_addresses);
96 jbyte* addr_array = jni->GetByteArrayElements(j_addresses, nullptr);
97 CHECK_EXCEPTION(jni) << "Error during GetIPAddressFromJava";
98 if (address_length == 4) {
99 // IP4
100 struct in_addr ip4_addr;
101 memcpy(&ip4_addr.s_addr, addr_array, 4);
102 jni->ReleaseByteArrayElements(j_addresses, addr_array, JNI_ABORT);
103 return rtc::IPAddress(ip4_addr);
104 }
105 // IP6
106 RTC_CHECK(address_length == 16);
107 struct in6_addr ip6_addr;
108 memcpy(ip6_addr.s6_addr, addr_array, address_length);
109 jni->ReleaseByteArrayElements(j_addresses, addr_array, JNI_ABORT);
110 return rtc::IPAddress(ip6_addr);
111 }
112
113 static void GetIPAddressesFromJava(JNIEnv* jni,
114 jobjectArray j_ip_addresses,
115 std::vector<rtc::IPAddress>* ip_addresses) {
116 ip_addresses->clear();
117 size_t num_addresses = jni->GetArrayLength(j_ip_addresses);
118 CHECK_EXCEPTION(jni) << "Error during GetArrayLength";
119 for (size_t i = 0; i < num_addresses; ++i) {
120 jobject j_ip_address = jni->GetObjectArrayElement(j_ip_addresses, i);
121 CHECK_EXCEPTION(jni) << "Error during GetObjectArrayElement";
122 rtc::IPAddress ip = GetIPAddressFromJava(jni, j_ip_address);
123 ip_addresses->push_back(ip);
124 }
125 }
126
127 static NetworkInformation GetNetworkInformationFromJava(
128 JNIEnv* jni,
129 jobject j_network_info) {
130 jclass j_network_info_class = GetObjectClass(jni, j_network_info);
131 jfieldID j_interface_name_id =
132 GetFieldID(jni, j_network_info_class, "name", "Ljava/lang/String;");
133 jfieldID j_handle_id = GetFieldID(jni, j_network_info_class, "handle", "J");
134 jfieldID j_type_id =
135 GetFieldID(jni, j_network_info_class, "type",
136 "Lorg/webrtc/NetworkMonitorAutoDetect$ConnectionType;");
137 jfieldID j_ip_addresses_id =
138 GetFieldID(jni, j_network_info_class, "ipAddresses",
139 "[Lorg/webrtc/NetworkMonitorAutoDetect$IPAddress;");
140
141 NetworkInformation network_info;
142 network_info.interface_name = JavaToStdString(
143 jni, GetStringField(jni, j_network_info, j_interface_name_id));
144 network_info.handle = static_cast<NetworkHandle>(
145 GetLongField(jni, j_network_info, j_handle_id));
146 network_info.type = GetNetworkTypeFromJava(
147 jni, GetObjectField(jni, j_network_info, j_type_id));
148 jobjectArray j_ip_addresses = static_cast<jobjectArray>(
149 GetObjectField(jni, j_network_info, j_ip_addresses_id));
150 GetIPAddressesFromJava(jni, j_ip_addresses, &network_info.ip_addresses);
151 return network_info;
152 }
153
154 std::string NetworkInformation::ToString() const {
155 std::stringstream ss;
156 ss << "NetInfo[name " << interface_name << "; handle " << handle << "; type "
157 << type << "; address";
158 for (const rtc::IPAddress address : ip_addresses) {
159 ss << " " << address.ToString();
160 }
161 ss << "]";
162 return ss.str();
163 }
164
165 AndroidNetworkMonitor::AndroidNetworkMonitor()
166 : j_network_monitor_class_(jni(),
167 FindClass(jni(), "org/webrtc/NetworkMonitor")),
168 j_network_monitor_(
169 jni(),
170 jni()->CallStaticObjectMethod(
171 *j_network_monitor_class_,
172 GetStaticMethodID(jni(),
173 *j_network_monitor_class_,
174 "getInstance",
175 "()Lorg/webrtc/NetworkMonitor;"))) {
176 CHECK_EXCEPTION(jni()) << "Error during NetworkMonitor.init";
177 if (android_sdk_int_ <= 0) {
178 jmethodID m = GetStaticMethodID(jni(), *j_network_monitor_class_,
179 "androidSdkInt", "()I");
180 android_sdk_int_ = jni()->CallStaticIntMethod(*j_network_monitor_class_, m);
181 CHECK_EXCEPTION(jni()) << "Error during NetworkMonitor.androidSdkInt";
182 }
183 }
184
185 void AndroidNetworkMonitor::Start() {
186 RTC_CHECK(thread_checker_.CalledOnValidThread());
187 if (started_) {
188 return;
189 }
190 started_ = true;
191
192 // This is kind of magic behavior, but doing this allows the SocketServer to
193 // use this as a NetworkBinder to bind sockets on a particular network when
194 // it creates sockets.
195 worker_thread()->socketserver()->set_network_binder(this);
196
197 jmethodID m =
198 GetMethodID(jni(), *j_network_monitor_class_, "startMonitoring", "(J)V");
199 jni()->CallVoidMethod(*j_network_monitor_, m, jlongFromPointer(this));
200 CHECK_EXCEPTION(jni()) << "Error during CallVoidMethod";
201 }
202
203 void AndroidNetworkMonitor::Stop() {
204 RTC_CHECK(thread_checker_.CalledOnValidThread());
205 if (!started_) {
206 return;
207 }
208 started_ = false;
209
210 // Once the network monitor stops, it will clear all network information and
211 // it won't find the network handle to bind anyway.
212 if (worker_thread()->socketserver()->network_binder() == this) {
213 worker_thread()->socketserver()->set_network_binder(nullptr);
214 }
215
216 jmethodID m =
217 GetMethodID(jni(), *j_network_monitor_class_, "stopMonitoring", "(J)V");
218 jni()->CallVoidMethod(*j_network_monitor_, m, jlongFromPointer(this));
219 CHECK_EXCEPTION(jni()) << "Error during NetworkMonitor.stopMonitoring";
220
221 network_handle_by_address_.clear();
222 network_info_by_handle_.clear();
223 }
224
225 // The implementation is largely taken from UDPSocketPosix::BindToNetwork in
226 // https://cs.chromium.org/chromium/src/net/udp/udp_socket_posix.cc
227 rtc::NetworkBindingResult AndroidNetworkMonitor::BindSocketToNetwork(
228 int socket_fd,
229 const rtc::IPAddress& address) {
230 RTC_CHECK(thread_checker_.CalledOnValidThread());
231
232 if (socket_fd == 0 /* NETWORK_UNSPECIFIED */) {
233 return rtc::NetworkBindingResult::NOT_IMPLEMENTED;
234 }
235
236 jmethodID network_binding_supported_id = GetMethodID(
237 jni(), *j_network_monitor_class_, "networkBindingSupported", "()Z");
238 // Android prior to Lollipop didn't have support for binding sockets to
239 // networks. This may also occur if there is no connectivity manager service.
240 bool network_binding_supported = jni()->CallBooleanMethod(
241 *j_network_monitor_, network_binding_supported_id);
242 CHECK_EXCEPTION(jni())
243 << "Error during NetworkMonitor.networkBindingSupported";
244 if (!network_binding_supported) {
245 LOG(LS_WARNING) << "BindSocketToNetwork is not supported on this platform "
246 << "(Android SDK: " << android_sdk_int_ << ")";
247 return rtc::NetworkBindingResult::NOT_IMPLEMENTED;
248 }
249
250 auto iter = network_handle_by_address_.find(address);
251 if (iter == network_handle_by_address_.end()) {
252 return rtc::NetworkBindingResult::ADDRESS_NOT_FOUND;
253 }
254 NetworkHandle network_handle = iter->second;
255
256 int rv = 0;
257 if (android_sdk_int_ >= SDK_VERSION_MARSHMALLOW) {
258 // See declaration of android_setsocknetwork() here:
259 // http://androidxref.com/6.0.0_r1/xref/development/ndk/platforms/android-M/ include/android/multinetwork.h#65
260 // Function cannot be called directly as it will cause app to fail to load
261 // on pre-marshmallow devices.
262 typedef int (*MarshmallowSetNetworkForSocket)(NetworkHandle net,
263 int socket);
264 static MarshmallowSetNetworkForSocket marshmallowSetNetworkForSocket;
265 // This is not thread-safe, but we are running this only on the worker
266 // thread.
267 if (!marshmallowSetNetworkForSocket) {
268 const std::string android_native_lib_path = "libandroid.so";
269 void* lib = dlopen(android_native_lib_path.c_str(), RTLD_NOW);
270 if (lib == nullptr) {
271 LOG(LS_ERROR) << "Library " << android_native_lib_path << " not found!";
272 return rtc::NetworkBindingResult::NOT_IMPLEMENTED;
273 }
274 marshmallowSetNetworkForSocket =
275 reinterpret_cast<MarshmallowSetNetworkForSocket>(
276 dlsym(lib, "android_setsocknetwork"));
277 }
278 if (!marshmallowSetNetworkForSocket) {
279 LOG(LS_ERROR) << "Symbol marshmallowSetNetworkForSocket is not found";
280 return rtc::NetworkBindingResult::NOT_IMPLEMENTED;
281 }
282 rv = marshmallowSetNetworkForSocket(network_handle, socket_fd);
283 } else {
284 // NOTE: This relies on Android implementation details, but it won't change
285 // because Lollipop is already released.
286 typedef int (*LollipopSetNetworkForSocket)(unsigned net, int socket);
287 static LollipopSetNetworkForSocket lollipopSetNetworkForSocket;
288 // This is not threadsafe, but we are running this only on the worker
289 // thread.
290 if (!lollipopSetNetworkForSocket) {
291 // Android's netd client library should always be loaded in our address
292 // space as it shims libc functions like connect().
293 const std::string net_library_path = "libnetd_client.so";
294 // Use RTLD_NOW to match Android's prior loading of the library:
295 // http://androidxref.com/6.0.0_r5/xref/bionic/libc/bionic/NetdClient.cpp# 37
296 // Use RTLD_NOLOAD to assert that the library is already loaded and
297 // avoid doing any disk IO.
298 void* lib = dlopen(net_library_path.c_str(), RTLD_NOW | RTLD_NOLOAD);
299 if (lib == nullptr) {
300 LOG(LS_ERROR) << "Library " << net_library_path << " not found!";
301 return rtc::NetworkBindingResult::NOT_IMPLEMENTED;
302 }
303 lollipopSetNetworkForSocket =
304 reinterpret_cast<LollipopSetNetworkForSocket>(
305 dlsym(lib, "setNetworkForSocket"));
306 }
307 if (!lollipopSetNetworkForSocket) {
308 LOG(LS_ERROR) << "Symbol lollipopSetNetworkForSocket is not found ";
309 return rtc::NetworkBindingResult::NOT_IMPLEMENTED;
310 }
311 rv = lollipopSetNetworkForSocket(network_handle, socket_fd);
312 }
313
314 // If |network| has since disconnected, |rv| will be ENONET. Surface this as
315 // ERR_NETWORK_CHANGED, rather than MapSystemError(ENONET) which gives back
316 // the less descriptive ERR_FAILED.
317 if (rv == 0) {
318 return rtc::NetworkBindingResult::SUCCESS;
319 }
320 if (rv == ENONET) {
321 return rtc::NetworkBindingResult::NETWORK_CHANGED;
322 }
323 return rtc::NetworkBindingResult::FAILURE;
324 }
325
326 void AndroidNetworkMonitor::OnNetworkConnected(
327 const NetworkInformation& network_info) {
328 worker_thread()->Invoke<void>(
329 RTC_FROM_HERE, rtc::Bind(&AndroidNetworkMonitor::OnNetworkConnected_w,
330 this, network_info));
331 // Fire SignalNetworksChanged to update the list of networks.
332 OnNetworksChanged();
333 }
334
335 void AndroidNetworkMonitor::OnNetworkConnected_w(
336 const NetworkInformation& network_info) {
337 LOG(LS_INFO) << "Network connected: " << network_info.ToString();
338 adapter_type_by_name_[network_info.interface_name] =
339 AdapterTypeFromNetworkType(network_info.type);
340 network_info_by_handle_[network_info.handle] = network_info;
341 for (const rtc::IPAddress& address : network_info.ip_addresses) {
342 network_handle_by_address_[address] = network_info.handle;
343 }
344 }
345
346 void AndroidNetworkMonitor::OnNetworkDisconnected(NetworkHandle handle) {
347 LOG(LS_INFO) << "Network disconnected for handle " << handle;
348 worker_thread()->Invoke<void>(
349 RTC_FROM_HERE,
350 rtc::Bind(&AndroidNetworkMonitor::OnNetworkDisconnected_w, this, handle));
351 }
352
353 void AndroidNetworkMonitor::OnNetworkDisconnected_w(NetworkHandle handle) {
354 auto iter = network_info_by_handle_.find(handle);
355 if (iter != network_info_by_handle_.end()) {
356 for (const rtc::IPAddress& address : iter->second.ip_addresses) {
357 network_handle_by_address_.erase(address);
358 }
359 network_info_by_handle_.erase(iter);
360 }
361 }
362
363 void AndroidNetworkMonitor::SetNetworkInfos(
364 const std::vector<NetworkInformation>& network_infos) {
365 RTC_CHECK(thread_checker_.CalledOnValidThread());
366 network_handle_by_address_.clear();
367 network_info_by_handle_.clear();
368 LOG(LS_INFO) << "Android network monitor found " << network_infos.size()
369 << " networks";
370 for (NetworkInformation network : network_infos) {
371 OnNetworkConnected_w(network);
372 }
373 }
374
375 rtc::AdapterType AndroidNetworkMonitor::GetAdapterType(
376 const std::string& if_name) {
377 auto iter = adapter_type_by_name_.find(if_name);
378 rtc::AdapterType type = (iter == adapter_type_by_name_.end())
379 ? rtc::ADAPTER_TYPE_UNKNOWN
380 : iter->second;
381 if (type == rtc::ADAPTER_TYPE_UNKNOWN) {
382 LOG(LS_WARNING) << "Get an unknown type for the interface " << if_name;
383 }
384 return type;
385 }
386
387 rtc::NetworkMonitorInterface*
388 AndroidNetworkMonitorFactory::CreateNetworkMonitor() {
389 return new AndroidNetworkMonitor();
390 }
391
392 JOW(void, NetworkMonitor_nativeNotifyConnectionTypeChanged)(
393 JNIEnv* jni, jobject j_monitor, jlong j_native_monitor) {
394 rtc::NetworkMonitorInterface* network_monitor =
395 reinterpret_cast<rtc::NetworkMonitorInterface*>(j_native_monitor);
396 network_monitor->OnNetworksChanged();
397 }
398
399 JOW(void, NetworkMonitor_nativeNotifyOfActiveNetworkList)(
400 JNIEnv* jni, jobject j_monitor, jlong j_native_monitor,
401 jobjectArray j_network_infos) {
402 AndroidNetworkMonitor* network_monitor =
403 reinterpret_cast<AndroidNetworkMonitor*>(j_native_monitor);
404 std::vector<NetworkInformation> network_infos;
405 size_t num_networks = jni->GetArrayLength(j_network_infos);
406 for (size_t i = 0; i < num_networks; ++i) {
407 jobject j_network_info = jni->GetObjectArrayElement(j_network_infos, i);
408 CHECK_EXCEPTION(jni) << "Error during GetObjectArrayElement";
409 network_infos.push_back(GetNetworkInformationFromJava(jni, j_network_info));
410 }
411 network_monitor->SetNetworkInfos(network_infos);
412 }
413
414 JOW(void, NetworkMonitor_nativeNotifyOfNetworkConnect)(
415 JNIEnv* jni, jobject j_monitor, jlong j_native_monitor,
416 jobject j_network_info) {
417 AndroidNetworkMonitor* network_monitor =
418 reinterpret_cast<AndroidNetworkMonitor*>(j_native_monitor);
419 NetworkInformation network_info =
420 GetNetworkInformationFromJava(jni, j_network_info);
421 network_monitor->OnNetworkConnected(network_info);
422 }
423
424 JOW(void, NetworkMonitor_nativeNotifyOfNetworkDisconnect)(
425 JNIEnv* jni, jobject j_monitor, jlong j_native_monitor,
426 jlong network_handle) {
427 AndroidNetworkMonitor* network_monitor =
428 reinterpret_cast<AndroidNetworkMonitor*>(j_native_monitor);
429 network_monitor->OnNetworkDisconnected(
430 static_cast<NetworkHandle>(network_handle));
431 }
432
433 } // namespace webrtc_jni
OLDNEW
« 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