| // Copyright 2020 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "chromeos/services/cellular_setup/esim_manager.h" |
| |
| #include <sstream> |
| |
| #include "base/strings/utf_string_conversions.h" |
| #include "chromeos/dbus/hermes/hermes_manager_client.h" |
| #include "chromeos/network/network_event_log.h" |
| #include "chromeos/network/network_handler.h" |
| #include "chromeos/services/cellular_setup/esim_profile.h" |
| #include "chromeos/services/cellular_setup/euicc.h" |
| #include "chromeos/services/cellular_setup/public/mojom/esim_manager.mojom.h" |
| #include "components/device_event_log/device_event_log.h" |
| #include "dbus/object_path.h" |
| #include "third_party/cros_system_api/dbus/hermes/dbus-constants.h" |
| |
| namespace chromeos { |
| namespace cellular_setup { |
| namespace { |
| |
| void LogEuiccPaths(const std::set<dbus::ObjectPath>& new_euicc_paths) { |
| if (new_euicc_paths.empty()) { |
| NET_LOG(EVENT) << "EUICC list updated; no EUICCs present"; |
| return; |
| } |
| |
| std::stringstream ss("["); |
| for (const auto& new_path : new_euicc_paths) |
| ss << new_path.value() << ", "; |
| ss.seekp(-2, ss.cur); // Remove last ", " from the stream. |
| ss << "]"; |
| |
| NET_LOG(EVENT) << "EUICC list updated; paths: " << ss.str(); |
| } |
| |
| } // namespace |
| |
| ESimManager::ESimManager() |
| : ESimManager(NetworkHandler::Get()->cellular_connection_handler(), |
| NetworkHandler::Get()->cellular_esim_profile_handler(), |
| NetworkHandler::Get()->cellular_esim_uninstall_handler(), |
| NetworkHandler::Get()->cellular_inhibitor(), |
| NetworkHandler::Get()->network_connection_handler(), |
| NetworkHandler::Get()->network_state_handler()) {} |
| |
| ESimManager::ESimManager( |
| CellularConnectionHandler* cellular_connection_handler, |
| CellularESimProfileHandler* cellular_esim_profile_handler, |
| CellularESimUninstallHandler* cellular_esim_uninstall_handler, |
| CellularInhibitor* cellular_inhibitor, |
| NetworkConnectionHandler* network_connection_handler, |
| NetworkStateHandler* network_state_handler) |
| : cellular_connection_handler_(cellular_connection_handler), |
| cellular_esim_profile_handler_(cellular_esim_profile_handler), |
| cellular_esim_uninstall_handler_(cellular_esim_uninstall_handler), |
| cellular_inhibitor_(cellular_inhibitor), |
| network_connection_handler_(network_connection_handler), |
| network_state_handler_(network_state_handler) { |
| HermesManagerClient::Get()->AddObserver(this); |
| HermesEuiccClient::Get()->AddObserver(this); |
| cellular_esim_profile_handler_->AddObserver(this); |
| OnESimProfileListUpdated(); |
| } |
| |
| ESimManager::~ESimManager() { |
| HermesManagerClient::Get()->RemoveObserver(this); |
| HermesEuiccClient::Get()->RemoveObserver(this); |
| cellular_esim_profile_handler_->RemoveObserver(this); |
| } |
| |
| void ESimManager::AddObserver( |
| mojo::PendingRemote<mojom::ESimManagerObserver> observer) { |
| observers_.Add(std::move(observer)); |
| } |
| |
| void ESimManager::GetAvailableEuiccs(GetAvailableEuiccsCallback callback) { |
| std::vector<mojo::PendingRemote<mojom::Euicc>> euicc_list; |
| for (auto const& euicc : available_euiccs_) |
| euicc_list.push_back(euicc->CreateRemote()); |
| std::move(callback).Run(std::move(euicc_list)); |
| } |
| |
| void ESimManager::OnAvailableEuiccListChanged() { |
| UpdateAvailableEuiccs(); |
| } |
| |
| void ESimManager::OnEuiccPropertyChanged(const dbus::ObjectPath& euicc_path, |
| const std::string& property_name) { |
| Euicc* euicc = GetEuiccFromPath(euicc_path); |
| // Skip notifying observers if the euicc object is not tracked. |
| if (!euicc) |
| return; |
| |
| // Profile lists are handled in OnESimProfileListUpdated notification from |
| // CellularESimProfileHandler. |
| if (property_name == hermes::euicc::kPendingProfilesProperty || |
| property_name == hermes::euicc::kInstalledProfilesProperty) { |
| return; |
| } |
| euicc->UpdateProperties(); |
| for (auto& observer : observers_) |
| observer->OnEuiccChanged(euicc->CreateRemote()); |
| } |
| |
| void ESimManager::OnESimProfileListUpdated() { |
| // Force update available euiccs in case OnAvailableEuiccListChanged on this |
| // class was not called before this handler |
| UpdateAvailableEuiccs(); |
| |
| std::vector<CellularESimProfile> esim_profile_states = |
| cellular_esim_profile_handler_->GetESimProfiles(); |
| for (auto& euicc : available_euiccs_) { |
| euicc->UpdateProfileList(esim_profile_states); |
| } |
| } |
| |
| void ESimManager::BindReceiver( |
| mojo::PendingReceiver<mojom::ESimManager> receiver) { |
| NET_LOG(EVENT) << "ESimManager::BindReceiver()"; |
| receivers_.Add(this, std::move(receiver)); |
| } |
| |
| void ESimManager::NotifyESimProfileChanged(ESimProfile* esim_profile) { |
| for (auto& observer : observers_) |
| observer->OnProfileChanged(esim_profile->CreateRemote()); |
| } |
| |
| void ESimManager::NotifyESimProfileListChanged(Euicc* euicc) { |
| for (auto& observer : observers_) |
| observer->OnProfileListChanged(euicc->CreateRemote()); |
| } |
| |
| void ESimManager::UpdateAvailableEuiccs() { |
| NET_LOG(DEBUG) << "Updating available Euiccs"; |
| |
| std::set<dbus::ObjectPath> new_euicc_paths; |
| bool available_euiccs_changed = false; |
| |
| for (auto& euicc_path : HermesManagerClient::Get()->GetAvailableEuiccs()) { |
| available_euiccs_changed |= CreateEuiccIfNew(euicc_path); |
| new_euicc_paths.insert(euicc_path); |
| } |
| |
| available_euiccs_changed |= RemoveUntrackedEuiccs(new_euicc_paths); |
| |
| if (!available_euiccs_changed) |
| return; |
| |
| LogEuiccPaths(new_euicc_paths); |
| |
| for (auto& observer : observers_) |
| observer->OnAvailableEuiccListChanged(); |
| } |
| |
| bool ESimManager::RemoveUntrackedEuiccs( |
| const std::set<dbus::ObjectPath> new_euicc_paths) { |
| bool removed = false; |
| for (auto euicc_it = available_euiccs_.begin(); |
| euicc_it != available_euiccs_.end();) { |
| if (new_euicc_paths.find((*euicc_it)->path()) == new_euicc_paths.end()) { |
| removed = true; |
| euicc_it = available_euiccs_.erase(euicc_it); |
| } else { |
| euicc_it++; |
| } |
| } |
| return removed; |
| } |
| |
| bool ESimManager::CreateEuiccIfNew(const dbus::ObjectPath& euicc_path) { |
| Euicc* euicc_info = GetEuiccFromPath(euicc_path); |
| if (euicc_info) |
| return false; |
| available_euiccs_.push_back(std::make_unique<Euicc>(euicc_path, this)); |
| return true; |
| } |
| |
| Euicc* ESimManager::GetEuiccFromPath(const dbus::ObjectPath& path) { |
| for (auto& euicc : available_euiccs_) { |
| if (euicc->path() == path) { |
| return euicc.get(); |
| } |
| } |
| return nullptr; |
| } |
| |
| } // namespace cellular_setup |
| } // namespace chromeos |