blob: 2c11a80641030dbe0d18d7956da18ddae1341545 [file] [edit]
// Copyright 2023 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "shill/mojom/mojo_service_provider.h"
#include <cstdint>
#include <memory>
#include <base/functional/bind.h>
#include <base/task/single_thread_task_runner.h>
#include <chromeos/mojo/service_constants.h>
#include <mojo/core/embedder/scoped_ipc_support.h>
#include <mojo/public/cpp/bindings/enum_utils.h>
#include <mojo_service_manager/lib/mojom/service_manager.mojom.h>
#include "shill/manager.h"
#include "shill/mojom/mojo_passpoint_service.h"
#include "shill/wifi/wifi_provider.h"
namespace shill {
// The delay of reconnecting when disconnected from the service.
constexpr base::TimeDelta kReconnectDelay = base::Seconds(1);
MojoServiceProvider::MojoServiceProvider(Manager* manager)
: ipc_thread_("Mojo IPC"), passpoint_service_(manager), manager_(manager) {}
MojoServiceProvider::~MojoServiceProvider() = default;
void MojoServiceProvider::Start() {
WiFiProvider* provider = manager_->wifi_provider();
CHECK(provider);
provider->AddPasspointCredentialsObserver(&passpoint_service_);
// TODO(b/266150324): investigate if we really need a separate IO thread.
ipc_thread_.StartWithOptions(
base::Thread::Options(base::MessagePumpType::IO, 0));
// Note: this must be called only once per process and after
// mojo::core::Init(). It works because Start() is called only once by
// DaemonTask on Shill startup.
ipc_support_ = std::make_unique<mojo::core::ScopedIPCSupport>(
ipc_thread_.task_runner(),
mojo::core::ScopedIPCSupport::ShutdownPolicy::CLEAN);
// Register the service providers
ConnectAndRegister();
}
void MojoServiceProvider::Stop() {
WiFiProvider* provider = manager_->wifi_provider();
CHECK(provider);
provider->RemovePasspointCredentialsObserver(&passpoint_service_);
if (ipc_thread_.IsRunning()) {
ipc_support_.reset();
ipc_thread_.Stop();
}
}
void MojoServiceProvider::ConnectAndRegister() {
// Connect to the service manager and watch errors.
auto pending_remote =
chromeos::mojo_service_manager::ConnectToMojoServiceManager();
if (!pending_remote.is_valid()) {
LOG(ERROR) << "Mojo service manager is not available.";
return;
}
service_manager_.Bind(std::move(pending_remote));
service_manager_.set_disconnect_with_reason_handler(
base::BindOnce(&MojoServiceProvider::OnManagerDisconnected,
weak_ptr_factory_.GetWeakPtr()));
// Register Passpoint Mojo service.
service_manager_->Register(chromeos::mojo_services::kCrosPasspointService,
receiver_.BindNewPipeAndPassRemote());
}
void MojoServiceProvider::OnManagerDisconnected(uint32_t error,
const std::string& message) {
if (error == 0) {
LOG(WARNING)
<< "Disconnected from service manager, scheduling reconnection";
// The remote service probably restarted, try to reconnect.
// TODO(b/266150324): implement a backoff or a max reconnection logic.
service_manager_.reset();
base::SingleThreadTaskRunner::GetCurrentDefault()->PostDelayedTask(
FROM_HERE,
base::BindOnce(&MojoServiceProvider::ConnectAndRegister,
weak_ptr_factory_.GetWeakPtr()),
kReconnectDelay);
return;
}
const auto error_enum = mojo::ConvertIntToMojoEnum<
chromeos::mojo_service_manager::mojom::ErrorCode>(
static_cast<int32_t>(error));
if (error_enum) {
LOG(ERROR) << "Service manager disconnected with error "
<< error_enum.value() << ", message: " << message;
} else {
LOG(ERROR) << "Service manager disconnected with error " << error
<< ", message: " << message;
}
}
void MojoServiceProvider::Request(
chromeos::mojo_service_manager::mojom::ProcessIdentityPtr identity,
mojo::ScopedMessagePipeHandle receiver) {
// The dispatch logic will be implemented here when there will be multiple
// services.
service_receiver_set_.Add(
&passpoint_service_,
mojo::PendingReceiver<chromeos::connectivity::mojom::PasspointService>(
std::move(receiver)));
}
} // namespace shill