headless_debug: add debug features 03/207203/1
authorSung-Jin Park <sj76.park@samsung.com>
Mon, 20 May 2019 11:44:50 +0000 (20:44 +0900)
committerSung-Jin Park <sj76.park@samsung.com>
Thu, 30 May 2019 08:34:58 +0000 (17:34 +0900)
headless_debug provides some debug features such as wayland protocol
trace (event trace), redirection of STDOUT/STDERR, displaying keygrab
status, top-visible stack of windows and connected clients information.

Intially, enabling/disabling event trace features and redirection have
been added. The rest of the features will be added soon.

Change-Id: I800249045e785988a59fd2e5b904c98a00436e3f
Signed-off-by: Sung-Jin Park <sj76.park@samsung.com>
data/units/display-manager.service.headless
src/bin/headless/Makefile.am
src/bin/headless/debug/debug.c [new file with mode: 0644]
src/bin/headless/headless_server.c
src/bin/headless/headless_server.h

index 35ecc6b..5b4663d 100644 (file)
@@ -5,6 +5,7 @@ Description=Headless Display Manager
 Type=simple
 EnvironmentFile=/etc/sysconfig/display-manager.env
 SmackProcessLabel=System
+ExecStartPre=/usr/bin/bash -c "/usr/bin/mkdir -p ${XDG_RUNTIME_DIR}/pepper/"
 ExecStart=/usr/bin/headless_server
 
 [Install]
index 88e6f44..1cdb324 100644 (file)
@@ -6,6 +6,7 @@ headless_server_CFLAGS = $(HEADLESS_SERVER_CFLAGS)
 headless_server_LDADD  = $(HEADLESS_SERVER_LIBS)
 
 headless_server_SOURCES = headless_server.c \
+                         debug/debug.c \
                          input/input.c \
                          output/output_led.c \
                          output/HL_UI_LED_APA102.c \
