diff options
author | 2022-09-10 12:15:20 -0400 | |
---|---|---|
committer | 2022-09-10 12:30:27 -0400 | |
commit | c52afaf8b5c96136fe20e5d5a1332121d3b09ee9 (patch) | |
tree | 4f749a779cdf92abb7e49fee7398b8e0e2ef852a /src/AppLauncherImpl.cc | |
parent | c675bafdf15cc19276bd8276c34f56404a5ecb62 (diff) |
Add gRPC API implementation
Changes:
- Rename the existing daemon to applaunchd-dbus, and add a new
version that exposes a gRPC based implementation of the API based
on the protobuf definition added in a top-level protos directory.
Having both the D-Bus and gRPC APIs exposed by a single daemon was
posing difficulties around startup dependencies stemming from D-Bus
activation of the daemon. Since the end goal is dropping the D-Bus
API entirely, it is easier to just add a second daemon for gRPC that
will eventually be the only one present.
- To facilitate building the two implementations, a significant amount
of code refactoring has been done to move things from the D-Bus API
implementing app_launcher.[ch] to systemd_manager.[ch] so the code
can be reused.
- All use of the systemd D-Bus library except for the path encoding
helper function has been replaced with GDBus. The systemd interface
wrapper code was generated with gdbus-codegen from XML files captured
via introspection on a running system. The motivation for this
change was to avoid multithreading issues with sd_bus exposed when
calling into it from the gRPC threads.
- The copyright headers in the source files have been tweaked to
remove the Apache license boilerplate in favour of a SPDX license
tag.
Notes:
- The gRPC API differs slightly from the D-Bus one in that it has a
single status streaming RPC method as opposed to the separate signals
for application started or terminated that the D-Bus API has.
- The gRPC API is currently unauthenticated, the aim is to circle back
and implement authentication once a consensus can be reached on what
mechanism should be used (fixed JWT configuration, OAuth, etc.).
Bug-AGL: SPEC-4559
Signed-off-by: Scott Murray <scott.murray@konsulko.com>
Change-Id: I828f38a58b60e9959162b98054982124d4fa4380
Diffstat (limited to 'src/AppLauncherImpl.cc')
-rw-r--r-- | src/AppLauncherImpl.cc | 137 |
1 files changed, 137 insertions, 0 deletions
diff --git a/src/AppLauncherImpl.cc b/src/AppLauncherImpl.cc new file mode 100644 index 0000000..d691120 --- /dev/null +++ b/src/AppLauncherImpl.cc @@ -0,0 +1,137 @@ +// SPDX-License-Identifier: Apache-2.0 +/* + * Copyright (C) 2022 Konsulko Group + */ + +#include <AppLauncherImpl.h> +#include <systemd_manager.h> + +using grpc::StatusCode; +using automotivegradelinux::AppStatus; + + +AppLauncherImpl::AppLauncherImpl(SystemdManager *manager) : + m_manager(manager) +{ + systemd_manager_connect_callbacks(m_manager, + G_CALLBACK(started_cb), + G_CALLBACK(terminated_cb), + this); +} + +Status AppLauncherImpl::StartApplication(ServerContext* context, + const StartRequest* request, + StartResponse* response) +{ + if (!m_manager) + return Status(StatusCode::INTERNAL, "Initialization failed"); + + // Search the apps list for the given app-id + std::string app_id = request->id(); + auto dbus_launcher_info = systemd_manager_get_app_info(m_manager, app_id.c_str()); + if (!dbus_launcher_info) { + std::string error("Unknown application '"); + error += app_id; + error += "'"; + return Status(StatusCode::INVALID_ARGUMENT, error); + } + + gboolean status = systemd_manager_start_app(m_manager, dbus_launcher_info); + response->set_status(status); + if (!status) { + // Maybe just return StatusCode::NOT_FOUND instead? + std::string error("Failed to start application '"); + error += app_id; + error += "'"; + response->set_message(error); + } + + return Status::OK; +} + +Status AppLauncherImpl::ListApplications(ServerContext* context, + const ListRequest* request, + ListResponse* response) +{ + if (!m_manager) + return Status(StatusCode::INTERNAL, "Initialization failed"); + + GList *apps = systemd_manager_get_app_list(m_manager); + if (!apps) + return Status::OK; // Perhaps return failure here? + + guint len = g_list_length(apps); + for (guint i = 0; i < len; i++) { + struct _AppInfo *app_info = (struct _AppInfo*) g_list_nth_data(apps, i); + auto info = response->add_apps(); + info->set_id(app_info_get_app_id(app_info)); + info->set_name(app_info_get_name(app_info)); + info->set_icon_path(app_info_get_icon_path(app_info)); + } + + return Status::OK; +} + +Status AppLauncherImpl::GetStatusEvents(ServerContext* context, + const StatusRequest* request, + ServerWriter<StatusResponse>* writer) +{ + + // Save client information + m_clients_mutex.lock(); + m_clients.push_back(std::pair(context, writer)); + m_clients_mutex.unlock(); + + // For now block until client disconnect / server shutdown + // A switch to the async or callback server APIs might be more elegant than + // holding the thread like this, and may be worth investigating at some point. + std::unique_lock lock(m_done_mutex); + m_done_cv.wait(lock, [context, this]{ return (context->IsCancelled() || m_done); }); + + return Status::OK; +} + + +void AppLauncherImpl::SendStatus(std::string id, std::string status) +{ + const std::lock_guard<std::mutex> lock(m_clients_mutex); + + if (m_clients.empty()) + return; + + StatusResponse response; + auto app_status = response.mutable_app(); + app_status->set_id(id); + app_status->set_status(status); + + auto it = m_clients.begin(); + while (it != m_clients.end()) { + if (it->first->IsCancelled()) { + // Client has gone away, remove from list + std::cout << "Removing cancelled RPC client!" << std::endl; + it = m_clients.erase(it); + + // We're not exiting, but wake up blocked client RPC handlers so + // the canceled one will clean exit. + // Note that in practice this means the client RPC handler thread + // sticks around until the next status event is sent. + m_done_cv.notify_all(); + + continue; + } else { + it->second->Write(response); + ++it; + } + } +} + +void AppLauncherImpl::HandleAppStarted(std::string id) +{ + SendStatus(id, "started"); +} + +void AppLauncherImpl::HandleAppTerminated(std::string id) +{ + SendStatus(id, "terminated"); +} + |