xref: /aosp_15_r20/external/webrtc/sdk/android/src/jni/android_network_monitor.cc (revision d9f758449e529ab9291ac668be2861e7a55c2422)
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 
15 #include "absl/strings/string_view.h"
16 #ifndef RTLD_NOLOAD
17 // This was added in Lollipop to dlfcn.h
18 #define RTLD_NOLOAD 4
19 #endif
20 
21 #include "api/sequence_checker.h"
22 #include "rtc_base/checks.h"
23 #include "rtc_base/ip_address.h"
24 #include "rtc_base/logging.h"
25 #include "rtc_base/strings/string_builder.h"
26 #include "sdk/android/generated_base_jni/NetworkChangeDetector_jni.h"
27 #include "sdk/android/generated_base_jni/NetworkMonitor_jni.h"
28 #include "sdk/android/native_api/jni/java_types.h"
29 #include "sdk/android/src/jni/jni_helpers.h"
30 
31 namespace webrtc {
32 namespace jni {
33 
34 namespace {
35 
NetworkTypeToString(NetworkType type)36 const char* NetworkTypeToString(NetworkType type) {
37   switch (type) {
38     case NETWORK_UNKNOWN:
39       return "UNKNOWN";
40     case NETWORK_ETHERNET:
41       return "ETHERNET";
42     case NETWORK_WIFI:
43       return "WIFI";
44     case NETWORK_5G:
45       return "5G";
46     case NETWORK_4G:
47       return "4G";
48     case NETWORK_3G:
49       return "3G";
50     case NETWORK_2G:
51       return "2G";
52     case NETWORK_UNKNOWN_CELLULAR:
53       return "UNKNOWN_CELLULAR";
54     case NETWORK_BLUETOOTH:
55       return "BLUETOOTH";
56     case NETWORK_VPN:
57       return "VPN";
58     case NETWORK_NONE:
59       return "NONE";
60   }
61 }
62 
63 }  // namespace
64 
65 enum AndroidSdkVersion {
66   SDK_VERSION_LOLLIPOP = 21,
67   SDK_VERSION_MARSHMALLOW = 23
68 };
69 
GetNetworkTypeFromJava(JNIEnv * jni,const JavaRef<jobject> & j_network_type)70 static NetworkType GetNetworkTypeFromJava(
71     JNIEnv* jni,
72     const JavaRef<jobject>& j_network_type) {
73   std::string enum_name = GetJavaEnumName(jni, j_network_type);
74   if (enum_name == "CONNECTION_UNKNOWN") {
75     return NetworkType::NETWORK_UNKNOWN;
76   }
77   if (enum_name == "CONNECTION_ETHERNET") {
78     return NetworkType::NETWORK_ETHERNET;
79   }
80   if (enum_name == "CONNECTION_WIFI") {
81     return NetworkType::NETWORK_WIFI;
82   }
83   if (enum_name == "CONNECTION_5G") {
84     return NetworkType::NETWORK_5G;
85   }
86   if (enum_name == "CONNECTION_4G") {
87     return NetworkType::NETWORK_4G;
88   }
89   if (enum_name == "CONNECTION_3G") {
90     return NetworkType::NETWORK_3G;
91   }
92   if (enum_name == "CONNECTION_2G") {
93     return NetworkType::NETWORK_2G;
94   }
95   if (enum_name == "CONNECTION_UNKNOWN_CELLULAR") {
96     return NetworkType::NETWORK_UNKNOWN_CELLULAR;
97   }
98   if (enum_name == "CONNECTION_BLUETOOTH") {
99     return NetworkType::NETWORK_BLUETOOTH;
100   }
101   if (enum_name == "CONNECTION_VPN") {
102     return NetworkType::NETWORK_VPN;
103   }
104   if (enum_name == "CONNECTION_NONE") {
105     return NetworkType::NETWORK_NONE;
106   }
107   RTC_DCHECK_NOTREACHED();
108   return NetworkType::NETWORK_UNKNOWN;
109 }
110 
AdapterTypeFromNetworkType(NetworkType network_type,bool surface_cellular_types)111 static rtc::AdapterType AdapterTypeFromNetworkType(
112     NetworkType network_type,
113     bool surface_cellular_types) {
114   switch (network_type) {
115     case NETWORK_UNKNOWN:
116       return rtc::ADAPTER_TYPE_UNKNOWN;
117     case NETWORK_ETHERNET:
118       return rtc::ADAPTER_TYPE_ETHERNET;
119     case NETWORK_WIFI:
120       return rtc::ADAPTER_TYPE_WIFI;
121     case NETWORK_5G:
122       return surface_cellular_types ? rtc::ADAPTER_TYPE_CELLULAR_5G
123                                     : rtc::ADAPTER_TYPE_CELLULAR;
124     case NETWORK_4G:
125       return surface_cellular_types ? rtc::ADAPTER_TYPE_CELLULAR_4G
126                                     : rtc::ADAPTER_TYPE_CELLULAR;
127     case NETWORK_3G:
128       return surface_cellular_types ? rtc::ADAPTER_TYPE_CELLULAR_3G
129                                     : rtc::ADAPTER_TYPE_CELLULAR;
130     case NETWORK_2G:
131       return surface_cellular_types ? rtc::ADAPTER_TYPE_CELLULAR_2G
132                                     : rtc::ADAPTER_TYPE_CELLULAR;
133     case NETWORK_UNKNOWN_CELLULAR:
134       return rtc::ADAPTER_TYPE_CELLULAR;
135     case NETWORK_VPN:
136       return rtc::ADAPTER_TYPE_VPN;
137     case NETWORK_BLUETOOTH:
138       // There is no corresponding mapping for bluetooth networks.
139       // Map it to UNKNOWN for now.
140       return rtc::ADAPTER_TYPE_UNKNOWN;
141     case NETWORK_NONE:
142       return rtc::ADAPTER_TYPE_UNKNOWN;
143   }
144 
145   RTC_DCHECK_NOTREACHED() << "Invalid network type " << network_type;
146   return rtc::ADAPTER_TYPE_UNKNOWN;
147 }
148 
JavaToNativeIpAddress(JNIEnv * jni,const JavaRef<jobject> & j_ip_address)149 static rtc::IPAddress JavaToNativeIpAddress(
150     JNIEnv* jni,
151     const JavaRef<jobject>& j_ip_address) {
152   std::vector<int8_t> address =
153       JavaToNativeByteArray(jni, Java_IPAddress_getAddress(jni, j_ip_address));
154   size_t address_length = address.size();
155   if (address_length == 4) {
156     // IP4
157     struct in_addr ip4_addr;
158     memcpy(&ip4_addr.s_addr, address.data(), 4);
159     return rtc::IPAddress(ip4_addr);
160   }
161   // IP6
162   RTC_CHECK(address_length == 16);
163   struct in6_addr ip6_addr;
164   memcpy(ip6_addr.s6_addr, address.data(), address_length);
165   return rtc::IPAddress(ip6_addr);
166 }
167 
GetNetworkInformationFromJava(JNIEnv * jni,const JavaRef<jobject> & j_network_info)168 static NetworkInformation GetNetworkInformationFromJava(
169     JNIEnv* jni,
170     const JavaRef<jobject>& j_network_info) {
171   NetworkInformation network_info;
172   network_info.interface_name = JavaToStdString(
173       jni, Java_NetworkInformation_getName(jni, j_network_info));
174   network_info.handle = static_cast<NetworkHandle>(
175       Java_NetworkInformation_getHandle(jni, j_network_info));
176   network_info.type = GetNetworkTypeFromJava(
177       jni, Java_NetworkInformation_getConnectionType(jni, j_network_info));
178   network_info.underlying_type_for_vpn = GetNetworkTypeFromJava(
179       jni, Java_NetworkInformation_getUnderlyingConnectionTypeForVpn(
180                jni, j_network_info));
181   ScopedJavaLocalRef<jobjectArray> j_ip_addresses =
182       Java_NetworkInformation_getIpAddresses(jni, j_network_info);
183   network_info.ip_addresses = JavaToNativeVector<rtc::IPAddress>(
184       jni, j_ip_addresses, &JavaToNativeIpAddress);
185   return network_info;
186 }
187 
AddressMatch(const rtc::IPAddress & ip1,const rtc::IPAddress & ip2)188 static bool AddressMatch(const rtc::IPAddress& ip1, const rtc::IPAddress& ip2) {
189   if (ip1.family() != ip2.family()) {
190     return false;
191   }
192   if (ip1.family() == AF_INET) {
193     return ip1.ipv4_address().s_addr == ip2.ipv4_address().s_addr;
194   }
195   if (ip1.family() == AF_INET6) {
196     // The last 64-bits of an ipv6 address are temporary address and it could
197     // change over time. So we only compare the first 64-bits.
198     return memcmp(ip1.ipv6_address().s6_addr, ip2.ipv6_address().s6_addr,
199                   sizeof(in6_addr) / 2) == 0;
200   }
201   return false;
202 }
203 
204 NetworkInformation::NetworkInformation() = default;
205 
206 NetworkInformation::NetworkInformation(const NetworkInformation&) = default;
207 
208 NetworkInformation::NetworkInformation(NetworkInformation&&) = default;
209 
210 NetworkInformation::~NetworkInformation() = default;
211 
212 NetworkInformation& NetworkInformation::operator=(const NetworkInformation&) =
213     default;
214 
215 NetworkInformation& NetworkInformation::operator=(NetworkInformation&&) =
216     default;
217 
ToString() const218 std::string NetworkInformation::ToString() const {
219   rtc::StringBuilder ss;
220   ss << "NetInfo[name " << interface_name << "; handle " << handle << "; type "
221      << type;
222   if (type == NETWORK_VPN) {
223     ss << "; underlying_type_for_vpn " << underlying_type_for_vpn;
224   }
225   ss << "]";
226   return ss.Release();
227 }
228 
AndroidNetworkMonitor(JNIEnv * env,const JavaRef<jobject> & j_application_context,const FieldTrialsView & field_trials)229 AndroidNetworkMonitor::AndroidNetworkMonitor(
230     JNIEnv* env,
231     const JavaRef<jobject>& j_application_context,
232     const FieldTrialsView& field_trials)
233     : android_sdk_int_(Java_NetworkMonitor_androidSdkInt(env)),
234       j_application_context_(env, j_application_context),
235       j_network_monitor_(env, Java_NetworkMonitor_getInstance(env)),
236       network_thread_(rtc::Thread::Current()),
237       field_trials_(field_trials) {}
238 
~AndroidNetworkMonitor()239 AndroidNetworkMonitor::~AndroidNetworkMonitor() {
240   RTC_DCHECK(!started_);
241 }
242 
Start()243 void AndroidNetworkMonitor::Start() {
244   RTC_DCHECK_RUN_ON(network_thread_);
245   if (started_) {
246     return;
247   }
248   reset();
249   started_ = true;
250   surface_cellular_types_ =
251       field_trials_.IsEnabled("WebRTC-SurfaceCellularTypes");
252   find_network_handle_without_ipv6_temporary_part_ = field_trials_.IsEnabled(
253       "WebRTC-FindNetworkHandleWithoutIpv6TemporaryPart");
254   bind_using_ifname_ =
255       !field_trials_.IsDisabled("WebRTC-BindUsingInterfaceName");
256   disable_is_adapter_available_ = field_trials_.IsDisabled(
257       "WebRTC-AndroidNetworkMonitor-IsAdapterAvailable");
258 
259   // This pointer is also accessed by the methods called from java threads.
260   // Assigning it here is safe, because the java monitor is in a stopped state,
261   // and will not make any callbacks.
262   safety_flag_ = PendingTaskSafetyFlag::Create();
263 
264   JNIEnv* env = AttachCurrentThreadIfNeeded();
265   Java_NetworkMonitor_startMonitoring(
266       env, j_network_monitor_, j_application_context_, jlongFromPointer(this),
267       NativeToJavaString(
268           env, field_trials_.Lookup("WebRTC-NetworkMonitorAutoDetect")));
269 }
270 
reset()271 void AndroidNetworkMonitor::reset() {
272   RTC_DCHECK_RUN_ON(network_thread_);
273   network_handle_by_address_.clear();
274   network_handle_by_if_name_.clear();
275   network_info_by_handle_.clear();
276   network_preference_by_adapter_type_.clear();
277 }
278 
Stop()279 void AndroidNetworkMonitor::Stop() {
280   RTC_DCHECK_RUN_ON(network_thread_);
281   if (!started_) {
282     return;
283   }
284   started_ = false;
285   find_network_handle_without_ipv6_temporary_part_ = false;
286 
287   // Cancel any pending tasks. We should not call
288   // `InvokeNetworksChangedCallback()` when the monitor is stopped.
289   safety_flag_->SetNotAlive();
290 
291   JNIEnv* env = AttachCurrentThreadIfNeeded();
292   Java_NetworkMonitor_stopMonitoring(env, j_network_monitor_,
293                                      jlongFromPointer(this));
294 
295   reset();
296 }
297 
298 // The implementation is largely taken from UDPSocketPosix::BindToNetwork in
299 // https://cs.chromium.org/chromium/src/net/udp/udp_socket_posix.cc
BindSocketToNetwork(int socket_fd,const rtc::IPAddress & address,absl::string_view if_name)300 rtc::NetworkBindingResult AndroidNetworkMonitor::BindSocketToNetwork(
301     int socket_fd,
302     const rtc::IPAddress& address,
303     absl::string_view if_name) {
304   RTC_DCHECK_RUN_ON(network_thread_);
305 
306   // Android prior to Lollipop didn't have support for binding sockets to
307   // networks. This may also occur if there is no connectivity manager
308   // service.
309   JNIEnv* env = AttachCurrentThreadIfNeeded();
310   const bool network_binding_supported =
311       Java_NetworkMonitor_networkBindingSupported(env, j_network_monitor_);
312   if (!network_binding_supported) {
313     RTC_LOG(LS_WARNING)
314         << "BindSocketToNetwork is not supported on this platform "
315            "(Android SDK: "
316         << android_sdk_int_ << ")";
317     return rtc::NetworkBindingResult::NOT_IMPLEMENTED;
318   }
319 
320   absl::optional<NetworkHandle> network_handle =
321       FindNetworkHandleFromAddressOrName(address, if_name);
322   if (!network_handle) {
323     RTC_LOG(LS_WARNING)
324         << "BindSocketToNetwork unable to find network handle for"
325         << " addr: " << address.ToSensitiveString() << " ifname: " << if_name;
326     return rtc::NetworkBindingResult::ADDRESS_NOT_FOUND;
327   }
328 
329   if (*network_handle == 0 /* NETWORK_UNSPECIFIED */) {
330     RTC_LOG(LS_WARNING) << "BindSocketToNetwork 0 network handle for"
331                         << " addr: " << address.ToSensitiveString()
332                         << " ifname: " << if_name;
333     return rtc::NetworkBindingResult::NOT_IMPLEMENTED;
334   }
335 
336   int rv = 0;
337   if (android_sdk_int_ >= SDK_VERSION_MARSHMALLOW) {
338     // See declaration of android_setsocknetwork() here:
339     // http://androidxref.com/6.0.0_r1/xref/development/ndk/platforms/android-M/include/android/multinetwork.h#65
340     // Function cannot be called directly as it will cause app to fail to load
341     // on pre-marshmallow devices.
342     typedef int (*MarshmallowSetNetworkForSocket)(NetworkHandle net,
343                                                   int socket);
344     static MarshmallowSetNetworkForSocket marshmallowSetNetworkForSocket;
345     // This is not thread-safe, but we are running this only on the worker
346     // thread.
347     if (!marshmallowSetNetworkForSocket) {
348       const std::string android_native_lib_path = "libandroid.so";
349       void* lib = dlopen(android_native_lib_path.c_str(), RTLD_NOW);
350       if (lib == nullptr) {
351         RTC_LOG(LS_ERROR) << "Library " << android_native_lib_path
352                           << " not found!";
353         return rtc::NetworkBindingResult::NOT_IMPLEMENTED;
354       }
355       marshmallowSetNetworkForSocket =
356           reinterpret_cast<MarshmallowSetNetworkForSocket>(
357               dlsym(lib, "android_setsocknetwork"));
358     }
359     if (!marshmallowSetNetworkForSocket) {
360       RTC_LOG(LS_ERROR) << "Symbol marshmallowSetNetworkForSocket is not found";
361       return rtc::NetworkBindingResult::NOT_IMPLEMENTED;
362     }
363     rv = marshmallowSetNetworkForSocket(*network_handle, socket_fd);
364   } else {
365     // NOTE: This relies on Android implementation details, but it won't
366     // change because Lollipop is already released.
367     typedef int (*LollipopSetNetworkForSocket)(unsigned net, int socket);
368     static LollipopSetNetworkForSocket lollipopSetNetworkForSocket;
369     // This is not threadsafe, but we are running this only on the worker
370     // thread.
371     if (!lollipopSetNetworkForSocket) {
372       // Android's netd client library should always be loaded in our address
373       // space as it shims libc functions like connect().
374       const std::string net_library_path = "libnetd_client.so";
375       // Use RTLD_NOW to match Android's prior loading of the library:
376       // http://androidxref.com/6.0.0_r5/xref/bionic/libc/bionic/NetdClient.cpp#37
377       // Use RTLD_NOLOAD to assert that the library is already loaded and
378       // avoid doing any disk IO.
379       void* lib = dlopen(net_library_path.c_str(), RTLD_NOW | RTLD_NOLOAD);
380       if (lib == nullptr) {
381         RTC_LOG(LS_ERROR) << "Library " << net_library_path << " not found!";
382         return rtc::NetworkBindingResult::NOT_IMPLEMENTED;
383       }
384       lollipopSetNetworkForSocket =
385           reinterpret_cast<LollipopSetNetworkForSocket>(
386               dlsym(lib, "setNetworkForSocket"));
387     }
388     if (!lollipopSetNetworkForSocket) {
389       RTC_LOG(LS_ERROR) << "Symbol lollipopSetNetworkForSocket is not found ";
390       return rtc::NetworkBindingResult::NOT_IMPLEMENTED;
391     }
392     rv = lollipopSetNetworkForSocket(*network_handle, socket_fd);
393   }
394 
395   // If `network` has since disconnected, `rv` will be ENONET. Surface this as
396   // ERR_NETWORK_CHANGED, rather than MapSystemError(ENONET) which gives back
397   // the less descriptive ERR_FAILED.
398   if (rv == 0) {
399     RTC_LOG(LS_VERBOSE) << "BindSocketToNetwork bound network handle for"
400                         << " addr: " << address.ToSensitiveString()
401                         << " ifname: " << if_name;
402     return rtc::NetworkBindingResult::SUCCESS;
403   }
404 
405   RTC_LOG(LS_WARNING) << "BindSocketToNetwork got error: " << rv
406                       << " addr: " << address.ToSensitiveString()
407                       << " ifname: " << if_name;
408   if (rv == ENONET) {
409     return rtc::NetworkBindingResult::NETWORK_CHANGED;
410   }
411 
412   return rtc::NetworkBindingResult::FAILURE;
413 }
414 
OnNetworkConnected_n(const NetworkInformation & network_info)415 void AndroidNetworkMonitor::OnNetworkConnected_n(
416     const NetworkInformation& network_info) {
417   RTC_DCHECK_RUN_ON(network_thread_);
418   RTC_LOG(LS_INFO) << "Network connected: " << network_info.ToString();
419 
420   // We speculate that OnNetworkConnected_n can be called with the same handle
421   // and different if_names. Handle this as if the network was first
422   // disconnected.
423   auto iter = network_info_by_handle_.find(network_info.handle);
424   if (iter != network_info_by_handle_.end()) {
425     // Remove old if_name for this handle if they don't match.
426     if (network_info.interface_name != iter->second.interface_name) {
427       RTC_LOG(LS_INFO) << "Network"
428                        << " handle " << network_info.handle
429                        << " change if_name from: "
430                        << iter->second.interface_name
431                        << " to: " << network_info.interface_name;
432       RTC_DCHECK(network_handle_by_if_name_[iter->second.interface_name] ==
433                  network_info.handle);
434       network_handle_by_if_name_.erase(iter->second.interface_name);
435     }
436   }
437 
438   network_info_by_handle_[network_info.handle] = network_info;
439   for (const rtc::IPAddress& address : network_info.ip_addresses) {
440     network_handle_by_address_[address] = network_info.handle;
441   }
442   network_handle_by_if_name_[network_info.interface_name] = network_info.handle;
443   RTC_CHECK(network_info_by_handle_.size() >=
444             network_handle_by_if_name_.size());
445   InvokeNetworksChangedCallback();
446 }
447 
448 absl::optional<NetworkHandle>
FindNetworkHandleFromAddressOrName(const rtc::IPAddress & ip_address,absl::string_view if_name) const449 AndroidNetworkMonitor::FindNetworkHandleFromAddressOrName(
450     const rtc::IPAddress& ip_address,
451     absl::string_view if_name) const {
452   RTC_DCHECK_RUN_ON(network_thread_);
453   if (find_network_handle_without_ipv6_temporary_part_) {
454     for (auto const& iter : network_info_by_handle_) {
455       const std::vector<rtc::IPAddress>& addresses = iter.second.ip_addresses;
456       auto address_it = std::find_if(addresses.begin(), addresses.end(),
457                                      [ip_address](rtc::IPAddress address) {
458                                        return AddressMatch(ip_address, address);
459                                      });
460       if (address_it != addresses.end()) {
461         return absl::make_optional(iter.first);
462       }
463     }
464   } else {
465     auto iter = network_handle_by_address_.find(ip_address);
466     if (iter != network_handle_by_address_.end()) {
467       return absl::make_optional(iter->second);
468     }
469   }
470 
471   return FindNetworkHandleFromIfname(if_name);
472 }
473 
474 absl::optional<NetworkHandle>
FindNetworkHandleFromIfname(absl::string_view if_name) const475 AndroidNetworkMonitor::FindNetworkHandleFromIfname(
476     absl::string_view if_name) const {
477   RTC_DCHECK_RUN_ON(network_thread_);
478 
479   auto iter = network_handle_by_if_name_.find(if_name);
480   if (iter != network_handle_by_if_name_.end()) {
481     return iter->second;
482   }
483 
484   if (bind_using_ifname_) {
485     for (auto const& iter : network_handle_by_if_name_) {
486       // Use substring match so that e.g if_name="v4-wlan0" is matched
487       // agains iter="wlan0"
488       if (if_name.find(iter.first) != absl::string_view::npos) {
489         return absl::make_optional(iter.second);
490       }
491     }
492   }
493 
494   return absl::nullopt;
495 }
496 
OnNetworkDisconnected_n(NetworkHandle handle)497 void AndroidNetworkMonitor::OnNetworkDisconnected_n(NetworkHandle handle) {
498   RTC_DCHECK_RUN_ON(network_thread_);
499   RTC_LOG(LS_INFO) << "Network disconnected for handle " << handle;
500   auto iter = network_info_by_handle_.find(handle);
501   if (iter == network_info_by_handle_.end()) {
502     return;
503   }
504 
505   const auto& network_info = iter->second;
506   for (const rtc::IPAddress& address : network_info.ip_addresses) {
507     network_handle_by_address_.erase(address);
508   }
509 
510   // We've discovered that the if_name is not always unique,
511   // i.e it can be several network connected with same if_name.
512   //
513   // This is handled the following way,
514   // 1) OnNetworkConnected_n overwrites any previous "owner" of an interface
515   // name ("owner" == entry in network_handle_by_if_name_).
516   // 2) OnNetworkDisconnected_n, we scan and see if there are any remaining
517   // connected network with the interface name, and set it as owner.
518   //
519   // This means that network_info_by_handle can have more entries than
520   // network_handle_by_if_name_.
521 
522   // Check if we are registered as "owner" of if_name.
523   const auto& if_name = network_info.interface_name;
524   auto iter2 = network_handle_by_if_name_.find(if_name);
525   RTC_DCHECK(iter2 != network_handle_by_if_name_.end());
526   if (iter2 != network_handle_by_if_name_.end() && iter2->second == handle) {
527     // We are owner...
528     // Check if there is someone else we can set as owner.
529     bool found = false;
530     for (const auto& info : network_info_by_handle_) {
531       if (info.first == handle) {
532         continue;
533       }
534       if (info.second.interface_name == if_name) {
535         found = true;
536         network_handle_by_if_name_[if_name] = info.first;
537         break;
538       }
539     }
540     if (!found) {
541       // No new owner...
542       network_handle_by_if_name_.erase(iter2);
543     }
544   } else {
545     // We are not owner...don't do anything.
546 #if RTC_DCHECK_IS_ON
547     auto owner_handle = FindNetworkHandleFromIfname(if_name);
548     RTC_DCHECK(owner_handle && *owner_handle != handle);
549 #endif
550   }
551 
552   network_info_by_handle_.erase(iter);
553 }
554 
OnNetworkPreference_n(NetworkType type,rtc::NetworkPreference preference)555 void AndroidNetworkMonitor::OnNetworkPreference_n(
556     NetworkType type,
557     rtc::NetworkPreference preference) {
558   RTC_DCHECK_RUN_ON(network_thread_);
559   RTC_LOG(LS_INFO) << "Android network monitor preference for "
560                    << NetworkTypeToString(type) << " changed to "
561                    << rtc::NetworkPreferenceToString(preference);
562   auto adapter_type = AdapterTypeFromNetworkType(type, surface_cellular_types_);
563   network_preference_by_adapter_type_[adapter_type] = preference;
564   InvokeNetworksChangedCallback();
565 }
566 
SetNetworkInfos(const std::vector<NetworkInformation> & network_infos)567 void AndroidNetworkMonitor::SetNetworkInfos(
568     const std::vector<NetworkInformation>& network_infos) {
569   RTC_DCHECK_RUN_ON(network_thread_);
570 
571   // We expect this method to be called once directly after startMonitoring.
572   // All the caches should be empty.
573   RTC_DCHECK(network_handle_by_if_name_.empty());
574   RTC_DCHECK(network_handle_by_address_.empty());
575   RTC_DCHECK(network_info_by_handle_.empty());
576   RTC_DCHECK(network_preference_by_adapter_type_.empty());
577 
578   // ...but reset just in case.
579   reset();
580   RTC_LOG(LS_INFO) << "Android network monitor found " << network_infos.size()
581                    << " networks";
582   for (const NetworkInformation& network : network_infos) {
583     OnNetworkConnected_n(network);
584   }
585 }
586 
587 rtc::NetworkMonitorInterface::InterfaceInfo
GetInterfaceInfo(absl::string_view if_name)588 AndroidNetworkMonitor::GetInterfaceInfo(absl::string_view if_name) {
589   RTC_DCHECK_RUN_ON(network_thread_);
590   auto handle = FindNetworkHandleFromIfname(if_name);
591   if (!handle) {
592     return {
593         .adapter_type = rtc::ADAPTER_TYPE_UNKNOWN,
594         .available = (disable_is_adapter_available_ ? true : false),
595     };
596   }
597   auto iter = network_info_by_handle_.find(*handle);
598   RTC_DCHECK(iter != network_info_by_handle_.end());
599   if (iter == network_info_by_handle_.end()) {
600     return {
601         .adapter_type = rtc::ADAPTER_TYPE_UNKNOWN,
602         .available = (disable_is_adapter_available_ ? true : false),
603     };
604   }
605 
606   auto type =
607       AdapterTypeFromNetworkType(iter->second.type, surface_cellular_types_);
608   auto vpn_type =
609       (type == rtc::ADAPTER_TYPE_VPN)
610           ? AdapterTypeFromNetworkType(iter->second.underlying_type_for_vpn,
611                                        surface_cellular_types_)
612           : rtc::ADAPTER_TYPE_UNKNOWN;
613   return {
614       .adapter_type = type,
615       .underlying_type_for_vpn = vpn_type,
616       .network_preference = GetNetworkPreference(type),
617       .available = true,
618   };
619 }
620 
GetNetworkPreference(rtc::AdapterType adapter_type) const621 rtc::NetworkPreference AndroidNetworkMonitor::GetNetworkPreference(
622     rtc::AdapterType adapter_type) const {
623   RTC_DCHECK_RUN_ON(network_thread_);
624   auto preference_iter = network_preference_by_adapter_type_.find(adapter_type);
625   if (preference_iter == network_preference_by_adapter_type_.end()) {
626     return rtc::NetworkPreference::NEUTRAL;
627   }
628 
629   return preference_iter->second;
630 }
631 
AndroidNetworkMonitorFactory()632 AndroidNetworkMonitorFactory::AndroidNetworkMonitorFactory()
633     : j_application_context_(nullptr) {}
634 
AndroidNetworkMonitorFactory(JNIEnv * env,const JavaRef<jobject> & j_application_context)635 AndroidNetworkMonitorFactory::AndroidNetworkMonitorFactory(
636     JNIEnv* env,
637     const JavaRef<jobject>& j_application_context)
638     : j_application_context_(env, j_application_context) {}
639 
640 AndroidNetworkMonitorFactory::~AndroidNetworkMonitorFactory() = default;
641 
642 rtc::NetworkMonitorInterface*
CreateNetworkMonitor(const FieldTrialsView & field_trials)643 AndroidNetworkMonitorFactory::CreateNetworkMonitor(
644     const FieldTrialsView& field_trials) {
645   return new AndroidNetworkMonitor(AttachCurrentThreadIfNeeded(),
646                                    j_application_context_, field_trials);
647 }
648 
NotifyConnectionTypeChanged(JNIEnv * env,const JavaRef<jobject> & j_caller)649 void AndroidNetworkMonitor::NotifyConnectionTypeChanged(
650     JNIEnv* env,
651     const JavaRef<jobject>& j_caller) {
652   network_thread_->PostTask(SafeTask(safety_flag_, [this] {
653     RTC_LOG(LS_INFO)
654         << "Android network monitor detected connection type change.";
655     InvokeNetworksChangedCallback();
656   }));
657 }
658 
NotifyOfActiveNetworkList(JNIEnv * env,const JavaRef<jobject> & j_caller,const JavaRef<jobjectArray> & j_network_infos)659 void AndroidNetworkMonitor::NotifyOfActiveNetworkList(
660     JNIEnv* env,
661     const JavaRef<jobject>& j_caller,
662     const JavaRef<jobjectArray>& j_network_infos) {
663   std::vector<NetworkInformation> network_infos =
664       JavaToNativeVector<NetworkInformation>(env, j_network_infos,
665                                              &GetNetworkInformationFromJava);
666   SetNetworkInfos(network_infos);
667 }
668 
NotifyOfNetworkConnect(JNIEnv * env,const JavaRef<jobject> & j_caller,const JavaRef<jobject> & j_network_info)669 void AndroidNetworkMonitor::NotifyOfNetworkConnect(
670     JNIEnv* env,
671     const JavaRef<jobject>& j_caller,
672     const JavaRef<jobject>& j_network_info) {
673   NetworkInformation network_info =
674       GetNetworkInformationFromJava(env, j_network_info);
675   network_thread_->PostTask(
676       SafeTask(safety_flag_, [this, network_info = std::move(network_info)] {
677         OnNetworkConnected_n(network_info);
678       }));
679 }
680 
NotifyOfNetworkDisconnect(JNIEnv * env,const JavaRef<jobject> & j_caller,jlong network_handle)681 void AndroidNetworkMonitor::NotifyOfNetworkDisconnect(
682     JNIEnv* env,
683     const JavaRef<jobject>& j_caller,
684     jlong network_handle) {
685   network_thread_->PostTask(SafeTask(safety_flag_, [this, network_handle] {
686     OnNetworkDisconnected_n(static_cast<NetworkHandle>(network_handle));
687   }));
688 }
689 
NotifyOfNetworkPreference(JNIEnv * env,const JavaRef<jobject> & j_caller,const JavaRef<jobject> & j_connection_type,jint jpreference)690 void AndroidNetworkMonitor::NotifyOfNetworkPreference(
691     JNIEnv* env,
692     const JavaRef<jobject>& j_caller,
693     const JavaRef<jobject>& j_connection_type,
694     jint jpreference) {
695   NetworkType type = GetNetworkTypeFromJava(env, j_connection_type);
696   rtc::NetworkPreference preference =
697       static_cast<rtc::NetworkPreference>(jpreference);
698 
699   network_thread_->PostTask(SafeTask(safety_flag_, [this, type, preference] {
700     OnNetworkPreference_n(type, preference);
701   }));
702 }
703 
704 }  // namespace jni
705 }  // namespace webrtc
706