AC_DEFINE([TOR_EVENT_TRACING_ENABLED], [1], [Compile the event tracing instrumentation])
fi
+dnl Enable Android only features.
+AC_ARG_ENABLE(android,
+ AS_HELP_STRING(--enable-android, [build with Android features enabled]))
+AM_CONDITIONAL([USE_ANDROID], [test "x$enable_android" = "xyes"])
+
+if test "x$enable_android" = "xyes"; then
+ AC_DEFINE([USE_ANDROID], [1], [Compile with Android specific features enabled])
+
+ dnl Check if the Android log library is available.
+ AC_CHECK_HEADERS([android/log.h])
+ AC_SEARCH_LIBS(__android_log_write, [log])
+
+fi
+
dnl check for the correct "ar" when cross-compiling.
dnl (AM_PROG_AR was new in automake 1.11.2, which we do not yet require,
dnl so kludge up a replacement for the case where it isn't there yet.)
#define LOG_PRIVATE
#include "torlog.h"
#include "container.h"
+#ifdef HAVE_ANDROID_LOG_H
+#include <android/log.h>
+#endif // HAVE_ANDROID_LOG_H.
/** Given a severity, yields an index into log_severity_list_t.masks to use
* for that severity. */
int needs_close; /**< Boolean: true if the stream gets closed on shutdown. */
int is_temporary; /**< Boolean: close after initializing logging subsystem.*/
int is_syslog; /**< Boolean: send messages to syslog. */
+ int is_android; /**< Boolean: send messages to Android's log subsystem. */
+ char *android_tag; /**< Identity Tag used in Android's log subsystem. */
log_callback callback; /**< If not NULL, send messages to this function. */
log_severity_list_t *severities; /**< Which severity of messages should we
* log for each log domain? */
}
}
+#ifdef HAVE_ANDROID_LOG_H
+/** Helper function to convert Tor's log severity into the matching
+ * Android log priority.
+ */
+static int
+severity_to_android_log_priority(int severity)
+{
+ switch (severity) {
+ case LOG_DEBUG:
+ return ANDROID_LOG_VERBOSE;
+ case LOG_INFO:
+ return ANDROID_LOG_DEBUG;
+ case LOG_NOTICE:
+ return ANDROID_LOG_INFO;
+ case LOG_WARN:
+ return ANDROID_LOG_WARN;
+ case LOG_ERR:
+ return ANDROID_LOG_ERROR;
+ default:
+ // LCOV_EXCL_START
+ raw_assert(0);
+ return 0;
+ // LCOV_EXCL_STOP
+ }
+}
+#endif // HAVE_ANDROID_LOG_H.
+
/** A mutex to guard changes to logfiles and logging. */
static tor_mutex_t log_mutex;
/** True iff we have initialized log_mutex */
if (! (lf->severities->masks[SEVERITY_MASK_IDX(severity)] & domain)) {
return 0;
}
- if (! (lf->fd >= 0 || lf->is_syslog || lf->callback)) {
+ if (! (lf->fd >= 0 || lf->is_syslog || lf->is_android || lf->callback)) {
return 0;
}
if (lf->seems_dead) {
syslog(severity, "%s", msg_after_prefix);
#endif /* defined(MAXLINE) */
#endif /* defined(HAVE_SYSLOG_H) */
+ } else if (lf->is_android) {
+#ifdef HAVE_ANDROID_LOG_H
+ int priority = severity_to_android_log_priority(severity);
+ __android_log_write(priority, lf->android_tag, msg_after_prefix);
+#endif // HAVE_ANDROID_LOG_H.
} else if (lf->callback) {
if (domain & LD_NOCB) {
if (!*callbacks_deferred && pending_cb_messages) {
/* Don't try callback to the control port, or syslogs: We can't
* do them from a signal handler. Don't try stdout: we always do stderr.
*/
- if (lf->is_temporary || lf->is_syslog ||
+ if (lf->is_temporary || lf->is_syslog || lf->is_android ||
lf->callback || lf->seems_dead || lf->fd < 0)
continue;
if (lf->severities->masks[SEVERITY_MASK_IDX(LOG_ERR)] &
LOCK_LOGS();
for (lf = logfiles; lf; lf = lf->next) {
- if (lf->is_temporary || lf->is_syslog || lf->callback)
+ if (lf->is_temporary || lf->is_syslog || lf->is_android || lf->callback)
continue;
if (lf->filename == NULL)
continue;
return;
tor_free(victim->severities);
tor_free(victim->filename);
+ tor_free(victim->android_tag);
tor_free(victim);
}
}
#endif /* defined(HAVE_SYSLOG_H) */
+#ifdef HAVE_ANDROID_LOG_H
+/**
+ * Add a log handler to send messages to the Android platform log facility.
+ */
+int
+add_android_log(const log_severity_list_t *severity,
+ const char *android_tag)
+{
+ logfile_t *lf = NULL;
+
+ lf = tor_malloc_zero(sizeof(logfile_t));
+ lf->fd = -1;
+ lf->severities = tor_memdup(severity, sizeof(log_severity_list_t));
+ lf->filename = tor_strdup("<android>");
+ lf->is_android = 1;
+
+ if (android_tag == NULL)
+ lf->android_tag = tor_strdup("Tor");
+ else {
+ char buf[256];
+ tor_snprintf(buf, sizeof(buf), "Tor-%s", android_tag);
+ lf->android_tag = tor_strdup(buf);
+ }
+
+ LOCK_LOGS();
+ lf->next = logfiles;
+ logfiles = lf;
+ log_global_min_severity_ = get_min_log_level();
+ UNLOCK_LOGS();
+ return 0;
+}
+#endif // HAVE_ANDROID_LOG_H.
+
/** If <b>level</b> is a valid log severity, return the corresponding
* numeric value. Otherwise, return -1. */
int
if (!strcasecmpstart(cfg, "file") ||
!strcasecmpstart(cfg, "stderr") ||
!strcasecmpstart(cfg, "stdout") ||
- !strcasecmpstart(cfg, "syslog")) {
+ !strcasecmpstart(cfg, "syslog") ||
+ !strcasecmpstart(cfg, "android")) {
goto done;
}
if (got_an_unqualified_range > 1)
V(LogTimeGranularity, MSEC_INTERVAL, "1 second"),
V(TruncateLogFile, BOOL, "0"),
V(SyslogIdentityTag, STRING, NULL),
+ V(AndroidIdentityTag, STRING, NULL),
V(LongLivedPorts, CSV,
"21,22,706,1863,5050,5190,5222,5223,6523,6667,6697,8300"),
VAR("MapAddress", LINELIST, AddressMap, NULL),
return -1;
}
+ if (!opt_streq(old->AndroidIdentityTag, new_val->AndroidIdentityTag)) {
+ *msg = tor_strdup("While Tor is running, changing "
+ "AndroidIdentityTag is not allowed.");
+ return -1;
+ }
+
if ((old->HardwareAccel != new_val->HardwareAccel)
|| !opt_streq(old->AccelName, new_val->AccelName)
|| !opt_streq(old->AccelDir, new_val->AccelDir)) {
#endif /* defined(HAVE_SYSLOG_H) */
goto cleanup;
}
+
+ if (!strcasecmp(smartlist_get(elts, 0), "android")) {
+#ifdef HAVE_ANDROID_LOG_H
+ if (!validate_only) {
+ add_android_log(severity, options->AndroidIdentityTag);
+ }
+#else
+ log_warn(LD_CONFIG, "Android logging is not supported"
+ " on this system. Sorry.");
+#endif // HAVE_ANDROID_LOG_H.
+ goto cleanup;
+ }
}
if (smartlist_len(elts) == 2 &&