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 "sdk/android/src/jni/android_network_monitor.h"
12
13 #include <dlfcn.h>
14 #ifndef RTLD_NOLOAD
15 // This was added in Lollipop to dlfcn.h
16 #define RTLD_NOLOAD 4
17 #endif
18
19 #include "rtc_base/bind.h"
20 #include "rtc_base/checks.h"
21 #include "rtc_base/ip_address.h"
22 #include "rtc_base/logging.h"
23 #include "rtc_base/strings/string_builder.h"
24 #include "sdk/android/generated_base_jni/NetworkMonitorAutoDetect_jni.h"
25 #include "sdk/android/generated_base_jni/NetworkMonitor_jni.h"
26 #include "sdk/android/native_api/jni/java_types.h"
27 #include "sdk/android/src/jni/jni_helpers.h"
28 #include "system_wrappers/include/field_trial.h"
29
30 namespace webrtc {
31 namespace jni {
32
33 enum AndroidSdkVersion {
34 SDK_VERSION_LOLLIPOP = 21,
35 SDK_VERSION_MARSHMALLOW = 23
36 };
37
GetNetworkTypeFromJava(JNIEnv * jni,const JavaRef<jobject> & j_network_type)38 static NetworkType GetNetworkTypeFromJava(
39 JNIEnv* jni,
40 const JavaRef<jobject>& j_network_type) {
41 std::string enum_name = GetJavaEnumName(jni, j_network_type);
42 if (enum_name == "CONNECTION_UNKNOWN") {
43 return NetworkType::NETWORK_UNKNOWN;
44 }
45 if (enum_name == "CONNECTION_ETHERNET") {
46 return NetworkType::NETWORK_ETHERNET;
47 }
48 if (enum_name == "CONNECTION_WIFI") {
49 return NetworkType::NETWORK_WIFI;
50 }
51 if (enum_name == "CONNECTION_5G") {
52 return NetworkType::NETWORK_5G;
53 }
54 if (enum_name == "CONNECTION_4G") {
55 return NetworkType::NETWORK_4G;
56 }
57 if (enum_name == "CONNECTION_3G") {
58 return NetworkType::NETWORK_3G;
59 }
60 if (enum_name == "CONNECTION_2G") {
61 return NetworkType::NETWORK_2G;
62 }
63 if (enum_name == "CONNECTION_UNKNOWN_CELLULAR") {
64 return NetworkType::NETWORK_UNKNOWN_CELLULAR;
65 }
66 if (enum_name == "CONNECTION_BLUETOOTH") {
67 return NetworkType::NETWORK_BLUETOOTH;
68 }
69 if (enum_name == "CONNECTION_VPN") {
70 return NetworkType::NETWORK_VPN;
71 }
72 if (enum_name == "CONNECTION_NONE") {
73 return NetworkType::NETWORK_NONE;
74 }
75 RTC_NOTREACHED();
76 return NetworkType::NETWORK_UNKNOWN;
77 }
78
AdapterTypeFromNetworkType(NetworkType network_type,bool surface_cellular_types)79 static rtc::AdapterType AdapterTypeFromNetworkType(
80 NetworkType network_type,
81 bool surface_cellular_types) {
82 switch (network_type) {
83 case NETWORK_UNKNOWN:
84 return rtc::ADAPTER_TYPE_UNKNOWN;
85 case NETWORK_ETHERNET:
86 return rtc::ADAPTER_TYPE_ETHERNET;
87 case NETWORK_WIFI:
88 return rtc::ADAPTER_TYPE_WIFI;
89 case NETWORK_5G:
90 return surface_cellular_types ? rtc::ADAPTER_TYPE_CELLULAR_5G
91 : rtc::ADAPTER_TYPE_CELLULAR;
92 case NETWORK_4G:
93 return surface_cellular_types ? rtc::ADAPTER_TYPE_CELLULAR_4G
94 : rtc::ADAPTER_TYPE_CELLULAR;
95 case NETWORK_3G:
96 return surface_cellular_types ? rtc::ADAPTER_TYPE_CELLULAR_3G
97 : rtc::ADAPTER_TYPE_CELLULAR;
98 case NETWORK_2G:
99 return surface_cellular_types ? rtc::ADAPTER_TYPE_CELLULAR_2G
100 : rtc::ADAPTER_TYPE_CELLULAR;
101 case NETWORK_UNKNOWN_CELLULAR:
102 return rtc::ADAPTER_TYPE_CELLULAR;
103 case NETWORK_VPN:
104 case NETWORK_BLUETOOTH:
105 // There is no corresponding mapping for bluetooth networks.
106 // Map it to VPN for now.
107 return rtc::ADAPTER_TYPE_VPN;
108 default:
109 RTC_NOTREACHED() << "Invalid network type " << network_type;
110 return rtc::ADAPTER_TYPE_UNKNOWN;
111 }
112 }
113
JavaToNativeIpAddress(JNIEnv * jni,const JavaRef<jobject> & j_ip_address)114 static rtc::IPAddress JavaToNativeIpAddress(
115 JNIEnv* jni,
116 const JavaRef<jobject>& j_ip_address) {
117 std::vector<int8_t> address =
118 JavaToNativeByteArray(jni, Java_IPAddress_getAddress(jni, j_ip_address));
119 size_t address_length = address.size();
120 if (address_length == 4) {
121 // IP4
122 struct in_addr ip4_addr;
123 memcpy(&ip4_addr.s_addr, address.data(), 4);
124 return rtc::IPAddress(ip4_addr);
125 }
126 // IP6
127 RTC_CHECK(address_length == 16);
128 struct in6_addr ip6_addr;
129 memcpy(ip6_addr.s6_addr, address.data(), address_length);
130 return rtc::IPAddress(ip6_addr);
131 }
132
GetNetworkInformationFromJava(JNIEnv * jni,const JavaRef<jobject> & j_network_info)133 static NetworkInformation GetNetworkInformationFromJava(
134 JNIEnv* jni,
135 const JavaRef<jobject>& j_network_info) {
136 NetworkInformation network_info;
137 network_info.interface_name = JavaToStdString(
138 jni, Java_NetworkInformation_getName(jni, j_network_info));
139 network_info.handle = static_cast<NetworkHandle>(
140 Java_NetworkInformation_getHandle(jni, j_network_info));
141 network_info.type = GetNetworkTypeFromJava(
142 jni, Java_NetworkInformation_getConnectionType(jni, j_network_info));
143 network_info.underlying_type_for_vpn = GetNetworkTypeFromJava(
144 jni, Java_NetworkInformation_getUnderlyingConnectionTypeForVpn(
145 jni, j_network_info));
146 ScopedJavaLocalRef<jobjectArray> j_ip_addresses =
147 Java_NetworkInformation_getIpAddresses(jni, j_network_info);
148 network_info.ip_addresses = JavaToNativeVector<rtc::IPAddress>(
149 jni, j_ip_addresses, &JavaToNativeIpAddress);
150 return network_info;
151 }
152
AddressMatch(const rtc::IPAddress & ip1,const rtc::IPAddress & ip2)153 static bool AddressMatch(const rtc::IPAddress& ip1, const rtc::IPAddress& ip2) {
154 if (ip1.family() != ip2.family()) {
155 return false;
156 }
157 if (ip1.family() == AF_INET) {
158 return ip1.ipv4_address().s_addr == ip2.ipv4_address().s_addr;
159 }
160 if (ip1.family() == AF_INET6) {
161 // The last 64-bits of an ipv6 address are temporary address and it could
162 // change over time. So we only compare the first 64-bits.
163 return memcmp(ip1.ipv6_address().s6_addr, ip2.ipv6_address().s6_addr,
164 sizeof(in6_addr) / 2) == 0;
165 }
166 return false;
167 }
168
169 NetworkInformation::NetworkInformation() = default;
170
171 NetworkInformation::NetworkInformation(const NetworkInformation&) = default;
172
173 NetworkInformation::NetworkInformation(NetworkInformation&&) = default;
174
175 NetworkInformation::~NetworkInformation() = default;
176
177 NetworkInformation& NetworkInformation::operator=(const NetworkInformation&) =
178 default;
179
180 NetworkInformation& NetworkInformation::operator=(NetworkInformation&&) =
181 default;
182
ToString() const183 std::string NetworkInformation::ToString() const {
184 rtc::StringBuilder ss;
185 ss << "NetInfo[name " << interface_name << "; handle " << handle << "; type "
186 << type;
187 if (type == NETWORK_VPN) {
188 ss << "; underlying_type_for_vpn " << underlying_type_for_vpn;
189 }
190 ss << "]";
191 return ss.Release();
192 }
193
AndroidNetworkMonitor(JNIEnv * env,const JavaRef<jobject> & j_application_context)194 AndroidNetworkMonitor::AndroidNetworkMonitor(
195 JNIEnv* env,
196 const JavaRef<jobject>& j_application_context)
197 : android_sdk_int_(Java_NetworkMonitor_androidSdkInt(env)),
198 j_application_context_(env, j_application_context),
199 j_network_monitor_(env, Java_NetworkMonitor_getInstance(env)) {}
200
201 AndroidNetworkMonitor::~AndroidNetworkMonitor() = default;
202
Start()203 void AndroidNetworkMonitor::Start() {
204 RTC_CHECK(thread_checker_.IsCurrent());
205 if (started_) {
206 return;
207 }
208 started_ = true;
209 surface_cellular_types_ =
210 webrtc::field_trial::IsEnabled("WebRTC-SurfaceCellularTypes");
211 find_network_handle_without_ipv6_temporary_part_ =
212 webrtc::field_trial::IsEnabled(
213 "WebRTC-FindNetworkHandleWithoutIpv6TemporaryPart");
214
215 // This is kind of magic behavior, but doing this allows the SocketServer to
216 // use this as a NetworkBinder to bind sockets on a particular network when
217 // it creates sockets.
218 worker_thread()->socketserver()->set_network_binder(this);
219
220 JNIEnv* env = AttachCurrentThreadIfNeeded();
221 Java_NetworkMonitor_startMonitoring(
222 env, j_network_monitor_, j_application_context_, jlongFromPointer(this));
223 }
224
Stop()225 void AndroidNetworkMonitor::Stop() {
226 RTC_CHECK(thread_checker_.IsCurrent());
227 if (!started_) {
228 return;
229 }
230 started_ = false;
231 find_network_handle_without_ipv6_temporary_part_ = false;
232
233 // Once the network monitor stops, it will clear all network information and
234 // it won't find the network handle to bind anyway.
235 if (worker_thread()->socketserver()->network_binder() == this) {
236 worker_thread()->socketserver()->set_network_binder(nullptr);
237 }
238
239 JNIEnv* env = AttachCurrentThreadIfNeeded();
240 Java_NetworkMonitor_stopMonitoring(env, j_network_monitor_,
241 jlongFromPointer(this));
242
243 network_handle_by_address_.clear();
244 network_info_by_handle_.clear();
245 }
246
247 // The implementation is largely taken from UDPSocketPosix::BindToNetwork in
248 // https://cs.chromium.org/chromium/src/net/udp/udp_socket_posix.cc
BindSocketToNetwork(int socket_fd,const rtc::IPAddress & address)249 rtc::NetworkBindingResult AndroidNetworkMonitor::BindSocketToNetwork(
250 int socket_fd,
251 const rtc::IPAddress& address) {
252 RTC_CHECK(thread_checker_.IsCurrent());
253
254 // Android prior to Lollipop didn't have support for binding sockets to
255 // networks. This may also occur if there is no connectivity manager
256 // service.
257 JNIEnv* env = AttachCurrentThreadIfNeeded();
258 const bool network_binding_supported =
259 Java_NetworkMonitor_networkBindingSupported(env, j_network_monitor_);
260 if (!network_binding_supported) {
261 RTC_LOG(LS_WARNING)
262 << "BindSocketToNetwork is not supported on this platform "
263 "(Android SDK: "
264 << android_sdk_int_ << ")";
265 return rtc::NetworkBindingResult::NOT_IMPLEMENTED;
266 }
267
268 absl::optional<NetworkHandle> network_handle =
269 FindNetworkHandleFromAddress(address);
270 if (!network_handle) {
271 return rtc::NetworkBindingResult::ADDRESS_NOT_FOUND;
272 }
273
274 if (*network_handle == 0 /* NETWORK_UNSPECIFIED */) {
275 return rtc::NetworkBindingResult::NOT_IMPLEMENTED;
276 }
277
278 int rv = 0;
279 if (android_sdk_int_ >= SDK_VERSION_MARSHMALLOW) {
280 // See declaration of android_setsocknetwork() here:
281 // http://androidxref.com/6.0.0_r1/xref/development/ndk/platforms/android-M/include/android/multinetwork.h#65
282 // Function cannot be called directly as it will cause app to fail to load
283 // on pre-marshmallow devices.
284 typedef int (*MarshmallowSetNetworkForSocket)(NetworkHandle net,
285 int socket);
286 static MarshmallowSetNetworkForSocket marshmallowSetNetworkForSocket;
287 // This is not thread-safe, but we are running this only on the worker
288 // thread.
289 if (!marshmallowSetNetworkForSocket) {
290 const std::string android_native_lib_path = "libandroid.so";
291 void* lib = dlopen(android_native_lib_path.c_str(), RTLD_NOW);
292 if (lib == nullptr) {
293 RTC_LOG(LS_ERROR) << "Library " << android_native_lib_path
294 << " not found!";
295 return rtc::NetworkBindingResult::NOT_IMPLEMENTED;
296 }
297 marshmallowSetNetworkForSocket =
298 reinterpret_cast<MarshmallowSetNetworkForSocket>(
299 dlsym(lib, "android_setsocknetwork"));
300 }
301 if (!marshmallowSetNetworkForSocket) {
302 RTC_LOG(LS_ERROR) << "Symbol marshmallowSetNetworkForSocket is not found";
303 return rtc::NetworkBindingResult::NOT_IMPLEMENTED;
304 }
305 rv = marshmallowSetNetworkForSocket(*network_handle, socket_fd);
306 } else {
307 // NOTE: This relies on Android implementation details, but it won't
308 // change because Lollipop is already released.
309 typedef int (*LollipopSetNetworkForSocket)(unsigned net, int socket);
310 static LollipopSetNetworkForSocket lollipopSetNetworkForSocket;
311 // This is not threadsafe, but we are running this only on the worker
312 // thread.
313 if (!lollipopSetNetworkForSocket) {
314 // Android's netd client library should always be loaded in our address
315 // space as it shims libc functions like connect().
316 const std::string net_library_path = "libnetd_client.so";
317 // Use RTLD_NOW to match Android's prior loading of the library:
318 // http://androidxref.com/6.0.0_r5/xref/bionic/libc/bionic/NetdClient.cpp#37
319 // Use RTLD_NOLOAD to assert that the library is already loaded and
320 // avoid doing any disk IO.
321 void* lib = dlopen(net_library_path.c_str(), RTLD_NOW | RTLD_NOLOAD);
322 if (lib == nullptr) {
323 RTC_LOG(LS_ERROR) << "Library " << net_library_path << " not found!";
324 return rtc::NetworkBindingResult::NOT_IMPLEMENTED;
325 }
326 lollipopSetNetworkForSocket =
327 reinterpret_cast<LollipopSetNetworkForSocket>(
328 dlsym(lib, "setNetworkForSocket"));
329 }
330 if (!lollipopSetNetworkForSocket) {
331 RTC_LOG(LS_ERROR) << "Symbol lollipopSetNetworkForSocket is not found ";
332 return rtc::NetworkBindingResult::NOT_IMPLEMENTED;
333 }
334 rv = lollipopSetNetworkForSocket(*network_handle, socket_fd);
335 }
336
337 // If |network| has since disconnected, |rv| will be ENONET. Surface this as
338 // ERR_NETWORK_CHANGED, rather than MapSystemError(ENONET) which gives back
339 // the less descriptive ERR_FAILED.
340 if (rv == 0) {
341 return rtc::NetworkBindingResult::SUCCESS;
342 }
343 if (rv == ENONET) {
344 return rtc::NetworkBindingResult::NETWORK_CHANGED;
345 }
346 return rtc::NetworkBindingResult::FAILURE;
347 }
348
OnNetworkConnected(const NetworkInformation & network_info)349 void AndroidNetworkMonitor::OnNetworkConnected(
350 const NetworkInformation& network_info) {
351 worker_thread()->Invoke<void>(
352 RTC_FROM_HERE, rtc::Bind(&AndroidNetworkMonitor::OnNetworkConnected_w,
353 this, network_info));
354 // Fire SignalNetworksChanged to update the list of networks.
355 OnNetworksChanged();
356 }
357
OnNetworkConnected_w(const NetworkInformation & network_info)358 void AndroidNetworkMonitor::OnNetworkConnected_w(
359 const NetworkInformation& network_info) {
360 RTC_LOG(LS_INFO) << "Network connected: " << network_info.ToString();
361 adapter_type_by_name_[network_info.interface_name] =
362 AdapterTypeFromNetworkType(network_info.type, surface_cellular_types_);
363 if (network_info.type == NETWORK_VPN) {
364 vpn_underlying_adapter_type_by_name_[network_info.interface_name] =
365 AdapterTypeFromNetworkType(network_info.underlying_type_for_vpn,
366 surface_cellular_types_);
367 }
368 network_info_by_handle_[network_info.handle] = network_info;
369 for (const rtc::IPAddress& address : network_info.ip_addresses) {
370 network_handle_by_address_[address] = network_info.handle;
371 }
372 }
373
374 absl::optional<NetworkHandle>
FindNetworkHandleFromAddress(const rtc::IPAddress & ip_address) const375 AndroidNetworkMonitor::FindNetworkHandleFromAddress(
376 const rtc::IPAddress& ip_address) const {
377 RTC_LOG(LS_INFO) << "Find network handle.";
378 if (find_network_handle_without_ipv6_temporary_part_) {
379 for (auto const& iter : network_info_by_handle_) {
380 const std::vector<rtc::IPAddress>& addresses = iter.second.ip_addresses;
381 auto address_it = std::find_if(addresses.begin(), addresses.end(),
382 [ip_address](rtc::IPAddress address) {
383 return AddressMatch(ip_address, address);
384 });
385 if (address_it != addresses.end()) {
386 return absl::make_optional(iter.first);
387 }
388 }
389 return absl::nullopt;
390 } else {
391 auto iter = network_handle_by_address_.find(ip_address);
392 if (iter == network_handle_by_address_.end()) {
393 return absl::nullopt;
394 }
395 return absl::make_optional(iter->second);
396 }
397 }
398
OnNetworkDisconnected(NetworkHandle handle)399 void AndroidNetworkMonitor::OnNetworkDisconnected(NetworkHandle handle) {
400 RTC_LOG(LS_INFO) << "Network disconnected for handle " << handle;
401 worker_thread()->Invoke<void>(
402 RTC_FROM_HERE,
403 rtc::Bind(&AndroidNetworkMonitor::OnNetworkDisconnected_w, this, handle));
404 }
405
OnNetworkDisconnected_w(NetworkHandle handle)406 void AndroidNetworkMonitor::OnNetworkDisconnected_w(NetworkHandle handle) {
407 auto iter = network_info_by_handle_.find(handle);
408 if (iter != network_info_by_handle_.end()) {
409 for (const rtc::IPAddress& address : iter->second.ip_addresses) {
410 network_handle_by_address_.erase(address);
411 }
412 network_info_by_handle_.erase(iter);
413 }
414 }
415
SetNetworkInfos(const std::vector<NetworkInformation> & network_infos)416 void AndroidNetworkMonitor::SetNetworkInfos(
417 const std::vector<NetworkInformation>& network_infos) {
418 RTC_CHECK(thread_checker_.IsCurrent());
419 network_handle_by_address_.clear();
420 network_info_by_handle_.clear();
421 RTC_LOG(LS_INFO) << "Android network monitor found " << network_infos.size()
422 << " networks";
423 for (const NetworkInformation& network : network_infos) {
424 OnNetworkConnected_w(network);
425 }
426 }
427
GetAdapterType(const std::string & if_name)428 rtc::AdapterType AndroidNetworkMonitor::GetAdapterType(
429 const std::string& if_name) {
430 auto iter = adapter_type_by_name_.find(if_name);
431 rtc::AdapterType type = (iter == adapter_type_by_name_.end())
432 ? rtc::ADAPTER_TYPE_UNKNOWN
433 : iter->second;
434 if (type == rtc::ADAPTER_TYPE_UNKNOWN) {
435 RTC_LOG(LS_WARNING) << "Get an unknown type for the interface " << if_name;
436 }
437 return type;
438 }
439
GetVpnUnderlyingAdapterType(const std::string & if_name)440 rtc::AdapterType AndroidNetworkMonitor::GetVpnUnderlyingAdapterType(
441 const std::string& if_name) {
442 auto iter = vpn_underlying_adapter_type_by_name_.find(if_name);
443 rtc::AdapterType type = (iter == vpn_underlying_adapter_type_by_name_.end())
444 ? rtc::ADAPTER_TYPE_UNKNOWN
445 : iter->second;
446 return type;
447 }
448
AndroidNetworkMonitorFactory()449 AndroidNetworkMonitorFactory::AndroidNetworkMonitorFactory()
450 : j_application_context_(nullptr) {}
451
AndroidNetworkMonitorFactory(JNIEnv * env,const JavaRef<jobject> & j_application_context)452 AndroidNetworkMonitorFactory::AndroidNetworkMonitorFactory(
453 JNIEnv* env,
454 const JavaRef<jobject>& j_application_context)
455 : j_application_context_(env, j_application_context) {}
456
457 AndroidNetworkMonitorFactory::~AndroidNetworkMonitorFactory() = default;
458
459 rtc::NetworkMonitorInterface*
CreateNetworkMonitor()460 AndroidNetworkMonitorFactory::CreateNetworkMonitor() {
461 return new AndroidNetworkMonitor(AttachCurrentThreadIfNeeded(),
462 j_application_context_);
463 }
464
NotifyConnectionTypeChanged(JNIEnv * env,const JavaRef<jobject> & j_caller)465 void AndroidNetworkMonitor::NotifyConnectionTypeChanged(
466 JNIEnv* env,
467 const JavaRef<jobject>& j_caller) {
468 OnNetworksChanged();
469 }
470
NotifyOfActiveNetworkList(JNIEnv * env,const JavaRef<jobject> & j_caller,const JavaRef<jobjectArray> & j_network_infos)471 void AndroidNetworkMonitor::NotifyOfActiveNetworkList(
472 JNIEnv* env,
473 const JavaRef<jobject>& j_caller,
474 const JavaRef<jobjectArray>& j_network_infos) {
475 std::vector<NetworkInformation> network_infos =
476 JavaToNativeVector<NetworkInformation>(env, j_network_infos,
477 &GetNetworkInformationFromJava);
478 SetNetworkInfos(network_infos);
479 }
480
NotifyOfNetworkConnect(JNIEnv * env,const JavaRef<jobject> & j_caller,const JavaRef<jobject> & j_network_info)481 void AndroidNetworkMonitor::NotifyOfNetworkConnect(
482 JNIEnv* env,
483 const JavaRef<jobject>& j_caller,
484 const JavaRef<jobject>& j_network_info) {
485 NetworkInformation network_info =
486 GetNetworkInformationFromJava(env, j_network_info);
487 OnNetworkConnected(network_info);
488 }
489
NotifyOfNetworkDisconnect(JNIEnv * env,const JavaRef<jobject> & j_caller,jlong network_handle)490 void AndroidNetworkMonitor::NotifyOfNetworkDisconnect(
491 JNIEnv* env,
492 const JavaRef<jobject>& j_caller,
493 jlong network_handle) {
494 OnNetworkDisconnected(static_cast<NetworkHandle>(network_handle));
495 }
496
497 } // namespace jni
498 } // namespace webrtc
499