Reset all maps in AndroidNetworkMonitor Start()/Stop()

This cl/ fixes another race condition with the recent additions
to NetworkMonitorAutoDetect (getAllNetworksFromCache).

The getAllNetworksFromCache-feature uses the by the Android team
preferred way of enumerating networks, i.e to register network listeners.

Th recent fix to add IsAdapterAvailable, https://webrtc-review.googlesource.com/c/src/+/257400
contained a bug in that the adapter_type_by_name_ map was not
reset either on disconnect or Start/Stop.

This cl/ addresses that including unit test.
It also de-obfuscates NetworkMonitor so that it always
calls NotifyOfActiveNetworkList on startMonitoring even
if list.size() == 0. This should not matter but makes
code easier to understand.

Bug: webrtc:13741
Change-Id: I438b877eebf769a8b2e7292b697ef1c0a349b24f
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/258721
Reviewed-by: Harald Alvestrand <hta@webrtc.org>
Commit-Queue: Jonas Oreland <jonaso@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#36530}
This commit is contained in:
Jonas Oreland 2022-04-12 10:54:19 +02:00 committed by WebRTC LUCI CQ
parent 86aa03e238
commit 02293096f9
4 changed files with 100 additions and 6 deletions

View File

@ -138,10 +138,11 @@ public class NetworkMonitor {
startMonitoring( startMonitoring(
applicationContext != null ? applicationContext : ContextUtils.getApplicationContext(), applicationContext != null ? applicationContext : ContextUtils.getApplicationContext(),
fieldTrialsString); fieldTrialsString);
// The native observers expect a network list update after they call startMonitoring.
synchronized (nativeNetworkObservers) { synchronized (nativeNetworkObservers) {
nativeNetworkObservers.add(nativeObserver); nativeNetworkObservers.add(nativeObserver);
} }
// The native observer expects a network list update after startMonitoring.
updateObserverActiveNetworkList(nativeObserver); updateObserverActiveNetworkList(nativeObserver);
// currentConnectionType was updated in startMonitoring(). // currentConnectionType was updated in startMonitoring().
// Need to notify the native observers here. // Need to notify the native observers here.
@ -271,7 +272,7 @@ public class NetworkMonitor {
networkInfoList = networkInfoList =
(networkChangeDetector == null) ? null : networkChangeDetector.getActiveNetworkList(); (networkChangeDetector == null) ? null : networkChangeDetector.getActiveNetworkList();
} }
if (networkInfoList == null || networkInfoList.size() == 0) { if (networkInfoList == null) {
return; return;
} }

View File

