• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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