[vlc-devel] [PATCH] logger/android: add an option to print stdout/stderr

Thomas Guillem thomas at gllm.fr
Thu Apr 16 16:27:48 CEST 2015


By default, stdout/stderr are deactivated, i.e. they are opened on /dev/null.
If "androidlog-std" is true, stdout and stderr fd will be duplicated on a write
end of a pipe. A thread will be cloned and will print the read end of the pipe.

Standard output will be printed with "VLC-std" TAG with debug priority.
Standard error will be printed with "VLC-std" TAG with error priority.

It's not activated by default since we don't want to mess up with the
application file descriptors.
---
 modules/logger/android.c | 176 +++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 172 insertions(+), 4 deletions(-)

diff --git a/modules/logger/android.c b/modules/logger/android.c
index a89eb86..bddee2e 100644
--- a/modules/logger/android.c
+++ b/modules/logger/android.c
@@ -34,6 +34,18 @@
 #include <vlc_common.h>
 #include <vlc_plugin.h>
 
+typedef struct
+{
+    int verbosity;
+
+    int stop_pipe[2];
+    int stdout_pipe[2];
+    int stderr_pipe[2];
+    int old_stdout, old_stderr;
+
+    vlc_thread_t stdthread;
+} vlc_logger_sys_t;
+
 static const int ptr_width = 2 * /* hex digits */ sizeof (uintptr_t);
 
 static void AndroidPrintMsg(void *opaque, int type, const vlc_log_t *p_item,
@@ -41,9 +53,9 @@ static void AndroidPrintMsg(void *opaque, int type, const vlc_log_t *p_item,
 {
     int prio;
     char *format2;
-    int verbose = (intptr_t)opaque;
+    vlc_logger_sys_t *sys = opaque;
 
-    if (verbose < type)
+    if (sys->verbosity < type)
         return;
 
     int canc = vlc_savecancel();
@@ -71,23 +83,179 @@ static void AndroidPrintMsg(void *opaque, int type, const vlc_log_t *p_item,
     vlc_restorecancel(canc);
 }
 
+static ssize_t StdPrint(int fd, int prio)
+{
+    char buf[1024 + 1];
+    ssize_t ret;
+
+    ret = read(fd, buf, 1024);
+    if (ret <= 0)
+        return ret;
+
+    buf[ret] = '\0';
+    __android_log_print(prio, "VLC-std", "%s", buf);
+
+    return ret;
+}
+
+static void *StdThread(void *arg)
+{
+    vlc_logger_sys_t *sys = arg;
+
+    while (true)
+    {
+        fd_set rfds;
+        int ret, nfds;
+
+        FD_ZERO(&rfds);
+
+        FD_SET(sys->stop_pipe[0], &rfds);
+        nfds = sys->stop_pipe[0];
+
+        FD_SET(sys->stdout_pipe[0], &rfds);
+        if (sys->stdout_pipe[0] > nfds)
+            nfds = sys->stdout_pipe[0];
+
+        FD_SET(sys->stderr_pipe[0], &rfds);
+        if (sys->stderr_pipe[0] > nfds)
+            nfds = sys->stderr_pipe[0];
+
+        ret = select(nfds + 1, &rfds, NULL, NULL, NULL);
+
+        if (ret == -1)
+            break;
+        else if (ret == 0)
+            continue;
+
+        if (FD_ISSET(sys->stop_pipe[0], &rfds))
+            break;
+
+        if (FD_ISSET(sys->stdout_pipe[0], &rfds)
+         && StdPrint(sys->stdout_pipe[0], ANDROID_LOG_DEBUG) <= 0)
+            break;
+
+        if (FD_ISSET(sys->stderr_pipe[0], &rfds)
+         && StdPrint(sys->stderr_pipe[0], ANDROID_LOG_ERROR) <= 0)
+            break;
+    }
+    return NULL;
+}
+
+static void ClosePipe(int *pipe)
+{
+    if (pipe[0] != -1)
+    {
+        close(pipe[0]);
+        pipe[0] = -1;
+    }
+    if (pipe[1] != -1)
+    {
+        close(pipe[1]);
+        pipe[1] = -1;
+    }
+}
+
+static void CleanUp(vlc_logger_sys_t *sys)
+{
+    if (sys->stop_pipe[1] != -1)
+    {
+        write(sys->stop_pipe[1], '\0', 1);
+        close(sys->stop_pipe[1]);
+        sys->stop_pipe[1] = -1;
+        vlc_join(sys->stdthread, NULL);
+    }
+    ClosePipe(sys->stop_pipe);
+    ClosePipe(sys->stdout_pipe);
+    ClosePipe(sys->stderr_pipe);
+
+    if (sys->old_stdout != -1 && sys->old_stderr != -1) {
+        dup2(sys->old_stdout, STDOUT_FILENO);
+        dup2(sys->old_stderr, STDERR_FILENO);
+        close(sys->old_stdout);
+        close(sys->old_stderr);
+        sys->old_stdout = sys->old_stderr = -1;
+    }
+}
+
 static vlc_log_cb Open(vlc_object_t *obj, void **sysp)
 {
+    vlc_logger_sys_t *sys = NULL;
     int verbosity = var_InheritInteger(obj, "verbose");
 
     if (verbosity < 0)
         return NULL;
 
-    *sysp = (void *)(uintptr_t)verbosity;
+    sys = calloc(1, sizeof (vlc_logger_sys_t));
+    if (!sys)
+        return NULL;
+
+    sys->verbosity = verbosity;
+    sys->stop_pipe[0] = sys->stop_pipe[1] =
+    sys->stdout_pipe[0] = sys->stdout_pipe[1] =
+    sys->old_stdout = sys->old_stderr = -1;
+    *sysp = sys;
+
+    /* By default, stdout/stderr are deactivated, i.e. they are opened on
+     * /dev/null. If androidlog-std is true, stdout and stderr fd will be
+     * duplicated on a write end of a pipe. A thread will be cloned and will
+     * print the read end of the pipe. */
+    if (!var_InheritBool(obj, "androidlog-std"))
+        return AndroidPrintMsg;
+
+    /* save the old stdout/stderr fd to restore it when logged is closed */
+    sys->old_stdout = dup(STDOUT_FILENO);
+    sys->old_stderr = dup(STDERR_FILENO);
+    if (sys->old_stdout == -1 || sys->old_stderr == -1)
+        goto bailout;
+
+    /* duplicate stdout */
+    if (pipe(sys->stdout_pipe) == -1)
+        goto bailout;
+    if (dup2(sys->stdout_pipe[1], STDOUT_FILENO) == -1)
+        goto bailout;
 
+    /* duplicate stderr */
+    if (pipe(sys->stderr_pipe) == -1)
+        goto bailout;
+    if (dup2(sys->stderr_pipe[1], STDERR_FILENO) == -1)
+        goto bailout;
+
+    /* pipe to signal the thread to stop */
+    if (pipe(sys->stop_pipe) == -1)
+        goto bailout;
+
+    if (vlc_clone(&sys->stdthread, StdThread, sys, VLC_THREAD_PRIORITY_LOW))
+    {
+        ClosePipe(sys->stop_pipe);
+        goto bailout;
+    }
+
+    return AndroidPrintMsg;
+bailout:
+    CleanUp(sys);
     return AndroidPrintMsg;
 }
 
+static void Close(void *opaque)
+{
+    vlc_logger_sys_t *sys = opaque;
+    CleanUp(sys);
+    free(sys);
+}
+
+#define ANDROIDLOG_STD_TEXT N_("Log stdout/stderr")
+#define ANDROIDLOG_STD_LONGTEXT N_( \
+    "On android, stdout and stderr are deactivated by default." \
+    "If set to true, the standard output and error will be printed " \
+    "via logcat with the 'VLC-std' TAG.")
+
 vlc_module_begin()
     set_shortname(N_("Android log"))
     set_description(N_("Android log using logcat"))
     set_category(CAT_ADVANCED)
     set_subcategory(SUBCAT_ADVANCED_MISC)
     set_capability("logger", 30)
-    set_callbacks(Open, NULL)
+    set_callbacks(Open, Close)
+    add_bool("androidlog-std", false, ANDROIDLOG_STD_TEXT,
+             ANDROIDLOG_STD_LONGTEXT, true)
 vlc_module_end ()
-- 
2.1.3




More information about the vlc-devel mailing list