@ -11,6 +11,7 @@
#include "sdk/android/src/jni/android_network_monitor.h" #include "sdk/android/src/jni/android_network_monitor.h"
#include "rtc_base/ip_address.h" #include "rtc_base/ip_address.h"
#include "rtc_base/logging.h"
#include "sdk/android/native_unittests/application_context_provider.h" #include "sdk/android/native_unittests/application_context_provider.h"
#include "sdk/android/src/jni/jni_helpers.h" #include "sdk/android/src/jni/jni_helpers.h"
#include "test/gtest.h" #include "test/gtest.h"
@ -60,6 +61,10 @@ class AndroidNetworkMonitorTest : public ::testing::Test {
network_monitor_->Stop(); network_monitor_->Stop();
} }
void Disconnect(jni::NetworkHandle handle) {
network_monitor_->OnNetworkDisconnected_n(handle);
}
protected: protected:
test::ScopedKeyValueConfig field_trials_; test::ScopedKeyValueConfig field_trials_;
std::unique_ptr<jni::AndroidNetworkMonitor> network_monitor_; std::unique_ptr<jni::AndroidNetworkMonitor> network_monitor_;
@ -169,5 +174,63 @@ TEST_F(AndroidNetworkMonitorTest, TestUnderlyingVpnType) {
network_monitor_->GetVpnUnderlyingAdapterType("v4-wlan0")); network_monitor_->GetVpnUnderlyingAdapterType("v4-wlan0"));
} }
// Verify that Disconnect makes interface unavailable.
TEST_F(AndroidNetworkMonitorTest, Disconnect) {
network_monitor_->Start();
jni::NetworkHandle ipv4_handle = 100;
rtc::IPAddress ipv4_address(kTestIpv4Address);
jni::NetworkInformation net_info =
CreateNetworkInformation("wlan0", ipv4_handle, ipv4_address);
net_info.type = jni::NETWORK_WIFI;
network_monitor_->SetNetworkInfos({net_info});
EXPECT_TRUE(network_monitor_->IsAdapterAvailable("wlan0"));
EXPECT_TRUE(network_monitor_
->FindNetworkHandleFromAddressOrName(ipv4_address, "v4-wlan0")
.has_value());
EXPECT_EQ(network_monitor_->GetAdapterType("v4-wlan0"),
rtc::ADAPTER_TYPE_WIFI);
// Check that values are reset on disconnect().
Disconnect(ipv4_handle);
EXPECT_FALSE(network_monitor_->IsAdapterAvailable("wlan0"));
EXPECT_FALSE(
network_monitor_
->FindNetworkHandleFromAddressOrName(ipv4_address, "v4-wlan0")
.has_value());
EXPECT_EQ(network_monitor_->GetAdapterType("v4-wlan0"),
rtc::ADAPTER_TYPE_UNKNOWN);
}
// Verify that Stop() resets all caches.
TEST_F(AndroidNetworkMonitorTest, Reset) {
network_monitor_->Start();
jni::NetworkHandle ipv4_handle = 100;
rtc::IPAddress ipv4_address(kTestIpv4Address);
jni::NetworkInformation net_info =
CreateNetworkInformation("wlan0", ipv4_handle, ipv4_address);
net_info.type = jni::NETWORK_WIFI;
network_monitor_->SetNetworkInfos({net_info});
EXPECT_TRUE(network_monitor_->IsAdapterAvailable("wlan0"));
EXPECT_TRUE(network_monitor_
->FindNetworkHandleFromAddressOrName(ipv4_address, "v4-wlan0")
.has_value());
EXPECT_EQ(network_monitor_->GetAdapterType("v4-wlan0"),
rtc::ADAPTER_TYPE_WIFI);
// Check that values are reset on Stop().
network_monitor_->Stop();
EXPECT_FALSE(network_monitor_->IsAdapterAvailable("wlan0"));
EXPECT_FALSE(
network_monitor_
->FindNetworkHandleFromAddressOrName(ipv4_address, "v4-wlan0")
.has_value());
EXPECT_EQ(network_monitor_->GetAdapterType("v4-wlan0"),
rtc::ADAPTER_TYPE_UNKNOWN);
}
} // namespace test } // namespace test
} // namespace webrtc } // namespace webrtc

View File

