diff options
Diffstat (limited to 'chromium/components/arc/net')
-rw-r--r-- | chromium/components/arc/net/OWNERS | 3 | ||||
-rw-r--r-- | chromium/components/arc/net/arc_net_host_impl.cc | 524 | ||||
-rw-r--r-- | chromium/components/arc/net/arc_net_host_impl.h | 6 |
3 files changed, 164 insertions, 369 deletions
diff --git a/chromium/components/arc/net/OWNERS b/chromium/components/arc/net/OWNERS new file mode 100644 index 00000000000..522f9d41ab5 --- /dev/null +++ b/chromium/components/arc/net/OWNERS @@ -0,0 +1,3 @@ +hugobenichi@google.com + +# COMPONENT: Platform>Apps>ARC diff --git a/chromium/components/arc/net/arc_net_host_impl.cc b/chromium/components/arc/net/arc_net_host_impl.cc index 6b5aa63e8f5..be411029899 100644 --- a/chromium/components/arc/net/arc_net_host_impl.cc +++ b/chromium/components/arc/net/arc_net_host_impl.cc @@ -13,8 +13,6 @@ #include "base/memory/singleton.h" #include "base/posix/eintr_wrapper.h" #include "base/stl_util.h" -#include "base/threading/thread_task_runner_handle.h" -#include "base/time/time.h" #include "chromeos/login/login_state/login_state.h" #include "chromeos/network/device_state.h" #include "chromeos/network/managed_network_configuration_handler.h" @@ -24,7 +22,6 @@ #include "chromeos/network/network_state.h" #include "chromeos/network/network_state_handler.h" #include "chromeos/network/network_type_pattern.h" -#include "chromeos/network/network_util.h" #include "chromeos/network/onc/onc_utils.h" #include "components/arc/arc_browser_context_keyed_service_factory_base.h" #include "components/arc/arc_prefs.h" @@ -36,10 +33,6 @@ namespace { constexpr int kGetNetworksListLimit = 100; -// Delay in millisecond before asking for a network property update when no IP -// configuration can be retrieved for a network. -constexpr base::TimeDelta kNetworkPropertyUpdateDelay = - base::TimeDelta::FromMilliseconds(5000); chromeos::NetworkStateHandler* GetStateHandler() { return chromeos::NetworkHandler::Get()->network_state_handler(); @@ -70,171 +63,25 @@ bool IsDeviceOwner() { user_manager::UserManager::Get()->GetOwnerAccountId(); } -std::string GetStringFromONCDictionary(const base::Value* dict, - const char* key, - bool required) { - DCHECK(dict->is_dict()); - const base::Value* string_value = - dict->FindKeyOfType(key, base::Value::Type::STRING); - if (!string_value) { - LOG_IF(ERROR, required) << "Required property " << key << " not found."; - return std::string(); - } - std::string result = string_value->GetString(); - LOG_IF(ERROR, required && result.empty()) - << "Required property " << key << " is empty."; - return result; -} - -arc::mojom::SecurityType TranslateONCWifiSecurityType( - const base::DictionaryValue* dict) { - std::string type = GetStringFromONCDictionary(dict, onc::wifi::kSecurity, - true /* required */); - if (type == onc::wifi::kWEP_PSK) +arc::mojom::SecurityType TranslateWiFiSecurity(const std::string& type) { + if (type == shill::kSecurityNone) + return arc::mojom::SecurityType::NONE; + if (type == shill::kSecurityWep) return arc::mojom::SecurityType::WEP_PSK; - if (type == onc::wifi::kWEP_8021X) - return arc::mojom::SecurityType::WEP_8021X; - if (type == onc::wifi::kWPA_PSK) + if (type == shill::kSecurityPsk) + return arc::mojom::SecurityType::WPA_PSK; + if (type == shill::kSecurityWpa) return arc::mojom::SecurityType::WPA_PSK; - if (type == onc::wifi::kWPA_EAP) + if (type == shill::kSecurity8021x) + return arc::mojom::SecurityType::WPA_EAP; + // Robust Security Network does not appear to be defined in Android. + // Approximate it with WPA_EAP + if (type == shill::kSecurityRsn) return arc::mojom::SecurityType::WPA_EAP; + LOG(WARNING) << "Unknown WiFi security type " << type; return arc::mojom::SecurityType::NONE; } -arc::mojom::TetheringClientState TranslateTetheringState( - const std::string& tethering_state) { - if (tethering_state == onc::tethering_state::kTetheringConfirmedState) - return arc::mojom::TetheringClientState::CONFIRMED; - else if (tethering_state == onc::tethering_state::kTetheringNotDetectedState) - return arc::mojom::TetheringClientState::NOT_DETECTED; - else if (tethering_state == onc::tethering_state::kTetheringSuspectedState) - return arc::mojom::TetheringClientState::SUSPECTED; - NOTREACHED() << "Invalid tethering state: " << tethering_state; - return arc::mojom::TetheringClientState::NOT_DETECTED; -} - -arc::mojom::WiFiPtr TranslateONCWifi(const base::DictionaryValue* dict) { - arc::mojom::WiFiPtr wifi = arc::mojom::WiFi::New(); - - // Optional; defaults to 0. - dict->GetInteger(onc::wifi::kFrequency, &wifi->frequency); - - wifi->bssid = - GetStringFromONCDictionary(dict, onc::wifi::kBSSID, false /* required */); - wifi->hex_ssid = GetStringFromONCDictionary(dict, onc::wifi::kHexSSID, - true /* required */); - - // Optional; defaults to false. - dict->GetBoolean(onc::wifi::kHiddenSSID, &wifi->hidden_ssid); - - wifi->security = TranslateONCWifiSecurityType(dict); - - // Optional; defaults to 0. - dict->GetInteger(onc::wifi::kSignalStrength, &wifi->signal_strength); - - return wifi; -} - -// Extracts WiFi's tethering client state from a dictionary of WiFi properties. -arc::mojom::TetheringClientState GetWifiTetheringClientState( - const base::DictionaryValue* dict) { - std::string tethering_state; - dict->GetString(onc::wifi::kTetheringState, &tethering_state); - return TranslateTetheringState(tethering_state); -} - -arc::mojom::IPConfigurationPtr TranslateONCIPConfig( - const base::Value* ip_dict) { - DCHECK(ip_dict->is_dict()); - - arc::mojom::IPConfigurationPtr configuration = - arc::mojom::IPConfiguration::New(); - - const base::Value* ip_address = ip_dict->FindKeyOfType( - onc::ipconfig::kIPAddress, base::Value::Type::STRING); - if (ip_address && !ip_address->GetString().empty()) { - configuration->ip_address = ip_address->GetString(); - const base::Value* routing_prefix = ip_dict->FindKeyOfType( - onc::ipconfig::kRoutingPrefix, base::Value::Type::INTEGER); - if (routing_prefix) - configuration->routing_prefix = routing_prefix->GetInt(); - else - LOG(ERROR) << "Required property RoutingPrefix not found."; - configuration->gateway = GetStringFromONCDictionary( - ip_dict, onc::ipconfig::kGateway, true /* required */); - } - - const base::Value* name_servers = ip_dict->FindKeyOfType( - onc::ipconfig::kNameServers, base::Value::Type::LIST); - if (name_servers) { - for (const auto& entry : name_servers->GetList()) - configuration->name_servers.push_back(entry.GetString()); - } - - const base::Value* type = - ip_dict->FindKeyOfType(onc::ipconfig::kType, base::Value::Type::STRING); - configuration->type = type && type->GetString() == onc::ipconfig::kIPv6 - ? arc::mojom::IPAddressType::IPV6 - : arc::mojom::IPAddressType::IPV4; - - configuration->web_proxy_auto_discovery_url = GetStringFromONCDictionary( - ip_dict, onc::ipconfig::kWebProxyAutoDiscoveryUrl, false /* required */); - - return configuration; -} - -// Returns true if the IP configuration is valid enough for ARC. Empty IP -// config objects can be generated when IPv4 DHCP or IPv6 autoconf has not -// completed yet. -bool IsValidIPConfiguration(const arc::mojom::IPConfiguration& ip_config) { - return !ip_config.ip_address.empty() && !ip_config.gateway.empty(); -} - -// Returns an IPConfiguration vector from the IPConfigs ONC property, which may -// include multiple IP configurations (e.g. IPv4 and IPv6). -std::vector<arc::mojom::IPConfigurationPtr> IPConfigurationsFromONCIPConfigs( - const base::Value* dict) { - const base::Value* ip_config_list = - dict->FindKey(onc::network_config::kIPConfigs); - if (!ip_config_list || !ip_config_list->is_list()) - return {}; - std::vector<arc::mojom::IPConfigurationPtr> result; - for (const auto& entry : ip_config_list->GetList()) { - arc::mojom::IPConfigurationPtr config = TranslateONCIPConfig(&entry); - if (config && IsValidIPConfiguration(*config)) - result.push_back(std::move(config)); - } - return result; -} - -// Returns an IPConfiguration vector from ONC property |property|, which will -// include a single IP configuration. -std::vector<arc::mojom::IPConfigurationPtr> IPConfigurationsFromONCProperty( - const base::Value* dict, - const char* property_key) { - const base::Value* ip_dict = dict->FindKey(property_key); - if (!ip_dict) - return {}; - arc::mojom::IPConfigurationPtr config = TranslateONCIPConfig(ip_dict); - if (!config || !IsValidIPConfiguration(*config)) - return {}; - std::vector<arc::mojom::IPConfigurationPtr> result; - result.push_back(std::move(config)); - return result; -} - -arc::mojom::ConnectionStateType TranslateONCConnectionState( - const base::DictionaryValue* dict) { - std::string connection_state = GetStringFromONCDictionary( - dict, onc::network_config::kConnectionState, false /* required */); - - if (connection_state == onc::connection_state::kConnected) - return arc::mojom::ConnectionStateType::CONNECTED; - if (connection_state == onc::connection_state::kConnecting) - return arc::mojom::ConnectionStateType::CONNECTING; - return arc::mojom::ConnectionStateType::NOT_CONNECTED; -} - // Translates a shill connection state into a mojo ConnectionStateType. // This is effectively the inverse function of shill.Service::GetStateString // defined in platform2/shill/service.cc, with in addition some of shill's @@ -273,54 +120,47 @@ bool IsActiveNetworkState(const chromeos::NetworkState* network) { state == shill::kStatePortalSuspected; } -void TranslateONCNetworkTypeDetails(const base::DictionaryValue* dict, - arc::mojom::NetworkConfiguration* mojo) { - std::string type = GetStringFromONCDictionary( - dict, onc::network_config::kType, true /* required */); - // This property will be updated as required by the relevant network types - // below. - mojo->tethering_client_state = arc::mojom::TetheringClientState::NOT_DETECTED; - if (type == onc::network_type::kCellular) { - mojo->type = arc::mojom::NetworkType::CELLULAR; - } else if (type == onc::network_type::kEthernet) { - mojo->type = arc::mojom::NetworkType::ETHERNET; - } else if (type == onc::network_type::kVPN) { - mojo->type = arc::mojom::NetworkType::VPN; - } else if (type == onc::network_type::kWiFi) { - mojo->type = arc::mojom::NetworkType::WIFI; - const base::DictionaryValue* wifi_dict = nullptr; - dict->GetDictionary(onc::network_config::kWiFi, &wifi_dict); - DCHECK(wifi_dict); - mojo->wifi = TranslateONCWifi(wifi_dict); - mojo->tethering_client_state = GetWifiTetheringClientState(wifi_dict); - } else { - NOTREACHED() << "Unknown network type: " << type; - } -} - -// Parse a shill IPConfig dictionary and appends the resulting mojo -// IPConfiguration object to the given |ip_configs| vector. -void AddIpConfiguration(std::vector<arc::mojom::IPConfigurationPtr>& ip_configs, +arc::mojom::NetworkType TranslateNetworkType(const std::string& type) { + if (type == shill::kTypeWifi) + return arc::mojom::NetworkType::WIFI; + if (type == shill::kTypeVPN) + return arc::mojom::NetworkType::VPN; + if (type == shill::kTypeEthernet) + return arc::mojom::NetworkType::ETHERNET; + if (type == shill::kTypeEthernetEap) + return arc::mojom::NetworkType::ETHERNET; + if (type == shill::kTypeCellular) + return arc::mojom::NetworkType::CELLULAR; + NOTREACHED() << "Unknown network type: " << type; + return arc::mojom::NetworkType::ETHERNET; +} + +// Parses a shill IPConfig dictionary and adds the relevant fields to +// the given |network| NetworkConfiguration object. +void AddIpConfiguration(arc::mojom::NetworkConfiguration* network, const base::Value* shill_ipconfig) { if (!shill_ipconfig || !shill_ipconfig->is_dict()) return; - auto ip_config = arc::mojom::IPConfiguration::New(); - if (const auto* address_property = - shill_ipconfig->FindStringPath(shill::kAddressProperty)) - ip_config->ip_address = *address_property; - - if (const auto* gateway_property = - shill_ipconfig->FindStringPath(shill::kGatewayProperty)) - ip_config->gateway = *gateway_property; - - ip_config->routing_prefix = + // Only set the IP address and gateway if both are defined and non empty. + const auto* address = shill_ipconfig->FindStringPath(shill::kAddressProperty); + const auto* gateway = shill_ipconfig->FindStringPath(shill::kGatewayProperty); + const int prefixlen = shill_ipconfig->FindIntPath(shill::kPrefixlenProperty).value_or(0); + if (address && !address->empty() && gateway && !gateway->empty()) { + if (prefixlen < 64) { + network->host_ipv4_prefix_length = prefixlen; + network->host_ipv4_address = *address; + network->host_ipv4_gateway = *gateway; + } else { + network->host_ipv6_prefix_length = prefixlen; + network->host_ipv6_global_addresses->push_back(*address); + network->host_ipv6_gateway = *gateway; + } + } - ip_config->type = (ip_config->routing_prefix < 64) - ? arc::mojom::IPAddressType::IPV4 - : arc::mojom::IPAddressType::IPV6; - + // If the user has overridden DNS with the "Google nameservers" UI options, + // the kStaticIPConfigProperty object will be empty except for DNS addresses. if (const auto* dns_list = shill_ipconfig->FindListKey(shill::kNameServersProperty)) { for (const auto& dns_value : dns_list->GetList()) { @@ -333,80 +173,80 @@ void AddIpConfiguration(std::vector<arc::mojom::IPConfigurationPtr>& ip_configs, if (dns == "0.0.0.0") continue; - ip_config->name_servers.push_back(dns); + network->host_dns_addresses->push_back(dns); } } - if (IsValidIPConfiguration(*ip_config)) - ip_configs.push_back(std::move(ip_config)); -} - -// Add shill's Device properties to the given mojo NetworkConfiguration objects. -// This adds the network interface and current IP configurations. -void AddDeviceProperties(arc::mojom::NetworkConfiguration* network, - const std::string& device_path) { - const auto* device = GetStateHandler()->GetDeviceState(device_path); - if (!device) - return; - - network->network_interface = device->interface(); - - std::vector<arc::mojom::IPConfigurationPtr> ip_configs; - for (const auto& kv : device->ip_configs()) - AddIpConfiguration(ip_configs, kv.second.get()); + if (const auto* domains = + shill_ipconfig->FindKey(shill::kSearchDomainsProperty)) { + if (domains->is_list()) { + for (const auto& domain : domains->GetList()) + network->host_search_domains->push_back(domain.GetString()); + } + } - // If the DeviceState had any IP configuration, always use them and ignore - // any other IP configuration previously obtained through NetworkState. - if (!ip_configs.empty()) - network->ip_configs = std::move(ip_configs); + const int mtu = shill_ipconfig->FindIntPath(shill::kMtuProperty).value_or(0); + if (mtu > 0) + network->host_mtu = mtu; } -arc::mojom::NetworkConfigurationPtr TranslateONCConfiguration( +arc::mojom::NetworkConfigurationPtr TranslateNetworkProperties( const chromeos::NetworkState* network_state, - const base::Value* shill_dict, - const base::DictionaryValue* onc_dict) { + const base::Value* shill_dict) { auto mojo = arc::mojom::NetworkConfiguration::New(); - - mojo->connection_state = TranslateONCConnectionState(onc_dict); - - mojo->guid = GetStringFromONCDictionary(onc_dict, onc::network_config::kGUID, - true /* required */); - - // crbug.com/761708 - VPNs do not currently have an IPConfigs array, - // so in order to fetch the parameters (particularly the DNS server list), - // fall back to StaticIPConfig or SavedIPConfig. - // TODO(b/145960788) Remove IP configuration retrieval from ONC properties. - std::vector<arc::mojom::IPConfigurationPtr> ip_configs = - IPConfigurationsFromONCIPConfigs(onc_dict); - if (ip_configs.empty()) { - ip_configs = IPConfigurationsFromONCProperty( - onc_dict, onc::network_config::kStaticIPConfig); + // Initialize optional array fields to avoid null guards both here and in ARC. + mojo->host_ipv6_global_addresses = std::vector<std::string>(); + mojo->host_search_domains = std::vector<std::string>(); + mojo->host_dns_addresses = std::vector<std::string>(); + mojo->connection_state = + TranslateConnectionState(network_state->connection_state()); + mojo->guid = network_state->guid(); + if (mojo->guid.empty()) + LOG(ERROR) << "Missing GUID property for network " << network_state->path(); + mojo->type = TranslateNetworkType(network_state->type()); + mojo->is_metered = + shill_dict && + shill_dict->FindBoolPath(shill::kMeteredProperty).value_or(false); + + // IP configuration data is added from the properties of the underlying shill + // Device and shill Service attached to the Device. Device properties are + // preferred because Service properties cannot have both IPv4 and IPv6 + // configurations at the same time for dual stack networks. It is necessary to + // fallback on Service properties for networks without a shill Device exposed + // over DBus (builtin OpenVPN, builtin L2TP client, Chrome extension VPNs), + // particularly to obtain the DNS server list (b/155129178). + // A connecting or newly connected network may not immediately have any + // usable IP config object if IPv4 dhcp or IPv6 autoconf have not completed + // yet. This case is covered by requesting shill properties asynchronously + // when chromeos::NetworkStateHandlerObserver::NetworkPropertiesUpdated is + // called. + + // Add shill's Device properties to the given mojo NetworkConfiguration + // objects. This adds the network interface and current IP configurations. + if (const auto* device = + GetStateHandler()->GetDeviceState(network_state->device_path())) { + mojo->network_interface = device->interface(); + for (const auto& kv : device->ip_configs()) + AddIpConfiguration(mojo.get(), kv.second.get()); } - if (ip_configs.empty()) { - ip_configs = IPConfigurationsFromONCProperty( - onc_dict, onc::network_config::kSavedIPConfig); - } - // b/155129178 Also use cached shill properties if available. + if (shill_dict) { for (const auto* property : - {shill::kIPConfigProperty, shill::kStaticIPConfigProperty, - shill::kSavedIPConfigProperty}) { - if (!ip_configs.empty()) - break; - - AddIpConfiguration(ip_configs, shill_dict->FindKey(property)); + {shill::kStaticIPConfigProperty, shill::kSavedIPConfigProperty}) { + AddIpConfiguration(mojo.get(), shill_dict->FindKey(property)); } } - mojo->ip_configs = std::move(ip_configs); - mojo->guid = GetStringFromONCDictionary(onc_dict, onc::network_config::kGUID, - true /* required */); - TranslateONCNetworkTypeDetails(onc_dict, mojo.get()); - - if (network_state) { - mojo->connection_state = - TranslateConnectionState(network_state->connection_state()); - AddDeviceProperties(mojo.get(), network_state->device_path()); + if (mojo->type == arc::mojom::NetworkType::WIFI) { + mojo->wifi = arc::mojom::WiFi::New(); + mojo->wifi->bssid = network_state->bssid(); + mojo->wifi->hex_ssid = network_state->GetHexSsid(); + mojo->wifi->security = + TranslateWiFiSecurity(network_state->security_class()); + mojo->wifi->frequency = network_state->frequency(); + mojo->wifi->hidden_ssid = shill_dict && + shill_dict->FindBoolPath(shill::kWifiHiddenSsid).value_or(false); + mojo->wifi->signal_strength = network_state->signal_strength(); } return mojo; @@ -440,25 +280,22 @@ std::vector<arc::mojom::NetworkConfigurationPtr> TranslateNetworkStates( std::vector<arc::mojom::NetworkConfigurationPtr> networks; for (const chromeos::NetworkState* state : network_states) { const std::string& network_path = state->path(); - if (network_path == arc_vpn_path) { - // Never tell Android about its own VPN. + // Never tell Android about its own VPN. + if (network_path == arc_vpn_path) continue; - } + // For tethered networks, the underlying WiFi networks are not part of // active networks. Replace any such tethered network with its underlying // backing network, because ARC cannot match its datapath with the tethered // network configuration. state = GetShillBackedNetwork(state); - if (!state) { + if (!state) continue; - } const auto it = shill_network_properties.find(network_path); const auto* shill_dict = (it != shill_network_properties.end()) ? &it->second : nullptr; - const auto onc_dict = - chromeos::network_util::TranslateNetworkStateToONC(state); - auto network = TranslateONCConfiguration(state, shill_dict, onc_dict.get()); + auto network = TranslateNetworkProperties(state, shill_dict); network->is_default_network = state == GetStateHandler()->DefaultNetwork(); network->service_name = network_path; networks.push_back(std::move(network)); @@ -475,7 +312,6 @@ void ForgetNetworkFailureCallback( base::OnceCallback<void(arc::mojom::NetworkResult)> callback, const std::string& error_name, std::unique_ptr<base::DictionaryValue> error_data) { - VLOG(1) << "ForgetNetworkFailureCallback: " << error_name; std::move(callback).Run(arc::mojom::NetworkResult::FAILURE); } @@ -488,7 +324,6 @@ void StartConnectFailureCallback( base::OnceCallback<void(arc::mojom::NetworkResult)> callback, const std::string& error_name, std::unique_ptr<base::DictionaryValue> error_data) { - VLOG(1) << "StartConnectFailureCallback: " << error_name; std::move(callback).Run(arc::mojom::NetworkResult::FAILURE); } @@ -501,17 +336,15 @@ void StartDisconnectFailureCallback( base::OnceCallback<void(arc::mojom::NetworkResult)> callback, const std::string& error_name, std::unique_ptr<base::DictionaryValue> error_data) { - VLOG(1) << "StartDisconnectFailureCallback: " << error_name; std::move(callback).Run(arc::mojom::NetworkResult::FAILURE); } -void ArcVpnSuccessCallback() { - DVLOG(1) << "ArcVpnSuccessCallback"; -} +void ArcVpnSuccessCallback() {} -void ArcVpnErrorCallback(const std::string& error_name, +void ArcVpnErrorCallback(const std::string& operation, + const std::string& error_name, std::unique_ptr<base::DictionaryValue> error_data) { - LOG(ERROR) << "ArcVpnErrorCallback: " << error_name; + LOG(ERROR) << "ArcVpnErrorCallback: " << operation << ": " << error_name; } } // namespace @@ -588,10 +421,9 @@ void ArcNetHostImpl::OnConnectionReady() { GetShillBackedNetwork(GetStateHandler()->DefaultNetwork()); if (default_network && default_network->type() == shill::kTypeVPN && default_network->GetVpnProviderType() == shill::kProviderArcVpn) { - VLOG(0) << "Disconnecting stale ARC VPN " << default_network->path(); GetNetworkConnectionHandler()->DisconnectNetwork( default_network->path(), base::Bind(&ArcVpnSuccessCallback), - base::Bind(&ArcVpnErrorCallback)); + base::Bind(&ArcVpnErrorCallback, "disconnecting stale ARC VPN")); } } @@ -638,8 +470,6 @@ void ArcNetHostImpl::CreateNetworkSuccessCallback( base::OnceCallback<void(const std::string&)> callback, const std::string& service_path, const std::string& guid) { - VLOG(1) << "CreateNetworkSuccessCallback"; - cached_guid_ = guid; cached_service_path_ = service_path; @@ -650,13 +480,14 @@ void ArcNetHostImpl::CreateNetworkFailureCallback( base::OnceCallback<void(const std::string&)> callback, const std::string& error_name, std::unique_ptr<base::DictionaryValue> error_data) { - VLOG(1) << "CreateNetworkFailureCallback: " << error_name; + LOG(ERROR) << "CreateNetworkFailureCallback: " << error_name; std::move(callback).Run(std::string()); } void ArcNetHostImpl::CreateNetwork(mojom::WifiConfigurationPtr cfg, CreateNetworkCallback callback) { if (!IsDeviceOwner()) { + LOG(ERROR) << "Only device owner can create WiFi networks"; std::move(callback).Run(std::string()); return; } @@ -665,12 +496,16 @@ void ArcNetHostImpl::CreateNetwork(mojom::WifiConfigurationPtr cfg, std::unique_ptr<base::DictionaryValue> wifi_dict(new base::DictionaryValue); if (!cfg->hexssid.has_value() || !cfg->details) { + LOG(ERROR) + << "Cannot create WiFi network without hex ssid or WiFi properties"; std::move(callback).Run(std::string()); return; } + mojom::ConfiguredNetworkDetailsPtr details = std::move(cfg->details->get_configured()); if (!details) { + LOG(ERROR) << "Cannot create WiFi network without WiFi properties"; std::move(callback).Run(std::string()); return; } @@ -707,7 +542,7 @@ void ArcNetHostImpl::CreateNetwork(mojom::WifiConfigurationPtr cfg, bool ArcNetHostImpl::GetNetworkPathFromGuid(const std::string& guid, std::string* path) { - const chromeos::NetworkState* network = + const auto* network = GetShillBackedNetwork(GetStateHandler()->GetNetworkStateFromGuid(guid)); if (network) { *path = network->path(); @@ -718,18 +553,21 @@ bool ArcNetHostImpl::GetNetworkPathFromGuid(const std::string& guid, *path = cached_service_path_; return true; } + return false; } void ArcNetHostImpl::ForgetNetwork(const std::string& guid, ForgetNetworkCallback callback) { if (!IsDeviceOwner()) { + LOG(ERROR) << "Only device owner can remove WiFi networks"; std::move(callback).Run(mojom::NetworkResult::FAILURE); return; } std::string path; if (!GetNetworkPathFromGuid(guid, &path)) { + LOG(ERROR) << "Could not retrieve Service path from GUID " << guid; std::move(callback).Run(mojom::NetworkResult::FAILURE); return; } @@ -748,6 +586,7 @@ void ArcNetHostImpl::StartConnect(const std::string& guid, StartConnectCallback callback) { std::string path; if (!GetNetworkPathFromGuid(guid, &path)) { + LOG(ERROR) << "Could not retrieve Service path from GUID " << guid; std::move(callback).Run(mojom::NetworkResult::FAILURE); return; } @@ -766,6 +605,7 @@ void ArcNetHostImpl::StartDisconnect(const std::string& guid, StartDisconnectCallback callback) { std::string path; if (!GetNetworkPathFromGuid(guid, &path)) { + LOG(ERROR) << "Could not retrieve Service path from GUID " << guid; std::move(callback).Run(mojom::NetworkResult::FAILURE); return; } @@ -788,17 +628,17 @@ void ArcNetHostImpl::GetWifiEnabledState(GetWifiEnabledStateCallback callback) { void ArcNetHostImpl::SetWifiEnabledState(bool is_enabled, SetWifiEnabledStateCallback callback) { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - chromeos::NetworkStateHandler::TechnologyState state = - GetStateHandler()->GetTechnologyState( - chromeos::NetworkTypePattern::WiFi()); + auto state = GetStateHandler()->GetTechnologyState( + chromeos::NetworkTypePattern::WiFi()); // WiFi can't be enabled or disabled in these states. if ((state == chromeos::NetworkStateHandler::TECHNOLOGY_PROHIBITED) || (state == chromeos::NetworkStateHandler::TECHNOLOGY_UNINITIALIZED) || (state == chromeos::NetworkStateHandler::TECHNOLOGY_UNAVAILABLE)) { - VLOG(1) << "SetWifiEnabledState failed due to WiFi state: " << state; + LOG(ERROR) << "SetWifiEnabledState failed due to WiFi state: " << state; std::move(callback).Run(false); return; } + GetStateHandler()->SetTechnologyEnabled( chromeos::NetworkTypePattern::WiFi(), is_enabled, chromeos::network_handler::ErrorCallback()); @@ -836,43 +676,39 @@ std::string ArcNetHostImpl::LookupArcVpnServicePath() { false /* visible_only */, kGetNetworksListLimit, &state_list); for (const chromeos::NetworkState* state : state_list) { - const chromeos::NetworkState* shill_backed_network = - GetShillBackedNetwork(state); + const auto* shill_backed_network = GetShillBackedNetwork(state); if (!shill_backed_network) continue; - if (shill_backed_network->GetVpnProviderType() == shill::kProviderArcVpn) { + + if (shill_backed_network->GetVpnProviderType() == shill::kProviderArcVpn) return shill_backed_network->path(); - } } return std::string(); } void ArcNetHostImpl::ConnectArcVpn(const std::string& service_path, const std::string& /* guid */) { - DVLOG(1) << "ConnectArcVpn " << service_path; arc_vpn_service_path_ = service_path; GetNetworkConnectionHandler()->ConnectToNetwork( service_path, base::Bind(&ArcVpnSuccessCallback), - base::Bind(&ArcVpnErrorCallback), false /* check_error_state */, + base::Bind(&ArcVpnErrorCallback, "connecting ARC VPN"), + false /* check_error_state */, chromeos::ConnectCallbackMode::ON_COMPLETED); } std::unique_ptr<base::Value> ArcNetHostImpl::TranslateStringListToValue( const std::vector<std::string>& string_list) { - std::unique_ptr<base::Value> result = - std::make_unique<base::Value>(base::Value::Type::LIST); - for (const auto& item : string_list) { + auto result = std::make_unique<base::Value>(base::Value::Type::LIST); + for (const auto& item : string_list) result->Append(item); - } return result; } std::unique_ptr<base::DictionaryValue> ArcNetHostImpl::TranslateVpnConfigurationToOnc( const mojom::AndroidVpnConfiguration& cfg) { - std::unique_ptr<base::DictionaryValue> top_dict = - std::make_unique<base::DictionaryValue>(); + auto top_dict = std::make_unique<base::DictionaryValue>(); // Name, Type top_dict->SetKey( @@ -930,31 +766,26 @@ ArcNetHostImpl::TranslateVpnConfigurationToOnc( void ArcNetHostImpl::AndroidVpnConnected( mojom::AndroidVpnConfigurationPtr cfg) { - std::unique_ptr<base::DictionaryValue> properties = - TranslateVpnConfigurationToOnc(*cfg); + auto properties = TranslateVpnConfigurationToOnc(*cfg); std::string service_path = LookupArcVpnServicePath(); if (!service_path.empty()) { - VLOG(1) << "AndroidVpnConnected: reusing " << service_path; GetManagedConfigurationHandler()->SetProperties( service_path, *properties, base::Bind(&ArcNetHostImpl::ConnectArcVpn, weak_factory_.GetWeakPtr(), service_path, std::string()), - base::Bind(&ArcVpnErrorCallback)); + base::Bind(&ArcVpnErrorCallback, + "reconnecting ARC VPN " + service_path)); return; } - VLOG(1) << "AndroidVpnConnected: creating new ARC VPN"; std::string user_id_hash = chromeos::LoginState::Get()->primary_user_hash(); GetManagedConfigurationHandler()->CreateConfiguration( user_id_hash, *properties, base::Bind(&ArcNetHostImpl::ConnectArcVpn, weak_factory_.GetWeakPtr()), - base::Bind(&ArcVpnErrorCallback)); + base::Bind(&ArcVpnErrorCallback, "connecting new ARC VPN")); } void ArcNetHostImpl::AndroidVpnStateChanged(mojom::ConnectionStateType state) { - VLOG(1) << "AndroidVpnStateChanged: state=" << state - << " service=" << arc_vpn_service_path_; - if (state != arc::mojom::ConnectionStateType::NOT_CONNECTED || arc_vpn_service_path_.empty()) { return; @@ -968,7 +799,7 @@ void ArcNetHostImpl::AndroidVpnStateChanged(mojom::ConnectionStateType state) { GetNetworkConnectionHandler()->DisconnectNetwork( service_path, base::Bind(&ArcVpnSuccessCallback), - base::Bind(&ArcVpnErrorCallback)); + base::Bind(&ArcVpnErrorCallback, "disconnecting ARC VPN")); } void ArcNetHostImpl::SetAlwaysOnVpn(const std::string& vpn_package, @@ -984,10 +815,9 @@ void ArcNetHostImpl::DisconnectArcVpn() { auto* net_instance = ARC_GET_INSTANCE_FOR_METHOD(arc_bridge_service_->net(), DisconnectAndroidVpn); - if (!net_instance) { - LOG(ERROR) << "User requested VPN disconnection but API is unavailable"; + if (!net_instance) return; - } + net_instance->DisconnectAndroidVpn(); } @@ -999,27 +829,23 @@ void ArcNetHostImpl::DisconnectRequested(const std::string& service_path) { // This code path is taken when a user clicks the blue Disconnect button // in Chrome OS. Chrome is about to send the Disconnect call to shill, // so update our local state and tell Android to disconnect the VPN. - VLOG(1) << "DisconnectRequested " << service_path; DisconnectArcVpn(); } void ArcNetHostImpl::NetworkConnectionStateChanged( const chromeos::NetworkState* network) { - const chromeos::NetworkState* shill_backed_network = - GetShillBackedNetwork(network); + const auto* shill_backed_network = GetShillBackedNetwork(network); if (!shill_backed_network) return; if (arc_vpn_service_path_ != shill_backed_network->path() || - shill_backed_network->IsConnectingOrConnected()) { + shill_backed_network->IsConnectingOrConnected()) return; - } // This code path is taken when shill disconnects the Android VPN // service. This can happen if a user tries to connect to a Chrome OS // VPN, and shill's VPNProvider::DisconnectAll() forcibly disconnects // all other VPN services to avoid a conflict. - VLOG(1) << "NetworkConnectionStateChanged " << shill_backed_network->path(); DisconnectArcVpn(); } @@ -1064,43 +890,8 @@ void ArcNetHostImpl::UpdateActiveNetworks() { if (!net_instance) return; - const auto active_networks = GetActiveNetworks(); - auto network_configurations = TranslateNetworkStates( - arc_vpn_service_path_, active_networks, shill_network_properties_); - - // A newly connected network may not immediately have any usable IP config - // object if IPv4 dhcp or IPv6 autoconf have not completed yet. Schedule - // with a few seconds delay a forced property update for that service to - // ensure the IP configuration is sent to ARC. Ensure that at most one such - // request is scheduled for a given service. - for (const auto& network : network_configurations) { - if (!network->ip_configs->empty()) - continue; - - if (!network->service_name) - continue; - - const std::string& path = network->service_name.value(); - if (pending_service_property_requests_.insert(path).second) { - LOG(WARNING) << "No IP configuration for " << path; - // TODO(hugobenichi): add exponential backoff for the case when IP - // configuration stays unavailable. - base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( - FROM_HERE, - base::BindOnce(&ArcNetHostImpl::RequestUpdateForNetwork, - weak_factory_.GetWeakPtr(), path), - kNetworkPropertyUpdateDelay); - } - } - - net_instance->ActiveNetworksChanged(std::move(network_configurations)); -} - -void ArcNetHostImpl::RequestUpdateForNetwork(const std::string& service_path) { - // TODO(hugobenichi): skip the request if the IP configuration for this - // service has been received since then and ARC has been notified about it. - pending_service_property_requests_.erase(service_path); - GetStateHandler()->RequestUpdateForNetwork(service_path); + net_instance->ActiveNetworksChanged(TranslateNetworkStates( + arc_vpn_service_path_, GetActiveNetworks(), shill_network_properties_)); } void ArcNetHostImpl::NetworkListChanged() { @@ -1109,7 +900,14 @@ void ArcNetHostImpl::NetworkListChanged() { return !IsActiveNetworkState( GetStateHandler()->GetNetworkState(entry.first)); }); - for (const auto* network : GetActiveNetworks()) + const auto active_networks = GetActiveNetworks(); + // If there is no active networks, send an explicit ActiveNetworksChanged + // event to ARC and skip updating Shill properties. + if (active_networks.empty()) { + UpdateActiveNetworks(); + return; + } + for (const auto* network : active_networks) NetworkPropertiesUpdated(network); } diff --git a/chromium/components/arc/net/arc_net_host_impl.h b/chromium/components/arc/net/arc_net_host_impl.h index 1dcde71376c..5a072af14b5 100644 --- a/chromium/components/arc/net/arc_net_host_impl.h +++ b/chromium/components/arc/net/arc_net_host_impl.h @@ -8,7 +8,6 @@ #include <stdint.h> #include <map> #include <memory> -#include <set> #include <string> #include <vector> @@ -150,8 +149,6 @@ class ArcNetHostImpl : public KeyedService, const std::string& error_name, std::unique_ptr<base::DictionaryValue> error_data); - // Request properties of the Service corresponding to |service_path|. - void RequestUpdateForNetwork(const std::string& service_path); // Callback for chromeos::NetworkHandler::GetShillProperties void ReceiveShillProperties(const std::string& service_path, const base::DictionaryValue& shill_properties); @@ -161,9 +158,6 @@ class ArcNetHostImpl : public KeyedService, // True if the chrome::NetworkStateHandler is currently being observed for // state changes. bool observing_network_state_ = false; - // Contains all service paths for which a property update request is - // currently scheduled. - std::set<std::string> pending_service_property_requests_; // Cached shill properties for all active networks, keyed by Service path. std::map<std::string, base::Value> shill_network_properties_; |