diff --git a/src/bin/headless/debug/debug.c b/src/bin/headless/debug/debug.c
new file mode 100644 (file)
index 0000000..e840822
--- /dev/null
@@ -0,0 +1,273 @@
+/*
+* Copyright © 2018 Samsung Electronics co., Ltd. All Rights Reserved.
+*
+* 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 (including the next
+* paragraph) 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 <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#include <pepper.h>
+#include <wayland-server.h>
+#include <pepper-inotify.h>
+
+#define MAX_CMDS       256
+
+#define STDOUT_REDIR           "stdout"
+#define STDERR_REDIR                   "stderr"
+#define EVENT_TRACE_ON         "event_trace_on"
+#define EVENT_TRACE_OFF                "event_trace_off"
+#define KEYGRAB_STATUS         "keygrab_status"
+#define TOPVWINS                       "topvwins"
+#define CONNECT_CLIENTS                "connect_clients"
+#define HELP_MSG                       "help"
+
+extern void wl_debug_server_enable(int enable);
+
+typedef struct
+{
+       pepper_compositor_t *compositor;
+       pepper_inotify_t *inotify;
+} headless_debug_t;
+
+typedef void (*headless_debug_action_cb_t)(headless_debug_t *hd, void *data);
+
+typedef struct 
+{
+   const char *cmds;
+   headless_debug_action_cb_t cb;
+   headless_debug_action_cb_t disable_cb;
+} headless_debug_action_t;
+
+const static int KEY_DEBUG = 0xdeaddeb0;
+
+static void
+_headless_debug_usage()
+{
+       fprintf(stdout, "Commands:\n\n");
+       fprintf(stdout, "\t %s\n", EVENT_TRACE_ON);
+       fprintf(stdout, "\t %s\n", EVENT_TRACE_OFF);
+       fprintf(stdout, "\t %s\n", STDOUT_REDIR);
+       fprintf(stdout, "\t %s\n", STDERR_REDIR);
+       fprintf(stdout, "\t %s\n", KEYGRAB_STATUS);
+       fprintf(stdout, "\t %s\n", TOPVWINS);
+       fprintf(stdout, "\t %s\n", CONNECT_CLIENTS);
+       fprintf(stdout, "\t %s\n", HELP_MSG);
+
+       fprintf(stdout, "\nTo execute commands, just create/remove/update a file with the commands above.\n");
+       fprintf(stdout, "Please refer to the following examples.\n\n");
+       fprintf(stdout, "\t touch %s to enable event trace\n", EVENT_TRACE_ON);
+       fprintf(stdout, "\t rm -f %s to disable event trace\n", EVENT_TRACE_ON);
+       fprintf(stdout, "\t touch %s to disable event trace\n", EVENT_TRACE_OFF);
+       fprintf(stdout, "\t touch stdout to redirect STDOUT to stdout.txt\n");
+       fprintf(stdout, "\t touch stderr to redirect STDERR to stderr.txt\n");
+}
+
+static void
+_headless_debug_event_trace_on(headless_debug_t *hdebug, void *data)
+{
+       (void) hdebug;
+       (void) data;
+       wl_debug_server_enable(1);
+}
+
+static void
+_headless_debug_event_trace_off(headless_debug_t *hdebug, void *data)
+{
+       (void) hdebug;
+       (void) data;
+       wl_debug_server_enable(0);
+}
+
+static void
+_headless_debug_dummy(headless_debug_t *hdebug, void *data)
+{
+       (void) hdebug;
+       (void) data;
+       _headless_debug_usage();
+}
+
+static void
+_headless_debug_redir_stdout(headless_debug_t *hdebug, void *data)
+{
+       (void) hdebug;
+       (void) data;
+
+       static int fd = -1;
+
+       if (fd >= 0)
+               close(fd);
+
+       fd = open("/run/pepper/stdout.txt", O_CREAT | O_WRONLY | O_APPEND, S_IWUSR | S_IWGRP);
+
+       if (fd < 0) {
+               PEPPER_TRACE("Failed to open stdout.txt (errno=%s)\n", strerror(errno));
+               return;
+       }
+
+       dup2(fd, 1);
+       PEPPER_TRACE("STDOUT has been redirected to stdout.txt.\n");
+}
+
+static void
+_headless_debug_redir_stderr(headless_debug_t *hdebug, void *data)
+{
+       (void) hdebug;
+       (void) data;
+
+       static int fd = -1;
+
+       if (fd >= 0)
+               close(fd);
+
+       fd = open("/run/pepper/stderr.txt", O_CREAT | O_WRONLY | O_APPEND, S_IWUSR | S_IWGRP);
+
+       if (fd < 0) {
+               PEPPER_TRACE("Failed to open stderr.txt (errno=%s)\n", strerror(errno));
+               return;
+       }
+
+       dup2(fd, 2);
+       PEPPER_TRACE("STDERR has been redirected to stderr.txt.\n");
+
+}
+
+static const headless_debug_action_t debug_actions[] = 
+{
+       { STDOUT_REDIR,  _headless_debug_redir_stdout, NULL },
+       { STDERR_REDIR,  _headless_debug_redir_stderr, NULL },
+       { EVENT_TRACE_ON,  _headless_debug_event_trace_on, _headless_debug_event_trace_off },
+       { EVENT_TRACE_OFF, _headless_debug_event_trace_off, NULL },
+       { KEYGRAB_STATUS, _headless_debug_dummy, NULL },
+       { TOPVWINS, _headless_debug_dummy, NULL },
+       { CONNECT_CLIENTS, _headless_debug_dummy, NULL },
+       { HELP_MSG, _headless_debug_dummy, NULL },
+};
+
+static void
+_headless_debug_enable_action(headless_debug_t *hdebug, char *cmds)
+{
+       int n_actions = sizeof(debug_actions)/sizeof(debug_actions[0]);
+
+       for(int n=0 ; n < n_actions ; n++) {
+               if (!strncmp(cmds, debug_actions[n].cmds, MAX_CMDS)) {
+                       debug_actions[n].cb(hdebug, (void *)debug_actions[n].cmds);
+                       PEPPER_TRACE("[%s : %s]\n", __FUNCTION__, debug_actions[n].cmds);
+
+                       break;
+               }
+       }       
+}
+
+static void
+_headless_debug_disable_action(headless_debug_t *hdebug, char *cmds)
+{
+       int n_actions = sizeof(debug_actions)/sizeof(debug_actions[0]);
+
+       for(int n=0 ; n < n_actions ; n++) {
+               if (!strncmp(cmds, debug_actions[n].cmds, MAX_CMDS)) {
+                       if (debug_actions[n].disable_cb) {
+                               debug_actions[n].disable_cb(hdebug, (void *)debug_actions[n].cmds);
+                               PEPPER_TRACE("[%s : %s]\n", __FUNCTION__, debug_actions[n].cmds);
+                       }
+
+                       break;
+               }
+       }
+}
+
+static void
+_trace_cb_handle_inotify_event(uint32_t type, pepper_inotify_event_t *ev, void *data)
+{
+       headless_debug_t *hdebug = data;
+       char *file_name = pepper_inotify_event_name_get(ev);
+
+       PEPPER_CHECK(hdebug, return, "Invalid headless debug instance\n");
+
+       switch (type)
+       {
+               case PEPPER_INOTIFY_EVENT_TYPE_CREATE:
+                       _headless_debug_enable_action(hdebug, file_name);
+                       break;
+               case PEPPER_INOTIFY_EVENT_TYPE_REMOVE:
+                       _headless_debug_disable_action(hdebug, file_name);
+                       break;
+               case PEPPER_INOTIFY_EVENT_TYPE_MODIFY:
+                       _headless_debug_enable_action(hdebug, file_name);
+                       break;
+
+               default:
+                       PEPPER_TRACE("[%s] Unhandled event type (%d)\n", __FUNCTION__, type);
+                       break;
+       }
+}
+
+PEPPER_API void
+headless_debug_deinit(pepper_compositor_t * compositor)
+{
+       headless_debug_t *hdebug = NULL;
+
+       hdebug = (headless_debug_t *)pepper_object_get_user_data((pepper_object_t *) compositor, &KEY_DEBUG);
+       PEPPER_CHECK(hdebug, return, "Failed to get headless debug instance\n");
+
+       /* remove the directory watching already */
+       if (hdebug->inotify)
+               pepper_inotify_del(hdebug->inotify, "/run/pepper");
+
+       /* remove inotify */
+       pepper_inotify_destroy(hdebug->inotify);
+       hdebug->inotify = NULL;
+
+       pepper_object_set_user_data((pepper_object_t *)hdebug->compositor, &KEY_DEBUG, NULL, NULL);
+       free(hdebug);
+}
+
+pepper_bool_t
+headless_debug_init(pepper_compositor_t *compositor)
+{
+       headless_debug_t *hdebug = NULL;
+       pepper_inotify_t *inotify = NULL;
+       pepper_bool_t res = PEPPER_FALSE;
+
+       hdebug = (headless_debug_t*)calloc(1, sizeof(headless_debug_t));
+       PEPPER_CHECK(hdebug, goto error, "Failed to alloc for headless debug\n");
+       hdebug->compositor = compositor;
+
+       /* create inotify to watch file(s) for event trace */
+       inotify = pepper_inotify_create(hdebug->compositor, _trace_cb_handle_inotify_event, hdebug);
+       PEPPER_CHECK(inotify, goto error, "Failed to create inotify\n");
+
+       /* add a directory for watching */
+       res = pepper_inotify_add(inotify, "/run/pepper");
+       PEPPER_CHECK(res, goto error, "Failed on pepper_inotify_add()\n");
+
+       hdebug->inotify = inotify;
+
+       PEPPER_TRACE("[%s] ... done\n", __FUNCTION__);
+
+       pepper_object_set_user_data((pepper_object_t *)compositor, &KEY_DEBUG, hdebug, NULL);
+       return PEPPER_TRUE;
+
+error:
+       headless_debug_deinit(compositor);
+
+       return PEPPER_FALSE;
+}
index 99a81be..1627589 100644 (file)
@@ -57,6 +57,10 @@ int main(int argc, char *argv[])
        compositor = pepper_compositor_create(socket_name);
        PEPPER_CHECK(compositor, return EXIT_FAILURE, "Failed to create compositor !");
 
