blob: 87ca251e3e2bb1ce978aee8e876e1e6babd440e5 [file] [log] [blame]
// Copyright 2020 The Chromium OS 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 "hermes/profile.h"
#include <memory>
#include <string>
#include <utility>
#include <base/check.h>
#include <base/optional.h>
#include <chromeos/dbus/service_constants.h>
#include "hermes/executor.h"
#include "hermes/hermes_common.h"
#include "hermes/lpa_util.h"
namespace hermes {
namespace {
const char kBasePath[] = "/org/chromium/Hermes/profile/";
base::Optional<profile::State> LpaProfileStateToHermes(
lpa::proto::ProfileState state) {
switch (state) {
case lpa::proto::DISABLED:
return profile::kInactive;
case lpa::proto::ENABLED:
return profile::kActive;
default:
LOG(ERROR) << "Unrecognized lpa ProfileState: " << state;
return base::nullopt;
}
}
base::Optional<profile::ProfileClass> LpaProfileClassToHermes(
lpa::proto::ProfileClass cls) {
switch (cls) {
case lpa::proto::TESTING:
return profile::kTesting;
case lpa::proto::PROVISIONING:
return profile::kProvisioning;
case lpa::proto::OPERATIONAL:
return profile::kOperational;
default:
LOG(ERROR) << "Unrecognized lpa ProfileClass: " << cls;
return base::nullopt;
}
}
} // namespace
// static
std::unique_ptr<Profile> Profile::Create(
const lpa::proto::ProfileInfo& profile_info,
const uint32_t physical_slot,
const std::string& eid) {
CHECK(profile_info.has_iccid());
auto profile = std::unique_ptr<Profile>(new Profile(
dbus::ObjectPath(kBasePath + eid + "/" + profile_info.iccid()),
physical_slot));
LOG(INFO) << __func__ << " Slot:" << physical_slot << " "
<< GetObjectPathForLog(profile->object_path_);
// Initialize properties.
profile->SetIccid(profile_info.iccid());
profile->SetServiceProvider(profile_info.service_provider_name());
if (profile_info.has_profile_owner()) {
profile->SetMccMnc(profile_info.profile_owner().mcc() +
profile_info.profile_owner().mnc());
}
profile->SetActivationCode(profile_info.activation_code());
auto state = LpaProfileStateToHermes(profile_info.profile_state());
if (!state.has_value()) {
LOG(ERROR) << "Failed to create Profile for iccid " << profile_info.iccid()
<< "; invalid ProfileState " << profile_info.profile_state();
return nullptr;
}
profile->SetState(state.value());
auto cls = LpaProfileClassToHermes(profile_info.profile_class());
if (!cls.has_value()) {
LOG(ERROR) << "Failed to create Profile for iccid " << profile_info.iccid()
<< "; invalid ProfileClass " << profile_info.profile_class();
return nullptr;
}
profile->SetProfileClass(cls.value());
profile->SetName(profile_info.profile_name());
profile->SetNickname(profile_info.profile_nickname());
profile->RegisterWithDBusObject(&profile->dbus_object_);
profile->dbus_object_.RegisterAndBlock();
LOG(INFO) << "Successfuly created Profile";
VLOG(2) << profile_info.DebugString();
return profile;
}
Profile::Profile(dbus::ObjectPath object_path, const uint32_t physical_slot)
: org::chromium::Hermes::ProfileAdaptor(this),
context_(Context::Get()),
object_path_(std::move(object_path)),
dbus_object_(nullptr, context_->bus(), object_path_),
physical_slot_(physical_slot),
weak_factory_(this) {}
void Profile::Enable(std::unique_ptr<DBusResponse<>> response) {
LOG(INFO) << __func__ << " " << GetObjectPathForLog(object_path_);
if (!context_->lpa()->IsLpaIdle()) {
context_->executor()->PostDelayedTask(
FROM_HERE,
base::BindOnce(&Profile::Enable, weak_factory_.GetWeakPtr(),
std::move(response)),
kLpaRetryDelay);
return;
}
if (GetState() == profile::kPending) {
response->ReplyWithError(FROM_HERE, brillo::errors::dbus::kDomain,
kErrorPendingProfile,
"Cannot enable a pending Profile object");
return;
}
LOG(INFO) << "Enabling profile: " << object_path_.value();
context_->modem_control()->StartProfileOp(physical_slot_);
context_->lpa()->EnableProfile(
GetIccid(), context_->executor(),
[response{std::shared_ptr<DBusResponse<>>(std::move(response))},
weak{weak_factory_.GetWeakPtr()}](int error) mutable {
if (weak) {
weak->context_->modem_control()->FinishProfileOp();
weak->OnEnabled(error, std::move(response));
}
});
}
void Profile::Disable(std::unique_ptr<DBusResponse<>> response) {
LOG(INFO) << __func__ << " " << GetObjectPathForLog(object_path_);
if (!context_->lpa()->IsLpaIdle()) {
context_->executor()->PostDelayedTask(
FROM_HERE,
base::BindOnce(&Profile::Disable, weak_factory_.GetWeakPtr(),
std::move(response)),
kLpaRetryDelay);
return;
}
if (GetState() == profile::kPending) {
response->ReplyWithError(FROM_HERE, brillo::errors::dbus::kDomain,
kErrorPendingProfile,
"Cannot disable a pending Profile object");
return;
}
LOG(INFO) << "Disabling profile: " << object_path_.value();
context_->modem_control()->StartProfileOp(physical_slot_);
context_->lpa()->DisableProfile(
GetIccid(), context_->executor(),
[response{std::shared_ptr<DBusResponse<>>(std::move(response))},
weak{weak_factory_.GetWeakPtr()}](int error) mutable {
if (weak) {
weak->context_->modem_control()->FinishProfileOp();
weak->OnDisabled(error, std::move(response));
}
});
}
void Profile::OnEnabled(int error, std::shared_ptr<DBusResponse<>> response) {
LOG(INFO) << __func__ << " " << GetObjectPathForLog(object_path_);
auto decoded_error = LpaErrorToBrillo(FROM_HERE, error);
if (decoded_error) {
LOG(INFO) << "Failed enabling profile: " << object_path_.value()
<< " (error " << decoded_error << ")";
response->ReplyWithError(decoded_error.get());
return;
}
VLOG(2) << "Enabled profile: " << object_path_.value();
SetState(profile::kActive);
response->Return();
}
void Profile::OnDisabled(int error, std::shared_ptr<DBusResponse<>> response) {
LOG(INFO) << __func__ << " " << GetObjectPathForLog(object_path_);
auto decoded_error = LpaErrorToBrillo(FROM_HERE, error);
if (decoded_error) {
LOG(INFO) << "Failed disabling profile: " << object_path_.value()
<< " (error " << decoded_error << ")";
response->ReplyWithError(decoded_error.get());
return;
}
VLOG(2) << "Disabled profile: " << object_path_.value();
SetState(profile::kInactive);
response->Return();
}
void Profile::SetProfileNickname(std::string nickname) {
LOG(INFO) << __func__ << " " << GetObjectPathForLog(object_path_);
if (!context_->lpa()->IsLpaIdle()) {
context_->executor()->PostDelayedTask(
FROM_HERE,
base::BindOnce(&Profile::SetProfileNickname, weak_factory_.GetWeakPtr(),
std::move(nickname)),
kLpaRetryDelay);
return;
}
context_->modem_control()->StoreAndSetActiveSlot(physical_slot_);
context_->lpa()->SetProfileNickname(
GetIccid(), nickname, context_->executor(), [this](int error) {
auto decoded_error = LpaErrorToBrillo(FROM_HERE, error);
if (decoded_error) {
LOG(ERROR) << "Failed to set profile nickname: "
<< decoded_error->GetMessage();
}
context_->modem_control()->RestoreActiveSlot();
});
}
bool Profile::ValidateNickname(brillo::ErrorPtr* /*error*/,
const std::string& value) {
SetProfileNickname(value);
return true;
}
Profile::~Profile() {
dbus_object_.UnregisterAsync();
}
} // namespace hermes