blob: bff293e8d71f4ca70ff4f44bf60b8088436e2250 [file] [log] [blame]
// Copyright 2021 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 "oobe_config/network_exporter.h"
#include <memory>
#include <string>
#include <utility>
#include <base/bind.h>
#include <base/check.h>
#include <base/files/file_util.h>
#include <base/files/scoped_file.h>
#include <base/logging.h>
#include <base/memory/scoped_refptr.h>
#include <base/optional.h>
#include <base/threading/thread_task_runner_handle.h>
#include <base/time/time.h>
#include <brillo/dbus/dbus_connection.h>
#include <brillo/message_loops/base_message_loop.h>
#include <chromeos/dbus/service_constants.h>
#include <dbus/bus.h>
#include <dbus/message.h>
#include <dbus/object_proxy.h>
#include <dbus/object_path.h>
#include <mojo/core/embedder/embedder.h>
#include <mojo/core/embedder/scoped_ipc_support.h>
#include <mojo/public/cpp/bindings/pending_remote.h>
#include <mojo/public/cpp/bindings/remote.h>
#include <mojo/public/cpp/platform/platform_channel_endpoint.h>
#include <mojo/public/cpp/platform/platform_handle.h>
#include <mojo/public/cpp/system/invitation.h>
#include "mojom/rollback_network_config.mojom.h"
#include "oobe_config/rollback_constants.h"
namespace oobe_config {
namespace {
using chromeos::rollback_network_config::mojom::RollbackNetworkConfig;
std::unique_ptr<brillo::BaseMessageLoop> InitMessageLoop() {
DCHECK(!brillo::MessageLoop::ThreadHasCurrent());
auto message_loop = std::make_unique<brillo::BaseMessageLoop>();
message_loop->SetAsCurrent();
return message_loop;
}
scoped_refptr<dbus::Bus> InitDBus(brillo::DBusConnection* dbus_connection) {
return dbus_connection->Connect();
}
std::unique_ptr<mojo::core::ScopedIPCSupport> InitMojo() {
mojo::core::Init();
return std::make_unique<mojo::core::ScopedIPCSupport>(
base::ThreadTaskRunnerHandle::Get(),
mojo::core::ScopedIPCSupport::ShutdownPolicy::FAST);
}
mojo::Remote<RollbackNetworkConfig> BootstrapMojoConnection(dbus::Bus* bus) {
dbus::ObjectProxy* proxy = bus->GetObjectProxy(
::mojo_connection_service::kMojoConnectionServiceServiceName,
dbus::ObjectPath(
::mojo_connection_service::kMojoConnectionServiceServicePath));
dbus::MethodCall bootstrap_method_call(
::mojo_connection_service::kMojoConnectionServiceInterface,
::mojo_connection_service::
kBootstrapMojoConnectionForRollbackNetworkConfigMethod);
dbus::MessageWriter writer(&bootstrap_method_call);
std::unique_ptr<dbus::Response> bootstrap_response =
proxy->CallMethodAndBlock(&bootstrap_method_call, /*timeout_ms=*/25000);
if (!bootstrap_response) {
LOG(ERROR) << "Failed to establish dbus connection to Chrome. No response.";
return mojo::Remote<RollbackNetworkConfig>();
}
base::ScopedFD file_handle;
dbus::MessageReader reader(bootstrap_response.get());
if (!reader.PopFileDescriptor(&file_handle) || !file_handle.is_valid()) {
LOG(ERROR) << "Failed to set up mojo connection. Chrome did not return a "
"valid file descriptor.";
return mojo::Remote<RollbackNetworkConfig>();
}
if (!base::SetCloseOnExec(file_handle.get())) {
LOG(ERROR) << "Failed to set close on exec for file descriptor. Not "
"establishing mojo connection.";
return mojo::Remote<RollbackNetworkConfig>();
}
mojo::IncomingInvitation invitation =
mojo::IncomingInvitation::Accept(mojo::PlatformChannelEndpoint(
mojo::PlatformHandle(std::move(file_handle))));
return mojo::Remote<RollbackNetworkConfig>(
mojo::PendingRemote<RollbackNetworkConfig>(
invitation.ExtractMessagePipe(0), 0u));
}
void SaveNetworkConfig(brillo::BaseMessageLoop* message_loop,
std::string* config_out,
const std::string& onc_network_config) {
*config_out = onc_network_config;
message_loop->BreakLoop();
}
std::string FetchNetworkConfigs(
const mojo::Remote<RollbackNetworkConfig>& network_config_remote,
brillo::BaseMessageLoop* message_loop) {
std::string config;
network_config_remote.get()->RollbackConfigExport(
base::BindOnce(&SaveNetworkConfig, message_loop, &config));
// Schedule timeout after 90s.
message_loop->PostDelayedTask(
FROM_HERE, base::BindOnce([]() {
LOG(ERROR) << "Fetching network configuration timed out";
DCHECK(brillo::MessageLoop::current());
brillo::MessageLoop::current()->BreakLoop();
}),
base::TimeDelta::FromSeconds(90));
// Wait until the configuration was fetched.
message_loop->Run();
return config;
}
} // namespace
base::Optional<std::string> ExportNetworkConfig() {
brillo::DBusConnection dbus_connection;
auto bus = InitDBus(&dbus_connection);
// Initializing mojo requires that the current thread has an associated
// message loop.
std::unique_ptr<brillo::BaseMessageLoop> message_loop = InitMessageLoop();
auto ipc_support = InitMojo();
mojo::Remote<RollbackNetworkConfig> network_config_remote =
BootstrapMojoConnection(bus.get());
if (network_config_remote.is_bound()) {
return FetchNetworkConfigs(network_config_remote, message_loop.get());
}
return base::nullopt;
}
} // namespace oobe_config