blob: 15a6281e9a9651ae59e45a501ea8ae6432dd3b6a [file] [log] [blame]
// Copyright 2021 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/network/cellular_policy_handler.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/time/time.h"
#include "chromeos/dbus/hermes/hermes_profile_client.h"
#include "chromeos/network/cellular_esim_installer.h"
#include "chromeos/network/cellular_utils.h"
#include "chromeos/network/managed_network_configuration_handler.h"
#include "chromeos/network/network_event_log.h"
#include "chromeos/network/network_profile_handler.h"
#include "chromeos/network/policy_util.h"
namespace chromeos {
namespace {
const int kInstallRetryLimit = 3;
constexpr net::BackoffEntry::Policy kRetryBackoffPolicy = {
0, // Number of initial errors to ignore.
5 * 60 * 1000, // Initial delay of 5 minutes in ms.
2.0, // Factor by which the waiting time will be multiplied.
0, // Fuzzing percentage.
60 * 60 * 1000, // Maximum delay of 1 hour in ms.
-1, // Never discard the entry.
true, // Use initial delay.
};
} // namespace
CellularPolicyHandler::InstallPolicyESimRequest::InstallPolicyESimRequest(
const std::string& smdp_address,
const base::Value& onc_config)
: smdp_address(smdp_address),
onc_config(onc_config.Clone()),
retry_backoff(&kRetryBackoffPolicy) {}
CellularPolicyHandler::InstallPolicyESimRequest::~InstallPolicyESimRequest() =
default;
CellularPolicyHandler::CellularPolicyHandler() = default;
CellularPolicyHandler::~CellularPolicyHandler() = default;
void CellularPolicyHandler::Init(
CellularESimInstaller* cellular_esim_installer,
NetworkProfileHandler* network_profile_handler,
ManagedNetworkConfigurationHandler* managed_network_configuration_handler) {
cellular_esim_installer_ = cellular_esim_installer;
network_profile_handler_ = network_profile_handler;
managed_network_configuration_handler_ =
managed_network_configuration_handler;
}
void CellularPolicyHandler::InstallESim(const std::string& smdp_address,
const base::Value& onc_config) {
PushRequestAndProcess(
std::make_unique<InstallPolicyESimRequest>(smdp_address, onc_config));
}
void CellularPolicyHandler::ProcessRequests() {
if (remaining_install_requests_.empty())
return;
// Another install request is already underway; wait until it has completed
// before starting a new request.
if (is_installing_)
return;
is_installing_ = true;
NET_LOG(EVENT)
<< "Starting installing policy eSIM profile with SMDP address: "
<< GetCurrentSmdpAddress();
AttemptInstallESim();
}
void CellularPolicyHandler::AttemptInstallESim() {
DCHECK(is_installing_);
absl::optional<dbus::ObjectPath> euicc_path = GetCurrentEuiccPath();
if (!euicc_path) {
NET_LOG(ERROR) << "Error installing policy eSIM profile for SMDP address: "
<< GetCurrentSmdpAddress() << ": euicc is not found.";
PopRequest();
ProcessRequests();
return;
}
NET_LOG(EVENT) << "Attempt installing policy eSIM profile with SMDP address: "
<< GetCurrentSmdpAddress()
<< " on euicc path: " << euicc_path->value();
const NetworkProfile* profile =
network_profile_handler_->GetProfileForUserhash(
/*userhash=*/std::string());
const std::string* guid =
remaining_install_requests_.front()->onc_config.FindStringKey(
::onc::network_config::kGUID);
DCHECK(guid);
base::Value new_shill_properties = policy_util::CreateShillConfiguration(
*profile, *guid, /*global_policy=*/nullptr,
&(remaining_install_requests_.front()->onc_config),
/*user_settings=*/nullptr);
NET_LOG(EVENT) << "Install policy eSIM profile with properties: "
<< new_shill_properties;
// Remote provisioning of eSIM profiles via SMDP address in policy does not
// require confirmation code.
cellular_esim_installer_->InstallProfileFromActivationCode(
GetCurrentSmdpAddress(), /*confirmation_code=*/std::string(), *euicc_path,
std::move(new_shill_properties),
base::BindOnce(
&CellularPolicyHandler::OnESimProfileInstallAttemptComplete,
weak_ptr_factory_.GetWeakPtr()));
}
const std::string& CellularPolicyHandler::GetCurrentSmdpAddress() const {
DCHECK(is_installing_);
return remaining_install_requests_.front()->smdp_address;
}
void CellularPolicyHandler::OnESimProfileInstallAttemptComplete(
HermesResponseStatus hermes_status,
absl::optional<dbus::ObjectPath> profile_path,
absl::optional<std::string> service_path) {
DCHECK(is_installing_);
auto current_request = std::move(remaining_install_requests_.front());
PopRequest();
if (hermes_status == HermesResponseStatus::kSuccess) {
NET_LOG(EVENT) << "Successfully installed eSIM profile with SMDP address: "
<< current_request->smdp_address;
current_request->retry_backoff.InformOfRequest(/*succeeded=*/true);
managed_network_configuration_handler_->NotifyPolicyAppliedToNetwork(
*service_path);
ProcessRequests();
return;
}
if (current_request->retry_backoff.failure_count() >= kInstallRetryLimit) {
NET_LOG(ERROR) << "Install policy eSIM profile with SMDP address: "
<< current_request->smdp_address << " failed "
<< kInstallRetryLimit << " times.";
ProcessRequests();
return;
}
current_request->retry_backoff.InformOfRequest(/*succeeded=*/false);
base::TimeDelta retry_delay =
current_request->retry_backoff.GetTimeUntilRelease();
NET_LOG(ERROR) << "Install policy eSIM profile failed. Retrying in "
<< retry_delay;
base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
FROM_HERE,
base::BindOnce(&CellularPolicyHandler::PushRequestAndProcess,
weak_ptr_factory_.GetWeakPtr(),
std::move(current_request)),
retry_delay);
ProcessRequests();
}
void CellularPolicyHandler::PushRequestAndProcess(
std::unique_ptr<InstallPolicyESimRequest> request) {
remaining_install_requests_.push_back(std::move(request));
ProcessRequests();
}
void CellularPolicyHandler::PopRequest() {
remaining_install_requests_.pop_front();
is_installing_ = false;
if (remaining_install_requests_.empty()) {
const NetworkProfile* profile =
network_profile_handler_->GetProfileForUserhash(
/*userhash=*/std::string());
DCHECK(profile);
managed_network_configuration_handler_->OnCellularPoliciesApplied(*profile);
}
}
} // namespace chromeos