| // Copyright 2022 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "chrome/browser/ash/net/apn_migrator.h" |
| |
| #include "ash/constants/ash_features.h" |
| #include "ash/public/cpp/network_config_service.h" |
| #include "base/containers/contains.h" |
| #include "base/values.h" |
| #include "chromeos/ash/components/login/login_state/login_state.h" |
| #include "chromeos/ash/components/network/managed_cellular_pref_handler.h" |
| #include "chromeos/ash/components/network/managed_network_configuration_handler.h" |
| #include "chromeos/ash/components/network/metrics/cellular_network_metrics_logger.h" |
| #include "chromeos/ash/components/network/network_handler.h" |
| #include "chromeos/ash/components/network/network_metadata_store.h" |
| #include "chromeos/ash/components/network/network_state_handler.h" |
| #include "chromeos/services/network_config/public/cpp/cros_network_config_util.h" |
| #include "components/device_event_log/device_event_log.h" |
| #include "third_party/cros_system_api/dbus/service_constants.h" |
| |
| namespace ash { |
| |
| namespace { |
| |
| using chromeos::network_config::mojom::ApnPropertiesPtr; |
| using chromeos::network_config::mojom::ApnState; |
| using chromeos::network_config::mojom::ApnType; |
| using chromeos::network_config::mojom::ManagedApnPropertiesPtr; |
| |
| std::optional<ApnPropertiesPtr> GetPreRevampApnFromDict( |
| const base::Value::Dict* cellular_dict, |
| const char* key) { |
| const base::Value::Dict* apn_dict = |
| chromeos::network_config::GetDictionary(cellular_dict, key); |
| if (!apn_dict) { |
| return std::nullopt; |
| } |
| |
| // Pre-revamp APNs with empty kAccessPointName will be ignored as they |
| // indicate shill tried to send a NULL APN to modemmanager. If shill |
| // uses a custom APN or modem DB APN, the kAccessPointName will be |
| // non-empty. |
| const std::string* access_point_name = |
| apn_dict->FindString(::onc::cellular_apn::kAccessPointName); |
| if (!access_point_name || access_point_name->empty()) { |
| return std::nullopt; |
| } |
| |
| return chromeos::network_config::GetApnProperties( |
| *apn_dict, |
| /*is_apn_revamp_enabled=*/false); |
| } |
| |
| std::vector<ApnType> GetMigratedApnTypes( |
| const ApnPropertiesPtr& pre_revamp_apn) { |
| if (pre_revamp_apn->attach.has_value() && |
| !(*pre_revamp_apn->attach).empty()) { |
| return {ApnType::kDefault, ApnType::kAttach}; |
| } |
| return {ApnType::kDefault}; |
| } |
| |
| } // namespace |
| |
| ApnMigrator::ApnMigrator( |
| ManagedCellularPrefHandler* managed_cellular_pref_handler, |
| ManagedNetworkConfigurationHandler* network_configuration_handler, |
| NetworkStateHandler* network_state_handler) |
| : managed_cellular_pref_handler_(managed_cellular_pref_handler), |
| network_configuration_handler_(network_configuration_handler), |
| network_state_handler_(network_state_handler) { |
| if (!NetworkHandler::IsInitialized()) { |
| return; |
| } |
| // TODO(b/162365553): Only bind this lazily when CrosNetworkConfig is actually |
| // used. |
| ash::GetNetworkConfigService( |
| remote_cros_network_config_.BindNewPipeAndPassReceiver()); |
| network_state_handler_observer_.Observe(network_state_handler_.get()); |
| } |
| |
| ApnMigrator::~ApnMigrator() = default; |
| |
| bool ApnMigrator::has_iccids_changed(base::flat_set<std::string> new_iccids, |
| base::flat_set<std::string> old_iccids) { |
| if (new_iccids.size() != old_iccids.size()) { |
| return true; |
| } |
| |
| return !std::equal(new_iccids.begin(), new_iccids.end(), old_iccids.begin()); |
| } |
| |
| base::flat_set<std::string> ApnMigrator::extract_iccids( |
| NetworkStateHandler::NetworkStateList& network_list) { |
| base::flat_set<std::string> iccids; |
| |
| for (const NetworkState* network : network_list) { |
| if (!network->iccid().empty()) { |
| iccids.insert(network->iccid()); |
| } |
| } |
| |
| return iccids; |
| } |
| |
| void ApnMigrator::ResetOldIccidsForTesting() { |
| old_iccids_.clear(); |
| } |
| |
| void ApnMigrator::NetworkListChanged() { |
| NetworkStateHandler::NetworkStateList network_list; |
| network_state_handler_->GetVisibleNetworkListByType( |
| NetworkTypePattern::Cellular(), &network_list); |
| base::flat_set<std::string> new_iccids = extract_iccids(network_list); |
| |
| if (has_iccids_changed(new_iccids, old_iccids_)) { |
| old_iccids_ = new_iccids; |
| |
| for (const NetworkState* network : network_list) { |
| // Only attempt to migrate networks known by Shill. |
| if (network->IsNonShillCellularNetwork()) { |
| continue; |
| } |
| |
| if (network->iccid().empty()) { |
| // If the network somehow has no iccid, don't attempt to migrate. |
| NET_LOG(DEBUG) << "Network has no iccid, not migrating: " |
| << network->guid(); |
| continue; |
| } |
| |
| // The network has already been updated in Shill with the correct logic |
| // depending on if the flag is enabled or disabled. Finish early so we |
| // don't redundantly update Shill. |
| if (base::Contains(shill_updated_iccids_, network->iccid())) { |
| continue; |
| } |
| |
| bool has_network_been_migrated = |
| managed_cellular_pref_handler_->ContainsApnMigratedIccid( |
| network->iccid()); |
| if (!ash::features::IsApnRevampEnabled()) { |
| // If the network has been marked as migrated, but the ApnRevamp flag is |
| // disabled, the flag was disabled after being enabled. Clear |
| // CustomApnList so that Shill knows to use legacy APN selection logic. |
| if (has_network_been_migrated) { |
| NET_LOG(EVENT) << "Network has been migrated but the revamp flag is " |
| << "disabled. Clearing CustomAPNList: " |
| << network->iccid(); |
| network_configuration_handler_->ClearShillProperties( |
| network->path(), {shill::kCellularCustomApnListProperty}, |
| base::BindOnce(&ApnMigrator::OnClearPropertiesSuccess, |
| weak_factory_.GetWeakPtr(), network->iccid()), |
| base::BindOnce(&ApnMigrator::OnClearPropertiesFailure, |
| weak_factory_.GetWeakPtr(), network->iccid(), |
| network->guid())); |
| } |
| continue; |
| } |
| |
| if (!has_network_been_migrated) { |
| NET_LOG(EVENT) |
| << "Network has not been migrated, attempting to migrate: " |
| << network->iccid(); |
| MigrateNetwork(*network); |
| continue; |
| } |
| |
| // The network has already been migrated, either the last time the flag |
| // was on, or this time. Send Shill the revamp APN list. |
| if (const base::Value::List* custom_apn_list = |
| GetNetworkMetadataStore()->GetCustomApnList(network->guid())) { |
| if (!ash::features::IsAllowApnModificationPolicyEnabled() || |
| network_configuration_handler_->AllowApnModification()) { |
| NET_LOG(EVENT) |
| << "Network has already been migrated, setting with the " |
| << "populated custom APN list: " << network->iccid(); |
| SetShillCustomApnListForNetwork(*network, custom_apn_list); |
| } else if (!network_configuration_handler_->AllowApnModification()) { |
| NET_LOG(EVENT) |
| << "Not setting custom APN list as admin has restricted " |
| "use of custom APNs"; |
| base::Value::List empty_custom_apn_list; |
| SetShillCustomApnListForNetwork(*network, &empty_custom_apn_list); |
| } |
| continue; |
| } |
| |
| NET_LOG(EVENT) << "Network has already been migrated, setting with the " |
| << "empty custom APN list: " << network->iccid(); |
| base::Value::List empty_custom_apn_list; |
| SetShillCustomApnListForNetwork(*network, &empty_custom_apn_list); |
| } |
| } |
| } |
| |
| void ApnMigrator::OnClearPropertiesSuccess(const std::string iccid) { |
| NET_LOG(EVENT) << "Successfully cleared CustomAPNList for: " << iccid; |
| shill_updated_iccids_.emplace(iccid); |
| } |
| |
| void ApnMigrator::OnClearPropertiesFailure(const std::string iccid, |
| const std::string guid, |
| const std::string& error_name) { |
| NET_LOG(ERROR) << "Failed to clear CustomAPNList for: " << iccid; |
| } |
| |
| void ApnMigrator::SetShillCustomApnListForNetwork( |
| const NetworkState& network, |
| const base::Value::List* apn_list) { |
| network_configuration_handler_->SetProperties( |
| network.path(), |
| chromeos::network_config::CustomApnListToOnc(network.guid(), apn_list), |
| base::BindOnce(&ApnMigrator::OnSetShillCustomApnListSuccess, |
| weak_factory_.GetWeakPtr(), network.iccid()), |
| base::BindOnce(&ApnMigrator::OnSetShillCustomApnListFailure, |
| weak_factory_.GetWeakPtr(), network.iccid(), |
| network.guid())); |
| } |
| |
| void ApnMigrator::OnSetShillCustomApnListSuccess(const std::string iccid) { |
| // Shill has successfully updated the network with the revamp APN list. |
| shill_updated_iccids_.emplace(iccid); |
| NET_LOG(EVENT) << "ApnMigrator: Update the custom APN " |
| << "list in Shill for network with ICCID: " << iccid; |
| |
| // The network has just been migrated. |
| if (!managed_cellular_pref_handler_->ContainsApnMigratedIccid(iccid)) { |
| CompleteMigrationAttempt(iccid, /*success=*/true); |
| } |
| } |
| |
| void ApnMigrator::OnSetShillCustomApnListFailure( |
| const std::string iccid, |
| const std::string guid, |
| const std::string& error_name) { |
| NET_LOG(ERROR) << "ApnMigrator: Failed to update the custom APN " |
| << "list in Shill for network: " << guid << ": [" << error_name |
| << ']'; |
| |
| CompleteMigrationAttempt(iccid, /*success=*/false); |
| } |
| |
| void ApnMigrator::MigrateNetwork(const NetworkState& network) { |
| DCHECK(ash::features::IsApnRevampEnabled()); |
| |
| // Return early if the network is already in the process of being migrated. |
| if (base::Contains(iccids_in_migration_, network.iccid())) { |
| NET_LOG(DEBUG) << "Attempting to migrate network that already has a " |
| << "migration in progress, returning early: " |
| << network.iccid(); |
| return; |
| } |
| |
| DCHECK(!managed_cellular_pref_handler_->ContainsApnMigratedIccid( |
| network.iccid())); |
| |
| // Get the pre-revamp APN list. |
| const base::Value::List* custom_apn_list = |
| GetNetworkMetadataStore()->GetPreRevampCustomApnList(network.guid()); |
| |
| // If the pre-revamp APN list is empty, set the revamp list as empty and |
| // finish the migration. |
| if (!custom_apn_list || custom_apn_list->empty()) { |
| NET_LOG(EVENT) << "Pre-revamp APN list is empty, sending empty list to " |
| << "Shill: " << network.iccid(); |
| base::Value::List empty_apn_list; |
| SetShillCustomApnListForNetwork(network, &empty_apn_list); |
| return; |
| } |
| |
| // If the pre-revamp APN list is non-empty, get the network's managed |
| // properties, to be used for the migration heuristic. This call is |
| // asynchronous; mark the ICCID as migrating so that the network won't |
| // be attempted to be migrated again while these properties are being fetched. |
| iccids_in_migration_.emplace(network.iccid()); |
| |
| NET_LOG(EVENT) << "Fetching managed properties for network: " |
| << network.iccid(); |
| network_configuration_handler_->GetManagedProperties( |
| LoginState::Get()->primary_user_hash(), network.path(), |
| base::BindOnce(&ApnMigrator::OnGetManagedProperties, |
| weak_factory_.GetWeakPtr(), network.iccid(), |
| network.guid())); |
| } |
| |
| void ApnMigrator::OnGetManagedProperties( |
| std::string iccid, |
| std::string guid, |
| const std::string& service_path, |
| std::optional<base::Value::Dict> properties, |
| std::optional<std::string> error) { |
| if (error.has_value()) { |
| NET_LOG(ERROR) << "Error fetching managed properties for " << iccid |
| << ", error: " << error.value(); |
| CompleteMigrationAttempt(iccid, /*success=*/false); |
| return; |
| } |
| |
| if (!properties) { |
| NET_LOG(ERROR) << "Error fetching managed properties for " << iccid; |
| CompleteMigrationAttempt(iccid, /*success=*/false); |
| return; |
| } |
| |
| const NetworkState* network = |
| network_state_handler_->GetNetworkStateFromGuid(guid); |
| if (!network) { |
| NET_LOG(ERROR) << "Network no longer exists: " << guid; |
| CompleteMigrationAttempt(iccid, /*success=*/false); |
| return; |
| } |
| |
| // Get the pre-revamp APN list. |
| const base::Value::List* custom_apn_list = |
| GetNetworkMetadataStore()->GetPreRevampCustomApnList(guid); |
| |
| // At this point, the pre-revamp APN list should not be empty. However, there |
| // could be the case where the custom APN list was cleared during the |
| // GetManagedProperties() call. If so, set the revamp list as empty and finish |
| // the migration. |
| if (!custom_apn_list || custom_apn_list->empty()) { |
| NET_LOG(EVENT) << "Custom APN list cleared during GetManagedProperties() " |
| << "call, setting Shill with empty list for network: " |
| << guid; |
| base::Value::List empty_apn_list; |
| SetShillCustomApnListForNetwork(*network, &empty_apn_list); |
| return; |
| } |
| |
| ApnPropertiesPtr pre_revamp_custom_apn = |
| chromeos::network_config::GetApnProperties( |
| custom_apn_list->front().GetDict(), |
| /*is_apn_revamp_enabled=*/false); |
| |
| NET_LOG(EVENT) << "pre_revamp_custom_apn: " |
| << pre_revamp_custom_apn->access_point_name; |
| |
| const base::Value::Dict* cellular_dict = |
| chromeos::network_config::GetDictionary(&properties.value(), |
| ::onc::network_config::kCellular); |
| std::optional<ApnPropertiesPtr> last_connected_attach_apn = |
| GetPreRevampApnFromDict(cellular_dict, |
| ::onc::cellular::kLastConnectedAttachApnProperty); |
| NET_LOG(EVENT) << "last_connected_attach_apn: " |
| << (last_connected_attach_apn.has_value() |
| ? (*last_connected_attach_apn)->access_point_name |
| : "none"); |
| |
| std::optional<ApnPropertiesPtr> last_connected_default_apn = |
| GetPreRevampApnFromDict( |
| cellular_dict, ::onc::cellular::kLastConnectedDefaultApnProperty); |
| NET_LOG(EVENT) << "last_connected_default_apn: " |
| << (last_connected_default_apn.has_value() |
| ? (*last_connected_default_apn)->access_point_name |
| : "none"); |
| |
| const bool is_network_managed = network->IsManagedByPolicy(); |
| if (is_network_managed && !last_connected_default_apn) { |
| ManagedApnPropertiesPtr selected_apn = |
| chromeos::network_config::GetManagedApnProperties( |
| cellular_dict, ::onc::cellular::kAPN); |
| if (selected_apn && pre_revamp_custom_apn->access_point_name == |
| selected_apn->access_point_name->active_value) { |
| NET_LOG(EVENT) << "Managed network's selected APN matches the saved " |
| << "custom APN, migrating APN: " << guid; |
| // Ensure the APN is enabled when it's migrated so that it's attempted |
| // to be used by the new UI. |
| pre_revamp_custom_apn->state = ApnState::kEnabled; |
| pre_revamp_custom_apn->apn_types = |
| GetMigratedApnTypes(pre_revamp_custom_apn); |
| CellularNetworkMetricsLogger::LogManagedCustomApnMigrationType( |
| CellularNetworkMetricsLogger::ManagedApnMigrationType:: |
| kMatchesSelectedApn); |
| CreateCustomApn(iccid, guid, std::move(pre_revamp_custom_apn)); |
| } else { |
| NET_LOG(EVENT) |
| << "Managed network's selected APN doesn't match the saved custom " |
| << "APN, setting Shill with empty list for network: " << guid; |
| base::Value::List empty_apn_list; |
| CellularNetworkMetricsLogger::LogManagedCustomApnMigrationType( |
| CellularNetworkMetricsLogger::ManagedApnMigrationType:: |
| kDoesNotMatchSelectedApn); |
| SetShillCustomApnListForNetwork(*network, &empty_apn_list); |
| } |
| return; |
| } |
| |
| NET_LOG(EVENT) |
| << "Migrating network with non-managed flow, is network managed: " |
| << is_network_managed; |
| |
| const bool has_last_connected_attach = last_connected_attach_apn.has_value(); |
| const bool is_last_connected_attach_custom = |
| has_last_connected_attach && |
| pre_revamp_custom_apn->access_point_name == |
| (*last_connected_attach_apn)->access_point_name; |
| |
| const bool has_last_connected_default = |
| last_connected_default_apn.has_value(); |
| const bool is_last_connected_default_custom = |
| has_last_connected_default && |
| pre_revamp_custom_apn->access_point_name == |
| (*last_connected_default_apn)->access_point_name; |
| |
| if (is_last_connected_attach_custom && is_last_connected_default_custom) { |
| NET_LOG(EVENT) << "Network's last_connected_default_apn and " |
| "last_connected_attach_apn match the " |
| << "saved custom APN, migrating APN: " << guid |
| << " in the Enabled state with Apn types Attach and Default"; |
| |
| pre_revamp_custom_apn->state = ApnState::kEnabled; |
| pre_revamp_custom_apn->apn_types = {ApnType::kAttach, ApnType::kDefault}; |
| CellularNetworkMetricsLogger::LogUnmanagedCustomApnMigrationType( |
| CellularNetworkMetricsLogger::UnmanagedApnMigrationType:: |
| kMatchesLastConnectedAttachAndDefault); |
| CreateCustomApn(iccid, guid, std::move(pre_revamp_custom_apn)); |
| return; |
| } |
| |
| if (!has_last_connected_attach && !has_last_connected_default) { |
| std::optional<ApnPropertiesPtr> last_good_apn = |
| GetPreRevampApnFromDict(cellular_dict, ::onc::cellular::kLastGoodAPN); |
| |
| if (last_good_apn && pre_revamp_custom_apn->access_point_name == |
| (*last_good_apn)->access_point_name) { |
| NET_LOG(EVENT) << "Network's last good APN matches the saved " |
| << "custom APN, migrating APN: " << guid |
| << "in the Enabled state"; |
| // Ensure the APN is enabled when it's migrated so that it's |
| // attempted to be used by the new UI. |
| pre_revamp_custom_apn->state = ApnState::kEnabled; |
| CellularNetworkMetricsLogger::LogUnmanagedCustomApnMigrationType( |
| CellularNetworkMetricsLogger::UnmanagedApnMigrationType:: |
| kMatchesLastGoodApn); |
| } else { |
| NET_LOG(EVENT) << "Network's last good APN does not match the saved " |
| << "custom APN, migrating APN: " << guid |
| << "in the Disabled state"; |
| // The custom APN was last unsuccessful in connecting when the flag was |
| // off. Preserve the details of the custom APN but with a state of |
| // Disabled. |
| pre_revamp_custom_apn->state = ApnState::kDisabled; |
| CellularNetworkMetricsLogger::LogUnmanagedCustomApnMigrationType( |
| CellularNetworkMetricsLogger::UnmanagedApnMigrationType:: |
| kDoesNotMatchLastGoodApn); |
| } |
| pre_revamp_custom_apn->apn_types = |
| GetMigratedApnTypes(pre_revamp_custom_apn); |
| CreateCustomApn(iccid, guid, std::move(pre_revamp_custom_apn)); |
| return; |
| } |
| |
| if (!has_last_connected_attach && is_last_connected_default_custom) { |
| NET_LOG(EVENT) << "Network has no last connected attach APN but has " |
| << "a last connected default APN that matches the " |
| << "saved custom APN, migrating APN: " << guid |
| << " in the Enabled state with Apn type Default"; |
| |
| pre_revamp_custom_apn->state = ApnState::kEnabled; |
| pre_revamp_custom_apn->apn_types = {ApnType::kDefault}; |
| |
| CellularNetworkMetricsLogger::LogUnmanagedCustomApnMigrationType( |
| CellularNetworkMetricsLogger::UnmanagedApnMigrationType:: |
| kMatchesLastConnectedDefaultNoLastConnectedAttach); |
| CreateCustomApn(iccid, guid, std::move(pre_revamp_custom_apn)); |
| return; |
| } |
| |
| if (has_last_connected_attach && is_last_connected_default_custom) { |
| NET_LOG(EVENT) |
| << "Only last_connected_default_apn matches " |
| "pre_revamp_custom_apn, last_connected_attach_apn exists " |
| "but does not match pre_revamp_custom_apn, migrating " |
| "last_connected_default_apn APN in enabled state with " |
| "Default and Attach type, and last_connected_attach_apn APN in " |
| "enabled state with Attach type for network: " |
| << guid; |
| CellularNetworkMetricsLogger::LogUnmanagedCustomApnMigrationType( |
| CellularNetworkMetricsLogger::UnmanagedApnMigrationType:: |
| kMatchesLastConnectedDefaultOnlyAndAttachExists); |
| |
| CreateDefaultThenAttachCustomApns(std::move(*last_connected_attach_apn), |
| std::move(*last_connected_default_apn), |
| /*can_use_default_apn_as_attach=*/true, |
| guid, iccid); |
| return; |
| } |
| |
| if (has_last_connected_default && is_last_connected_attach_custom) { |
| NET_LOG(EVENT) << "Only last_connected_attach_apn matches " |
| "pre_revamp_custom_apn, last_connected_default exists " |
| "but does not match pre_revamp_custom_apn"; |
| CellularNetworkMetricsLogger::LogUnmanagedCustomApnMigrationType( |
| CellularNetworkMetricsLogger::UnmanagedApnMigrationType:: |
| kMatchesLastConnectedAttachOnlyAndDefaultExists); |
| CreateDefaultThenAttachCustomApns(std::move(*last_connected_attach_apn), |
| std::move(*last_connected_default_apn), |
| /*can_use_default_apn_as_attach=*/false, |
| guid, iccid); |
| return; |
| } |
| |
| NET_LOG(EVENT) << "Network's last connected default APN and attach APN " |
| << "do not match the saved custom APN, migrating APN: " << guid |
| << " in the Disabled state."; |
| pre_revamp_custom_apn->state = ApnState::kDisabled; |
| pre_revamp_custom_apn->apn_types = GetMigratedApnTypes(pre_revamp_custom_apn); |
| |
| CellularNetworkMetricsLogger::LogUnmanagedCustomApnMigrationType( |
| CellularNetworkMetricsLogger::UnmanagedApnMigrationType:: |
| kNoMatchingConnectedApn); |
| CreateCustomApn(iccid, guid, std::move(pre_revamp_custom_apn)); |
| } |
| |
| void ApnMigrator::CreateDefaultThenAttachCustomApns( |
| chromeos::network_config::mojom::ApnPropertiesPtr attach_apn, |
| chromeos::network_config::mojom::ApnPropertiesPtr default_apn, |
| bool can_use_default_apn_as_attach, |
| const std::string& guid, |
| const std::string& iccid) { |
| DCHECK(!attach_apn.is_null()); |
| DCHECK(!default_apn.is_null()); |
| NET_LOG(EVENT) << "Migrating default_apn: " << default_apn->access_point_name |
| << " in the enabled state; default_apn is also type attach: " |
| << can_use_default_apn_as_attach |
| << ". Then, migrate attach_apn: " |
| << attach_apn->access_point_name |
| << " in the enabled state for Network with guid: " << guid |
| << " and iccid: " << iccid; |
| |
| attach_apn->state = ApnState::kEnabled; |
| attach_apn->apn_types = {ApnType::kAttach}; |
| |
| default_apn->state = ApnState::kEnabled; |
| if (can_use_default_apn_as_attach) { |
| default_apn->apn_types = {ApnType::kAttach, ApnType::kDefault}; |
| } else { |
| default_apn->apn_types = {ApnType::kDefault}; |
| } |
| |
| // Migrate default APN first, then attach APN in case both are to |
| // be enabled; enabled default APN must be created before enabled attach APN. |
| // See b/303565348. |
| // Also, |CompleteMigrationAttempt()| should only be called |
| // once, when both APNs have been migrated. |
| auto create_custom_attach_apn_callback = |
| base::BindOnce(&ApnMigrator::CreateCustomApn, weak_factory_.GetWeakPtr(), |
| iccid, guid, std::move(attach_apn), std::nullopt); |
| |
| auto on_create_default_apn_callback = |
| base::BindOnce( |
| [](base::OnceClosure success_callback, const std::string& guid, |
| bool success) { |
| if (success) { |
| NET_LOG(EVENT) |
| << "ApnMigrator: Succeeded migrating custom default APN " |
| "for network guid in the enabled state: " |
| << guid |
| << ", now migrating different custom attach APN in enabled " |
| "state."; |
| std::move(success_callback).Run(); |
| return; |
| } |
| NET_LOG(ERROR) |
| << "ApnMigrator: Failed to create custom default APN for " |
| "network of guid: " |
| << guid |
| << ", so will not proceed to create associated custom attach " |
| "APN"; |
| }, |
| std::move(create_custom_attach_apn_callback), guid); |
| |
| CreateCustomApn(iccid, guid, std::move(default_apn), |
| std::move(on_create_default_apn_callback)); |
| } |
| |
| void ApnMigrator::CreateCustomApn( |
| const std::string& iccid, |
| const std::string& network_guid, |
| chromeos::network_config::mojom::ApnPropertiesPtr apn, |
| std::optional<base::OnceCallback<void(bool)>> success_callback) { |
| remote_cros_network_config_->CreateCustomApn( |
| network_guid, std::move(apn), |
| success_callback ? std::move(*success_callback) |
| : base::BindOnce(&ApnMigrator::CompleteMigrationAttempt, |
| weak_factory_.GetWeakPtr(), iccid)); |
| } |
| |
| void ApnMigrator::CompleteMigrationAttempt(const std::string& iccid, |
| bool success) { |
| iccids_in_migration_.erase(iccid); |
| |
| if (success) { |
| NET_LOG(EVENT) << "ApnMigrator: Mark network with ICCID: " << iccid |
| << " as migrated"; |
| managed_cellular_pref_handler_->AddApnMigratedIccid(iccid); |
| } |
| } |
| |
| NetworkMetadataStore* ApnMigrator::GetNetworkMetadataStore() { |
| if (network_metadata_store_for_testing_) { |
| return network_metadata_store_for_testing_; |
| } |
| |
| return NetworkHandler::Get()->network_metadata_store(); |
| } |
| |
| } // namespace ash |