+       /* Init event trace */
+       ret = headless_debug_init(compositor);
+       PEPPER_CHECK(ret, goto end, "headless_debug_init() failed\n");
+
        /* Init input for headless */
        ret = headless_input_init(compositor);
        PEPPER_CHECK(ret, goto end, "headless_input_init() failed\n");
@@ -80,6 +84,7 @@ end:
        headless_shell_deinit(compositor);
        headless_input_deinit(compositor);
        headless_output_deinit(compositor);
+       headless_debug_deinit(compositor);
        pepper_compositor_destroy(compositor);
 
        return EXIT_SUCCESS;
index 7a72496..42f28ef 100644 (file)
@@ -44,6 +44,10 @@ PEPPER_API void headless_input_deinit(pepper_compositor_t *compositor);
 PEPPER_API void headless_input_set_focus_view(pepper_compositor_t *compositor, pepper_view_t *view);
 PEPPER_API void headless_input_set_top_view(pepper_compositor_t *compositor, pepper_view_t *view);
 
+/* APIs for headless_debug */
+PEPPER_API pepper_bool_t headless_debug_init(pepper_compositor_t *compositor);
+PEPPER_API void headless_debug_deinit(pepper_compositor_t *compositor);
+
 #ifdef __cplusplus
 }
 #endif