aboutsummaryrefslogtreecommitdiffstats
path: root/xdg-launcher/src/runxdg.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'xdg-launcher/src/runxdg.cpp')
-rw-r--r--xdg-launcher/src/runxdg.cpp429
1 files changed, 429 insertions, 0 deletions
diff --git a/xdg-launcher/src/runxdg.cpp b/xdg-launcher/src/runxdg.cpp
new file mode 100644
index 0000000..7fca08c
--- /dev/null
+++ b/xdg-launcher/src/runxdg.cpp
@@ -0,0 +1,429 @@
+/*
+ * Copyright (c) 2017 Panasonic Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdarg.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+
+#include <cstdio>
+
+#include "runxdg.hpp"
+
+#define AFM_DBUS_SERVICE "org.AGL.afm.user"
+#define AFM_DBUS_PATH "/org/AGL/afm/user"
+#define AFM_DBUS_INTERFACE "org.AGL.afm.user"
+
+#ifdef TARGET_APP_ID
+std::string target_app_id("\"" TARGET_APP_ID "\"");
+#else
+// for test
+std::string target_app_id("\"" weston-simple-egl@0.1 "\"");
+#endif
+
+#ifdef RUNXDG_NAME
+std::string app_name(RUNXDG_NAME);
+#else
+// for test
+std::string app_name("Navigation");
+#endif
+
+void fatal(const char* format, ...)
+{
+ va_list va_args;
+ va_start(va_args, format);
+ vfprintf(stderr, format, va_args);
+ va_end(va_args);
+
+ exit(EXIT_FAILURE);
+}
+
+void warn(const char* format, ...)
+{
+ va_list va_args;
+ va_start(va_args, format);
+ vfprintf(stderr, format, va_args);
+ va_end(va_args);
+}
+
+void debug(const char* format, ...)
+{
+ va_list va_args;
+ va_start(va_args, format);
+ vfprintf(stderr, format, va_args);
+ va_end(va_args);
+}
+
+void RunXDG::notify_ivi_control_cb (ilmObjectType object, t_ilm_uint id,
+ t_ilm_bool created)
+{
+ if (object == ILM_SURFACE) {
+ struct ilmSurfaceProperties surf_props;
+
+ ilm_getPropertiesOfSurface(id, &surf_props);
+ pid_t surf_pid = surf_props.creatorPid;
+
+ if (!created) {
+ AGL_DEBUG("ivi surface (id=%d, pid=%d) destroyed.", id, surf_pid);
+ m_surfaces.erase(surf_pid);
+ return;
+ }
+
+ if (m_afm->m_rid == surf_pid) {
+ setup_surface(id);
+ }
+
+ m_surfaces[surf_pid] = id;
+ AGL_DEBUG("ivi surface (id=%d, pid=%d) is created.", id, surf_pid);
+ } else if (object == ILM_LAYER) {
+ if (created)
+ AGL_DEBUG("ivi layer: %d created.", id);
+ else
+ AGL_DEBUG("ivi layer: %d destroyed.", id);
+ }
+}
+
+void RunXDG::notify_ivi_control_cb_static (ilmObjectType object, t_ilm_uint id,
+ t_ilm_bool created, void *user_data)
+{
+ RunXDG *runxdg = static_cast<RunXDG*>(user_data);
+ runxdg->notify_ivi_control_cb(object, id, created);
+}
+
+int AFMDBus::get_dbus_message_bus (GBusType bus_type, GDBusConnection * &conn)
+{
+ GError* err = NULL;
+
+ conn = g_bus_get_sync(bus_type, NULL, &err);
+ if (err) {
+ AGL_WARN("Failed to get session bus: %s", err->message);
+ g_clear_error (&err);
+ return -1;
+ }
+
+ return 0;
+}
+
+int AFMDBus::launch (std::string &name)
+{
+ GDBusMessage* msg;
+ GDBusMessage* re;
+ GDBusConnection* conn;
+ GError* err = NULL;
+ GVariant* body;
+ char* val;
+ const char* xdg_app = name.c_str();
+
+ if (get_dbus_message_bus(G_BUS_TYPE_SESSION, conn)) {
+ return -1;
+ }
+
+ msg = g_dbus_message_new_method_call (
+ AFM_DBUS_SERVICE,
+ AFM_DBUS_PATH,
+ AFM_DBUS_INTERFACE,
+ "start");
+
+ if (msg == NULL) {
+ AGL_WARN("Failed to allocate the dbus message");
+ g_object_unref(conn);
+ return -1;
+ }
+
+ g_dbus_message_set_body(msg, g_variant_new("(s)", xdg_app));
+
+ re = g_dbus_connection_send_message_with_reply_sync (
+ conn, msg, G_DBUS_SEND_MESSAGE_FLAGS_NONE, -1, NULL, NULL, &err);
+
+ if (err != NULL) {
+ AGL_WARN("unable to send message: %s", err->message);
+ g_clear_error(&err);
+ g_object_unref(conn);
+ g_object_unref(msg);
+ return -1;
+ }
+
+ g_dbus_connection_flush_sync(conn, NULL, &err);
+ if (err != NULL) {
+ AGL_WARN("unable to flush message queue: %s", err->message);
+ g_object_unref(conn);
+ g_object_unref(msg);
+ g_object_unref(re);
+ return -1;
+ }
+
+ body = g_dbus_message_get_body(re);
+ g_variant_get(body, "(&s)", &val);
+
+ AGL_DEBUG("dbus message get (%s)", val);
+
+ m_rid = std::stol(std::string(val));
+ AGL_DEBUG("RID = %d", m_rid);
+
+ g_object_unref(conn);
+ g_object_unref(msg);
+ g_object_unref(re);
+
+ return 0;
+}
+
+volatile sig_atomic_t e_flag = 0;
+
+static void sigterm_handler (int signum)
+{
+ e_flag = 1;
+}
+
+static void init_signal (void)
+{
+ struct sigaction act, info;
+
+ /* Setup signal for SIGTERM */
+ if (!sigaction(SIGTERM, NULL, &info)) {
+ if (info.sa_handler == SIG_IGN) {
+ AGL_DEBUG("SIGTERM being ignored.");
+ } else if (info.sa_handler == SIG_DFL) {
+ AGL_DEBUG("SIGTERM being defaulted.");
+ }
+ }
+
+ act.sa_handler = &sigterm_handler;
+ if (sigemptyset(&act.sa_mask) != 0) {
+ AGL_FATAL("Cannot initialize sigaction");
+ }
+ act.sa_flags = 0;
+
+ if (sigaction(SIGTERM, &act, &info) != 0) {
+ AGL_FATAL("Cannot register signal handler for SIGTERM");
+ }
+}
+
+int RunXDG::init_wm (void)
+{
+ m_wm = new LibWindowmanager();
+ if (m_wm->init(m_port, m_token.c_str())) {
+ AGL_DEBUG("cannot initialize windowmanager");
+ return -1;
+ }
+
+ std::function< void(json_object*) > h_active= [](json_object* object) {
+ AGL_DEBUG("Got Event_Active");
+ };
+
+ std::function< void(json_object*) > h_inactive= [](json_object* object) {
+ AGL_DEBUG("Got Event_Inactive");
+ };
+
+ std::function< void(json_object*) > h_visible= [](json_object* object) {
+ AGL_DEBUG("Got Event_Visible");
+ };
+
+ std::function< void(json_object*) > h_invisible= [](json_object* object) {
+ AGL_DEBUG("Got Event_Invisible");
+ };
+
+ std::function< void(json_object*) > h_syncdraw = [this](json_object* object) {
+ AGL_DEBUG("Got Event_SyncDraw");
+ json_object* obj = json_object_new_object();
+ json_object_object_add(obj, this->m_wm->kKeyDrawingName,
+ json_object_new_string(app_name.c_str()));
+ this->m_wm->endDraw(obj);
+ };
+
+ std::function< void(json_object*) > h_flushdraw= [](json_object* object) {
+ AGL_DEBUG("Got Event_FlushDraw");
+ };
+
+ m_wm->set_event_handler(LibWindowmanager::Event_Active, h_active);
+ m_wm->set_event_handler(LibWindowmanager::Event_Inactive, h_inactive);
+ m_wm->set_event_handler(LibWindowmanager::Event_Visible, h_visible);
+ m_wm->set_event_handler(LibWindowmanager::Event_Invisible, h_invisible);
+ m_wm->set_event_handler(LibWindowmanager::Event_SyncDraw, h_syncdraw);
+ m_wm->set_event_handler(LibWindowmanager::Event_FlushDraw, h_flushdraw);
+
+ return 0;
+}
+
+int RunXDG::init_hs (void)
+{
+ m_hs = new LibHomeScreen();
+ if (m_hs->init(m_port, m_token.c_str())) {
+ AGL_DEBUG("cannot initialize homescreen");
+ return -1;
+ }
+
+ std::function< void(json_object*) > handler = [this] (json_object* object) {
+ json_object *val;
+
+ if (json_object_object_get_ex(object, "application_name", &val)) {
+ const char *name = json_object_get_string(val);
+
+ AGL_DEBUG("Event_TapShortcut <%s>", name);
+
+ if (strcmp(name, app_name.c_str()) == 0) {
+ AGL_DEBUG("Activesurface %s ", app_name.c_str());
+
+ json_object *obj = json_object_new_object();
+ json_object_object_add(obj, this->m_wm->kKeyDrawingName,
+ json_object_new_string(app_name.c_str()));
+ json_object_object_add(obj, this->m_wm->kKeyDrawingArea,
+ json_object_new_string("normal.full"));
+
+ this->m_wm->activateSurface(obj);
+ }
+ }
+ };
+ m_hs->set_event_handler(LibHomeScreen::Event_TapShortcut, handler);
+
+ std::function< void(json_object*) > h_default= [](json_object* object) {
+ const char *j_str = json_object_to_json_string(object);
+ AGL_DEBUG("Got event [%s]", j_str);
+ };
+ m_hs->set_event_handler(LibHomeScreen::Event_OnScreenMessage, h_default);
+
+ return 0;
+}
+
+RunXDG::RunXDG (int bus_type, int port, const char* &token)
+{
+ m_port = port;
+ m_token = std::string(token);
+
+ /* Setup API of AFM */
+ if (bus_type == AFM_DBUS)
+ m_afm = new AFMDBus();
+ else
+ m_afm = new AFMWebSocket();
+
+ // Setup HomeScreen/WindowManager API
+ if (init_wm())
+ AGL_FATAL("cannot setup wm API");
+
+ if (init_hs())
+ AGL_FATAL("cannot setup hs API");
+
+ // Setup ilmController API
+ m_ic = new ILMControl(notify_ivi_control_cb_static, this);
+
+ AGL_DEBUG("RunXDG created.");
+}
+
+void RunXDG::setup_surface (int id)
+{
+ std::string sid = std::to_string(id);
+
+ // This surface is mine, register pair app_name and ivi id.
+ json_object *obj = json_object_new_object();
+ json_object_object_add(obj, m_wm->kKeyDrawingName,
+ json_object_new_string(app_name.c_str()));
+ json_object_object_add(obj, m_wm->kKeyIviId,
+ json_object_new_string(sid.c_str()));
+ AGL_DEBUG("reqestSurfaceXDG(%s,%s)", app_name.c_str(), sid.c_str());
+ m_wm->requestSurfaceXDG(obj);
+
+ if (m_pending_create) {
+ // Recovering 1st time tap_shortcut is dropped because
+ // the application has not been run yet (1st time launch)
+ m_pending_create = false;
+
+ json_object *obj = json_object_new_object();
+ json_object_object_add(obj, m_wm->kKeyDrawingName,
+ json_object_new_string(app_name.c_str()));
+ json_object_object_add(obj, m_wm->kKeyDrawingArea,
+ json_object_new_string("normal.full"));
+ m_wm->activateSurface(obj);
+ }
+}
+
+void RunXDG::start (void)
+{
+ // Initialize SIGTERM handler
+ init_signal();
+
+ /* Launch XDG application */
+ int ret;
+
+ ret = m_afm->launch(target_app_id);
+ if (ret < 0) {
+ AGL_FATAL("cannot launch XDG app (%s)", target_app_id);
+ }
+
+ // take care 1st time launch
+ m_pending_create = true;
+ AGL_DEBUG("waiting for notification: surafce created");
+
+ // in case, target app has already run
+ auto itr = m_surfaces.find(m_afm->m_rid);
+ if (itr != m_surfaces.end()) {
+ int id = itr->second;
+ AGL_DEBUG("surface %d for <%s> already exists", id, app_name.c_str());
+ setup_surface(id);
+ }
+
+ /* sleep until terminate */
+ while (!e_flag) {
+ sleep(60*60*24);
+ }
+
+ if (e_flag) {
+ AGL_DEBUG("recieved SIGTERM");
+ }
+}
+
+int main (int argc, const char* argv[])
+{
+ AGL_DEBUG("runxdg: name(%s), target(%s)", app_name.c_str(),
+ target_app_id.c_str());
+
+ // Set debug flags
+ setenv("USE_HMI_DEBUG", "5", 1);
+ // setenv("WAYLAND_DEBUG", "1", 1);
+
+ // Parse args
+ long port;
+ const char* token;
+
+ if (argc < 3) {
+ AGL_FATAL("Missing port and token");
+ }
+
+ try {
+ port = std::stol(argv[1]);
+ token = argv[2];
+ } catch (const std::invalid_argument& e) {
+ AGL_FATAL("Invalid argument");
+ } catch (const std::out_of_range& e) {
+ AGL_FATAL("Out of range");
+ }
+
+ AGL_DEBUG("port=%lu, token=[%s]", port, token);
+ RunXDG runxdg(AFM_DBUS, port, token);
+
+ runxdg.start();
+
+ AGL_DEBUG("terminated.\n");
+
+ return 0;
+}
+