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