blob: 03916033a1ddbfe322c06d4add6bc307ef523b9e [file] [log] [blame]
// Copyright 2016 The Fuchsia 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 <fuchsia/hardware/power/statecontrol/cpp/fidl.h>
#include <fuchsia/modular/internal/cpp/fidl.h>
#include <fuchsia/modular/session/cpp/fidl.h>
#include <lib/async-loop/cpp/loop.h>
#include <lib/async-loop/default.h>
#include <lib/fit/defer.h>
#include <lib/fit/function.h>
#include <lib/sys/cpp/component_context.h>
#include <lib/sys/inspect/cpp/component.h>
#include <lib/syslog/cpp/log_settings.h>
#include <lib/syslog/cpp/macros.h>
#include <lib/trace-provider/provider.h>
#include "src/lib/files/directory.h"
#include "src/lib/files/path.h"
#include "src/lib/fxl/command_line.h"
#include "src/modular/bin/basemgr/basemgr_impl.h"
#include "src/modular/bin/basemgr/cobalt/cobalt.h"
#include "src/modular/lib/modular_config/modular_config.h"
#include "src/modular/lib/modular_config/modular_config_accessor.h"
#include "src/modular/lib/modular_config/modular_config_constants.h"
#include "zircon/system/ulib/inspect/include/lib/inspect/cpp/vmo/types.h"
// Command-line command to delete the persistent configuration.
constexpr std::string_view kDeletePersistentConfigCommand = "delete_persistent_config";
fit::deferred_action<fit::closure> SetupCobalt(bool enable_cobalt, async_dispatcher_t* dispatcher,
sys::ComponentContext* component_context) {
if (!enable_cobalt) {
return fit::defer<fit::closure>([] {});
}
return modular::InitializeCobalt(dispatcher, component_context);
};
std::unique_ptr<modular::BasemgrImpl> CreateBasemgrImpl(
modular::ModularConfigAccessor config_accessor, sys::ComponentContext* component_context,
async::Loop* loop) {
fit::deferred_action<fit::closure> cobalt_cleanup = SetupCobalt(
config_accessor.basemgr_config().enable_cobalt(), loop->dispatcher(), component_context);
return std::make_unique<modular::BasemgrImpl>(
std::move(config_accessor), component_context->outgoing(),
component_context->svc()->Connect<fuchsia::sys::Launcher>(),
component_context->svc()->Connect<fuchsia::ui::policy::Presenter>(),
component_context->svc()->Connect<fuchsia::hardware::power::statecontrol::Admin>(),
/*on_shutdown=*/
[loop, cobalt_cleanup = std::move(cobalt_cleanup), component_context]() mutable {
cobalt_cleanup.call();
component_context->outgoing()->debug_dir()->RemoveEntry(modular_config::kBasemgrConfigName);
loop->Quit();
});
}
inspect::StringProperty AddConfigToInspect(const modular::ModularConfigReader& config_reader,
sys::ComponentInspector* inspector) {
FX_DCHECK(inspector);
auto config_json = modular::ConfigToJsonString(config_reader.GetConfig());
inspect::Node& inspect_root = inspector->root();
return inspect_root.CreateString(modular_config::kInspectConfig, config_json);
}
std::string GetUsage() {
return R"(Usage: basemgr [<command>]
<command>
(none) Launches basemgr.
delete_persistent_config Deletes any existing persistent configuration, and exits.
basemgr cannot be launched from the shell. Please use `basemgr_launcher` or `run`.
)";
}
int main(int argc, const char** argv) {
syslog::SetTags({"basemgr"});
auto config_reader = modular::ModularConfigReader::CreateFromNamespace();
auto config_writer = modular::ModularConfigWriter::CreateFromNamespace();
// Process command line arguments.
const auto command_line = fxl::CommandLineFromArgcArgv(argc, argv);
const auto& positional_args = command_line.positional_args();
if (positional_args.size() == 1 && positional_args[0] == kDeletePersistentConfigCommand) {
if (auto result = config_writer.Delete(); result.is_error()) {
std::cerr << result.take_error() << std::endl;
return EXIT_FAILURE;
}
std::cout << "Deleted persistent configuration." << std::endl;
return EXIT_SUCCESS;
}
if (!positional_args.empty()) {
std::cerr << GetUsage() << std::endl;
return EXIT_FAILURE;
}
// Read configuration.
auto config_result = config_reader.ReadAndMaybePersistConfig(&config_writer);
if (config_result.is_error()) {
std::cerr << config_result.take_error() << std::endl;
return EXIT_FAILURE;
}
async::Loop loop(&kAsyncLoopConfigAttachToCurrentThread);
trace::TraceProviderWithFdio trace_provider(loop.dispatcher());
std::unique_ptr<sys::ComponentContext> component_context(
sys::ComponentContext::CreateAndServeOutgoingDirectory());
auto inspector = std::make_unique<sys::ComponentInspector>(component_context.get());
auto config_property = AddConfigToInspect(config_reader, inspector.get());
auto basemgr_impl = CreateBasemgrImpl(modular::ModularConfigAccessor(config_result.take_value()),
component_context.get(), &loop);
// NOTE: component_controller.events.OnDirectoryReady() is triggered when a
// component's out directory has mounted. basemgr_launcher uses this signal
// to determine when basemgr has completed initialization so it can detach
// and stop itself. When basemgr_launcher is used, it's responsible for
// providing basemgr a configuration file. To ensure we don't shutdown
// basemgr_launcher too early, we need additions to out/ to complete after
// configurations have been parsed.
component_context->outgoing()->debug_dir()->AddEntry(
modular_config::kBasemgrConfigName,
std::make_unique<vfs::Service>([basemgr_impl = basemgr_impl.get()](
zx::channel request, async_dispatcher_t* /* unused */) {
basemgr_impl->Connect(
fidl::InterfaceRequest<fuchsia::modular::internal::BasemgrDebug>(std::move(request)));
}));
loop.Run();
// The loop will run until graceful shutdown is complete so returning SUCCESS here indicates that.
return EXIT_SUCCESS;
}