@ -243,6 +243,7 @@ void AndroidNetworkMonitor::Start() {
if (started_) { if (started_) {
return; return;
} }
reset();
started_ = true; started_ = true;
surface_cellular_types_ = surface_cellular_types_ =
field_trials_.IsEnabled("WebRTC-SurfaceCellularTypes"); field_trials_.IsEnabled("WebRTC-SurfaceCellularTypes");
@ -265,6 +266,15 @@ void AndroidNetworkMonitor::Start() {
env, field_trials_.Lookup("WebRTC-NetworkMonitorAutoDetect"))); env, field_trials_.Lookup("WebRTC-NetworkMonitorAutoDetect")));
} }
void AndroidNetworkMonitor::reset() {
RTC_DCHECK_RUN_ON(network_thread_);
network_handle_by_address_.clear();
network_info_by_handle_.clear();
adapter_type_by_name_.clear();
vpn_underlying_adapter_type_by_name_.clear();
network_preference_by_adapter_type_.clear();
}
void AndroidNetworkMonitor::Stop() { void AndroidNetworkMonitor::Stop() {
RTC_DCHECK_RUN_ON(network_thread_); RTC_DCHECK_RUN_ON(network_thread_);
if (!started_) { if (!started_) {
@ -281,8 +291,7 @@ void AndroidNetworkMonitor::Stop() {
Java_NetworkMonitor_stopMonitoring(env, j_network_monitor_, Java_NetworkMonitor_stopMonitoring(env, j_network_monitor_,
jlongFromPointer(this)); jlongFromPointer(this));
network_handle_by_address_.clear(); reset();
network_info_by_handle_.clear();
} }
// The implementation is largely taken from UDPSocketPosix::BindToNetwork in // The implementation is largely taken from UDPSocketPosix::BindToNetwork in
@ -417,6 +426,7 @@ void AndroidNetworkMonitor::OnNetworkConnected_n(
for (const rtc::IPAddress& address : network_info.ip_addresses) { for (const rtc::IPAddress& address : network_info.ip_addresses) {
network_handle_by_address_[address] = network_info.handle; network_handle_by_address_[address] = network_info.handle;
} }
RTC_CHECK(adapter_type_by_name_.size() == network_info_by_handle_.size());
InvokeNetworksChangedCallback(); InvokeNetworksChangedCallback();
} }
@ -472,8 +482,12 @@ void AndroidNetworkMonitor::OnNetworkDisconnected_n(NetworkHandle handle) {
for (const rtc::IPAddress& address : iter->second.ip_addresses) { for (const rtc::IPAddress& address : iter->second.ip_addresses) {
network_handle_by_address_.erase(address); network_handle_by_address_.erase(address);
} }
adapter_type_by_name_.erase(iter->second.interface_name);
vpn_underlying_adapter_type_by_name_.erase(iter->second.interface_name);
network_info_by_handle_.erase(iter); network_info_by_handle_.erase(iter);
} }
RTC_CHECK(adapter_type_by_name_.size() == network_info_by_handle_.size());
} }
void AndroidNetworkMonitor::OnNetworkPreference_n( void AndroidNetworkMonitor::OnNetworkPreference_n(
@ -491,8 +505,17 @@ void AndroidNetworkMonitor::OnNetworkPreference_n(
void AndroidNetworkMonitor::SetNetworkInfos( void AndroidNetworkMonitor::SetNetworkInfos(
const std::vector<NetworkInformation>& network_infos) { const std::vector<NetworkInformation>& network_infos) {
RTC_DCHECK_RUN_ON(network_thread_); RTC_DCHECK_RUN_ON(network_thread_);
network_handle_by_address_.clear();
network_info_by_handle_.clear(); // We expect this method to be called once directly after startMonitoring.
// All the caches should be empty.
RTC_CHECK(network_handle_by_address_.empty());
RTC_CHECK(network_info_by_handle_.empty());
RTC_CHECK(adapter_type_by_name_.empty());
RTC_CHECK(vpn_underlying_adapter_type_by_name_.empty());
RTC_CHECK(network_preference_by_adapter_type_.empty());
// ...but reset just in case.
reset();
RTC_LOG(LS_INFO) << "Android network monitor found " << network_infos.size() RTC_LOG(LS_INFO) << "Android network monitor found " << network_infos.size()
<< " networks"; << " networks";
for (const NetworkInformation& network : network_infos) { for (const NetworkInformation& network : network_infos) {

View File

@ -29,6 +29,10 @@
#include "sdk/android/src/jni/jni_helpers.h" #include "sdk/android/src/jni/jni_helpers.h"
namespace webrtc { namespace webrtc {
namespace test {
class AndroidNetworkMonitorTest;
} // namespace test
namespace jni { namespace jni {
typedef int64_t NetworkHandle; typedef int64_t NetworkHandle;
@ -120,6 +124,7 @@ class AndroidNetworkMonitor : public rtc::NetworkMonitorInterface {
absl::string_view ifname) const; absl::string_view ifname) const;
private: private:
void reset();
void OnNetworkConnected_n(const NetworkInformation& network_info); void OnNetworkConnected_n(const NetworkInformation& network_info);
void OnNetworkDisconnected_n(NetworkHandle network_handle); void OnNetworkDisconnected_n(NetworkHandle network_handle);
void OnNetworkPreference_n(NetworkType type, void OnNetworkPreference_n(NetworkType type,
@ -163,6 +168,8 @@ class AndroidNetworkMonitor : public rtc::NetworkMonitorInterface {
RTC_PT_GUARDED_BY(network_thread_) = nullptr; RTC_PT_GUARDED_BY(network_thread_) = nullptr;
const FieldTrialsView& field_trials_; const FieldTrialsView& field_trials_;
friend class webrtc::test::AndroidNetworkMonitorTest;
}; };
class AndroidNetworkMonitorFactory : public rtc::NetworkMonitorFactory { class AndroidNetworkMonitorFactory : public rtc::NetworkMonitorFactory {