[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